Skip to content

Instantly share code, notes, and snippets.

@sburns
Last active July 9, 2018 08:35
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sburns/7eab2d8229bd9e6ff222 to your computer and use it in GitHub Desktop.
Save sburns/7eab2d8229bd9e6ff222 to your computer and use it in GitHub Desktop.
This is a 5-minute (hahaha yeah right) demo of some things you might not have thought to do with the jupyter notebook to make it a good dev environment.

tmux all the things

$ tmux new -s demo

Make & activate a virtualenv

pyenv virtualenv 3.5.0 demo
pyenv activate demo
python --version

Install jupyter

pip install jupyter

That's going to give you everything you need to boot up the notebook

Start the server

mkdir demo && cd demo
jupyter notebook

First trick: Importing notebooks

Hook into python's importer a way to discover & import notebooks

We need a way to execute code everytime a jupyter session (console or notebook) starts up

Open a notebook terminal...

vim ~/.ipython/profile_default/startup/00.py

Paste this...

import io, os, sys, types
from IPython import get_ipython
import nbformat
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 = ['']
    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 Jupyter 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, self.path)

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

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


        # 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['cells']:
            if cell['cell_type'] == 'code':
                # transform the input to executable Python
                code = self.shell.input_transformer_manager.transform_cell(cell['source'])
                # 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 Jupyter 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]


# Finally register the hook
sys.meta_path.append(NotebookFinder())

(protip: Use a powerline font in your browser for fixed-width fonts)

  • No need to restart the server :)

Demo with foo.ipynb and bar.ipynb

foo.ipynb

First cell is cookies = ['chocolate', 'oatmeal', 'peanut butter']

bar.ipynb

from foo import cookies
print(cookies)

Remember, it's some crazy terminal/editor/REPL thingy!

In the terminal that's open...

TMUX= tmux attach -t demo

COOL!

To detach and return to sanity, tmux detach-client

Little bit a fun django stuff

pip install django
django-admin.py startproject pynash
cd pynash
DJANGO_SETTINGS_MODULE=pynash.settings jupyter notebook

Start a new notebook called manage.ipynb

!./manage.py startapp talks
(edit pynash.settings and add talks to INSTALLED_APPS)

(edit talks.models and add this class):

class Talk(models.Model):
    topic = models.CharField(max_length=200)
    speaker = models.CharField(max_length=200)
    given_at = models.DateField()
---
!./manage.py makemigrations
!./manage.py migrate

---
from talks.models import Talk
from datetime import date

talks = [
    ('Scott Burns', 'Jupyter: You can do what???'),
    ('Bill Israel', 'python -m pynash.talk'),
    ('Ryan Osborne', 'Beginner\'s Toolkit'),
    ('Brian Pitts', 'Load Testing with Locust'),
    ('Chad Upjohn', 'Spark: dataframe'),
    ('Andrew Wright', 'Pillow: The friendly PIL fork'),
    ('Sophie Rapoport', 'Demystifying Python with (dis)assembly'),
    ('Jason Myers', 'Intro to Directed Graphs'),
]

for (speaker, topic) in talks:
    Talk.objects.create(topic=topic, speaker=speaker, given_at=date.today())

---
from django.template import Context, Template
from IPython.core.display import HTML

template_string = '''
<table>
    <thead>
        <tr>
            <th>Speaker</th>
            <th>Topic</th>
        </tr>
    </thead>
    <tbody>
    {% for talk in talks %}
        <tr>
            <td>{{ talk.speaker }}</td>
            <td>{{ talk.topic }}</td>
        </tr>
    {% endfor %}
    </tbody>
</table>
'''

context = Context({'talks': Talk.objects.all()})
template = Template(template_string)
HTML(template.render(context))

---

!git init
!git add -A
!git commit -m"initial commit"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment