1

I have a function stored in a .py file, call it my_methods.

def print_text(myText):
    print myText

I'm using ipython notebook to do my development (local server), and the my_methods file is frequently changing.

I'd like to use runipy to run other ipython notebooks via a shell script that reference the functions within my_methods. For example, one ipython notebook being launched from a shell script would look like this:

import my_methods as mm

mm.print_text("print me")

How do I set this up so that the import my_methods line can get the print_text function from the ipython notebook (.ipynb), instead of the .py version? Currently, I'd have to download the my_methods notebook as a .py file, which is causing version control issues (the .ipynb version of my_methods is different than the downloaded .py version)

Thanks for the help!

EDIT

So after reading through the blog post that was shown as the answer I made a slight modification to the find_notebook function. If a path for the ipython notebook isn't supplied,I just had it read through sys.path, rather than the current directory. I'm also not running on a linux machine like they were, so it made it easier for me to maintain all of my added python files in a separate directory, which is included in my path variable. I saved the following code in a module called iPyLoader, and then import it first in my other modules:

import io, os, sys, types
from IPython import get_ipython
from IPython.nbformat import current
from IPython.core.interactiveshell import InteractiveShell

def find_notebook(fullname, path=None):
    """find a notebook, given its fully qualified name and an optional path

    This turns "foo.bar" into "foo/bar.ipynb"
    and tries turning "Foo_Bar" into "Foo Bar" if Foo_Bar
    does not exist.
    """
    name = fullname.rsplit('.', 1)[-1]
    if not path:
        path = sys.path #EDITED HERE RATHER THAN CURRENT DIRECTORY
    for d in path:
        nb_path = os.path.join(d, name + ".ipynb")
        if os.path.isfile(nb_path):
            return nb_path
        # let import Notebook_Name find "Notebook Name.ipynb"
        nb_path = nb_path.replace("_", " ")
        if os.path.isfile(nb_path):
            return nb_path

class NotebookLoader(object):
    """Module Loader for IPython Notebooks"""
    def __init__(self, path=None):
        self.shell = InteractiveShell.instance()
        self.path = path

    def load_module(self, fullname):
        """import a notebook as a module"""
        path = find_notebook(fullname)

        print ("importing IPython notebook from %s" % path)

        # load the notebook object
        with io.open(path, 'r', encoding='utf-8') as f:
            nb = current.read(f, 'json')


        # create the module and add it to sys.modules
        # if name in sys.modules:
        #    return sys.modules[name]
        mod = types.ModuleType(fullname)
        mod.__file__ = path
        mod.__loader__ = self
        mod.__dict__['get_ipython'] = get_ipython
        sys.modules[fullname] = mod

        # extra work to ensure that magics that would affect the user_ns
        # actually affect the notebook module's ns
        save_user_ns = self.shell.user_ns
        self.shell.user_ns = mod.__dict__

        try:
          for cell in nb.worksheets[0].cells:
            if cell.cell_type == 'code' and cell.language == 'python':
                # transform the input to executable Python
                code = self.shell.input_transformer_manager.transform_cell(cell.input)
                # run the code in themodule
                exec(code, mod.__dict__)
        finally:
            self.shell.user_ns = save_user_ns
        return mod

class NotebookFinder(object):
    """Module finder that locates IPython Notebooks"""
    def __init__(self):
        self.loaders = {}

    def find_module(self, fullname, path=None):
        nb_path = find_notebook(fullname, path)
        if not nb_path:
            return

        key = path
        if path:
            # lists aren't hashable
            key = os.path.sep.join(path)

        if key not in self.loaders:
            self.loaders[key] = NotebookLoader(path)
        return self.loaders[key]

sys.meta_path.append(NotebookFinder())

then my sample file might run something like this

import iPyLoader
import testnotebook as printer #this is an .ipynb file
printer.myprinter("test")

and the output would be:

importing IPython notebook from C:\Python27\lib\testnotebook.ipynb
test
3
  • 1
    I guess you are looking for this Commented Apr 22, 2015 at 19:48
  • Good enough for government work, thanks! Commented Apr 22, 2015 at 19:53
  • Caution. This executes all cells in the notebook. It does not simply import a class or function by name. Commented Mar 25, 2021 at 4:24

1 Answer 1

1

A good approximation is exposed here.

Easy way not exist because ipython notebook is not regular plain text.

Sign up to request clarification or add additional context in comments.

1 Comment

yup that should do it, thanks

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.