In [ ]:
# See below the first header for documentation
# The code until then is bootstrap. It relies on an excessive number of hacks

# Do not allow the remainder of this file to be imported using the "import" statement
# The bootstrap process is designed for nbinclude instead of the import statement
#NBIMPORT_STOP

# This first cell is the only one run using the three-line nbinclude shim
try:
    nbinclude
except NameError:
    # Define nbinclude, if it is not already defined
    # Uses the variable "nbinclude_f" to get the path to "nbinclude.ipynb", so it can
    # be added to the module search path
    def nbinclude(nbfile, root=nbinclude_f.name):
        global __name__

        import io
        import IPython.nbformat.current
        import os

        # Find the notebook file
        if not nbfile.endswith(".ipynb"):
                nbfile = nbfile + ".ipynb"

        # Hacky notebook-finder. TODO: replace with the less hacky version below
        if not os.path.isfile(nbfile):
            candidate = os.path.join(os.getcwd(), nbfile)
            if os.path.isfile(candidate):
                nbfile = candidate
            else:
                candidate = os.path.join(get_ipython().config.NotebookManager.notebook_dir, nbfile)
                if os.path.isfile(candidate):
                    nbfile=candidate
                else:
                    candidate = os.path.join(os.path.dirname(root), nbfile)
                    if os.path.isfile(candidate):
                        nbfile = candidate

        if not os.path.isfile(nbfile):
            raise IOError, 'Notebook "{}" not found'.format(nbfile)

        # Read it
        with io.open(nbfile) as f:
            nb = IPython.nbformat.current.read(f, 'json')

        # Execute the cells in it
        ip = get_ipython()
        old_name = __name__
        __name__ = os.path.basename(nbfile).split(".ipynb")[0].replace(" ", "")
        for cell in nb.worksheets[0].cells:
            if cell.cell_type != 'code':
                continue
            inp = cell.input
            stop = False
            if "#" + "NBINCLUDE_STOP" in inp:
                inp = inp.split("#" + "NBINCLUDE_STOP")[0]
                stop = True
            ip.run_cell(inp)
            if stop:
                break
        __name__ = old_name
        
    # Now that nbinclude is available, we can run the remainder of this notebook until NBINCLUDE_STOP
    nbinclude("nbinclude")

This code sets up the python import statement for use with notebooks

It has been borrowed from: http://nbviewer.ipython.org/github/ipython/ipython/blob/master/examples/Notebook/Importing%20Notebooks.ipynb

Now that everything has been set up, don't let nbinclude read any farther into the documentation part of the file


In [ ]:
#NBINCLUDE_STOP

Documentation

Setup

This system allows importing and including IPython notebooks from other IPython notebooks.

Quite naturally, it is a notebook itself.

Other notebooks need access to nbinclude in order to use it. Since it's a notebook in itself, the following shim is required to import it:


In [1]:
# Cross-notebook include shim
with open("/home/nikita/dev/ipython-notebooks/nbtools/nbinclude.ipynb") as nbinclude_f: # don't rename nbinclude_f
    import IPython.nbformat.current
    get_ipython().run_cell(IPython.nbformat.current.read(nbinclude_f, 'json').worksheets[0].cells[0].input)

Adding this shim to your notebook file will enable the behavior below

Cross-notebook python-style imports

Notebooks can now be imported as if they were Python modules, for example:


In [2]:
import nbinclude as nbi


importing IPython notebook from /home/nikita/dev/ipython-notebooks/nbtools/nbinclude.ipynb

Importing normally reads all code cells in the notebook file.

One way to protect against this is the standard guard:


In [ ]:
if __name__ == "__main__":
    print "This code will not run if the notebook is imported via the import statement

The other is to use the #NBIMPORT_STOP macro (exact spelling - no space after the #). Everything in the notebook that is after this macro will not be run when the notebook is imported using the import statement

Cross-notebook c-style includes

C-style includes for notebooks are also supported:


In [ ]:
# Searches for notebooks relative to the following locations:
# 1. As absolute path
# 2. Relative to the current working directory
# 3. Relative to the default notebook folder
# 4. Relative to the folder that contains nbinclude.ipynb
nbinclude("nbinclude.ipynb")

In [ ]:
# Omitting the ".ipynb" works, too
nbinclude("nbinclude")

In [ ]:
# So do absolute paths
nbinclude("/home/nikita/dev/ipython-notebooks/nbtools/nbinclude.ipynb")

In [ ]:
# And absolute paths that omit the ".ipynb"
nbinclude("/home/nikita/dev/ipython-notebooks/nbtools/nbinclude")

The classic guard works here, too:


In [ ]:
if __name__ == "__main__":
    print "This code will not run if the notebook is imported via nbinclude"

There is also a magic macro, #NBINCLUDE_STOP (exact spelling). The remainder of the cell containing the macro, and any cells after it, will not be read by the nbinclude system.

This is useful for separating cells at the beginning of the notebook (which contain function definitions you want to include), from cells at the end of the notebook (that you don't want to include)

#NBINCLUDE_STOP and NBIMPORT_STOP are distinct macros on purpose.


In [12]:
%%file nbinclude2.py
# See below the first header for documentation
# The code until then is bootstrap. It relies on an excessive number of hacks

# Do not allow the remainder of this file to be imported using the "import" statement
# The bootstrap process is designed for nbinclude instead of the import statement
#NBIMPORT_STOP

# This first cell is the only one run using the three-line nbinclude shim
with open("nbinclude.ipynb") as nbinclude_f:
    import IPython.nbformat.current
    try:
        nbinclude
    except NameError:
        # Define nbinclude, if it is not already defined
        # Uses the variable "nbinclude_f" to get the path to "nbinclude.ipynb", so it can
        # be added to the module search path
    #     nbinclude_f = open("nbinclude.ipynb")
        print nbinclude_f.name
        def nbinclude(nbfile, root=nbinclude_f.name):
            global __name__

            import io
            import IPython.nbformat.current
            import os

            # Find the notebook file
            if not nbfile.endswith(".ipynb"):
                    nbfile = nbfile + ".ipynb"

            # Hacky notebook-finder. TODO: replace with the less hacky version below
            if not os.path.isfile(nbfile):
                candidate = os.path.join(os.getcwd(), nbfile)
                if os.path.isfile(candidate):
                    nbfile = candidate
                else:
                    candidate = os.path.join(get_ipython().config.NotebookManager.notebook_dir, nbfile)
                    if os.path.isfile(candidate):
                        nbfile=candidate
                    else:
                        candidate = os.path.join(os.path.dirname(root), nbfile)
                        if os.path.isfile(candidate):
                            nbfile = candidate

            if not os.path.isfile(nbfile):
                raise IOError, 'Notebook "{}" not found'.format(nbfile)

            # Read it
            with io.open(nbfile) as f:
                nb = IPython.nbformat.current.read(f, 'json')

            # Execute the cells in it
            ip = get_ipython()
            old_name = __name__
            __name__ = os.path.basename(nbfile).split(".ipynb")[0].replace(" ", "")
            for cell in nb.worksheets[0].cells:
                if cell.cell_type != 'code':
                    continue
                inp = cell.input
                stop = False
                if "#" + "NBINCLUDE_STOP" in inp:
                    inp = inp.split("#" + "NBINCLUDE_STOP")[0]
                    stop = True
                ip.run_cell(inp)
                if stop:
                    break
            __name__ = old_name

        # Now that nbinclude is available, we can run the remainder of this notebook until NBINCLUDE_STOP
        nbinclude("nbinclude")


Overwriting nbinclude2.py

In [ ]: