# Add jupyter sandbox in orchestrator

Managers Git in progress
dev-linux
Ivan Maslov 2 years ago
parent 417e18b389
commit e12168e384

@ -0,0 +1,6 @@
{
"python.defaultInterpreterPath": "${workspaceFolder}/Resources/WPy64-3720/python-3.7.2.amd64/python.exe",
"editor.fontSize": 16,
"editor.fontWeight": "700",
"autoDocstring.docstringFormat": "sphinx"
}

@ -35,4 +35,14 @@ def SettingsUpdate(inGSettings):
#Add RobotRDPActive in control panel
inGSettings["ControlPanelDict"]["RobotList"].append({"RenderFunction": ControlPanelRenderDict, "KeyStr": "VersionCheck"})
#Orchestrator.Managers.ControlPanel(inControlPanelNameStr="TestTTT",inRefreshHTMLJinja2TemplatePathStr="ControlPanel\\test.html", inJinja2TemplateRefreshBool = True)
lProcess = Orchestrator.Managers.ProcessInitSafe(inAgentHostNameStr="IVANMASLOV-DESKTOP",inAgentUserNameStr="ND",
inProcessNameWOExeStr="notepad",inStartCMDStr="notepad",inStopSafeTimeoutSecFloat=3)
# Some test
#lProcess.ScheduleStatusCheckEverySeconds(inIntervalSecondsInt=5)
#Orchestrator.OrchestratorScheduleGet().every(2).seconds.do(Orchestrator.OrchestratorThreadStart,
# lProcess.StartCheck)
#Orchestrator.OrchestratorScheduleGet().every(5).seconds.do(Orchestrator.OrchestratorThreadStart,lProcess.StatusCheckStart)
#lProcess.Start()
lGit = Orchestrator.Managers.Git(inAgentHostNameStr="IVANMASLOV-DESKTOP",inAgentUserNameStr="ND",inGitPathStr="")
return inGSettings

@ -13,7 +13,7 @@ from pyOpenRPA import Orchestrator # Import orchestrator main
if not Orchestrator.OrchestratorIsAdmin():
Orchestrator.OrchestratorRerunAsAdmin()
print(f"Orchestrator will be run as administrator!")
elif __name__ == "__main__": # New init way - allow run as module -m PyOpenRPA.Orchestrator
else:
gSettings = Orchestrator.GSettingsGet()
#gSettings = SettingsTemplate.Create(inModeStr="BASIC") # Create GSettings with basic configuration - no more config is available from the box - you can create own
@ -32,6 +32,4 @@ elif __name__ == "__main__": # New init way - allow run as module -m PyOpenRPA.O
lPyModules = Orchestrator.OrchestratorPySearchInit(inGlobPatternStr="ControlPanel\\CP_*.py", inDefStr="SettingsUpdate", inDefArgNameGSettingsStr="inGSettings")
# Call the orchestrator def
Orchestrator.Orchestrator(inGSettings=gSettings, inDumpRestoreBool=False)
else:
print("!WARNING! Current orchestrator settings do not support old type of the Orchestrator start. Use new Orchestrator type start (see v1.2.0)")

@ -0,0 +1,139 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Start orchestrator from the jupyter (sandbox)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import sys\n",
"# Set cwd to the orc wd\n",
"os.chdir(\"..\")\n",
"# %%capture # Use it if you want to toggle off output\n",
"import OrchestratorSettings"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Get module alias (use it for test)\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"Orchestrator = sys.modules[\"pyOpenRPA.Orchestrator\"]\n",
"Managers = sys.modules[\"pyOpenRPA.Orchestrator.Managers\"]"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Orchestrator.OSCredentialsVerify(inUserStr=\"ND\",inPasswordStr=\"deluxe\")"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<function pyOpenRPA.Orchestrator.Managers.Git.Git.BranchRevGet(self, inBranchNameStr='HEAD')>"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Managers.Git.BranchRevGet"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.2"
},
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}

@ -0,0 +1,6 @@
cd %~dp0..\..\Resources\WPy64-3720\python-3.7.2.amd64
python -m pip install jupyter_contrib_nbextensions
python -m jupyter contrib nbextension install --user
python -m pip install jupyter_nbextensions_configurator
python -m jupyter nbextensions_configurator enable --user
pause>nul

@ -0,0 +1,5 @@
cd %~dp0..\..\Resources\WPy64-3720\python-3.7.2.amd64
taskkill /im "pyOpenRPA_Orchestrator.exe" /F /fi "username eq %username%"
copy /Y python.exe pyOpenRPA_Orchestrator.exe
pyOpenRPA_Orchestrator -m notebook --notebook-dir=%~dp0
pause>nul

@ -0,0 +1,139 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Start orchestrator from the jupyter (sandbox)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import sys\n",
"# Set cwd to the orc wd\n",
"os.chdir(\"..\")\n",
"# %%capture # Use it if you want to toggle off output\n",
"import OrchestratorSettings"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Get module alias (use it for test)\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"Orchestrator = sys.modules[\"pyOpenRPA.Orchestrator\"]\n",
"Managers = sys.modules[\"pyOpenRPA.Orchestrator.Managers\"]"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Orchestrator.OSCredentialsVerify(inUserStr=\"ND\",inPasswordStr=\"deluxe\")"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<function pyOpenRPA.Orchestrator.Managers.Git.Git.BranchRevGet(self, inBranchNameStr='HEAD')>"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Managers.Git.BranchRevGet"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.2"
},
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}

@ -0,0 +1,9 @@
Common utilities for jupyter-contrib projects. Includes:
- providing a notebook-4.2-compatible nbextension API in order to
smooth over differences in versions 4.0 and 4.1
- common application components and cli scripts
- utility classes and functions for use in tests

@ -0,0 +1,39 @@
Metadata-Version: 2.0
Name: jupyter-contrib-core
Version: 0.3.3
Summary: Common utilities for jupyter-contrib projects.
Home-page: https://github.com/jupyter-contrib/jupyter_contrib_core
Author: jcb91, jupyter-contrib developers
Author-email: joshuacookebarnes@gmail.com
License: BSD 3-clause
Download-URL: https://github.com/jupyter-contrib/jupyter_contrib_core/tarball/0.3.3
Keywords: Jupyter,notebook
Platform: any
Classifier: Intended Audience :: End Users/Desktop
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: BSD License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: JavaScript
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Utilities
Requires-Dist: jupyter-core
Requires-Dist: notebook (>=4.0)
Requires-Dist: setuptools
Requires-Dist: tornado
Requires-Dist: traitlets
Provides-Extra: testing_utils
Requires-Dist: nose; extra == 'testing_utils'
Provides-Extra: testing_utils
Requires-Dist: mock; python_version == "2.7" and extra == 'testing_utils'
Common utilities for jupyter-contrib projects. Includes:
- providing a notebook-4.2-compatible nbextension API in order to
smooth over differences in versions 4.0 and 4.1
- common application components and cli scripts
- utility classes and functions for use in tests

@ -0,0 +1,31 @@
../../Scripts/jupyter-contrib.exe,sha256=-6s17Egr-Etw6fFD3GtbkqEwMaEcCXTCjw8qhXObg48,106407
jupyter_contrib_core-0.3.3.data/scripts/jupyter-contrib,sha256=VllNFlWWlrXr9K8g-CbYdRQTQCL-ylZn5AJbcckebjo,134
jupyter_contrib_core-0.3.3.dist-info/DESCRIPTION.rst,sha256=KX4THekyqTPLMOwGfbLVKTgBZDUvVUb6APowYhc9ZFM,282
jupyter_contrib_core-0.3.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
jupyter_contrib_core-0.3.3.dist-info/METADATA,sha256=fvyzBikN5C9iEtzMYkSVdKbWbCRTrWCf9BdSvOiDejs,1423
jupyter_contrib_core-0.3.3.dist-info/RECORD,,
jupyter_contrib_core-0.3.3.dist-info/WHEEL,sha256=o2k-Qa-RMNIJmUdIc7KU6VWR_ErNRbWNlxDIpl7lm34,110
jupyter_contrib_core-0.3.3.dist-info/entry_points.txt,sha256=MM-_RRnZ_TwNV5p1TlapKEyuibXEO2N2NZicC4hqBmE,75
jupyter_contrib_core-0.3.3.dist-info/metadata.json,sha256=PMHs8MzdJqL3FDsEsx2ZJW6B2ItF1j5MLvud3D9Ex9k,1468
jupyter_contrib_core-0.3.3.dist-info/top_level.txt,sha256=XamZbTnwOf-_DyoTTO8Sje0rOqForNrP0qhd9I8MIe4,21
jupyter_contrib_core-0.3.3.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
jupyter_contrib_core/__init__.py,sha256=eK1JD1qgGZMNu4w8jOXGpXjbedjNl1dO5kFAb03x4BM,202
jupyter_contrib_core/__pycache__/__init__.cpython-37.pyc,,
jupyter_contrib_core/__pycache__/application.cpython-37.pyc,,
jupyter_contrib_core/application.py,sha256=BuPFJWS-QqiPwqGSsdhBhVn-yJCan2J00aDsWzUXJLM,1960
jupyter_contrib_core/notebook_compat/__init__.py,sha256=Z2Fx-dPVJx4TUm1UJjc7-S2lAAiCPh4wJKKioZu9q5c,406
jupyter_contrib_core/notebook_compat/__pycache__/__init__.cpython-37.pyc,,
jupyter_contrib_core/notebook_compat/__pycache__/nbextensions.cpython-37.pyc,,
jupyter_contrib_core/notebook_compat/__pycache__/serverextensions.cpython-37.pyc,,
jupyter_contrib_core/notebook_compat/_compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
jupyter_contrib_core/notebook_compat/_compat/__pycache__/__init__.cpython-37.pyc,,
jupyter_contrib_core/notebook_compat/_compat/__pycache__/nbextensions.cpython-37.pyc,,
jupyter_contrib_core/notebook_compat/_compat/__pycache__/serverextensions.cpython-37.pyc,,
jupyter_contrib_core/notebook_compat/_compat/nbextensions.py,sha256=ExvzxtDUrr2WRpGTpBiAi3AOza7DuQzxb7k8MuQK-lg,18161
jupyter_contrib_core/notebook_compat/_compat/serverextensions.py,sha256=b3cxfOf7YKeys6uNqzapYXVHBVOmWRU7rJnajRGNqio,8220
jupyter_contrib_core/notebook_compat/nbextensions.py,sha256=fS8_-7jz4TjVXwnq9K9sfT5hLTEAfzaedfJZGIC3ML8,2695
jupyter_contrib_core/notebook_compat/serverextensions.py,sha256=4yI2NUvmJx1Npi8pPLpkjyBzpO3cTSs2n8JD1WW-djY,812
jupyter_contrib_core/testing_utils/__init__.py,sha256=5gxV2KL15tBOGk6B_Hv0PupRJ76VrlCE3U8GVIDSeSc,5482
jupyter_contrib_core/testing_utils/__pycache__/__init__.cpython-37.pyc,,
jupyter_contrib_core/testing_utils/__pycache__/jupyter_env.cpython-37.pyc,,
jupyter_contrib_core/testing_utils/jupyter_env.py,sha256=q7b5sEd7bPAeOWFWav77QkT0vhDjWNrKyR0O_l4Sin0,3126

@ -0,0 +1,6 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.29.0)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

@ -0,0 +1,3 @@
[console_scripts]
jupyter-contrib = jupyter_contrib_core.application:main

@ -0,0 +1 @@
{"classifiers": ["Intended Audience :: End Users/Desktop", "Intended Audience :: Science/Research", "License :: OSI Approved :: BSD License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: JavaScript", "Programming Language :: Python", "Programming Language :: Python :: 3", "Topic :: Utilities"], "download_url": "https://github.com/jupyter-contrib/jupyter_contrib_core/tarball/0.3.3", "extensions": {"python.commands": {"wrap_console": {"jupyter-contrib": "jupyter_contrib_core.application:main"}}, "python.details": {"contacts": [{"email": "joshuacookebarnes@gmail.com", "name": "jcb91, jupyter-contrib developers", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/jupyter-contrib/jupyter_contrib_core"}}, "python.exports": {"console_scripts": {"jupyter-contrib": "jupyter_contrib_core.application:main"}}}, "extras": ["testing_utils"], "generator": "bdist_wheel (0.29.0)", "keywords": ["Jupyter", "notebook"], "license": "BSD 3-clause", "metadata_version": "2.0", "name": "jupyter-contrib-core", "platform": "any", "run_requires": [{"requires": ["jupyter-core", "notebook (>=4.0)", "setuptools", "tornado", "traitlets"]}, {"extra": "testing_utils", "requires": ["nose"]}, {"environment": "python_version == \"2.7\"", "extra": "testing_utils", "requires": ["mock"]}], "summary": "Common utilities for jupyter-contrib projects.", "version": "0.3.3"}

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
# - Copyright (c) 2016-, jupyter-contrib development team
"""Core functionality for jupyter-contrib projects."""
from __future__ import unicode_literals
__version__ = '0.3.3'

@ -0,0 +1,62 @@
# coding: utf-8
"""
Common application classes for jupyter_contrib.
Including the root `jupyter-contrib` command.
"""
from __future__ import print_function
import sys
import pkg_resources
from jupyter_core.application import JupyterApp
from jupyter_contrib_core import __version__
class JupyterContribApp(JupyterApp):
"""Root level jupyter_contrib app."""
name = 'jupyter contrib'
version = __version__
description = (
'community-contributed spice for Jupyter Interactive Computing')
def __init__(self, *args, **kwargs):
self._refresh_subcommands()
super(JupyterContribApp, self).__init__(*args, **kwargs)
def _refresh_subcommands(self):
"""
Finds subcommands which have registered entry points.
Each entry point is a function which returns a subcommands-style dict,
where the keys are the name of the subcommand, and the values are
2-tuples containing the sub-application class, and a description of the
subcommand's action.
"""
group = 'jupyter_contrib_core.app.subcommands'
new_subcommands = {}
# import ipdb; ipdb.set_trace()
for entrypoint in pkg_resources.iter_entry_points(group=group):
get_subcommands_dict = entrypoint.load()
new_subcommands.update(get_subcommands_dict())
self.subcommands.clear()
self.subcommands.update(new_subcommands)
def start(self):
"""Perform the App's actions as configured"""
super(JupyterContribApp, self).start()
# The above should have called a subcommand and raised NoStart; if we
# get here, it didn't, so we should self.log.info a message.
self.print_help()
subcmds = ", ".join(sorted(self.subcommands))
sys.exit("Please supply at least one subcommand: %s" % subcmds)
main = JupyterContribApp.launch_instance
if __name__ == '__main__': # pragma: no cover
main()

@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
"""
Shim providing notebook-4.2 compatible extensions stuff for earlier versions.
objects imported from notebook_compat.nbextensions will be
- objects from notebook.nbextensions where notebook-4.2-compatible versions
are available
- versions from notebook_compat._compat.nbextensions shim scripts otherwise
and similarly for objects from notebook_compat.serverextensions
"""

@ -0,0 +1,490 @@
# -*- coding: utf-8 -*-
"""
Shim providing some notebook.nbextensions functions for versions < 4.2.0.
The main differences are:
* check_nbextension public API function omitted as unused
* all apps except BaseNBExtensionApp are omitted
* some unused private API stuff omitted
* all deprecated arguments are ignored, since we assume the caller knows what
they're doing
* docstrings limited to first line for brevity - we assume that if the caller
is using the function, they're familiar with notebook 4.2 API
"""
# Original jupyter notebook source is
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from __future__ import print_function
import copy
import os
import shutil
import tarfile
import zipfile
from ipython_genutils.path import ensure_dir_exists
from ipython_genutils.py3compat import cast_unicode_py2
from ipython_genutils.tempdir import TemporaryDirectory
from jupyter_core.application import JupyterApp
from jupyter_core.paths import (
ENV_CONFIG_PATH, ENV_JUPYTER_PATH, SYSTEM_CONFIG_PATH, SYSTEM_JUPYTER_PATH,
jupyter_config_dir, jupyter_data_dir,
)
from notebook.nbextensions import (
ArgumentConflict, __version__, _safe_is_tarfile,
)
from tornado.log import LogFormatter
from traitlets import Bool
from traitlets.config.manager import BaseJSONConfigManager
from traitlets.utils.importstring import import_item
try:
from urllib.parse import urlparse # Py3
from urllib.request import urlretrieve
except ImportError:
from urlparse import urlparse
from urllib import urlretrieve
# Constants for pretty printing
# Window doesn't support coloring in the commandline
GREEN_OK = '\033[32mOK\033[0m' if os.name != 'nt' else 'ok'
RED_X = '\033[31m X\033[0m' if os.name != 'nt' else ' X'
GREEN_ENABLED = '\033[32m enabled \033[0m' if os.name != 'nt' else 'enabled '
RED_DISABLED = '\033[31mdisabled\033[0m' if os.name != 'nt' else 'disabled'
NBCONFIG_SECTIONS = ['common', 'notebook', 'tree', 'edit', 'terminal']
# -----------------------------------------------------------------------------
# Public API - large parts omitted
# -----------------------------------------------------------------------------
# check_nbextension omitted as unused
def install_nbextension(path, overwrite=False, symlink=False,
user=False, prefix=None, nbextensions_dir=None,
destination=None, logger=None, sys_prefix=False):
"""Install a Javascript extension for the notebook."""
# the actual path to which we eventually installed
full_dest = None
nbext = _get_nbextension_dir(
user=user, sys_prefix=sys_prefix, prefix=prefix,
nbextensions_dir=nbextensions_dir)
# make sure nbextensions dir exists
ensure_dir_exists(nbext)
# forcing symlink parameter to False if os.symlink does not exist (e.g.,
# on Windows machines running python 2)
if not hasattr(os, 'symlink'):
symlink = False
if isinstance(path, (list, tuple)):
raise TypeError("path must be a string pointing to a single extension "
"to install; call this function multiple times to "
"install multiple extensions")
path = cast_unicode_py2(path)
if path.startswith(('https://', 'http://')):
if symlink:
raise ValueError("Cannot symlink from URLs")
# Given a URL, download it
with TemporaryDirectory() as td:
filename = urlparse(path).path.split('/')[-1]
local_path = os.path.join(td, filename)
if logger:
logger.info("Downloading: %s -> %s" % (path, local_path))
urlretrieve(path, local_path)
# now install from the local copy
full_dest = install_nbextension(
local_path, overwrite=overwrite, symlink=symlink,
nbextensions_dir=nbext, destination=destination, logger=logger)
elif path.endswith('.zip') or _safe_is_tarfile(path):
if symlink:
raise ValueError("Cannot symlink from archives")
if destination:
raise ValueError("Cannot give destination for archives")
if logger:
logger.info("Extracting: %s -> %s" % (path, nbext))
if path.endswith('.zip'):
archive = zipfile.ZipFile(path)
elif _safe_is_tarfile(path):
archive = tarfile.open(path)
archive.extractall(nbext)
archive.close()
# TODO: what to do here
full_dest = None
else:
if not destination:
destination = os.path.basename(path)
destination = cast_unicode_py2(destination)
full_dest = os.path.normpath(os.path.join(nbext, destination))
if overwrite and os.path.lexists(full_dest):
if logger:
logger.info("Removing: %s" % full_dest)
if os.path.isdir(full_dest) and not os.path.islink(full_dest):
shutil.rmtree(full_dest)
else:
os.remove(full_dest)
if symlink:
path = os.path.abspath(path)
if not os.path.exists(full_dest):
if logger:
logger.info("Symlinking: %s -> %s" % (full_dest, path))
os.symlink(path, full_dest)
elif os.path.isdir(path):
# end in path separator
path = os.path.join(os.path.abspath(path), '')
for parent, dirs, files in os.walk(path):
dest_dir = os.path.join(full_dest, parent[len(path):])
if not os.path.exists(dest_dir):
if logger:
logger.info("Making directory: %s" % dest_dir)
os.makedirs(dest_dir)
for file in files:
src = os.path.join(parent, file)
dest_file = os.path.join(dest_dir, file)
_maybe_copy(src, dest_file, logger=logger)
else:
src = path
_maybe_copy(src, full_dest, logger=logger)
return full_dest
def install_nbextension_python(module, overwrite=False, symlink=False,
user=False, sys_prefix=False, prefix=None,
nbextensions_dir=None, logger=None):
"""Install an nbextension bundled in a Python package."""
m, nbexts = _get_nbextension_metadata(module)
base_path = os.path.split(m.__file__)[0]
full_dests = []
for nbext in nbexts:
src = os.path.join(base_path, nbext['src'])
dest = nbext['dest']
if logger:
logger.info("Installing %s -> %s" % (src, dest))
full_dest = install_nbextension(
src, overwrite=overwrite, symlink=symlink,
user=user, sys_prefix=sys_prefix, prefix=prefix,
nbextensions_dir=nbextensions_dir,
destination=dest, logger=logger
)
validate_nbextension_python(nbext, full_dest, logger)
full_dests.append(full_dest)
return full_dests
def uninstall_nbextension(dest, require=None, user=False, sys_prefix=False,
prefix=None, nbextensions_dir=None, logger=None):
"""Uninstall a Javascript extension of the notebook."""
nbext = _get_nbextension_dir(user=user, sys_prefix=sys_prefix,
prefix=prefix,
nbextensions_dir=nbextensions_dir)
dest = cast_unicode_py2(dest)
full_dest = os.path.join(nbext, dest)
if os.path.lexists(full_dest):
if logger:
logger.info("Removing: %s" % full_dest)
if os.path.isdir(full_dest) and not os.path.islink(full_dest):
shutil.rmtree(full_dest)
else:
os.remove(full_dest)
# Look through all of the config sections making sure that the nbextension
# doesn't exist.
config_dir = os.path.join(
_get_config_dir(user=user, sys_prefix=sys_prefix), 'nbconfig')
cm = BaseJSONConfigManager(config_dir=config_dir)
if require:
for section in NBCONFIG_SECTIONS:
cm.update(section, {"load_extensions": {require: None}})
def uninstall_nbextension_python(module, user=False, sys_prefix=False,
prefix=None, nbextensions_dir=None,
logger=None):
"""Uninstall an nbextension bundled in a Python package."""
m, nbexts = _get_nbextension_metadata(module)
for nbext in nbexts:
dest = nbext['dest']
require = nbext['require']
if logger:
logger.info("Uninstalling {} {}".format(dest, require))
uninstall_nbextension(dest, require, user=user, sys_prefix=sys_prefix,
prefix=prefix, nbextensions_dir=nbextensions_dir,
logger=logger)
def _set_nbextension_state(section, require, state,
user=True, sys_prefix=False, logger=None):
"""Set whether the section's frontend should require the nbextension."""
user = False if sys_prefix else user
config_dir = os.path.join(
_get_config_dir(user=user, sys_prefix=sys_prefix), 'nbconfig')
cm = BaseJSONConfigManager(config_dir=config_dir)
if logger:
logger.info("{} {} extension {}...".format(
"Enabling" if state else "Disabling",
section,
require
))
cm.update(section, {"load_extensions": {require: state}})
validate_nbextension(require, logger=logger)
return cm.get(section).get(require) == state
def _set_nbextension_state_python(state, module, user, sys_prefix,
logger=None):
"""Enable or disable some nbextensions stored in a Python package."""
m, nbexts = _get_nbextension_metadata(module)
return [_set_nbextension_state(section=nbext["section"],
require=nbext["require"],
state=state,
user=user, sys_prefix=sys_prefix,
logger=logger)
for nbext in nbexts]
def enable_nbextension(section, require, user=True, sys_prefix=False,
logger=None):
"""Enable a named nbextension."""
return _set_nbextension_state(section=section, require=require,
state=True,
user=user, sys_prefix=sys_prefix,
logger=logger)
def disable_nbextension(section, require, user=True, sys_prefix=False,
logger=None):
"""Disable a named nbextension."""
return _set_nbextension_state(section=section, require=require,
state=False,
user=user, sys_prefix=sys_prefix,
logger=logger)
def enable_nbextension_python(module, user=True, sys_prefix=False,
logger=None):
"""Enable some nbextensions associated with a Python module."""
return _set_nbextension_state_python(True, module, user, sys_prefix,
logger=logger)
def disable_nbextension_python(module, user=True, sys_prefix=False,
logger=None):
"""Disable some nbextensions associated with a Python module."""
return _set_nbextension_state_python(False, module, user, sys_prefix,
logger=logger)
def validate_nbextension(require, logger=None):
"""Validate a named nbextension."""
warnings = []
infos = []
js_exists = False
for exts in _nbextension_dirs():
# Does the Javascript entrypoint actually exist on disk?
js = u"{}.js".format(os.path.join(exts, *require.split("/")))
js_exists = os.path.exists(js)
if js_exists:
break
require_tmpl = u" - require? {} {}"
if js_exists:
infos.append(require_tmpl.format(GREEN_OK, require))
else:
warnings.append(require_tmpl.format(RED_X, require))
if logger:
if warnings:
logger.warning(u" - Validating: problems found:")
for msg in warnings:
logger.warning(msg)
for msg in infos:
logger.info(msg)
else:
logger.info(u" - Validating: {}".format(GREEN_OK))
return warnings
def validate_nbextension_python(spec, full_dest, logger=None):
"""Assess the health of an installed nbextension."""
infos = []
warnings = []
section = spec.get("section", None)
if section in NBCONFIG_SECTIONS:
infos.append(u" {} section: {}".format(GREEN_OK, section))
else:
warnings.append(u" {} section: {}".format(RED_X, section))
require = spec.get("require", None)
if require is not None:
require_path = os.path.join(
full_dest[0:-len(spec["dest"])],
u"{}.js".format(require))
if os.path.exists(require_path):
infos.append(u" {} require: {}".format(GREEN_OK, require_path))
else:
warnings.append(u" {} require: {}".format(RED_X, require_path))
if logger:
if warnings:
logger.warning("- Validating: problems found:")
for msg in warnings:
logger.warning(msg)
for msg in infos:
logger.info(msg)
logger.warning(u"Full spec: {}".format(spec))
else:
logger.info(u"- Validating: {}".format(GREEN_OK))
return warnings
# -----------------------------------------------------------------------------
# Applications. Many omitted from notebook version.
# -----------------------------------------------------------------------------
class BaseNBExtensionApp(JupyterApp):
"""Base nbextension installer app"""
_log_formatter_cls = LogFormatter
version = __version__
flags = copy.deepcopy(JupyterApp.flags)
flags.update({
'user': ({
'BaseNBExtensionApp': {
'user': True,
}}, 'Apply the operation only for the given user'
),
'system': ({
'BaseNBExtensionApp': {
'user': False,
'sys_prefix': False,
}}, 'Apply the operation system-wide'
),
'sys-prefix': ({
'BaseNBExtensionApp': {
'sys_prefix': True,
}}, ('Use sys.prefix as the prefix for configuration operations ' +
'and installing nbextensions (for environments, packaging)')
),
'py': ({
'BaseNBExtensionApp': {
'python': True,
}}, 'Install from a Python package'
)
})
flags['python'] = flags['py']
flags.pop('y', None)
flags.pop('generate-config', None)
user = Bool(False, config=True, help="Whether to do a user install")
sys_prefix = Bool(False, config=True,
help="Use the sys.prefix as the prefix")
python = Bool(False, config=True, help="Install from a Python package")
# stuff about verbose from notebook version omitted
def _log_format_default(self):
"""A default format for messages"""
return '%(message)s'
# -----------------------------------------------------------------------------
# Private API
# -----------------------------------------------------------------------------
def _should_copy(src, dest, logger=None):
"""Return whether a file should be copied."""
if not os.path.exists(dest):
return True
if os.stat(src).st_mtime - os.stat(dest).st_mtime > 1e-6:
# we add a fudge factor to work around a bug in python 2.x
# that was fixed in python 3.x: http://bugs.python.org/issue12904
if logger:
logger.warn("Out of date: %s" % dest)
return True
if logger:
logger.info("Up to date: %s" % dest)
return False
def _maybe_copy(src, dest, logger=None):
"""Copy a file if it needs updating."""
if _should_copy(src, dest, logger=logger):
if logger:
logger.info("Copying: %s -> %s" % (src, dest))
shutil.copy2(src, dest)
def _get_nbextension_dir(user=False, sys_prefix=False, prefix=None,
nbextensions_dir=None):
"""Return the nbextension directory specified."""
if sum(map(bool, [user, prefix, nbextensions_dir, sys_prefix])) > 1:
raise ArgumentConflict(
"cannot specify more than one of user, sys_prefix, prefix, "
"or nbextensions_dir")
if user:
nbext = os.path.join(jupyter_data_dir(), u'nbextensions')
elif sys_prefix:
nbext = os.path.join(ENV_JUPYTER_PATH[0], u'nbextensions')
elif prefix:
nbext = os.path.join(prefix, 'share', 'jupyter', 'nbextensions')
elif nbextensions_dir:
nbext = nbextensions_dir
else:
nbext = os.path.join(SYSTEM_JUPYTER_PATH[0], 'nbextensions')
return nbext
def _nbextension_dirs():
"""The possible locations of nbextensions."""
return [
os.path.join(jupyter_data_dir(), u'nbextensions'),
os.path.join(ENV_JUPYTER_PATH[0], u'nbextensions'),
os.path.join(SYSTEM_JUPYTER_PATH[0], 'nbextensions')
]
def _get_config_dir(user=False, sys_prefix=False):
"""Get the location of config files for the current context."""
user = False if sys_prefix else user
if user and sys_prefix:
raise ArgumentConflict(
"Cannot specify more than one of user or sys_prefix")
if user:
nbext = jupyter_config_dir()
elif sys_prefix:
nbext = ENV_CONFIG_PATH[0]
else:
nbext = SYSTEM_CONFIG_PATH[0]
return nbext
def _get_nbextension_metadata(module):
"""Get the list of nbextension paths associated with a Python module."""
m = import_item(module)
if not hasattr(m, '_jupyter_nbextension_paths'):
raise KeyError(
'The Python module {} is not a valid nbextension'.format(module))
nbexts = m._jupyter_nbextension_paths()
return m, nbexts

@ -0,0 +1,259 @@
# -*- coding: utf-8 -*-
"""
Functions from notebook.serverextensions for versions < 4.2.0.
Note that functions aren't quite direct copies, because of the switch from the
config key
NotebookApp.server_extensions (a list) in notebook < 4.2.0
to the key
NotebookApp.nbserver_extensions (a dict) in notebook >= 4.2.0
"""
# Original jupyter notebook source is
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from __future__ import print_function
import importlib
from jupyter_core.application import JupyterApp
from traitlets import Bool
from traitlets.config.manager import BaseJSONConfigManager
from traitlets.utils.importstring import import_item
try:
from notebook.nbextensions import (
_get_config_dir, BaseNBExtensionApp, GREEN_OK, RED_X,
)
except ImportError:
from .nbextensions import (
_get_config_dir, BaseNBExtensionApp, GREEN_OK, RED_X,
)
# -----------------------------------------------------------------------------
# Public API
# -----------------------------------------------------------------------------
class ArgumentConflict(ValueError):
pass
def toggle_serverextension_python(import_name, enabled=None, parent=None,
user=True, sys_prefix=False, logger=None):
"""Toggle a server extension.
By default, toggles the extension in the system-wide Jupyter configuration
location (e.g. /usr/local/etc/jupyter).
Parameters
----------
import_name : str
Importable Python module (dotted-notation) exposing the magic-named
`load_jupyter_server_extension` function
enabled : bool [default: None]
Toggle state for the extension. Set to None to toggle, True to enable,
and False to disable the extension.
parent : Configurable [default: None]
user : bool [default: True]
Toggle in the user's configuration location (e.g. ~/.jupyter).
sys_prefix : bool [default: False]
Toggle in the current Python environment's configuration location
(e.g. ~/.envs/my-env/etc/jupyter). Will override `user`.
logger : Jupyter logger [optional]
Logger instance to use
"""
user = False if sys_prefix else user
config_dir = _get_config_dir(user=user, sys_prefix=sys_prefix)
cm = BaseJSONConfigManager(parent=parent, config_dir=config_dir)
cfg = cm.get("jupyter_notebook_config")
server_extensions = (
cfg.setdefault("NotebookApp", {})
.setdefault("server_extensions", [])
)
old_enabled = import_name in server_extensions
new_enabled = enabled if enabled is not None else not old_enabled
if logger:
if new_enabled:
logger.info(u"Enabling: %s" % (import_name))
else:
logger.info(u"Disabling: %s" % (import_name))
if new_enabled:
if not old_enabled:
server_extensions.append(import_name)
elif old_enabled:
while import_name in server_extensions:
server_extensions.pop(server_extensions.index(import_name))
if logger:
logger.info(u"- Writing config: {}".format(config_dir))
cm.update("jupyter_notebook_config", cfg)
if new_enabled:
validate_serverextension(import_name, logger)
def validate_serverextension(import_name, logger=None):
"""Assess the health of an installed server extension
Returns a list of validation warnings.
Parameters
----------
import_name : str
Importable Python module (dotted-notation) exposing the magic-named
`load_jupyter_server_extension` function
logger : Jupyter logger [optional]
Logger instance to use
"""
warnings = []
infos = []
func = None
if logger:
logger.info(" - Validating...")
try:
mod = importlib.import_module(import_name)
func = getattr(mod, 'load_jupyter_server_extension', None)
except Exception: # pragma: no cover
logger.warning("Error loading server extension %s", import_name)
import_msg = u" {} is {} importable?"
if func is not None:
infos.append(import_msg.format(GREEN_OK, import_name))
else: # pragma: no cover
warnings.append(import_msg.format(RED_X, import_name))
post_mortem = u" {} {} {}"
if logger:
if warnings: # pragma: no cover
[logger.info(info) for info in infos]
[logger.warn(warning) for warning in warnings]
else:
logger.info(post_mortem.format(import_name, "", GREEN_OK))
return warnings
# ----------------------------------------------------------------------------
# Applications. Some from the notebook version of serverextensions are skipped
# ----------------------------------------------------------------------------
flags = {}
flags.update(JupyterApp.flags)
flags.pop('y', None)
flags.pop('generate-config', None)
flags.update({
'user': ({
'ToggleServerExtensionApp': {
'user': True,
}}, 'Perform the operation for the current user'
),
'system': ({
'ToggleServerExtensionApp': {
'user': False,
'sys_prefix': False,
}}, 'Perform the operation system-wide'
),
'sys-prefix': ({
'ToggleServerExtensionApp': {
'sys_prefix': True,
}}, 'Use sys.prefix as the prefix for installing server extensions'
),
'py': ({
'ToggleServerExtensionApp': {
'python': True,
}}, 'Install from a Python package'
),
})
flags['python'] = flags['py']
class ToggleServerExtensionApp(BaseNBExtensionApp):
"""A base class for enabling/disabling extensions."""
name = 'jupyter serverextension enable/disable'
description = 'Enable/disable a server extension in config files.'
aliases = {}
flags = flags
user = Bool(True, config=True, help='Whether to do a user install')
sys_prefix = Bool(
False, config=True, help='Use the sys.prefix as the prefix')
python = Bool(False, config=True, help='Install from a Python package')
def toggle_server_extension(self, import_name):
"""Change the status of a named server extension.
Uses the value of `self._toggle_value`.
Parameters
---------
import_name : str
Importable Python module (dotted-notation) exposing the magic-named
`load_jupyter_server_extension` function
"""
toggle_serverextension_python(
import_name, self._toggle_value, parent=self, user=self.user,
sys_prefix=self.sys_prefix, logger=self.log)
def toggle_server_extension_python(self, package):
"""Change the status of some server extensions in a Python package.
Uses the value of `self._toggle_value`.
Parameters
---------
package : str
Importable Python module exposing the
magic-named `_jupyter_server_extension_paths` function
"""
m, server_exts = _get_server_extension_metadata(package)
for server_ext in server_exts:
module = server_ext['module']
self.toggle_server_extension(module)
# start definition omitted as it's overridden in
# jupyter_contrib_core.application anyway
# -----------------------------------------------------------------------------
# Private API
# -----------------------------------------------------------------------------
def _get_server_extension_metadata(module):
"""Load server extension metadata from a module.
Returns a tuple of (
the package as loaded
a list of server extension specs: [
{
"module": "mockextension"
}
]
)
Parameters
----------
module : str
Importable Python module exposing the
magic-named `_jupyter_server_extension_paths` function
"""
m = import_item(module)
if not hasattr(m, '_jupyter_server_extension_paths'): # pragma: no cover
raise KeyError(
u'The Python module {} does not include any valid server extensions'.format(module)) # noqa
return m, m._jupyter_server_extension_paths()

@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
"""Shim providing notebook.nbextensions stuff from 4.2 for earlier versions."""
try:
# notebook >= 5.0
from notebook.extensions import BaseExtensionApp
BaseNBExtensionApp = BaseExtensionApp
except ImportError as err:
try:
from notebook.nbextensions import BaseNBExtensionApp
except ImportError as err:
from ._compat.nbextensions import BaseNBExtensionApp
BaseExtensionApp = BaseNBExtensionApp
try:
from notebook.nbextensions import _nbextension_dirs
except ImportError as err:
from ._compat.nbextensions import _nbextension_dirs
try:
from notebook.nbextensions import (
# constants
GREEN_ENABLED, GREEN_OK, NBCONFIG_SECTIONS, RED_DISABLED, RED_X,
# Apps & classes
ArgumentConflict,
# public API functions
_set_nbextension_state, _set_nbextension_state_python,
disable_nbextension, disable_nbextension_python,
enable_nbextension, enable_nbextension_python,
install_nbextension, install_nbextension_python,
uninstall_nbextension, uninstall_nbextension_python,
validate_nbextension, validate_nbextension_python,
# private API functions
_get_nbextension_dir, _get_config_dir,
_get_nbextension_metadata,
)
except ImportError as err:
from ._compat.nbextensions import (
# constants
GREEN_ENABLED, GREEN_OK, NBCONFIG_SECTIONS, RED_DISABLED, RED_X,
# Apps & classes
ArgumentConflict,
# public API functions
_set_nbextension_state, _set_nbextension_state_python,
disable_nbextension, disable_nbextension_python,
enable_nbextension, enable_nbextension_python,
install_nbextension, install_nbextension_python,
uninstall_nbextension, uninstall_nbextension_python,
validate_nbextension, validate_nbextension_python,
# private API functions
_get_nbextension_dir, _get_config_dir,
_get_nbextension_metadata,
)
__all__ = [
# constants
'GREEN_ENABLED', 'GREEN_OK', 'NBCONFIG_SECTIONS', 'RED_DISABLED', 'RED_X',
# Apps & classes
'ArgumentConflict', 'BaseNBExtensionApp',
# public API functions
'_set_nbextension_state', '_set_nbextension_state_python',
'disable_nbextension', 'disable_nbextension_python',
'enable_nbextension', 'enable_nbextension_python',
'install_nbextension', 'install_nbextension_python',
'uninstall_nbextension', 'uninstall_nbextension_python',
'validate_nbextension', 'validate_nbextension_python',
# private API functions
'_get_nbextension_dir', '_nbextension_dirs', '_get_config_dir',
'_get_nbextension_metadata',
]

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
"""Shim providing notebook.serverextensions stuff for pre 4.2 versions."""
try:
# notebook >= 4.2
from notebook.serverextensions import (
ToggleServerExtensionApp, toggle_serverextension_python,
)
except ImportError:
# notebook <4.2
from ._compat.serverextensions import (
ToggleServerExtensionApp, toggle_serverextension_python,
)
try:
# notebook >= 5.0
from notebook.extensions import ArgumentConflict
except ImportError:
try:
# notebook 4.2.x
from notebook.serverextensions import ArgumentConflict
except ImportError:
# notebook < 4.2
from ._compat.serverextensions import ArgumentConflict
__all__ = [
'ArgumentConflict', 'ToggleServerExtensionApp',
'toggle_serverextension_python',
]

@ -0,0 +1,181 @@
# -*- coding: utf-8 -*-
"""Test utilities."""
from __future__ import (
absolute_import, division, print_function, unicode_literals,
)
import logging
import os
import re
import sys
from threading import RLock
from traitlets.config.application import LevelFormatter
from traitlets.traitlets import default
try:
from notebook.tests.test_notebookapp import raise_on_bad_version
except ImportError:
pep440re = re.compile(
r'^'
r'([1-9]\d*!)?(0|[1-9]\d*)(.(0|[1-9]\d*))*'
r'((a|b|rc)(0|[1-9]\d*))?'
r'(\.post(0|[1-9]\d*))?'
r'(\.dev(0|[1-9]\d*))?'
r'$'
)
def raise_on_bad_version(version):
if not pep440re.match(version):
raise ValueError(
"Versions String apparently does not match Pep 440 "
"specification, which might lead to sdist and wheel being "
"seen as 2 different release. "
"E.g: do not use dots for beta/alpha/rc markers."
)
def stringify_env(env):
"""
Convert environment vars dict to str: str (not unicode) for py2 on Windows.
Python 2 on Windows doesn't handle Unicode objects in environment, even if
they can be converted to ASCII string, which can cause problems for
subprocess calls in modules importing unicode_literals from future.
"""
if sys.version_info[0] < 3 and os.name == 'nt':
return {str(key): str(val) for key, val in env.iteritems()}
return env
class GlobalMemoryHandler(logging.Handler):
"""
A MemoryHandler which uses a single buffer across all instances.
In addition, will only flush logs when explicitly called to.
"""
_buffer = None # used as a class-wide attribute
_lock = None # used as a class-wide attribute
@classmethod
def _setup_class(cls):
if cls._lock is None:
cls._lock = RLock()
if cls._buffer is None:
with cls._lock:
cls._buffer = []
def __init__(self, target):
logging.Handler.__init__(self)
self.target = target
self._setup_class()
def emit(self, record):
"""
Emit a record.
Append the record and its target to the buffer.
Don't check shouldFlush like regular MemoryHandler does.
"""
self.__class__._buffer.append((record, self.target))
@classmethod
def flush_to_target(cls):
"""
Sending the buffered records to their respective targets.
The class-wide record buffer is also cleared by this operation.
"""
with cls._lock:
for record, target in cls._buffer:
target.handle(record)
cls.clear_buffer()
@classmethod
def clear_buffer(cls):
with cls._lock:
cls._buffer = []
@classmethod
def rotate_buffer(cls, num_places=1):
with cls._lock:
cls._buffer = cls._buffer[-num_places:] + cls._buffer[:-num_places]
def close(self):
"""Close the handler."""
try:
self.flush()
finally:
logging.Handler.close(self)
def wrap_logger_handlers(logger):
"""Wrap a logging handler in a GlobalMemoryHandler."""
# clear original log handlers, saving a copy
handlers_to_wrap = logger.handlers
logger.handlers = []
# wrap each one
for handler in handlers_to_wrap:
if isinstance(handler, GlobalMemoryHandler):
wrapping_handler = handler
else:
wrapping_handler = GlobalMemoryHandler(target=handler)
logger.addHandler(wrapping_handler)
return logger
def get_logger(name=__name__, log_level=logging.DEBUG):
"""
Return a logger with a default StreamHandler.
Adapted from
tratilets.config.application.Application._log_default
"""
log = logging.getLogger(name)
log.setLevel(log_level)
log.propagate = False
_log = log # copied from Logger.hasHandlers() (new in Python 3.2)
while _log:
if _log.handlers:
return log
if not _log.propagate:
break
else:
_log = _log.parent
if sys.executable.endswith('pythonw.exe'):
# this should really go to a file, but file-logging is only
# hooked up in parallel applications
_log_handler = logging.StreamHandler(open(os.devnull, 'w'))
else:
_log_handler = logging.StreamHandler()
_log_formatter = LevelFormatter(
fmt='[%(levelname)1.1s %(asctime)s.%(msecs).03d %(name)s] %(message)s',
datefmt='%H:%M:%S')
_log_handler.setFormatter(_log_formatter)
log.addHandler(_log_handler)
return log
def get_wrapped_logger(*args, **kwargs):
"""Return a logger with StreamHandler wrapped in a GlobalMemoryHandler."""
return wrap_logger_handlers(get_logger(*args, **kwargs))
def patch_traitlets_app_logs(klass):
"""
Patch an App's default log method for use in nose tests.
This is for use on subclasses of tratilets.config.application.Application
and essentially removes handlers from the default logger, then sets it to
propagate so that nose can capture the logs.
"""
@default('log')
def new_default_log(self):
logger = super(klass, self)._log_default()
# clear log handlers and propagate to root for nose to capture
logger.propagate = True
logger.handlers = []
return logger
klass._log_default = new_default_log

@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
"""Functions for patching jupyter env vars & paths."""
from __future__ import (
absolute_import, division, print_function, unicode_literals,
)
import os
import shutil
import sys
import tempfile
import jupyter_core.paths
from jupyter_contrib_core.notebook_compat import nbextensions
from jupyter_contrib_core.testing_utils import stringify_env
try:
from unittest.mock import patch
except ImportError:
from mock import patch # py2
def make_dirs(test_dir, base_dir):
"""Return a dict of root, config and data directory paths."""
dirs = {
'root': os.path.join(test_dir, base_dir),
'conf': os.path.join(test_dir, base_dir, 'config'),
'data': os.path.join(test_dir, base_dir, 'data'),
}
if not os.path.exists(dirs['root']):
os.makedirs(dirs['root'])
return dirs
def patch_jupyter_dirs():
"""
Patch jupyter paths to use temporary directories.
This just creates the patches and directories, caller is still
responsible for starting & stopping patches, and removing temp dir when
appropriate.
"""
test_dir = tempfile.mkdtemp(prefix='jupyter_')
jupyter_dirs = {name: make_dirs(test_dir, name) for name in (
'user_home', 'env_vars', 'system', 'sys_prefix', 'custom', 'server')}
jupyter_dirs['root'] = test_dir
for name in ('notebook', 'runtime'):
d = jupyter_dirs['server'][name] = os.path.join(
test_dir, 'server', name)
if not os.path.exists(d):
os.makedirs(d)
# patch relevant environment variables
jupyter_patches = []
jupyter_patches.append(
patch.dict('os.environ', stringify_env({
'HOME': jupyter_dirs['user_home']['root'],
'JUPYTER_CONFIG_DIR': jupyter_dirs['env_vars']['conf'],
'JUPYTER_DATA_DIR': jupyter_dirs['env_vars']['data'],
'JUPYTER_RUNTIME_DIR': jupyter_dirs['server']['runtime'],
})))
# patch jupyter path variables in various modules
# find the appropriate modules to patch according to compat.
# Should include either
# notebook.nbextensions
# or
# jupyter_contrib_core.notebook_compat._compat.nbextensions
modules_to_patch = set([
jupyter_core.paths,
sys.modules[nbextensions._get_config_dir.__module__],
sys.modules[nbextensions._get_nbextension_dir.__module__],
])
path_patches = dict(
SYSTEM_CONFIG_PATH=[jupyter_dirs['system']['conf']],
ENV_CONFIG_PATH=[jupyter_dirs['sys_prefix']['conf']],
SYSTEM_JUPYTER_PATH=[jupyter_dirs['system']['data']],
ENV_JUPYTER_PATH=[jupyter_dirs['sys_prefix']['data']],
)
for mod in modules_to_patch:
applicable_patches = {
attrname: newval for attrname, newval in path_patches.items()
if hasattr(mod, attrname)}
jupyter_patches.append(
patch.multiple(mod, **applicable_patches))
def remove_jupyter_dirs():
"""Remove all temporary directories created."""
shutil.rmtree(test_dir)
return jupyter_patches, jupyter_dirs, remove_jupyter_dirs

@ -0,0 +1,19 @@
Contains a collection of extensions that add functionality to the Jupyter
notebook. These extensions are mostly written in Javascript, and are loaded
locally in the browser.
Read
`the documentation <https://jupyter-contrib-nbextensions.readthedocs.io>`_
for more information.
The
`jupyter-contrib repository <https://github.com/ipython-contrib/jupyter_contrib_nbextensions>`_
is maintained independently by a group of users and developers, and is not
officially related to the Jupyter development team.
The maturity of the provided extensions varies, so please check
`the repository issues page <https://github.com/ipython-contrib/jupyter_contrib_nbextensions/issues>`_
if you encounter any problems, and create a new issue if needed!

@ -0,0 +1,60 @@
Metadata-Version: 2.0
Name: jupyter-contrib-nbextensions
Version: 0.5.1
Summary: A collection of Jupyter nbextensions.
Home-page: https://github.com/ipython-contrib/jupyter_contrib_nbextensions.git
Author: ipython-contrib and jupyter-contrib developers
Author-email: jupytercontrib@gmail.com
License: BSD
Download-URL: https://github.com/ipython-contrib/jupyter_contrib_nbextensions/tarball/0.5.1
Keywords: IPython,Jupyter,notebook
Platform: Any
Classifier: Development Status :: 1 - Planning
Classifier: Intended Audience :: End Users/Desktop
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: BSD License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: JavaScript
Classifier: Programming Language :: Python
Classifier: Topic :: Utilities
Provides-Extra: test
Requires-Dist: ipython-genutils
Requires-Dist: jupyter-contrib-core (>=0.3.3)
Requires-Dist: jupyter-core
Requires-Dist: jupyter-highlight-selected-word (>=0.1.1)
Requires-Dist: jupyter-latex-envs (>=1.3.8)
Requires-Dist: jupyter-nbextensions-configurator (>=0.4.0)
Requires-Dist: nbconvert (>=4.2)
Requires-Dist: notebook (>=4.0)
Requires-Dist: pyyaml
Requires-Dist: tornado
Requires-Dist: traitlets (>=4.1)
Requires-Dist: lxml
Provides-Extra: test
Requires-Dist: nbformat; extra == 'test'
Requires-Dist: nose; extra == 'test'
Requires-Dist: pip; extra == 'test'
Requires-Dist: requests; extra == 'test'
Provides-Extra: test
Requires-Dist: mock; python_version == "2.7" and extra == 'test'
Contains a collection of extensions that add functionality to the Jupyter
notebook. These extensions are mostly written in Javascript, and are loaded
locally in the browser.
Read
`the documentation <https://jupyter-contrib-nbextensions.readthedocs.io>`_
for more information.
The
`jupyter-contrib repository <https://github.com/ipython-contrib/jupyter_contrib_nbextensions>`_
is maintained independently by a group of users and developers, and is not
officially related to the Jupyter development team.
The maturity of the provided extensions varies, so please check
`the repository issues page <https://github.com/ipython-contrib/jupyter_contrib_nbextensions/issues>`_
if you encounter any problems, and create a new issue if needed!

@ -0,0 +1,426 @@
../../Scripts/jupyter-contrib-nbextension.exe,sha256=RYQV4JbQFhRIoHY06k-o3KvJ9-lFSYW8ekjipJx2kHo,106415
jupyter_contrib_nbextensions-0.5.1.data/scripts/jupyter-contrib-nbextension,sha256=Kbjz7srIIhUeqt5m3KLALT9p4f7S26l_Dz9NvHCAlWE,107
jupyter_contrib_nbextensions-0.5.1.dist-info/DESCRIPTION.rst,sha256=R_R-BcDs29TFSq4yhBeiA9sNTP5pDx3BNenq6t0xgow,741
jupyter_contrib_nbextensions-0.5.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
jupyter_contrib_nbextensions-0.5.1.dist-info/METADATA,sha256=A2BseMc9_b0Aoy7gbfkdorSfo3i7mUJxcI4rJvD5kyU,2307
jupyter_contrib_nbextensions-0.5.1.dist-info/RECORD,,
jupyter_contrib_nbextensions-0.5.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
jupyter_contrib_nbextensions-0.5.1.dist-info/WHEEL,sha256=kdsN-5OJAZIiHN-iO4Rhl82KyS0bDWf4uBwMbkNafr8,110
jupyter_contrib_nbextensions-0.5.1.dist-info/entry_points.txt,sha256=YMyu5iwWL9JzEpCJKOn43CjyUGyhvi6sHtZVTeELYZk,616
jupyter_contrib_nbextensions-0.5.1.dist-info/metadata.json,sha256=uAtSOZV8QOe1OQXG1LDNjEYcGNnKwtUteYYlT4Ujk-w,2298
jupyter_contrib_nbextensions-0.5.1.dist-info/top_level.txt,sha256=GZJKugWyvBhBZTPWBBWjboHOeBBxAoZoE1C1fcYB8AA,29
jupyter_contrib_nbextensions/__init__.py,sha256=DdiAEnJh85tvoAW-JBzDE4ZpWjvec6RTIwE03y-WYDA,1048
jupyter_contrib_nbextensions/__pycache__/__init__.cpython-37.pyc,,
jupyter_contrib_nbextensions/__pycache__/application.cpython-37.pyc,,
jupyter_contrib_nbextensions/__pycache__/install.cpython-37.pyc,,
jupyter_contrib_nbextensions/__pycache__/migrate.cpython-37.pyc,,
jupyter_contrib_nbextensions/application.py,sha256=D3eh-RSe9FdGjqQxm-LxiyiVNxg_o5unY3RLe7U-QQ0,9678
jupyter_contrib_nbextensions/config_scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
jupyter_contrib_nbextensions/config_scripts/__pycache__/__init__.cpython-37.pyc,,
jupyter_contrib_nbextensions/config_scripts/__pycache__/highlight_html_cfg.cpython-37.pyc,,
jupyter_contrib_nbextensions/config_scripts/__pycache__/highlight_latex_cfg.cpython-37.pyc,,
jupyter_contrib_nbextensions/config_scripts/highlight_html_cfg.py,sha256=X221HQIEmX4o54irbFszW4RFJGtRuQ5wBJYHV-62iik,649
jupyter_contrib_nbextensions/config_scripts/highlight_latex_cfg.py,sha256=VSKETyAs4je9N0C5IChbduU7A21ZiRL4ds8Ha37DEuo,706
jupyter_contrib_nbextensions/install.py,sha256=2LLH2OXQxoAq0RLyt5hbxR0XV6rcfN0r6EmSxxgKtLs,9383
jupyter_contrib_nbextensions/migrate.py,sha256=Emo-d-WMG4ktdU7dQJrmTC88DRNhlEFFj56W_LAXI9U,10905
jupyter_contrib_nbextensions/nbconvert_support/__init__.py,sha256=qroYvVr5bmeG6gYBrcXGnsdoHqRlbBD2bQa31Ibi30A,1211
jupyter_contrib_nbextensions/nbconvert_support/__pycache__/__init__.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbconvert_support/__pycache__/collapsible_headings.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbconvert_support/__pycache__/embedhtml.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbconvert_support/__pycache__/execute_time.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbconvert_support/__pycache__/exporter_inliner.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbconvert_support/__pycache__/js_highlight.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbconvert_support/__pycache__/nbTranslate.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbconvert_support/__pycache__/pp_highlighter.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbconvert_support/__pycache__/pre_codefolding.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbconvert_support/__pycache__/pre_embedimages.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbconvert_support/__pycache__/pre_pymarkdown.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbconvert_support/__pycache__/pre_svg2pdf.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbconvert_support/__pycache__/toc2.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbconvert_support/collapsible_headings.py,sha256=gfdNnqFNZCei00JZISZPgWsHyexq6ADJ5cfG9VvgDqE,1738
jupyter_contrib_nbextensions/nbconvert_support/embedhtml.py,sha256=_6hopAsUe_0denmbnbXxIZpCaQIs7vSh16Jd9d29Y6A,3624
jupyter_contrib_nbextensions/nbconvert_support/execute_time.py,sha256=mFIKj7olTfi6_NWRoKQIyWvWmA1eycSJ5o_JVHhpfMU,1451
jupyter_contrib_nbextensions/nbconvert_support/exporter_inliner.py,sha256=ag_p-n0LcXaBkcdUA36Gf8z1Gn6M5idcpBTvf0GhhNE,1563
jupyter_contrib_nbextensions/nbconvert_support/js_highlight.py,sha256=ss-W2wMV18_VkASNNg9V7aX2BvoEoikjSsnco29fCCA,5910
jupyter_contrib_nbextensions/nbconvert_support/nbTranslate.py,sha256=3icpvJHatZbfYGr3QnUpfDzCKkt7nYvQiJaL5cBw__g,6773
jupyter_contrib_nbextensions/nbconvert_support/pp_highlighter.py,sha256=p5BhLbEZygMS748bAZS8_TM3uR-Hc_Xnt21ddmRfc28,6484
jupyter_contrib_nbextensions/nbconvert_support/pre_codefolding.py,sha256=mmUIEZI45DbzipxkXBL2gcFuuT3q3QzJTsCBVOdwlgE,4449
jupyter_contrib_nbextensions/nbconvert_support/pre_embedimages.py,sha256=jnyKtPWzddL_aWMVjF_BkMRbg-GHoFYuBJJMqBHbwOg,5940
jupyter_contrib_nbextensions/nbconvert_support/pre_pymarkdown.py,sha256=wqdYxKLLZ7ZssREhzwO63pW0d1ZUiTzhg6ahoTc69UU,1564
jupyter_contrib_nbextensions/nbconvert_support/pre_svg2pdf.py,sha256=oWylxNVspS-nbzKGiwyzSjSDO1wcHbVs2FqaMqfZlcM,6733
jupyter_contrib_nbextensions/nbconvert_support/toc2.py,sha256=KKeONX6kzfDJLi9EJ3RbRx8yUGXvJ7aufnTBX186Tik,1842
jupyter_contrib_nbextensions/nbextensions/addbefore/addbefore.yaml,sha256=MpIR3vf35RydH_Jlif5bqbe67iWZCXaAFtOOTd1YPko,193
jupyter_contrib_nbextensions/nbextensions/addbefore/icon.png,sha256=_8MPoV8_r96O2M6_xxcAmC5oculCGyLQ3z6QnjmSGf8,5712
jupyter_contrib_nbextensions/nbextensions/addbefore/main.js,sha256=v88tEL4YtzlYhkKRBVYH6pkJfvD0PJytuAPmqhIXo4w,1632
jupyter_contrib_nbextensions/nbextensions/addbefore/readme.md,sha256=Hu8cJu_eF2PViNRo99OaMM-O-yziyXN6iI0V2Ps9akI,455
jupyter_contrib_nbextensions/nbextensions/autosavetime/README.md,sha256=vPaNpObj-YG17joFKL3UhBAUp9wK6tKeNQxj7586Qls,499
jupyter_contrib_nbextensions/nbextensions/autosavetime/autosavetime.yaml,sha256=NJcOF7vMdNPc9CIt5Ud5fvY5EAie0Kga2bI9eWjWT0c,748
jupyter_contrib_nbextensions/nbextensions/autosavetime/icon.png,sha256=J2QlWOq-ZrwLCnSMrnn7CvNvQn1ISq-C3DvqtPnc9ac,17906
jupyter_contrib_nbextensions/nbextensions/autosavetime/main.js,sha256=djI0ngp7s1ZpF2iyY5S0DKUcO1fM2m7dWbzuKBQdktU,2419
jupyter_contrib_nbextensions/nbextensions/autoscroll/README.md,sha256=QP-3Cn9FF2PcgqIC1e3B8dIF66LcgOS91Lg0GNQER30,647
jupyter_contrib_nbextensions/nbextensions/autoscroll/autoscroll.yaml,sha256=6zfsAKvd1fGHgqtOVsY68XvVpNQZA11d8dZtx_wF76Q,949
jupyter_contrib_nbextensions/nbextensions/autoscroll/icon.png,sha256=pQf4Pc9pccyx8WqbQab3f6VYt6_OFJ0kFZ7BEyYgNK4,32733
jupyter_contrib_nbextensions/nbextensions/autoscroll/main.js,sha256=jy29MZ8Fk5CpcUNILQt1N_H3X1Mc-7q6tWbpJhg4xNw,4249
jupyter_contrib_nbextensions/nbextensions/cell_filter/README.md,sha256=XNNw6VjjKqUzCsEXVZhYOERkuTD_5zAp80DVeE88khA,165
jupyter_contrib_nbextensions/nbextensions/cell_filter/cell_filter.js,sha256=YX6qyiHCHiIORqhFmlwVdDrhqN_Q1KbSAd3zuIKE89o,6093
jupyter_contrib_nbextensions/nbextensions/cell_filter/cell_filter.yml,sha256=qwGirdFNBC_0yhO9zXEY_W-JVztsXFqQvO9VqodsGhM,269
jupyter_contrib_nbextensions/nbextensions/code_font_size/README.md,sha256=E_QEp_y-QUs6KwmHvPxnouMpXfSBk0auoFVtDTxrJgI,154
jupyter_contrib_nbextensions/nbextensions/code_font_size/code_font_size.js,sha256=arAgyPMfPmNNl9MidfC0K4MX5T2OHtqyn6o20IYdrPA,2816
jupyter_contrib_nbextensions/nbextensions/code_font_size/code_font_size.yaml,sha256=9suNBiqzORFsaVm56ObfQ_IMgw8082dgzNa5Wis2ur4,267
jupyter_contrib_nbextensions/nbextensions/code_prettify/2to3.js,sha256=6zHLV_wcLpY1vvYT2_ftvib_on2Joh3ND-qiv7Zo_Ho,1853
jupyter_contrib_nbextensions/nbextensions/code_prettify/2to3.yaml,sha256=llzthZtWc2-DwzhZde4QKPR_1phCZzACbsODALKfbHo,2149
jupyter_contrib_nbextensions/nbextensions/code_prettify/README.md,sha256=MxFGD0VT8u-dDu00aNToiEKKZNaXCCHUZawFqgCRC10,12570
jupyter_contrib_nbextensions/nbextensions/code_prettify/README_2to3.md,sha256=K9XjYcWcYsTzso9rgUEXlLF4DEyb3Ya5ju2jySHhjSg,4988
jupyter_contrib_nbextensions/nbextensions/code_prettify/README_autopep8.md,sha256=DLyNa5kby1On6u8Iywa8hX3uQ7AXVh1tyJS2HMd5dJY,4792
jupyter_contrib_nbextensions/nbextensions/code_prettify/README_code_prettify.md,sha256=ZDOoNhb7jXAZLRkBa3Km3ZopwNG9gYWI_vlSE2cblEw,11772
jupyter_contrib_nbextensions/nbextensions/code_prettify/README_isort.md,sha256=Rg8ZA1uD_AFBlqFatL4Coo6y7tHargWviuB3EJPgPBA,1988
jupyter_contrib_nbextensions/nbextensions/code_prettify/autopep8.js,sha256=VWYOLCdHAmJMPfZXBwVIwlnq4ytGneD87gYQlhqIAj0,1104
jupyter_contrib_nbextensions/nbextensions/code_prettify/autopep8.yaml,sha256=cHroxq9ge-8g0ZVPwj4t-fssZZVooKWawKWic-Sv-XU,1836
jupyter_contrib_nbextensions/nbextensions/code_prettify/code_prettify.js,sha256=7uRvK6mHoSiLIENRteaVa_1BU7ps020UQnDbkpCX8YY,2178
jupyter_contrib_nbextensions/nbextensions/code_prettify/code_prettify.yaml,sha256=PlAsd_TFiapujUNkOJeu_SdMbjiXL_OJbzhyiB67cG0,2522
jupyter_contrib_nbextensions/nbextensions/code_prettify/demo-R.gif,sha256=pSCDEcCtd-ncxIEVoGbMPtLTIy7UTwsjRsIYep8xfME,234783
jupyter_contrib_nbextensions/nbextensions/code_prettify/demo-jv.gif,sha256=G3y8lmyL2uxgsrc8xAOHvoIS0AR09TZG5QqWM8NpNjM,121795
jupyter_contrib_nbextensions/nbextensions/code_prettify/demo-py.gif,sha256=Bqj6EAcRoaOqekJX4tEcmzvt9e82thAPw-zUkBHvk-Y,89830
jupyter_contrib_nbextensions/nbextensions/code_prettify/demo_2to3.gif,sha256=VBY6Df4ZHj0gMzIMd-xnXJO-nsG35_GYsQLuCDdkgNk,121036
jupyter_contrib_nbextensions/nbextensions/code_prettify/isort.js,sha256=06bJOeWLsdT6q_cypeS8iz1AfFLHrjIcbzQ_TgyheeM,1390
jupyter_contrib_nbextensions/nbextensions/code_prettify/isort.yaml,sha256=_Z6AZupHe88BPawRLa95kw2CHuvxVSzYCM43yfetAHM,1351
jupyter_contrib_nbextensions/nbextensions/code_prettify/kernel_exec_on_cell.js,sha256=3_C2JnCyFQeGfkT-QK34JorkH9To4Uxh3cHYhpa6KeE,15294
jupyter_contrib_nbextensions/nbextensions/codefolding/codefolding.yaml,sha256=r6To7xQorccwS6AuF7WcY3tHqaPvRQiMXhBU_vgxzKs,516
jupyter_contrib_nbextensions/nbextensions/codefolding/codefolding_editor.png,sha256=kqlfdFbKKiLBFZ9xpjjc7__-6L9aX3cuSAzmNm2e7Fk,23095
jupyter_contrib_nbextensions/nbextensions/codefolding/codefolding_editor.yaml,sha256=0F3B-cBrg5kDCuhvyVLrbMejtFABTuwfN6fvMXN8LAc,568
jupyter_contrib_nbextensions/nbextensions/codefolding/codefolding_firstline_folded.png,sha256=FjXw0LiG-OzcAK9sd4cEA65nXgXqpSfAjZec3h5jpsI,6159
jupyter_contrib_nbextensions/nbextensions/codefolding/codefolding_firstline_unfolded.png,sha256=I9ua0Zxaf8Wzce5of2XRkYdWP2DYGEabnWtxqugkabI,7418
jupyter_contrib_nbextensions/nbextensions/codefolding/codefolding_indent_folded_1.png,sha256=UJrzG6hyuv6oebXtMLTtbOp7f8M2sdWQ1c9C0zz_5d8,7837
jupyter_contrib_nbextensions/nbextensions/codefolding/codefolding_indent_folded_2.png,sha256=aDp7WuZJOYYVX7nG92lCr76SKBK8ZeXI0VcJbe462CI,4135
jupyter_contrib_nbextensions/nbextensions/codefolding/codefolding_indent_unfolded.png,sha256=iW6U0hvnvS3blQ7z2Zhi9-EGnX3HNQ8_tBlWCBdE0v8,12170
jupyter_contrib_nbextensions/nbextensions/codefolding/edit.js,sha256=7bcKbT27WDxb5jDewmmC4e6wgusMRFPycdOo8BbjH7A,90
jupyter_contrib_nbextensions/nbextensions/codefolding/firstline-fold.js,sha256=tuMEOd6QSn-8tC2rIG41YqXs2pc_Rl-2Z4EjVI7C5r8,496
jupyter_contrib_nbextensions/nbextensions/codefolding/foldgutter.css,sha256=yRcjwmUySpFK-9Nl1ztqv1_hD8dp_P14WSwwP70Fx4A,44
jupyter_contrib_nbextensions/nbextensions/codefolding/icon.png,sha256=p8s9BTpOffg_GhMv-0YbBqv2GrYiGA7_cUKJOq608QE,15419
jupyter_contrib_nbextensions/nbextensions/codefolding/magic-fold.js,sha256=xf8iaOH4nQjoWDjOUDxhTYWizQe8JXjKOiswdUpWUwg,501
jupyter_contrib_nbextensions/nbextensions/codefolding/magic-folded.png,sha256=fAZmhkiamle1reKfvoTf4ycMui9TnngB5w0RbLhaZrw,15877
jupyter_contrib_nbextensions/nbextensions/codefolding/magic-unfolded.png,sha256=b9JXmzYRle8ipqpNlDI8tror46BGUzgfSmJbcqorfyw,21858
jupyter_contrib_nbextensions/nbextensions/codefolding/main.js,sha256=J1Ms0SwLcQncQyV7D-ByprIgVcZh2kc-rjI7gAj-hzU,9792
jupyter_contrib_nbextensions/nbextensions/codefolding/readme.md,sha256=jyAjX9pPJ_Da_Qlx-364xEd7l-b9_R44JgBdg6MZPTA,2589
jupyter_contrib_nbextensions/nbextensions/codemirror_mode_extensions/codemirror_mode_extensions.yaml,sha256=YLz4bFEming7zFKchdhvb6imr9pdf_Q_Upic_jGIhGQ,255
jupyter_contrib_nbextensions/nbextensions/codemirror_mode_extensions/main.js,sha256=KkebW8vL6X3b8OPbO5RCIBF9oojq1-8wVOuMAn0wYSw,289
jupyter_contrib_nbextensions/nbextensions/collapsible_headings/collapsible_headings.yaml,sha256=hCMTcdHPL7aDEUShnyBPUvzgf47AjRw5MjIv_aPtQ0U,4490
jupyter_contrib_nbextensions/nbextensions/collapsible_headings/icon.png,sha256=aidE5FcfcnTrAMjryC5Y4mka_6grYjq0ZQXNVJjVT4U,20316
jupyter_contrib_nbextensions/nbextensions/collapsible_headings/main.css,sha256=djDaQMWEvN0Biz_vkI6dTwIRpRQkTXdV0mjTnq7qh7o,3158
jupyter_contrib_nbextensions/nbextensions/collapsible_headings/main.js,sha256=ogtInrp5cskY7aPs2oicH46N_OhiLgR6KfGjRS9DZ-8,35446
jupyter_contrib_nbextensions/nbextensions/collapsible_headings/readme.md,sha256=T_9qkASPamokZmRTu3K7t5tq_0FDycE9kLKx1Qcf4rA,5391
jupyter_contrib_nbextensions/nbextensions/collapsible_headings/screenshot.png,sha256=sJdyVqYt2CGZ7Kw_mZbRFGJPN9V8z3dhCjXyDOwAr7U,209015
jupyter_contrib_nbextensions/nbextensions/comment-uncomment/comment-uncomment.yaml,sha256=HaL82hkY-1LmYSHxKL04jW0nrpZrC-FJU6o5ggrNYi0,495
jupyter_contrib_nbextensions/nbextensions/comment-uncomment/icon.png,sha256=TESGQxX0xy4LfPpdSBCk2BWKZ5bp9cP4M2b0xY9JJXs,32613
jupyter_contrib_nbextensions/nbextensions/comment-uncomment/main.js,sha256=2GcATYpAMUHodwBaHzIshbwQcag00PIl0zZZpaZjmGQ,1873
jupyter_contrib_nbextensions/nbextensions/comment-uncomment/readme.md,sha256=tbBZaGNqsoxRwT3dPUEcNxg93Ltow0pHFSljXXjzhO0,306
jupyter_contrib_nbextensions/nbextensions/contrib_nbextensions_help_item/README.md,sha256=u4eYZFUUdUXdQQNJe9XMitxmiSw-0YP71AWTkW0nxDg,280
jupyter_contrib_nbextensions/nbextensions/contrib_nbextensions_help_item/contrib_nbextensions_help_item.yaml,sha256=FxCmO2hK9Tgw6r87fPUXQTJt0PrwKBRH2kT54eZf4wY,320
jupyter_contrib_nbextensions/nbextensions/contrib_nbextensions_help_item/main.js,sha256=xLCxL3oSpImxOVzOMYqd7rN9MxkHni_OaN5VC16FjmU,1120
jupyter_contrib_nbextensions/nbextensions/css_selector/css/compact.css,sha256=BGM5ZJKjZIam_BVhu_lKH-ieJ7C_SSY3srW7qGu_Zzo,115624
jupyter_contrib_nbextensions/nbextensions/css_selector/css/dark.css,sha256=jlnkNKXdrDTx7p9YpnDRH8vWqIgMi-K07nBFWulNfvg,190164
jupyter_contrib_nbextensions/nbextensions/css_selector/css/duck.css,sha256=vWMFVdd9V2wvmStm11wiGdUVGB0lPWERwemyOtfbktE,115723
jupyter_contrib_nbextensions/nbextensions/css_selector/css/xkcd.css,sha256=SR2cO0KtAZaWriXD21tJhKFMscr2FqVR4SVy5p-RvcU,796
jupyter_contrib_nbextensions/nbextensions/css_selector/main.js,sha256=lES8J3ioxx-DnbOsKT_XeG0RiwlHcNzOHeZqtQUzPlA,2740
jupyter_contrib_nbextensions/nbextensions/datestamper/icon.png,sha256=eMArxw68rPLGyAXghbFPHDybH3SdjJQF_nsaVZMrva4,33575
jupyter_contrib_nbextensions/nbextensions/datestamper/main.js,sha256=cIaAbUMYVU-IfMhZdV77xwjvwih6rMsoN2TVfDnbjXw,1284
jupyter_contrib_nbextensions/nbextensions/datestamper/main.yaml,sha256=TpKW2bv8Ha0X9zuGOmPj1NeXqVi12KtM1gOnM5PNZso,216
jupyter_contrib_nbextensions/nbextensions/datestamper/readme.md,sha256=KjaWZxMlv1ZM3KYCvxxV7fFBi8YbeW8znNA-X-CT8Ps,122
jupyter_contrib_nbextensions/nbextensions/equation-numbering/button.png,sha256=cAGs893-CTfpLJ4u3xSIduAJAoptgHfQqLSt5Bla8Jc,4612
jupyter_contrib_nbextensions/nbextensions/equation-numbering/icon.png,sha256=77idzmP0KvmOfzGDk4qpIDvbAYl9sojGuT6ShGvaFRs,2124
jupyter_contrib_nbextensions/nbextensions/equation-numbering/info.yaml,sha256=k_i81mC86VfPGQaglIP1Zb_twBlK0dACWwKQsGMid-A,225
jupyter_contrib_nbextensions/nbextensions/equation-numbering/main.js,sha256=wPtvrAIcx-PRFU1LRYHHgomH6qS6KvbIJKuZsCjuuPo,1247
jupyter_contrib_nbextensions/nbextensions/equation-numbering/readme.md,sha256=TOcLvmOcOMKltrlP4i8O5Q2SveRV3spCkFdHVDhTw0E,664
jupyter_contrib_nbextensions/nbextensions/execute_time/ExecuteTime.css,sha256=BMbWaq1AGMUYfop6O8BwqikdD3Y-f6EDxFTS0rVST64,110
jupyter_contrib_nbextensions/nbextensions/execute_time/ExecuteTime.js,sha256=nxWmzsdSHq6qmcmN8APNRmmMR2n5z41CdWpLQOnJv7U,12273
jupyter_contrib_nbextensions/nbextensions/execute_time/ExecuteTime.yaml,sha256=st8dB60KYDHz_TPQie57EWDfqwmkLT4Jt-RVNzjLLp0,2544
jupyter_contrib_nbextensions/nbextensions/execute_time/execution-timings-box.png,sha256=XEA9ZT-IFc-_RFvQ_88-rNsFxO22Ob0qJTaldv4eDJ8,132052
jupyter_contrib_nbextensions/nbextensions/execute_time/execution-timings-menu.png,sha256=Vj15V0cwAN8eXPESOIrtgp-5RGCzSgDz2ezRNCA31zA,84333
jupyter_contrib_nbextensions/nbextensions/execute_time/icon.png,sha256=sCsYU_sE7fL3pD_Y2r6D5q0_hueEiAbCf56SarZ9GOo,35837
jupyter_contrib_nbextensions/nbextensions/execute_time/readme.md,sha256=vhriFmA-jeYhv7W1I7pSitDxFJPW6MuS64sfwGdMtlA,7910
jupyter_contrib_nbextensions/nbextensions/execution_dependencies/README.md,sha256=fTi61YOcXFpX8TgIGulZLCjH_lIMbzN3xrLCwf44ZUY,2340
jupyter_contrib_nbextensions/nbextensions/execution_dependencies/execution_dependencies.js,sha256=jqRb8OiMwgZUk-yBDjh9V2rgdh91t5TKs59RTQzii4U,9549
jupyter_contrib_nbextensions/nbextensions/execution_dependencies/execution_dependencies.yml,sha256=YeL2PD1kKuRJW6QVh9LhA60hVhKDC8JO2KLeZg52ky0,406
jupyter_contrib_nbextensions/nbextensions/exercise/exercise.yaml,sha256=RI4JjswznQhsCp3KJmiXG65Qqdj_pONq98KnVp70WZ4,755
jupyter_contrib_nbextensions/nbextensions/exercise/history.md,sha256=SNiX66pBaZFWfv7bL3Ur9S7vAVaGynvS9HozFo5bEZY,1364
jupyter_contrib_nbextensions/nbextensions/exercise/icon.png,sha256=cCoMIKzore8yDqLTF5MGs8RRHctbXbuUcm336uVUuis,15750
jupyter_contrib_nbextensions/nbextensions/exercise/image.gif,sha256=dtnRWtD3_L5aF4rZ-RoUfDl8G6TFUe5t97b52NdS2cM,259578
jupyter_contrib_nbextensions/nbextensions/exercise/main.css,sha256=NnJvc7yzDVmqA5FSb_fnMnRkKrc_fgIqdTL7J-Yv5tE,273
jupyter_contrib_nbextensions/nbextensions/exercise/main.js,sha256=t4GFTEB3L6QQ-b3hKU-4MqfKZEvMglOMhnH0MEMon24,6319
jupyter_contrib_nbextensions/nbextensions/exercise/readme.md,sha256=c5xMiEEoMp8u-IPdJItPHZbwA51cmtGMcBF-dJuhp6U,2902
jupyter_contrib_nbextensions/nbextensions/exercise2/exercise2.yaml,sha256=UAt-mZuezZiM5K4OXghcPmGkspqOOv79uy9q7T_A8dM,756
jupyter_contrib_nbextensions/nbextensions/exercise2/icon.png,sha256=a2CZV3aTaOnOfTzzoJQxu7gH4PBxJ7NFB8rdA0tCo6I,11906
jupyter_contrib_nbextensions/nbextensions/exercise2/image.gif,sha256=dtnRWtD3_L5aF4rZ-RoUfDl8G6TFUe5t97b52NdS2cM,259578
jupyter_contrib_nbextensions/nbextensions/exercise2/main.css,sha256=T79ml0tvNH7IwNfGaTrUBjeeUPOqhdVU3Vi6pgHFR6M,1651
jupyter_contrib_nbextensions/nbextensions/exercise2/main.js,sha256=6BqVCLQK-EwUVFcg1_fGdq9LIBZDGtmFPOfjdU1kdvs,5901
jupyter_contrib_nbextensions/nbextensions/exercise2/readme.md,sha256=kOI721y7t2uEBpTPnVVpjH7CrzwRtAhd5SFannhOeoA,2904
jupyter_contrib_nbextensions/nbextensions/export_embedded/export_embedded.yaml,sha256=del4TE0L1zWQ_kqCigbGmIfGiKBpmw4alh-xE2-XHx0,173
jupyter_contrib_nbextensions/nbextensions/export_embedded/icon.png,sha256=aDh1Hb-psVkur8FhmNQ97BEUEPCBM40GV5kUogEbvD4,30335
jupyter_contrib_nbextensions/nbextensions/export_embedded/main.js,sha256=Z-ZdUyGmQcWbToWgQAvSKTVQlToboloTc7sYhsTN9pg,1598
jupyter_contrib_nbextensions/nbextensions/export_embedded/readme.md,sha256=PpTIG7bFFcMURPz9OLYW8tMmBNDEXh4rEucXW9ahnX4,493
jupyter_contrib_nbextensions/nbextensions/freeze/config.yaml,sha256=P6CME7Pl-5jSGbeQhlifsKIdCJsTwFf3FdGg5_xcoXc,452
jupyter_contrib_nbextensions/nbextensions/freeze/icon.png,sha256=nyDLhOxXerQFWuZwmt9T6Lw1KEj4K8g_JMOuK8o-plo,11100
jupyter_contrib_nbextensions/nbextensions/freeze/main.js,sha256=kJ3TQrgcsIZHkbdovEpiynwgPI-cCIhGnwOJxmnH3Mo,7032
jupyter_contrib_nbextensions/nbextensions/freeze/readme.md,sha256=u5_cZJR-jcxbjIcaOyM_RM_wXBhUKnCFdGtYYdk_EKQ,830
jupyter_contrib_nbextensions/nbextensions/gist_it/gist_it.yaml,sha256=R2UnRn8VxCi7GIuuAGcoHl8-IZA0Q6yZVLennTRljuE,976
jupyter_contrib_nbextensions/nbextensions/gist_it/icon.png,sha256=8GPC8X77PPa7yKyCWNlyP9TTmZjULchhD7eytjOoXHc,23735
jupyter_contrib_nbextensions/nbextensions/gist_it/main.js,sha256=JLDq_Cj-xcU4yxMiSwFaKZqOfwRIrE7_e3yRzrdbO70,17781
jupyter_contrib_nbextensions/nbextensions/gist_it/readme.md,sha256=gDDnK0K3KDjcVf9yjxPUrJyI_wHPfuoDOorePbAT_FU,2300
jupyter_contrib_nbextensions/nbextensions/help_panel/help_panel.css,sha256=SR9Rxi0Xj95IJuxCjDcPG6R-KTGMTWl9zIU7BdtFb6A,873
jupyter_contrib_nbextensions/nbextensions/help_panel/help_panel.js,sha256=WSSTnwIqurKZF9c4flfHEUwobeBxOLnWHqjfm_wwVpo,8938
jupyter_contrib_nbextensions/nbextensions/help_panel/help_panel.yaml,sha256=_snsJSbNJ6VYFLjMeqjV53LxY8XgvatNXg1mu31LOM0,401
jupyter_contrib_nbextensions/nbextensions/help_panel/help_panel_ext.png,sha256=DdQq8IsrIXegcBWTHSa_kry7PnfJaaDKaE2XDcZfMF8,488419
jupyter_contrib_nbextensions/nbextensions/help_panel/help_panel_ext_fullscreen.png,sha256=TNny0Vn1k7NI-908mU2QnKY9U3k8ZpsvC3UCb4nMpus,304127
jupyter_contrib_nbextensions/nbextensions/help_panel/icon.png,sha256=zRnIbUJtqKmSEdz9bOCOgUOOSWWGS8PyRYtUuAu6O_w,19451
jupyter_contrib_nbextensions/nbextensions/help_panel/img/handle-v.png,sha256=aNen47qw5wbOmgCb9raGGfWyHrRLmnbDU9_C_yqa-vY,196
jupyter_contrib_nbextensions/nbextensions/help_panel/readme.md,sha256=NGI1YGfJx_gj1KBZYTqdfPvn_wyQtQULa_9r-_aSsb4,520
jupyter_contrib_nbextensions/nbextensions/hide_header/README.md,sha256=NeVusgi7ewvmu2JBK1ASW13SF76RWpNk9AhxTdUGjkY,107
jupyter_contrib_nbextensions/nbextensions/hide_header/hide_header.yaml,sha256=yFZ-iQHTH68bb0x7acG6NHsMjin_r6UJ5Qc-4cn3yW0,317
jupyter_contrib_nbextensions/nbextensions/hide_header/main.js,sha256=Aci489sEjEv80eXnRUk2cgJeS16MwZ9OuItDKn-Cs3M,1896
jupyter_contrib_nbextensions/nbextensions/hide_input/hide-input.yaml,sha256=XRaN-czrf97XZ6SHWZDnHcOIghWrdPfWLl_c9cEWW5M,184
jupyter_contrib_nbextensions/nbextensions/hide_input/icon.png,sha256=Cso6ktLe4rHwvGlP6AoCGDcGnCHmJwPCDgwdq3XqjvM,21721
jupyter_contrib_nbextensions/nbextensions/hide_input/main.js,sha256=NM00cBLowsAZ1jp73vUufg3W1Qwg86A9Hambx8xEuFw,1750
jupyter_contrib_nbextensions/nbextensions/hide_input/readme.md,sha256=_WyB-N-9m0Ls4msUVU8HCNTZVYwa3RHGMvCfUMA5G70,1683
jupyter_contrib_nbextensions/nbextensions/hide_input_all/hide_input_all.yaml,sha256=FN1RotZ4Yh99fQ_eFtB9rt7De3442-8j_JG_8V7EKaY,182
jupyter_contrib_nbextensions/nbextensions/hide_input_all/hide_input_all_hide.png,sha256=WC4QpIVO_c-pV56snJKERqOBY63Iz50WsStcZDjrD80,29979
jupyter_contrib_nbextensions/nbextensions/hide_input_all/hide_input_all_show.png,sha256=8JX4sDgIJ5FLq26QYvNa-s543XMtx8fCeIIEBnZQADg,77728
jupyter_contrib_nbextensions/nbextensions/hide_input_all/icon.png,sha256=j04REzpEZb05eKni64lprGMcMJb6Df4m-kIJyprDKTw,21917
jupyter_contrib_nbextensions/nbextensions/hide_input_all/main.js,sha256=wHkgO4MXqRvwedVOg5sJazCnjOHW2oGxcnN33t2spzs,1746
jupyter_contrib_nbextensions/nbextensions/hide_input_all/readme.md,sha256=-2ftk4dP7yMNV9A92V2ACc6EJKv-UPd15iHZUjRJscM,1365
jupyter_contrib_nbextensions/nbextensions/highlighter/demo_highlighter.html,sha256=h4xl-WUACZXoCYftSUb5mCOSleReRwKYKz5xcCyWJpY,191800
jupyter_contrib_nbextensions/nbextensions/highlighter/demo_highlighter.ipynb,sha256=59eSPiJY692oY5TqjcoPr3OZqtJAGkw6bH-DbqBLMNs,3298
jupyter_contrib_nbextensions/nbextensions/highlighter/export_highlights.html,sha256=Go-HglVA46hHjCAlU4V9OVoXdtEeTztF0WEPIKUOCSg,198455
jupyter_contrib_nbextensions/nbextensions/highlighter/export_highlights.ipynb,sha256=TWdDIM_fCuwvjnfyGo8F2pr_WEi91aO5kBwYpCNPCDo,8521
jupyter_contrib_nbextensions/nbextensions/highlighter/export_highlights.pdf,sha256=BkIB-Jg5I7cTLDq2beTcjuzQw5nzdlQ6C-VIPYl6T7A,116458
jupyter_contrib_nbextensions/nbextensions/highlighter/export_highlights.tex,sha256=NytCKcWOilnfwF8gpkHREBe-OLKvBEOP31CGgLvLNlM,20676
jupyter_contrib_nbextensions/nbextensions/highlighter/highlighter.css,sha256=3pJT0JLS_FxfgrDu9YPlMh8bQTB193AwiuJw_gE7BE4,246
jupyter_contrib_nbextensions/nbextensions/highlighter/highlighter.js,sha256=5m9pdQncTdg1h63f4vVnv4XzH1NgFKUq8FhSHKDa7hg,11220
jupyter_contrib_nbextensions/nbextensions/highlighter/highlighter.yaml,sha256=VsgbYaXMm0OHAyZ3xa8hLdHAJJ83-IfkXoVhHMnZCs8,196
jupyter_contrib_nbextensions/nbextensions/highlighter/icon.png,sha256=DuJelAVKjNFUBbDHJYfehozsn8xVWqzfWVKGFBOFyPA,48481
jupyter_contrib_nbextensions/nbextensions/highlighter/image.gif,sha256=T_78XkPLaVHzTc2C_wiZ5uKJ9sv63qf_hTmdZSVYpIQ,270930
jupyter_contrib_nbextensions/nbextensions/highlighter/readme.md,sha256=KvIj7RaV7tffYGj7xyB4KFyUBdq97jsZzqKcDZVB8io,1781
jupyter_contrib_nbextensions/nbextensions/highlighter/tst_highlights.html,sha256=Lw4aZnKF42J-S3ZmN4qwCqCUJE7Tv7ECG4MJP1C9rZM,190362
jupyter_contrib_nbextensions/nbextensions/highlighter/tst_highlights.ipynb,sha256=Wm2fKmEppJbnF3J6PkVph9ia_1j3zPD7NjVHg-qXcjM,2496
jupyter_contrib_nbextensions/nbextensions/highlighter/tst_highlights.pdf,sha256=lpn83A2sAbDV30GmThucKvPAaaPhoLGIIZAXgDXQyKw,68588
jupyter_contrib_nbextensions/nbextensions/highlighter/tst_highlights.tex,sha256=uOSFP0zmgGk9Ml2RLSH4m1081N2hZmPtN5kUDKFHhdM,13868
jupyter_contrib_nbextensions/nbextensions/hinterland/README.md,sha256=NmfX_LHSbezJiK79BhYAPx5DTj7WdkXawbinu56ij7k,2199
jupyter_contrib_nbextensions/nbextensions/hinterland/hinterland.js,sha256=JDqODOKOj8hL_rr5qKr6rw8pvjnrg8toIrmLaUPV1bg,5521
jupyter_contrib_nbextensions/nbextensions/hinterland/hinterland.yaml,sha256=_XUBgUliqfuZNizOSvcubE1RC2a13M1tQZS5tVg3DVI,3034
jupyter_contrib_nbextensions/nbextensions/init_cell/README.md,sha256=MHesYfjRVDpivYLBNGo9h3uTV-b4M5B1I0eTj8p7Rck,1525
jupyter_contrib_nbextensions/nbextensions/init_cell/cell_toolbar_menu.png,sha256=ljKq0cqlglwAPSsxzvNAPAnwqS-ejhCcLvnkDhQfpMg,44518
jupyter_contrib_nbextensions/nbextensions/init_cell/icon.png,sha256=JGdz1lnBJmfKMhBjBn5C5jezX90SeC7mqHqncYlgWk4,26545
jupyter_contrib_nbextensions/nbextensions/init_cell/init_cell.yaml,sha256=5FnONqSCOi5QTzVnQM5d_pRnsdKze_IrFK4TQHeeuaw,579
jupyter_contrib_nbextensions/nbextensions/init_cell/main.js,sha256=U1i_T2NUgne_Jh1T1u6hNwx-He5OzPeqFba6D9h57hY,5736
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/README.md,sha256=3_1OywtgXRXwfceURI2PusD8FE4kfuQ_9Ck8mfI9g1M,4908
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/icon.png,sha256=0AsUecOKf9ibqHRmBDlcAq-F1Y6KY2EXu6w8LII9BCM,36773
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/keyboard_shortcut_editor.yaml,sha256=_XxpyJAWwfU631atS1iCV67zjApB7WjUKF027-rc0fY,543
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/kse_components.js,sha256=0gmB2gLwq71ouiMuQ1jL80Giw9RbiKmiOaqVKOHc6cM,9755
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/main.css,sha256=2xmHvToqx-dAhCwtrQGsZ1eEg5lZBa1sKf2NyNVekAw,541
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/main.js,sha256=5aj8SpFka_dDO5yjrgoVKstNLOPxdgWRn3vV1OI4kxg,22128
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/quickhelp_shim.js,sha256=34jFmmruVM1EtsrYjQ6LZWIOs2b72y35_CIxk8vn5lA,5860
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/readme_add_new_link.png,sha256=jrlKG2hYh0g0Kc4pUX0YWd-HmNomoy5wcYjqSWiHP9Q,91588
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/readme_add_new_select_action.png,sha256=4idBHAY3txDSdwR6ig2_OOGV5HZkQ1olp4Vbe3QIL1s,233793
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/readme_comma.png,sha256=XWFHgHQnIWLUPRhyoobK9NaHIGbWDWiuq9DRrjzFiQs,107724
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/readme_conflict.png,sha256=yMbCDPmy5kAE0-A_mPqjNrrzTPHyXZLyEtvfaesTaoQ,89818
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/readme_dropdown.png,sha256=tSwHQFNUHtyyn-nGxxRL1BlN6JnvcAO-6x8yGJLAw0M,92811
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/readme_menu_item.png,sha256=d3DS-KpeCkajBUmlqI61MSlm5eCj7OC2-SSn18PVAdg,123510
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/readme_reset_disabled.png,sha256=w7jw7uTfv9Rp3dZMHgYkBaAvZiUMQdbglBB6YY8acjE,100648
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/readme_shortcut_editor_blank.png,sha256=YnF9stuLHFT7DtF_aH6DELY-eAfEkZ5P6j17H36RcSk,74777
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/readme_shortcut_editor_success.png,sha256=Zqf5bJCkNPqGwD9tCji9W-3vy7Hz-PngZ6KnL7ea9i0,79437
jupyter_contrib_nbextensions/nbextensions/keyboard_shortcut_editor/readme_undefined_key.png,sha256=iu074PAHCfN8czJABIvMEgwNPVP1rVccwScBNrv_u_0,102150
jupyter_contrib_nbextensions/nbextensions/limit_output/icon.png,sha256=1AMtBhE2ulp6dbdUxVKFOwBMGX1FzZrRZ42kV8Vd5YM,9784
jupyter_contrib_nbextensions/nbextensions/limit_output/limit-output.yaml,sha256=qDc8OXuDYFgMAMdYHmZ2BnCAjHeWbQBpl62NQPnilf4,967
jupyter_contrib_nbextensions/nbextensions/limit_output/main.js,sha256=ULLu_vYEiYmOFQCiqFlmeLPJDcZxNCIOZ3BaNR01b8I,5885
jupyter_contrib_nbextensions/nbextensions/limit_output/readme.md,sha256=aVpPvojeED-d9UVzgPNskbhw8_EcePDFembaTzqRdmk,1654
jupyter_contrib_nbextensions/nbextensions/livemdpreview/livemdpreview.js,sha256=sAtazAuH_hVjLAHB5TBgA7L_Bu6bf8Hm9Y728W2wZYs,3464
jupyter_contrib_nbextensions/nbextensions/livemdpreview/livemdpreview.yml,sha256=BjCG7tjFnrAfMoR9iygEYTGmQw9vpEcXPuvwNYifdpw,742
jupyter_contrib_nbextensions/nbextensions/load_tex_macros/icon.png,sha256=TComH8gG0nNXlGP3KjH-lCw6I_3KZmfCc02VkiAM2ak,5735
jupyter_contrib_nbextensions/nbextensions/load_tex_macros/load_tex_macros.yaml,sha256=OYd2IH0wpZwfXUGdhQhlvXO5dex1WeeAU4ZCVAa98y8,251
jupyter_contrib_nbextensions/nbextensions/load_tex_macros/main.js,sha256=r8zg3Bdzb24ulbXWJ_LcoIbPxK46W8AJGz5BPtYYmPw,1377
jupyter_contrib_nbextensions/nbextensions/load_tex_macros/readme.md,sha256=5X7EoUCfokOnkj5G0MCj17_2cG_s7agdt531z6r6ByU,475
jupyter_contrib_nbextensions/nbextensions/move_selected_cells/README.md,sha256=3RuSusg9wtFbvaKM3qPkmy5ZeRryg_qilV5jfgBRz88,831
jupyter_contrib_nbextensions/nbextensions/move_selected_cells/main.js,sha256=L65JIAx2NnnfTssmjw0IeRcfoKG8EgZBI9RN4njB26s,3270
jupyter_contrib_nbextensions/nbextensions/move_selected_cells/move_selected_cells.yaml,sha256=ZtolFYw7UPePt4cxrOMTEqALyLsljyu8f2vYfqewT04,193
jupyter_contrib_nbextensions/nbextensions/navigation-hotkeys/hotkeys.yaml,sha256=2K7L5xfGNG4RIzjh9ggKFfk18V5AqCOYTZPMD5YSMjk,765
jupyter_contrib_nbextensions/nbextensions/navigation-hotkeys/icon.png,sha256=Ju2QGidzSDh06H3kBFPmAEzDZTDLJaRaTgy7HqBGlnM,29922
jupyter_contrib_nbextensions/nbextensions/navigation-hotkeys/main.js,sha256=muaUxrBpSjDXzmoiuuZaj3tvX8P_8DPJ5j9g5oGAMuw,8663
jupyter_contrib_nbextensions/nbextensions/navigation-hotkeys/readme.md,sha256=VT7ZpuvDLEUZiFlExbGAbe-clyH3ubTtnOz_l0CEsWQ,993
jupyter_contrib_nbextensions/nbextensions/nbTranslate/README.md,sha256=ZeLFaJVsoIWY2WQRl-vMmHql1crCxbiBsP8klB0mt-4,3690
jupyter_contrib_nbextensions/nbextensions/nbTranslate/demo1.gif,sha256=1ajJDYN1o6T7Yt7jdt6RKBuWx2FtN2Puq6nMHU-cH5w,2341673
jupyter_contrib_nbextensions/nbextensions/nbTranslate/demo2.gif,sha256=wnreryupBVZlAsPzGfHQHlmjaDx3OS2JDCSkUyOWiEw,3099913
jupyter_contrib_nbextensions/nbextensions/nbTranslate/languages.js,sha256=mj7Ly3at_eb87yPfPsYmo4lUN6trovSYnNCt0ApPZnE,2489
jupyter_contrib_nbextensions/nbextensions/nbTranslate/main.js,sha256=vrlMJKxMR2WfZghjQDtlxQ8As0VBp3qTFZvknlgNOiE,4830
jupyter_contrib_nbextensions/nbextensions/nbTranslate/mutils.js,sha256=OSgxuu2SohYVTfnsWoNyRZbYGNvpIfMnmQH3mIijbX8,8367
jupyter_contrib_nbextensions/nbextensions/nbTranslate/nbTranslate.js,sha256=FuGV8C6JSaUwPkkIFq-f0rzMT_aLu4E739CW17gkETI,23055
jupyter_contrib_nbextensions/nbextensions/nbTranslate/nbTranslate.yaml,sha256=VN9eJIrMmIlFMI1LohFoJnkHj3ol0K91F5iYMC3dJg8,1475
jupyter_contrib_nbextensions/nbextensions/notify/notification.png,sha256=7snskKqnp3qxcmDqXxQIe8msLb5RgbvXSP9zamYqErg,30035
jupyter_contrib_nbextensions/nbextensions/notify/notify.js,sha256=YKCMCzS65HGsuRt9HObkPYeNZrPiibYfVIEXbI9zGDI,6341
jupyter_contrib_nbextensions/nbextensions/notify/notify.mp3,sha256=HdIIg0vEBqAZTtwX4Oa09-z2fF2PDEPfJYCXdHmJSws,13945
jupyter_contrib_nbextensions/nbextensions/notify/notify.yaml,sha256=dUa4a98Q9ZIl_55Vz_xsZisyDOmZulx_vEoJsHOHn64,549
jupyter_contrib_nbextensions/nbextensions/notify/readme.md,sha256=eeyk9aXEa7oL81BtqfRG2T_fkfV_K_N2BVgMsLGzF7Y,2817
jupyter_contrib_nbextensions/nbextensions/printview/icon.png,sha256=HgrsFA9H2pF1-jEaix1TfXyM9Wixq-BtdQ2S_5aykgQ,3552
jupyter_contrib_nbextensions/nbextensions/printview/main.js,sha256=9pMNdVACRRc8EvVxT2vI8ayAJ_Iv51P8--0IzanRjzU,2226
jupyter_contrib_nbextensions/nbextensions/printview/printview-button.png,sha256=9IaI8tbUs61znbP1nmWDQUgQA9P7KjHgLnjajoEHRAA,18982
jupyter_contrib_nbextensions/nbextensions/printview/printview.yaml,sha256=ZQTBgGx7461WbHd2TbTKHDXtz2_7dMAIhtdI48kkjCo,485
jupyter_contrib_nbextensions/nbextensions/printview/readme.md,sha256=ALmgiW9TtjWHWOR5RPHXtN7V5TyWFzo-mLEnsOc0pzQ,1946
jupyter_contrib_nbextensions/nbextensions/python-markdown/main.css,sha256=xV0sv78ISSSVfGfP3l-YrS9JXlfPRdcVJtgZXM23674,43
jupyter_contrib_nbextensions/nbextensions/python-markdown/main.js,sha256=mtsbBDFTvVWZ7qG9QJqV99Se0WZ6n0Z4serwK7XXv4I,9193
jupyter_contrib_nbextensions/nbextensions/python-markdown/python-markdown-post.png,sha256=PJ8N9IpIE-SiIW69VUJ82kWbsqLTyWghHeofbNvbLVE,37725
jupyter_contrib_nbextensions/nbextensions/python-markdown/python-markdown-pre.png,sha256=UT08-uU6Btu4bwTDZs9Mxi4MYJjKsrYDL3JHTHfzF0o,19639
jupyter_contrib_nbextensions/nbextensions/python-markdown/python-markdown.png,sha256=3bvMYEm4OysXahJrF24T3AQUORhyq8KnF9GT6XLYOd4,20996
jupyter_contrib_nbextensions/nbextensions/python-markdown/python-markdown.yaml,sha256=5zFspC4Eu6_Fpj87-SbmcRrjMK9WGw5Fzh_M3EZ5rS4,229
jupyter_contrib_nbextensions/nbextensions/python-markdown/readme.md,sha256=SxpYy965PgC3PSziVxuKGceQ5clpjTVtpfU2BgwzNB8,3127
jupyter_contrib_nbextensions/nbextensions/python-markdown/trusted.png,sha256=8MYFNX4D9hXnui5z-1FojMl6nLNcp82sxYxJOldauIg,10464
jupyter_contrib_nbextensions/nbextensions/python-markdown/untrusted.png,sha256=oQRnipa-qrPoU5yxwZ5h6tHf1-u_pwqEGg5_RSQMItg,9548
jupyter_contrib_nbextensions/nbextensions/qtconsole/README.md,sha256=2TV1msi3dXRObb-UGVgGOQ0OxmaoxoezJlj_5wLGw8s,73
jupyter_contrib_nbextensions/nbextensions/qtconsole/qtconsole.js,sha256=FobESQS9quOKtLdM_tgooio3p8EqDtS7wMLDrCA8TTI,793
jupyter_contrib_nbextensions/nbextensions/qtconsole/qtconsole.yaml,sha256=RI-WX7ySp-Zjd3xi4BX_UPmvImxM7hducG4vz5tIFWM,173
jupyter_contrib_nbextensions/nbextensions/rubberband/icon.png,sha256=fUcxfq3pFFSr5JcDcAvyToPQcaEeUsFzYegxRqad4h0,57476
jupyter_contrib_nbextensions/nbextensions/rubberband/main.css,sha256=bJ3nlZrQCZbdkABUmDk2LuWzkELYQapEc3829x7mZdY,181
jupyter_contrib_nbextensions/nbextensions/rubberband/main.js,sha256=bwvz1QWefc2CgsFPNvLJKbK8KeCjYV3hihsvA5YP1S8,7657
jupyter_contrib_nbextensions/nbextensions/rubberband/readme.md,sha256=TH-MgJ7GCVZxmqibDa1xGGHAljhVN_cjnyUpA0_pAF8,1174
jupyter_contrib_nbextensions/nbextensions/rubberband/rubberband.yaml,sha256=ITSHK7gGhR44yx_FRae27HRruglLtl6Qhma-cnUKR_E,189
jupyter_contrib_nbextensions/nbextensions/ruler/edit.js,sha256=oG8X6n8TCjd8b548jHF3f-fgVy95PpA4juR146oerks,78
jupyter_contrib_nbextensions/nbextensions/ruler/icon.png,sha256=P8Iue4dc7BC7PNZ7isjkEfEJwjfXNaedmo0kHDFsFrc,3239
jupyter_contrib_nbextensions/nbextensions/ruler/main.js,sha256=fK5EacOqjoGO6N0JkXRfXMIBNJ7kxHtVwH7ymeLaHO0,3815
jupyter_contrib_nbextensions/nbextensions/ruler/readme.md,sha256=oQOS29hJz2e4UBZNkBZrI4P5hvQFckIX164dHOClngE,1793
jupyter_contrib_nbextensions/nbextensions/ruler/ruler.yaml,sha256=gO4Lv27HOmabkmGsRUR-Mmp_i3HMKCrtA2i1Q50qudo,716
jupyter_contrib_nbextensions/nbextensions/ruler/ruler_editor.yaml,sha256=aBViebTCqLJbomin3-Cm7NGS6agKng93xcQXe6SiT4U,605
jupyter_contrib_nbextensions/nbextensions/runtools/annotations.odg,sha256=suDn68WMYqXvvYbpnueI53h2Shgvg9SfmNxV2qPWhP0,19785
jupyter_contrib_nbextensions/nbextensions/runtools/cellstate.js,sha256=UR_jjdf-1yiZJ9jNJOgVTu45UuZWcqUdq-gvd4x9yYY,644
jupyter_contrib_nbextensions/nbextensions/runtools/demo.gif,sha256=EARAoFXTqHEpjWgI8mC_9qf8HVEwxUNJRqBfesfW95c,723994
jupyter_contrib_nbextensions/nbextensions/runtools/gutter.css,sha256=6dBom4jzfIStutmgGCTs_RcRF-2XvAjCbH5w3FXzCcE,42
jupyter_contrib_nbextensions/nbextensions/runtools/icon.png,sha256=DZEBR960bf5GYJsSgmjVHM38I2icKxaA26rbWAJbOpA,12750
jupyter_contrib_nbextensions/nbextensions/runtools/main.css,sha256=pxgAcUdiJ8X7ki66VtCLs989A2Kfqk0dXzlOPTGK6k0,743
jupyter_contrib_nbextensions/nbextensions/runtools/main.js,sha256=s-hyNEgNoK0qtIgulWiYLGtyXs2STnrkJ3ujj-XjGC8,24380
jupyter_contrib_nbextensions/nbextensions/runtools/readme.md,sha256=2yMtGsj3pN1r0XdBEimgVIqB2w803b9je9mAidfvqdw,3569
jupyter_contrib_nbextensions/nbextensions/runtools/runtools.yaml,sha256=jRiRu7azFKaV9FW7xn_DYd7nKLQwj05RKKaTX7MQE7s,1580
jupyter_contrib_nbextensions/nbextensions/runtools/runtools_execute.png,sha256=AupS7j7gpBeVZ-RiJLk34nZ1BblYQJ6i9fuFhQz83rQ,43869
jupyter_contrib_nbextensions/nbextensions/runtools/runtools_lock.png,sha256=SPbCVDK3iZR-4maXv0N5QUuNpTQq7g22NUoAWLs4voA,15774
jupyter_contrib_nbextensions/nbextensions/runtools/runtools_marker.png,sha256=fkZnMpEBrasNI6KsGIacynxSMbaygkgHsdIXZRU_wWU,23685
jupyter_contrib_nbextensions/nbextensions/runtools/runtools_nb.png,sha256=kjxb9ChMPmGKYW3z03K8EdxvTV8S5Ygl7NUBdavkVsI,4075
jupyter_contrib_nbextensions/nbextensions/runtools/runtools_show_hide.png,sha256=UD41JH_by7E9Ds_Wv11fMdLYSR6wOoFVaYJX7WSwd7g,25909
jupyter_contrib_nbextensions/nbextensions/scratchpad/LICENSE,sha256=HV-RC-_hMC2tFU-w3p5xe_OqWbfPtABk5UdVQt4pWlA,1486
jupyter_contrib_nbextensions/nbextensions/scratchpad/README.md,sha256=5ox-BYq0cRvI5rkNYBKcq4E-7rJBcgK7BPT6N_iRGF8,561
jupyter_contrib_nbextensions/nbextensions/scratchpad/demo.gif,sha256=z7xjWdMsSwcv7qSdykiAp1xvSd1UxtFCJWWPc-DTric,1160320
jupyter_contrib_nbextensions/nbextensions/scratchpad/main.js,sha256=HOZOt4aMxTzbQm89nPeAGiQOllrsN8HCZKAPLgOMlTU,4144
jupyter_contrib_nbextensions/nbextensions/scratchpad/scratchpad.css,sha256=mSmmnq8n1fCjeiUVSwsDzpzH7yVGzITISYUutm3_5SU,571
jupyter_contrib_nbextensions/nbextensions/scratchpad/scratchpad.yaml,sha256=4FJLDpajpRN2ORt-CeWV4Spi8zVakI_jDkaWCGxwCDg,161
jupyter_contrib_nbextensions/nbextensions/scroll_down/config.yaml,sha256=fY9eXAwWsKd0BHsOjgGDkb26CFL5aLW_bH_FY-j_Z_g,295
jupyter_contrib_nbextensions/nbextensions/scroll_down/icon.png,sha256=3aVc5lzv_boP-mfWdzLGy24leulLoLYnK4E_k0xunVY,20617
jupyter_contrib_nbextensions/nbextensions/scroll_down/main.js,sha256=OiKg4jZPlAREuIEaZ_N5a6iRu-coSj-XptCp0FhE7A4,1695
jupyter_contrib_nbextensions/nbextensions/scroll_down/readme.md,sha256=tBxnGtJeU3RrQOzpoqViHogeEzmQu2dvDeWQ7rjE0Vg,341
jupyter_contrib_nbextensions/nbextensions/select_keymap/README.md,sha256=--GVJkDXdZMAQkkMINzEx748UskSfgH2JeXE6SUCrxE,681
jupyter_contrib_nbextensions/nbextensions/select_keymap/main.js,sha256=NKv-gn7-WntukzId6j22ZX4U-53fOz2gsCjnZOCaY18,12237
jupyter_contrib_nbextensions/nbextensions/select_keymap/select_keymap.png,sha256=xch45-X6q5XVyJyUq20LJFBFNgr6WRLLPE8aVg-EzzU,43352
jupyter_contrib_nbextensions/nbextensions/select_keymap/select_keymap.yaml,sha256=diF0JtAnq9iI1b1oM5VleJ-rpZVz23ZA1CGill8bHwM,504
jupyter_contrib_nbextensions/nbextensions/skill/README.md,sha256=EqtQAxLI2Msc89cJTuNDLhNRz5wplcih2fPZdqsYFO4,587
jupyter_contrib_nbextensions/nbextensions/skill/main.js,sha256=YzFBDiIuXb2EvB7LQCOr6nMxYxrR2kShu7YlOAntYYg,429
jupyter_contrib_nbextensions/nbextensions/skill/skill.js,sha256=yCdcwSmtncZoV4LoU19X0OljjjvDyCbvMZYgnowGhoc,134311
jupyter_contrib_nbextensions/nbextensions/skill/skill.yaml,sha256=f_lASzosfAbMiMNgUBiy3J0l7oSJ10hLJmxtlrNiyCk,162
jupyter_contrib_nbextensions/nbextensions/skip-traceback/icon.png,sha256=C5NU54liYWmx9aAKM8yTaC_HGDYY9RxCdjJFi1WeIek,4160
jupyter_contrib_nbextensions/nbextensions/skip-traceback/main.js,sha256=GfoZW0vfDe0sa7KGI283AXE-OYgLHIXwMx_yKoSrUz0,8309
jupyter_contrib_nbextensions/nbextensions/skip-traceback/readme.md,sha256=6BCN8NxYtFJYjmmexILwqchK-diwmbu_VBeH8LKLxDc,2365
jupyter_contrib_nbextensions/nbextensions/skip-traceback/skip-traceback.png,sha256=C0j_INSeBaMc1NSD_ogn3I3mbr7MmHw7cdKkBxJ3YQM,19138
jupyter_contrib_nbextensions/nbextensions/skip-traceback/skip-traceback.yaml,sha256=ClQltOy7_O8MgDbixJRjrFUgA1obuOKvzRfLrTlj5rw,1272
jupyter_contrib_nbextensions/nbextensions/skip-traceback/traceback.png,sha256=mCKrtPk9-z85I9hzEC49Edioho3JxnOjk8J8lqCo8nE,59231
jupyter_contrib_nbextensions/nbextensions/snippets/README.md,sha256=uKIM-UO3rhkiF5YDCONZs-38V0nnxWKz-WCQ0z5RfJM,1852
jupyter_contrib_nbextensions/nbextensions/snippets/main.js,sha256=-ovJPzUwOO99BjRuubMa2Fov1_68C6LUA9jt_pxjA88,2521
jupyter_contrib_nbextensions/nbextensions/snippets/snippets-demo.gif,sha256=ov12CvVRqYawKZZREQ-nfXeuLZt3MrUrKI9WlFUiHU8,430716
jupyter_contrib_nbextensions/nbextensions/snippets/snippets.json,sha256=8trMsO_t7uEk3yEsBEvq3t3j5luir_xRDHLLUKYMr30,407
jupyter_contrib_nbextensions/nbextensions/snippets/snippets.yaml,sha256=PSCbBP_Sx4MzQ3N-FvBi9BVa3V-xTq_43WVX064G5iw,188
jupyter_contrib_nbextensions/nbextensions/snippets_menu/config.yaml,sha256=vBa-CLUTuLaw5SPm8I3kfOGmsFxGT82p5TUKhlQMDIo,3927
jupyter_contrib_nbextensions/nbextensions/snippets_menu/examples_for_custom.js,sha256=xUit6Tgu2tD0BI4fHyuYQsDBeL0ND1Irc84NZ3z3cys,8255
jupyter_contrib_nbextensions/nbextensions/snippets_menu/main.js,sha256=D2sb0DBCyBokfHIuiYA91N-NgPAIqiQ9PdoXTdJUVZE,10543
jupyter_contrib_nbextensions/nbextensions/snippets_menu/readme.md,sha256=PxRCXXh1ZMpa6t9kPgPMNqBYWbWqcc0Q7bGT9O7brGo,29359
jupyter_contrib_nbextensions/nbextensions/snippets_menu/screenshot1.png,sha256=4MgwUF8ONx0XHZBgYC4gWn6XkB7O3LLPdsu-jede1os,549596
jupyter_contrib_nbextensions/nbextensions/snippets_menu/screenshot2.png,sha256=FFltRxn-VpoLBqcYZpitlTBGcj__NKxAgMX5yvSL4Q0,478926
jupyter_contrib_nbextensions/nbextensions/snippets_menu/screenshot3.png,sha256=JEW1NMo2kCsok1K5a0AUrAqQL8hnVpMQkHXbDa14e5E,402696
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_menu.css,sha256=JQjLwEZlAtK153mUI8aA4ou3NLVUzy1BC_XGyIHS9Gc,1848
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenu_markdown.js,sha256=z-Ao1Kls8WDE6UHWItaQCaaHmtzbDUSOlgotphbT6Lw,2863
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenu_python.js,sha256=fY3rsxKangoiotYeu57KS8D4JjOK6aNvTuSf6Df7cH4,718
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/astropy.js,sha256=KHvZx5aMYYvu4UwAWz_CN26oXxBOSxfC9iDrSWWyi7U,6702
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/h5py.js,sha256=5gO4CN2C4cmgcYDjqenGJNtBN2BSiq1GUbDdbBgfa_o,886
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/matplotlib.js,sha256=idj5j4iuYpHisIaM594HhYPuK_mw5Kam5FC4uSPUEEg,8282
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/numba.js,sha256=9zM80ZaP_8DGAlmHUTRWrmQd2KWsDXUhmEjtUHQS_FE,1481
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/numpy.js,sha256=Ypv39YsNz27rKE-r7CsoGgEEHccrL0JJECxcwtiWVnw,29733
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/numpy_polynomial.js,sha256=ZHUC7quJxBf0UhaszNYRR0h-55fGy0pbeqUKJjMCp4g,3638
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/numpy_ufuncs.js,sha256=K7ZxrzZn8KkOblpRU_wPzqkdhFY76gyqwQMZ3T_D6ow,35530
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/pandas.js,sha256=uEYb0vALDRAdwxnF9WHzziUmsPKDRmTSB46vLaQL0tI,5560
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/python.js,sha256=HivFerNG10P_qUXE3Zyzp2xDcn1vZVLubOZ4Qy7JQ2g,9117
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/python_regex.js,sha256=byuRuGZYZDz32wfWcueW6i8mb0FWY_L2SsTC2QE9Jvw,11298
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/scipy.js,sha256=MvmWFRb7-EXUrrz1WJ742gSBhdq6gGdevgaF2VNtQeY,31620
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/scipy_constants.js,sha256=dC0X_DDPbkMFKR4EfwnEFV0OJ_hS5bXIQIGKdFB4fsU,103938
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/scipy_special.js,sha256=ua5K7L5rpLyhK5I5iLK8vabYo3ICPHMQBNAcNoEsIrU,76141
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/sympy.js,sha256=P2ilZP0uOpb814IYekQHpYPi20SQwapWcmcnSvfsCMM,34425
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/sympy_assumptions.js,sha256=9royuX29ax34k5xOoQeseT0uYkoLRFCFt8JfgTCYx3k,2643
jupyter_contrib_nbextensions/nbextensions/snippets_menu/snippets_submenus_python/sympy_functions.js,sha256=R9395MGdKHxLxM3hn-DFygpXsY0rWWTg7K-lJBYsOUs,25192
jupyter_contrib_nbextensions/nbextensions/snippets_menu/thumbnail.png,sha256=o9fqmU7JwllPkmfS7lqh6NIV3WDSUzZ0VxtX2idbtok,141685
jupyter_contrib_nbextensions/nbextensions/spellchecker/README.md,sha256=hgQ0uxKJTkBfeitmY-8WRIC2bpvHJwIbXNdGw4X2kDM,4422
jupyter_contrib_nbextensions/nbextensions/spellchecker/__pycache__/download_new_dict.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbextensions/spellchecker/config.yaml,sha256=s8YbdF6bxL9KcWmMmb3XF8gHyQTjnJWdC_UdmkEqOWQ,1005
jupyter_contrib_nbextensions/nbextensions/spellchecker/download_new_dict.py,sha256=Z7YueTQBguO-oul5IqKgTW4s1wmwopaIqwf0anSj2FM,1254
jupyter_contrib_nbextensions/nbextensions/spellchecker/main.css,sha256=2hQNeFbcEDLWLfUYQbtVeofQXFQ04sxeo_lQk6xuD5E,244
jupyter_contrib_nbextensions/nbextensions/spellchecker/main.js,sha256=Z21BKeiTmrcYT9_Djt2_P3YiigFdrxLeaOA__Z3krXA,6110
jupyter_contrib_nbextensions/nbextensions/spellchecker/screenshot.png,sha256=njxGUXbbx0t7zqESTvVxF-4jZcjywKpdchLOcqigqkI,25608
jupyter_contrib_nbextensions/nbextensions/spellchecker/typo/LICENSE.txt,sha256=BdpfojyzzyqPL9St-eB11gI1-vSC9L5EdmIiElRbLaU,1674
jupyter_contrib_nbextensions/nbextensions/spellchecker/typo/typo.js,sha256=hz5Qli7gofpHb1vwpqpbeOh1R8YWzMCABwKYJg3LVpw,21170
jupyter_contrib_nbextensions/nbextensions/splitcell/icon.png,sha256=r7hhWR4P4iBp_2ZHOeZpwV0990jCkyQ5bFMXURLLUZU,6382
jupyter_contrib_nbextensions/nbextensions/splitcell/readme.md,sha256=cx10KVK3mYjT1wywEGEGzzCJR9ehomyXYPlSZEVYAcs,118
jupyter_contrib_nbextensions/nbextensions/splitcell/splitcell.js,sha256=hAHyxGB7zqZnJKVWXVqRiRiQFd1wM1Psrhi9YgIZGAA,2666
jupyter_contrib_nbextensions/nbextensions/splitcell/splitcell.yaml,sha256=NKfIirN-t6AfIJBTUOPfmfXqF8d4kpWUhx72GzztrT4,198
jupyter_contrib_nbextensions/nbextensions/table_beautifier/README.md,sha256=gfd9FCQ0qonFQRZH-uWuysPOMvgOQzzzOylduDwiGOI,108
jupyter_contrib_nbextensions/nbextensions/table_beautifier/main.css,sha256=57avNUy34vc05UECpmhk8QNwE9wwqolR5GvzMp2GXAg,1196
jupyter_contrib_nbextensions/nbextensions/table_beautifier/main.js,sha256=xcdXEQcFYjwPz7-Ey4uJEQestgqC8VHS-HEdTZeGN1I,2048
jupyter_contrib_nbextensions/nbextensions/table_beautifier/table_beautifier.yaml,sha256=eHCr8B_Hf1XFkspLL4feFbsGdlwFnbBzReg71GGJ2t0,195
jupyter_contrib_nbextensions/nbextensions/toc2/README.md,sha256=tBdMgRGjlHrB7v0YrzHrGTJwVo5BuWfq2J9-uHBKQf0,11008
jupyter_contrib_nbextensions/nbextensions/toc2/demo.gif,sha256=GRiWIHEGMMYHO8n7BkZOazt_qoXQnqUvpw2APZz7pYc,3485814
jupyter_contrib_nbextensions/nbextensions/toc2/demo2.gif,sha256=EQB7I3R6AXIMZL16vRyCIu8NvQL5jX7f2L6yb25fPAw,420511
jupyter_contrib_nbextensions/nbextensions/toc2/demo3.gif,sha256=3qBWMmq6GtOnlpWNUFwIejltU0klWvc9nMxTKnqvDIg,88268
jupyter_contrib_nbextensions/nbextensions/toc2/demo_dark.png,sha256=uGT3d8vRpU10h7f5zbRoLPlk5mxghZucdI0F_nnoF-Y,77531
jupyter_contrib_nbextensions/nbextensions/toc2/icon.png,sha256=qnWTfoW5YTF-qrH76cE6Q_3Wq32_zptFcj8lvKn56fo,25717
jupyter_contrib_nbextensions/nbextensions/toc2/image.png,sha256=R_FwSMg0K7VwkvUSHmP_JMkXXKfbB2DxmWctnAXWhiI,35639
jupyter_contrib_nbextensions/nbextensions/toc2/main.css,sha256=aoReDx6BocITvIiC9HWd2B84C-kT2aDbB0xwH0Hkico,3751
jupyter_contrib_nbextensions/nbextensions/toc2/main.js,sha256=TwzguuR1S_6vDzX8YBnlmweOWvYNAKVtmeEtIITyk6M,8131
jupyter_contrib_nbextensions/nbextensions/toc2/toc2.js,sha256=WiuOhNZFfE8C5Tur3TDL8UzOFVvjAdCBHj6HfRvvWb0,35209
jupyter_contrib_nbextensions/nbextensions/toc2/toc2.yaml,sha256=KK1qvic8ipzK8UhMSYx4irVbOG0UPnh_sGy4Acx19eA,3572
jupyter_contrib_nbextensions/nbextensions/toggle_all_line_numbers/icon.png,sha256=GKC3pmRy9Kfp5pZXoSC6e9GCo-g6yAnvBi8cAShb-sE,29356
jupyter_contrib_nbextensions/nbextensions/toggle_all_line_numbers/main.js,sha256=_4jiibrgG1Fv9xQEI_D8zV3OeykMXcvBczHDtPV2gXQ,2609
jupyter_contrib_nbextensions/nbextensions/toggle_all_line_numbers/main.yaml,sha256=vXKugGVG_bZInPEToYSbWATaCybzpF_X3C9uaz3hLZk,504
jupyter_contrib_nbextensions/nbextensions/toggle_all_line_numbers/readme.md,sha256=YP84oLg3vtjDb6owwMibxxcIKOnJzQgHCay1gX_BxXo,177
jupyter_contrib_nbextensions/nbextensions/tree-filter/demo.gif,sha256=CLous2zEK81D6I-7wmt6p2e7-d5lTosCMh13mmG8sPE,222667
jupyter_contrib_nbextensions/nbextensions/tree-filter/index.js,sha256=4eHmaekpv4X3GEe3PGOe9nHikkbHoxGAzEUSsjsAhrw,4214
jupyter_contrib_nbextensions/nbextensions/tree-filter/readme.md,sha256=J6BYV62mn1njO0XOjRgk3emWk3dntdhx4qlo0JNc3Xw,237
jupyter_contrib_nbextensions/nbextensions/tree-filter/tree-filter.yaml,sha256=J434qpk_X0B50snK9CvPog3Pny9IPA9Y_pmYMSMGXJ8,340
jupyter_contrib_nbextensions/nbextensions/varInspector/README.md,sha256=6xcrz09Yw1Fo7WdVW2F5NWKxXckLC-4XzFuZcO9EoEM,2854
jupyter_contrib_nbextensions/nbextensions/varInspector/__pycache__/var_list.cpython-37.pyc,,
jupyter_contrib_nbextensions/nbextensions/varInspector/demo.gif,sha256=Nmy1FnRUabvCGKdXmGuC7Jy5LHUPbN3zMplBFapxxR8,705345
jupyter_contrib_nbextensions/nbextensions/varInspector/icon.png,sha256=0IV3ZbBkesUQyQ2GVARNCAxuVFDZLknjDdv5MMYH74E,9557
jupyter_contrib_nbextensions/nbextensions/varInspector/jquery.tablesorter.min.js,sha256=Qu834FiMpsNuakUchQ2zzjGJllvnMHtAhJFksZ4LL-A,41811
jupyter_contrib_nbextensions/nbextensions/varInspector/main.css,sha256=P0IOjL0PGvEZz7OaydR7GXdAa6iJ_fGiJ-fT5A92bNM,2477
jupyter_contrib_nbextensions/nbextensions/varInspector/main.js,sha256=_nzKbfWYULuzjh6AL-nmNslINfvfFt8B8JjbsQJqci8,20119
jupyter_contrib_nbextensions/nbextensions/varInspector/tablesorter_LICENSE.txt,sha256=-95ADqb_71YpfqeqwjHtL0bqwWsyaXrc_e8LBazZwto,1080
jupyter_contrib_nbextensions/nbextensions/varInspector/varInspector.yaml,sha256=B6AfSYnj4_9IOgTPyV237c2D1J_LpDNEWN_dikTTwT8,1559
jupyter_contrib_nbextensions/nbextensions/varInspector/var_list.py,sha256=ds8ge6T7Nz4aUqyiSOswvKz3boJAsnLoHXiYI1qpCIg,1530
jupyter_contrib_nbextensions/nbextensions/varInspector/var_list.r,sha256=Hy0ln7MjWqALPq8KEDdO6cXSxGtCzWEuLBRJanbJQ6o,710
jupyter_contrib_nbextensions/nbextensions/zenmode/README.md,sha256=rqorOwXr97EVnIfl6veyqu_0yLnEEz4vUe9v5-8yI-E,89
jupyter_contrib_nbextensions/nbextensions/zenmode/images/back1.jpg,sha256=-btTTjCcJzfZTxZ2hkDciZuxUfuEdQm6B4f_xjboaVo,297914
jupyter_contrib_nbextensions/nbextensions/zenmode/images/back11.jpg,sha256=scOkWFgy-McVRoqAPNASetFx6AWqm_OamNnZc_ZGMS4,433805
jupyter_contrib_nbextensions/nbextensions/zenmode/images/back12.jpg,sha256=vMbVKNdkKuNltgXFMw4GRqfM3oveELZSLWh_8PauJro,332399
jupyter_contrib_nbextensions/nbextensions/zenmode/images/back2.jpg,sha256=EQe3uYJPg3clCC3WohT7HzGZ7n7msRvxUPwrZafWDLE,189571
jupyter_contrib_nbextensions/nbextensions/zenmode/images/back21.jpg,sha256=m6LID_pDh8dfcNO2nUQSBm3npVd52sI8hFuqpVFy2rc,318671
jupyter_contrib_nbextensions/nbextensions/zenmode/images/back22.jpg,sha256=3EhIkE9S4Ys-kUP-rUw-bd2qDUFcY0OVFbrytB7bICQ,258565
jupyter_contrib_nbextensions/nbextensions/zenmode/images/back3.jpg,sha256=xOLru3Xd6Ph14r_mKHfMZt7qeJ3Mpz5b25-katm0AzY,66940
jupyter_contrib_nbextensions/nbextensions/zenmode/images/ipynblogo0.png,sha256=oMI6piRrWhjlvUZTCTQztEoYjoOnt9m0q0bk7-QUb7A,24862
jupyter_contrib_nbextensions/nbextensions/zenmode/images/ipynblogo1.png,sha256=adKpJud0CMdeCxlrSUGzWSQ-XIxRy3nN5H8zvs9tSHg,215078
jupyter_contrib_nbextensions/nbextensions/zenmode/main.css,sha256=xAp-mz9aRUj8bkJeuPHuTv6sh1bo8TiD2tghG7zopno,553
jupyter_contrib_nbextensions/nbextensions/zenmode/main.js,sha256=ohd2yxF40WfWtkyDYnkRp0rPuqr6GQGqHSx4RvusDNY,7017
jupyter_contrib_nbextensions/nbextensions/zenmode/zenmode.yaml,sha256=VSmVhnFNNKQuXPr0sR4k_iwmoooQ0pbUeJOpT4S1FsM,862
jupyter_contrib_nbextensions/templates/collapsible_headings.tpl,sha256=rTKto-1r16avJC91lR45D-0UhpvJcKEFab3tsnpecpk,500
jupyter_contrib_nbextensions/templates/highlighter.tpl,sha256=3MIqmqmqfMOCL5_kRQgIpiZnRrJ-tcFga17-GHNe-EM,161
jupyter_contrib_nbextensions/templates/highlighter.tplx,sha256=zHsqwTLKdIVGEtXUVgObBuoRyl1fXngNRxPH7lGG_dA,1422
jupyter_contrib_nbextensions/templates/inliner.tpl,sha256=IYlDnjI_-nYqaXLaKoyYZ85JUVfVbDPxlG3wUIZ0vdE,327
jupyter_contrib_nbextensions/templates/nbextensions.tpl,sha256=6klByxD0vP_46EGxjY4g0IUgfcFNFLMB4GBGPVcEQOg,525
jupyter_contrib_nbextensions/templates/nbextensions.tplx,sha256=1u9YrCWhk-3wHP9lWxFn8BTRWmBunIhl1rnU1p6hFZ0,2096
jupyter_contrib_nbextensions/templates/printviewlatex.tplx,sha256=KH93pF9vaqNh8DiDUOsymrigCNVvlKlxa4ke6GbqZXw,1230
jupyter_contrib_nbextensions/templates/toc2.tpl,sha256=GsZxlm1rpzIDNYh75NPVr0v6x1W5tzZ0A8NTpxXNOts,1111

@ -0,0 +1,6 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.30.0)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

@ -0,0 +1,12 @@
[console_scripts]
jupyter-contrib-nbextension = jupyter_contrib_nbextensions.application:main
[jupyter_contrib_core.app.subcommands]
nbextension = jupyter_contrib_nbextensions.application:jupyter_contrib_core_app_subcommands
[nbconvert.exporters]
html_ch = jupyter_contrib_nbextensions.nbconvert_support.collapsible_headings:ExporterCollapsibleHeadings
html_embed = jupyter_contrib_nbextensions.nbconvert_support.embedhtml:EmbedHTMLExporter
html_toc = jupyter_contrib_nbextensions.nbconvert_support.toc2:TocExporter
selectLanguage = jupyter_contrib_nbextensions.nbconvert_support.nbTranslate:NotebookLangExporter

@ -0,0 +1 @@
{"classifiers": ["Development Status :: 1 - Planning", "Intended Audience :: End Users/Desktop", "Intended Audience :: Science/Research", "License :: OSI Approved :: BSD License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: JavaScript", "Programming Language :: Python", "Topic :: Utilities"], "download_url": "https://github.com/ipython-contrib/jupyter_contrib_nbextensions/tarball/0.5.1", "extensions": {"python.commands": {"wrap_console": {"jupyter-contrib-nbextension": "jupyter_contrib_nbextensions.application:main"}}, "python.details": {"contacts": [{"email": "jupytercontrib@gmail.com", "name": "ipython-contrib and jupyter-contrib developers", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/ipython-contrib/jupyter_contrib_nbextensions.git"}}, "python.exports": {"console_scripts": {"jupyter-contrib-nbextension": "jupyter_contrib_nbextensions.application:main"}, "jupyter_contrib_core.app.subcommands": {"nbextension": "jupyter_contrib_nbextensions.application:jupyter_contrib_core_app_subcommands"}, "nbconvert.exporters": {"html_ch": "jupyter_contrib_nbextensions.nbconvert_support.collapsible_headings:ExporterCollapsibleHeadings", "html_embed": "jupyter_contrib_nbextensions.nbconvert_support.embedhtml:EmbedHTMLExporter", "html_toc": "jupyter_contrib_nbextensions.nbconvert_support.toc2:TocExporter", "selectLanguage": "jupyter_contrib_nbextensions.nbconvert_support.nbTranslate:NotebookLangExporter"}}}, "extras": ["test"], "generator": "bdist_wheel (0.30.0)", "keywords": ["IPython", "Jupyter", "notebook"], "license": "BSD", "metadata_version": "2.0", "name": "jupyter-contrib-nbextensions", "platform": "Any", "run_requires": [{"requires": ["ipython-genutils", "jupyter-contrib-core (>=0.3.3)", "jupyter-core", "jupyter-highlight-selected-word (>=0.1.1)", "jupyter-latex-envs (>=1.3.8)", "jupyter-nbextensions-configurator (>=0.4.0)", "lxml", "nbconvert (>=4.2)", "notebook (>=4.0)", "pyyaml", "tornado", "traitlets (>=4.1)"]}, {"extra": "test", "requires": ["nbformat", "nose", "pip", "requests"]}, {"environment": "python_version == \"2.7\"", "extra": "test", "requires": ["mock"]}], "summary": "A collection of Jupyter nbextensions.", "version": "0.5.1"}

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
import os
import jupyter_nbextensions_configurator
__version__ = '0.5.1'
def _jupyter_server_extension_paths():
"""Magically-named function for jupyter extension installations."""
return []
def _jupyter_nbextension_paths():
"""Magically-named function for jupyter extension installations."""
nbextension_dirs = [
os.path.join(os.path.dirname(__file__), 'nbextensions')]
specs = jupyter_nbextensions_configurator.get_configurable_nbextensions(
nbextension_dirs=nbextension_dirs)
return [dict(
section=nbext['Section'],
# src is a directory in which we assume the require file resides.
# the path is relative to the package directory
src=os.path.join(
'nbextensions',
os.path.dirname(nbext['require'])
),
# directory in the `nbextension/` namespace
dest=os.path.dirname(nbext['require']),
# _also_ in the `nbextension/` namespace
require=nbext['require'],
) for nbext in specs]

@ -0,0 +1,258 @@
# -*- coding: utf-8 -*-
"""App to install/remove jupyter_contrib_nbextensions."""
from __future__ import print_function, unicode_literals
import copy
import sys
from jupyter_contrib_core.notebook_compat.nbextensions import ArgumentConflict
from jupyter_core.application import JupyterApp
from tornado.log import LogFormatter
from traitlets import Bool, Unicode, default
import jupyter_contrib_nbextensions
from jupyter_contrib_nbextensions.install import (
NotebookRunningError, install, toggle_install_config, toggle_install_files,
uninstall,
)
from jupyter_contrib_nbextensions.migrate import migrate
class BaseContribNbextensionsApp(JupyterApp):
"""Base class for jupyter_contrib_nbextensions apps."""
version = jupyter_contrib_nbextensions.__version__
_log_formatter_cls = LogFormatter
@default('log_datefmt')
def _log_datefmt_default(self):
"""Exclude date from timestamp."""
return "%H:%M:%S"
@default('log_format')
def _log_format_default(self):
"""Override default log format to include time."""
return ('%(color)s['
'%(levelname)1.1s %(asctime)s %(name)s'
']%(end_color)s '
'%(message)s')
class BaseContribNbextensionsInstallApp(BaseContribNbextensionsApp):
"""Install/Uninstall jupyter_contrib_nbextensions."""
aliases = {
'prefix': 'BaseContribNbextensionsInstallApp.prefix',
'nbextensions': 'BaseContribNbextensionsInstallApp.nbextensions_dir',
}
flags = {
'debug': JupyterApp.flags['debug'],
'user': ({
'BaseContribNbextensionsInstallApp': {'user': True}},
'Perform the operation for the current user'
),
'system': ({
'BaseContribNbextensionsInstallApp': {
'user': False, 'sys_prefix': False}},
'Perform the operation system-wide'
),
'sys-prefix': (
{'BaseContribNbextensionsInstallApp': {'sys_prefix': True}},
'Use sys.prefix as the prefix for installing'
),
# below flags apply only to nbextensions, not server extensions
'overwrite': (
{'BaseContribNbextensionsInstallApp': {'overwrite': True}},
'Force overwrite of existing nbextension files, '
'regardless of modification time'
),
'symlink': (
{'BaseContribNbextensionsInstallApp': {'symlink': True}},
'Create symlinks for nbextensions instead of copying files'
),
'skip-running-check': (
{'BaseContribNbextensionsInstallApp':
{'skip_running_check': True}},
'Perform actions even if notebook server(s) are already running'
),
'perform-running-check': (
{'BaseContribNbextensionsInstallApp':
{'skip_running_check': False}},
'Only perform actions if no notebook server(s) are running'
),
}
_conflicting_flagsets = [['--user', '--system', '--sys-prefix'], ]
user = Bool(False, config=True, help='Whether to do a user install')
sys_prefix = Bool(False, config=True,
help='Use the sys.prefix as the prefix')
# settings pertaining to nbextensions installation only
overwrite = Bool(False, config=True,
help='Force overwrite of existing nbextension files')
symlink = Bool(False, config=True,
help='Create symlinks instead of copying nbextension files')
prefix = Unicode(
'', config=True,
help='Installation prefix, currently only used for nbextensions')
nbextensions_dir = Unicode(
'', config=True,
help='Full path to nbextensions dir '
'(consider instead using system, sys_prefix, prefix or user option)')
skip_running_check = Bool(
True, config=True,
help='Perform actions even if notebook server(s) are already running')
def parse_command_line(self, argv=None):
"""
Overriden to check for conflicting flags
Since notebook version doesn't do it very well
"""
for conflicting_flags in map(set, self._conflicting_flagsets):
if len(conflicting_flags.intersection(set(argv))) > 1:
raise ArgumentConflict(
'cannot specify more than one of {}'.format(
', '.join(conflicting_flags)))
return super(BaseContribNbextensionsInstallApp,
self).parse_command_line(argv)
BaseContribNbextensionsInstallApp.flags['s'] = (
BaseContribNbextensionsInstallApp.flags['symlink'])
class InstallContribNbextensionsApp(BaseContribNbextensionsInstallApp):
"""Install jupyter_contrib_nbextensions."""
_toggle_value = True # whether to install or uninstall
flags = copy.deepcopy(BaseContribNbextensionsInstallApp.flags)
flags.update({
'only-config': (
{'BaseContribNbextensionsInstallApp': {'only_config': True}},
'Edit config files, but do not install/remove nbextensions files'
),
'only-files': (
{'BaseContribNbextensionsInstallApp': {'only_files': True}},
'Install/remove nbextensions files, but do not edit config files'
),
})
_conflicting_flagsets = (
BaseContribNbextensionsInstallApp._conflicting_flagsets +
['--only-config', '--only-files'])
only_config = Bool(False, config=True, help=(
'Edit config files, but do not install/remove nbextensions files'))
only_files = Bool(False, config=True, help=(
'Install/remove nbextensions files, but do not edit config files'))
@property
def name(self):
return 'jupyter contrib nbextension {}'.format(
'install' if self._toggle_value else 'uninstall')
@property
def description(self):
return '{} jupyter_contrib_nbextensions.'.format(
'Install' if self._toggle_value else 'Uninstall')
def start(self):
"""Perform the App's actions as configured."""
if self.extra_args:
sys.exit('{} takes no extra arguments'.format(self.name))
self.log.info('{} {}'.format(self.name, ' '.join(self.argv)))
kwargs = dict(
user=self.user, sys_prefix=self.sys_prefix, logger=self.log,
skip_running_check=self.skip_running_check)
kwargs_files = dict(**kwargs)
kwargs_files.update(dict(
prefix=self.prefix, nbextensions_dir=self.nbextensions_dir,
overwrite=self.overwrite, symlink=self.symlink))
try:
if not self.only_config:
toggle_install_files(self._toggle_value, **kwargs_files)
if not self.only_files:
toggle_install_config(self._toggle_value, **kwargs)
except NotebookRunningError as err:
self.log.warn('Error: %s', err)
self.log.info(
'To perform actions even while a notebook server is running,'
'you may use the flag\n--skip-running-check')
raise
class UninstallContribNbextensionsApp(InstallContribNbextensionsApp):
"""Uninstall jupyter_contrib_nbextensions."""
_toggle_value = False
class MigrateContribNbextensionsApp(BaseContribNbextensionsInstallApp):
"""
Migrate config from an old pre-jupyter_contrib_nbextensions install.
Neatly edits/removes config keys and/or files from installs of
ipython-contrib/IPython-notebook-extensions.
"""
name = 'jupyter contrib nbextension migrate'
description = ('Uninstall any old pre-jupyter_contrib_nbextensions install'
' by removing old config keys and files.')
def start(self):
"""Perform the App's actions as configured."""
self.log.info('{} {}'.format(self.name, ' '.join(self.argv)))
return migrate(logger=self.log)
class ContribNbextensionsApp(BaseContribNbextensionsApp):
"""Main jupyter_contrib_nbextensions application."""
name = 'jupyter contrib nbextension'
description = (
'Install or uninstall all of jupyter_contrib_nbextensions.'
)
examples = '\n'.join(['jupyter contrib nbextension ' + t for t in [
'install # {}'.format(install.__doc__),
'uninstall # {}'.format(uninstall.__doc__),
'migrate # {}'.format(migrate.__doc__),
]])
subcommands = dict(
install=(InstallContribNbextensionsApp, install.__doc__),
uninstall=(UninstallContribNbextensionsApp, uninstall.__doc__),
migrate=(MigrateContribNbextensionsApp, migrate.__doc__),
)
def start(self):
"""Perform the App's functions as configured."""
super(ContribNbextensionsApp, self).start()
# The above should have called a subcommand and raised NoStart; if we
# get here, it didn't, so we should self.log.info a message.
subcmds = ', '.join(sorted(self.subcommands))
sys.exit('Please supply at least one subcommand: {}'.format(subcmds))
def jupyter_contrib_core_app_subcommands():
"""Return dict of subcommands for use by jupyter_contrib_core."""
subcommands = dict(
nbextension=(ContribNbextensionsApp,
ContribNbextensionsApp.description)
)
# alias with an 's' as well as without
subcommands['nbextensions'] = subcommands['nbextension']
return subcommands
# -----------------------------------------------------------------------------
# Main
# -----------------------------------------------------------------------------
main = ContribNbextensionsApp.launch_instance
if __name__ == '__main__':
main()

@ -0,0 +1,18 @@
import os
import jupyter_contrib_nbextensions.nbconvert_support
jcnbe_dir = os.path.dirname(jupyter_contrib_nbextensions.__file__)
pp_mod_name = 'jupyter_contrib_nbextensions.nbconvert_support.pp_highlighter'
c = get_config() # noqa
c.NbConvertApp.export_format = "html"
c.Exporter.template_path = [
'.',
jupyter_contrib_nbextensions.nbconvert_support.templates_directory(),
os.path.join(jcnbe_dir, 'nbextensions', 'highlighter')
]
c.Exporter.preprocessors = [pp_mod_name + '.HighlighterPreprocessor']
c.NbConvertApp.postprocessor_class = pp_mod_name + '.HighlighterPostProcessor'
# html
c.Exporter.template_file = 'highlighter.tpl'

@ -0,0 +1,20 @@
import os
import jupyter_contrib_nbextensions.nbconvert_support
jcnbe_dir = os.path.dirname(jupyter_contrib_nbextensions.__file__)
pp_mod_name = 'jupyter_contrib_nbextensions.nbconvert_support.pp_highlighter'
c = get_config() # noqa
c.NbConvertApp.export_format = "latex"
c.Exporter.template_path = [
'.',
jupyter_contrib_nbextensions.nbconvert_support.templates_directory(),
os.path.join(jcnbe_dir, 'nbextensions', 'highlighter')
]
c.Exporter.preprocessors = [pp_mod_name + '.HighlighterPreprocessor']
c.NbConvertApp.postprocessor_class = pp_mod_name + '.HighlighterPostProcessor'
# latex
c.Exporter.template_file = 'highlighter.tplx'
# html
# c.Exporter.template_file = 'highlighter.tpl'

@ -0,0 +1,239 @@
# -*- coding: utf-8 -*-
"""API to install/remove all jupyter_contrib_nbextensions."""
from __future__ import (
absolute_import, division, print_function, unicode_literals,
)
import errno
import os
import jupyter_highlight_selected_word
import latex_envs
from jupyter_contrib_core.notebook_compat import nbextensions
from jupyter_nbextensions_configurator.application import (
EnableJupyterNbextensionsConfiguratorApp,
)
from notebook.notebookapp import list_running_servers
from traitlets.config import Config
from traitlets.config.manager import BaseJSONConfigManager
import jupyter_contrib_nbextensions.nbconvert_support
class NotebookRunningError(Exception):
pass
def notebook_is_running(runtime_dir=None):
"""Return true if a notebook process appears to be running."""
try:
return bool(next(list_running_servers(runtime_dir=runtime_dir)))
except StopIteration:
return False
def toggle_install(install, user=False, sys_prefix=False, overwrite=False,
symlink=False, prefix=None, nbextensions_dir=None,
logger=None, skip_running_check=False):
"""Install or remove all jupyter_contrib_nbextensions files & config."""
_err_on_running(skip_running_check=skip_running_check)
_check_conflicting_kwargs(user=user, sys_prefix=sys_prefix, prefix=prefix,
nbextensions_dir=nbextensions_dir)
toggle_install_files(
install, user=user, sys_prefix=sys_prefix, overwrite=overwrite,
symlink=symlink, prefix=prefix, nbextensions_dir=nbextensions_dir,
logger=logger, skip_running_check=skip_running_check)
toggle_install_config(
install, user=user, sys_prefix=sys_prefix, logger=logger,
skip_running_check=skip_running_check)
def toggle_install_files(install, user=False, sys_prefix=False, logger=None,
overwrite=False, symlink=False, prefix=None,
nbextensions_dir=None, skip_running_check=False):
"""Install/remove jupyter_contrib_nbextensions files."""
_err_on_running(skip_running_check=skip_running_check)
kwargs = dict(user=user, sys_prefix=sys_prefix, prefix=prefix,
nbextensions_dir=nbextensions_dir)
_check_conflicting_kwargs(**kwargs)
kwargs['logger'] = logger
if logger:
logger.info(
'{} jupyter_contrib_nbextensions nbextension files {} {}'.format(
'Installing' if install else 'Uninstalling',
'to' if install else 'from',
'jupyter data directory'))
component_nbext_packages = [
jupyter_contrib_nbextensions,
jupyter_highlight_selected_word,
latex_envs,
]
for mod in component_nbext_packages:
if install:
nbextensions.install_nbextension_python(
mod.__name__, overwrite=overwrite, symlink=symlink, **kwargs)
else:
nbextensions.uninstall_nbextension_python(mod.__name__, **kwargs)
def toggle_install_config(install, user=False, sys_prefix=False,
skip_running_check=False, logger=None):
"""Install/remove contrib nbextensions to/from jupyter_nbconvert_config."""
_err_on_running(skip_running_check=skip_running_check)
_check_conflicting_kwargs(user=user, sys_prefix=sys_prefix)
config_dir = nbextensions._get_config_dir(user=user, sys_prefix=sys_prefix)
if logger:
logger.info(
'{} jupyter_contrib_nbextensions items {} config in {}'.format(
'Installing' if install else 'Uninstalling',
'to' if install else 'from',
config_dir))
# Configure the jupyter_nbextensions_configurator serverextension to load
if install:
configurator_app = EnableJupyterNbextensionsConfiguratorApp(
user=user, sys_prefix=sys_prefix, logger=logger)
configurator_app.start()
nbextensions.enable_nbextension(
'notebook', 'contrib_nbextensions_help_item/main',
user=user, sys_prefix=sys_prefix, logger=logger)
else:
nbconf_cm = BaseJSONConfigManager(
config_dir=os.path.join(config_dir, 'nbconfig'))
for require, section in {
'contrib_nbextensions_help_item/main': 'notebook'}.items():
if logger:
logger.info('- Disabling {}'.format(require))
logger.info(
'-- Editing config: {}'.format(
nbconf_cm.file_name(section)))
nbconf_cm.update(section, {'load_extensions': {require: None}})
# Set extra template path, pre- and post-processors for nbconvert
cm = BaseJSONConfigManager(config_dir=config_dir)
config_basename = 'jupyter_nbconvert_config'
config = cm.get(config_basename)
# avoid warnings about unset version
config.setdefault('version', 1)
if logger:
logger.info(
u'- Editing config: {}'.format(cm.file_name(config_basename)))
# Set extra template path, pre- and post-processors for nbconvert
if logger:
logger.info('-- Configuring nbconvert template path')
# our templates directory
_update_config_list(config, 'Exporter.template_path', [
'.',
jupyter_contrib_nbextensions.nbconvert_support.templates_directory(),
], install)
# our preprocessors
if logger:
logger.info('-- Configuring nbconvert preprocessors')
proc_mod = 'jupyter_contrib_nbextensions.nbconvert_support'
_update_config_list(config, 'Exporter.preprocessors', [
proc_mod + '.CodeFoldingPreprocessor',
proc_mod + '.PyMarkdownPreprocessor',
], install)
if logger:
logger.info(
u'- Writing config: {}'.format(cm.file_name(config_basename)))
_set_managed_config(cm, config_basename, config, logger=logger)
def install(user=False, sys_prefix=False, prefix=None, nbextensions_dir=None,
logger=None, overwrite=False, symlink=False,
skip_running_check=False):
"""Install all jupyter_contrib_nbextensions files & config."""
return toggle_install(
True, user=user, sys_prefix=sys_prefix, prefix=prefix,
nbextensions_dir=nbextensions_dir, logger=logger,
overwrite=overwrite, symlink=symlink,
skip_running_check=skip_running_check)
def uninstall(user=False, sys_prefix=False, prefix=None, nbextensions_dir=None,
logger=None, skip_running_check=False):
"""Uninstall all jupyter_contrib_nbextensions files & config."""
return toggle_install(
False, user=user, sys_prefix=sys_prefix, prefix=prefix,
nbextensions_dir=nbextensions_dir, logger=logger,
skip_running_check=skip_running_check)
# -----------------------------------------------------------------------------
# Private API
# -----------------------------------------------------------------------------
def _err_on_running(skip_running_check=False, runtime_dir=None):
if skip_running_check:
return
try:
srv = next(list_running_servers(runtime_dir=runtime_dir))
except StopIteration:
return
raise NotebookRunningError("""
Will not configure while a Jupyter notebook server appears to be running.
At least this server appears to be running:
{}
Note that the json file indicating that this server is running may
be stale, see
https://github.com/jupyter/notebook/issues/2829
for further details.
""".format(srv))
def _check_conflicting_kwargs(**kwargs):
if sum(map(bool, kwargs.values())) > 1:
raise nbextensions.ArgumentConflict(
"Cannot specify more than one of {}.\nBut recieved {}".format(
', '.join(kwargs.keys()),
', '.join(['{}={}'.format(k, v)
for k, v in kwargs.items() if v])))
def _set_managed_config(cm, config_basename, config, logger=None):
"""Write config owned by the given config manager, removing if empty."""
config_path = cm.file_name(config_basename)
msg = 'config file {}'.format(config_path)
if len(config) > ('version' in config):
if logger:
logger.info('-- Writing updated {}'.format(msg))
# use set to ensure removed keys get removed
cm.set(config_basename, config)
else:
if logger:
logger.info('-- Removing now-empty {}'.format(msg))
try:
os.remove(config_path)
except OSError as ex:
if ex.errno != errno.ENOENT:
raise
def _update_config_list(config, list_key, values, insert):
"""
Add or remove items as required to/from a config value which is a list.
This exists in order to avoid clobbering values other than those which we
wish to add/remove, and to neatly remove a list when it ends up empty.
"""
section, list_key = list_key.split('.')
conf_list = config.setdefault(section, Config()).setdefault(list_key, [])
list_alteration_method = 'append' if insert else 'remove'
for val in values:
if (val in conf_list) != insert:
getattr(conf_list, list_alteration_method)(val)
if not insert:
# remove empty list
if len(conf_list) == 0:
config[section].pop(list_key)
# remove empty section
if len(config[section]) == 0:
config.pop(section)

@ -0,0 +1,286 @@
# -*- coding: utf-8 -*-
"""
Functions to remove old installs, and migrate to newer module names.
This may change or disappear at any time, so don't rely on it!
"""
import errno
import io
import os
import shutil
import tempfile
from jupyter_core.paths import jupyter_config_dir, jupyter_data_dir
from notebook.services.config import ConfigManager as FrontendConfigManager
from traitlets.config import Config
from traitlets.config.manager import BaseJSONConfigManager
from jupyter_contrib_nbextensions.install import (
_set_managed_config, _update_config_list,
)
def _migrate_require_paths(logger=None):
"""Migrate require paths from old to new values."""
if logger:
logger.info('- Migrating require paths from old to new locations')
mappings = {
'notebook': [
('config/config_menu/main', 'nbextensions_configurator/config_menu/main'), # noqa: E501
('skill/skill', 'skill/main'),
('yapf_ext/yapf_ext', 'code_prettify/code_prettify'),
] + [(req, req.split('/', 1)[1]) for req in [
'codemirrormode/skill/skill',
'publishing/gist_it/main',
'publishing/printview/main',
'styling/table_beautifier/main',
'styling/zenmode/main',
'usability/autosavetime/main',
'usability/autoscroll/main',
'usability/chrome-clipboard/main',
'usability/code_font_size/code_font_size',
'usability/codefolding/main',
'usability/collapsible_headings/main',
'usability/comment-uncomment/main',
'usability/datestamper/main',
'usability/dragdrop/main',
'usability/equation-numbering/main',
'usability/execute_time/ExecuteTime',
'usability/exercise/main',
'usability/exercise2/main',
'usability/freeze/main',
'usability/help_panel/help_panel',
'usability/hide_input/main',
'usability/hide_input_all/main',
'usability/highlighter/highlighter',
'usability/hinterland/hinterland',
'usability/init_cell/main',
'usability/keyboard_shortcut_editor/main',
'usability/latex_envs/latex_envs',
'usability/limit_output/main',
'usability/move_selected_cells/main',
'usability/navigation-hotkeys/main',
'usability/notify/notify',
'usability/python-markdown/main',
'usability/qtconsole/qtconsole',
'usability/rubberband/main',
'usability/ruler/main',
'usability/runtools/main',
'usability/scratchpad/main',
'usability/search-replace/main',
'usability/skip-traceback/main',
'usability/spellchecker/main',
'usability/splitcell/splitcell',
'usability/toc2/main',
'usability/toggle_all_line_numbers/main',
]],
'tree': [
('usability/tree-filter/index', 'tree-filter/index'),
]
}
fecm = FrontendConfigManager()
for section in mappings:
conf = fecm.get(section)
load_extensions = conf.get('load_extensions', {})
for old, new in mappings[section]:
status = load_extensions.pop(old, None)
if status is not None:
if logger:
logger.debug('-- Migrating {!r} -> {!r}'.format(old, new))
load_extensions[new] = status
fecm.set(section, conf)
def _uninstall_pre_config(logger=None):
"""Undo config settings inserted by an old installation."""
# for application json config files
cm = BaseJSONConfigManager(config_dir=jupyter_config_dir())
# -------------------------------------------------------------------------
# notebook json config
config_basename = 'jupyter_notebook_config'
config = Config(cm.get(config_basename))
config_path = cm.file_name(config_basename)
if config and logger:
logger.info('- Removing old config values from {}'.format(config_path))
to_remove = ['nbextensions']
# remove from notebook >= 4.2 key nbserver_extensions
section = config.get('NotebookApp', Config())
server_extensions = section.get('nbserver_extensions', {})
for se in to_remove:
server_extensions.pop(se, None)
if len(server_extensions) == 0:
section.pop('nbserver_extensions', None)
# and notebook < 4.2 key server_extensions
_update_config_list(
config, 'NotebookApp.server_extensions', to_remove, False)
_update_config_list(config, 'NotebookApp.extra_template_paths', [
os.path.join(jupyter_data_dir(), 'templates'),
], False)
_set_managed_config(cm, config_basename, config, logger)
# -------------------------------------------------------------------------
# nbconvert json config
config_basename = 'jupyter_nbconvert_config'
config = Config(cm.get(config_basename))
if config and logger:
logger.info('- Removing old config values from {}'.format(config_path))
_update_config_list(config, 'Exporter.template_path', [
'.', os.path.join(jupyter_data_dir(), 'templates'),
], False)
_update_config_list(config, 'Exporter.preprocessors', [
'pre_codefolding.CodeFoldingPreprocessor',
'pre_pymarkdown.PyMarkdownPreprocessor',
], False)
section = config.get('NbConvertApp', {})
old_postproc_classes = [
'post_embedhtml.EmbedPostProcessor',
'jupyter_contrib_nbextensions.nbconvert_support.EmbedPostProcessor',
'jupyter_contrib_nbextensions.nbconvert_support.post_embedhtml.EmbedPostProcessor', # noqa: E501
]
if section.get('postprocessor_class') in old_postproc_classes:
section.pop('postprocessor_class', None)
if len(section) == 0:
config.pop('NbConvertApp', None)
_set_managed_config(cm, config_basename, config, logger)
# -------------------------------------------------------------------------
# Remove old config lines from .py configuration files
for config_basename in ('jupyter_notebook_config.py',
'jupyter_nbconvert_config.py'):
py_config_path = os.path.join(jupyter_config_dir(), config_basename)
if not os.path.isfile(py_config_path):
continue
if logger:
logger.info(
'-- Removing now-empty config file {}'.format(py_config_path))
with io.open(py_config_path, 'r') as f:
lines = f.readlines()
marker = '#--- nbextensions configuration ---'
marker_inds = [ii for ii, l in enumerate(lines) if l.find(marker) >= 0]
if len(marker_inds) >= 2:
lines = lines[0:marker_inds[0]] + lines[marker_inds[1] + 1:]
if [l for l in lines if l.strip]:
with io.open(py_config_path, 'w') as f:
f.writelines(lines)
else:
if logger:
logger.info(
'Removing now-empty config file {}'.format(
py_config_path))
try:
os.remove(py_config_path)
except OSError as ex:
if ex.errno != errno.ENOENT:
raise
def _uninstall_pre_files(logger=None):
"""
Remove any files recorded from a previous installation.
Rather than actually deleting, this function copies everything to a
temporary directory without explicit cleanup, in case a user wants to try
manual recovery at some point.
The OS can then handle actual removal from the temp directory as and when
it chooses to.
"""
data_dir = jupyter_data_dir()
bom_pref = 'ipython-contrib-IPython-notebook-extensions-'
bom_path = os.path.join(data_dir, bom_pref + 'installed_files.txt')
if not os.path.exists(bom_path):
if logger:
logger.info('- No list of previously-installed files at {}'.format(
bom_path))
return
elif logger:
logger.info(
'- Removing previously-installed files listed in {}'.format(
bom_path))
deleted_to = tempfile.mkdtemp(prefix=bom_pref)
if logger:
logger.info(
'-- Files will be copied to the temp directory {}'.format(
deleted_to))
with open(bom_path, 'r') as bom_file:
for src in bom_file.readlines():
src = src.rstrip('\n').rstrip('\r')
if os.path.exists(src):
if logger:
logger.info(' ' + src)
dest = os.path.join(
deleted_to, os.path.relpath(src, data_dir))
dest_dir = os.path.dirname(dest)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
shutil.move(src, dest)
# remove empty directories
allowed_errnos = (errno.ENOTDIR, errno.ENOTEMPTY, errno.ENOENT)
while len(src) > len(data_dir):
src = os.path.dirname(src)
try:
os.rmdir(src)
except OSError as ex:
if ex.errno not in allowed_errnos:
raise
break
else:
if logger:
logger.info(' ' + src)
os.remove(bom_path)
return deleted_to
def _uninstall_pre_pip(logger=None):
"""Uninstall the old package name from pip."""
old_pkg_name = 'Python-contrib-nbextensions'
try:
import pip
except ImportError:
pass
logger.info((
"- Couldn't import pip, so can't attempt to "
"pip uninstall the old package name {}").format(old_pkg_name))
else:
installed_pkg_names = [
pkg.project_name for pkg in pip.get_installed_distributions()]
if old_pkg_name not in installed_pkg_names:
return
if logger:
logger.info('- Uninstalling old package name from pip: {}'.format(
old_pkg_name))
try:
pip.main(['uninstall', '-y', old_pkg_name])
except SystemExit:
pass
def migrate(logger=None):
"""Remove an old (pre-jupyter_contrib_nbextensions) install."""
_migrate_require_paths(logger=logger)
_uninstall_pre_files(logger=logger)
_uninstall_pre_config(logger=logger)
_uninstall_pre_pip(logger=logger)
def main():
"""Allow for running module as a script."""
import logging
logger = logging.getLogger('jupyter_contrib_nbextensions.migrate.main')
logger.info(
'Retiring pre-jupyter_contrib_nbextensions IPython-notebook-extensions'
)
migrate(logger)
if __name__ == '__main__': # pragma: no cover
"""Run module as a script."""
main()

@ -0,0 +1,37 @@
"""Classes and functions provided for use with nbconvert."""
import os
from .collapsible_headings import ExporterCollapsibleHeadings
from .embedhtml import EmbedHTMLExporter
from .execute_time import ExecuteTimePreprocessor
from .exporter_inliner import ExporterInliner
from .nbTranslate import NotebookLangExporter
from .pp_highlighter import HighlighterPostProcessor, HighlighterPreprocessor
from .pre_codefolding import CodeFoldingPreprocessor
from .pre_embedimages import EmbedImagesPreprocessor
from .pre_pymarkdown import PyMarkdownPreprocessor
from .pre_svg2pdf import SVG2PDFPreprocessor
from .toc2 import TocExporter
__all__ = [
'templates_directory',
'CodeFoldingPreprocessor',
'EmbedHTMLExporter',
'ExecuteTimePreprocessor',
'ExporterCollapsibleHeadings',
'ExporterInliner',
'HighlighterPostProcessor',
'HighlighterPreprocessor',
'EmbedImagesPreprocessor',
'NotebookLangExporter',
'PyMarkdownPreprocessor',
'SVG2PDFPreprocessor',
'TocExporter',
]
def templates_directory():
"""Return path to the jupyter_contrib_nbextensions nbconvert templates."""
return os.path.join(
os.path.dirname(os.path.dirname(__file__)), 'templates')

@ -0,0 +1,53 @@
"""Nbconvert exporter to inline css & js for collapsible_headings."""
import json
import os
from notebook.services.config import ConfigManager
from jupyter_contrib_nbextensions import __file__ as contrib_init
from .exporter_inliner import ExporterInliner
class ExporterCollapsibleHeadings(ExporterInliner):
"""
HTMLExporter which inlines the collapsible_headings nbextension.
Export collapsible_headings nbextension functionality to html
by inlining relevant css and js content.
Example usage::
jupyter nbconvert --to html_ch FILE.ipynb
"""
def __init__(self, *args, **kwargs):
super(ExporterCollapsibleHeadings, self).__init__(*args, **kwargs)
self.inliner_resources['css'].append("""
/* no local copies of fontawesome fonts in basic templates, so use cdn */
@import url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css)
""") # noqa: E501
ch_dir = os.path.join(
os.path.dirname(contrib_init), 'nbextensions',
'collapsible_headings')
with open(os.path.join(ch_dir, 'main.css'), 'r') as f:
self.inliner_resources['css'].append(f.read())
with open(os.path.join(ch_dir, 'main.js'), 'r') as f:
self.inliner_resources['js'].append(f.read())
cm = ConfigManager()
collapsible_headings_options = cm.get('notebook').get(
'collapsible_headings', {})
self.inliner_resources['js'].append("""
$(document).ready(function () {
require(['nbextensions/collapsible_headings/main'], function (ch) {
ch.set_collapsible_headings_options(%s);
ch.refresh_all_headings();
});
});
""" % json.dumps(collapsible_headings_options))

@ -0,0 +1,99 @@
"""Embed graphics into HTML Exporter class"""
import base64
import os
from ipython_genutils.ipstruct import Struct
from nbconvert.exporters.html import HTMLExporter
try:
from urllib.request import urlopen # py3
except ImportError:
from urllib2 import urlopen
class EmbedHTMLExporter(HTMLExporter):
"""
:mod:`nbconvert` Exporter which embeds graphics as base64 into html.
Convert to HTML and embed graphics (pdf, svg and raster images) in the HTML
file.
Example usage::
jupyter nbconvert --to html_embed mynotebook.ipynb
"""
def replfunc(self, node):
"""Replace source url or file link with base64 encoded blob."""
url = node.attrib["src"]
imgformat = url.split('.')[-1]
b64_data = None
prefix = None
if url.startswith('data'):
return # Already in base64 Format
self.log.info("try embedding url: %s, format: %s" % (url, imgformat))
if url.startswith('http'):
b64_data = base64.b64encode(urlopen(url).read()).decode("utf-8")
elif url.startswith('attachment'):
imgname = url.split(':')[1]
available_formats = self.attachments[imgname]
# get the image based on the configured image type priority
for imgformat in self.config.NbConvertBase.display_data_priority:
if imgformat in available_formats.keys():
b64_data = self.attachments[imgname][imgformat]
prefix = "data:%s;base64," % imgformat
if b64_data is None:
raise ValueError("""Could not find attachment for image '%s'
in notebook""" % imgname)
else:
filename = os.path.join(self.path, url)
with open(filename, 'rb') as f:
b64_data = base64.b64encode(f.read()).decode("utf-8")
if prefix is None:
if imgformat == "svg":
prefix = "data:image/svg+xml;base64,"
elif imgformat == "pdf":
prefix = "data:application/pdf;base64,"
else:
prefix = "data:image/" + imgformat + ';base64,'
node.attrib["src"] = prefix + b64_data
def from_notebook_node(self, nb, resources=None, **kw):
# The parent nbconvert_support module imports this module, and
# nbconvert_support is imported as part of our install scripts, and
# other fairly basic stuff.
# By keeping lxml import in this method, we can still import this
# module even if lxml isn't available, or is missing dependencies, etc.
# In this way, problems with lxml should only bother people who are
# actually trying to *use* this.
import lxml.etree as et
output, resources = super(
EmbedHTMLExporter, self).from_notebook_node(nb, resources)
self.path = resources['metadata']['path']
# Get attachments
self.attachments = Struct()
for cell in nb.cells:
if 'attachments' in cell.keys():
self.attachments += cell['attachments']
# Parse HTML and replace <img> tags with the embedded data
parser = et.HTMLParser()
root = et.fromstring(output, parser=parser)
nodes = root.findall(".//img")
for n in nodes:
self.replfunc(n)
# Convert back to HTML
embedded_output = et.tostring(root.getroottree(),
method="html",
encoding='unicode')
return embedded_output, resources

@ -0,0 +1,40 @@
"""
Module containing a preprocessor tto execute code cells, updating time metadata
"""
from datetime import datetime
from nbconvert.preprocessors.execute import ExecutePreprocessor
try:
# notebook >= 5.0.0-rc1
import notebook._tz as nbtz
except ImportError:
# notebook < 5.0.0-rc1
import notebook.services.contents.tz as nbtz
class ExecuteTimePreprocessor(ExecutePreprocessor):
"""
Executes all the cells in a notebook, updating their ExecuteTime metadata.
"""
def run_cell(self, cell, cell_index, *args, **kwargs):
before = datetime.utcnow()
exec_reply, outs = super(ExecuteTimePreprocessor, self).run_cell(
cell, cell_index, *args, **kwargs)
if exec_reply.get('msg_type', '') == 'execute_reply':
ets = cell.setdefault('metadata', {}).setdefault('ExecuteTime', {})
if 'started' in exec_reply.get('metadata', {}):
# started value should is already a string, so don't isoformat
ets['start_time'] = exec_reply['metadata']['started']
else:
# attempt to fallback to datetime obj for execution request msg
ets['start_time'] = exec_reply.get(
'parent_header', {}).get('date', before).isoformat()
ets['end_time'] = (
exec_reply.get('header', {}).get('date') or nbtz.utcnow()
).isoformat()
return exec_reply, outs

@ -0,0 +1,46 @@
"""Nbconvert exporter to inline css & js for collapsible_headings."""
from __future__ import print_function
from nbconvert.exporters.html import HTMLExporter
from traitlets import Dict
class ExporterInliner(HTMLExporter):
inliner_resources = Dict(
{'css': [], 'js': []}, config=True,
help='css and js scripts to wrap in html <style> or <script> tags')
def _template_file_default(self):
return 'inliner'
def from_notebook_node(self, nb, resources=None, **kw):
# ensure resources used by template actually exist, add in any from
# config
if resources is None:
resources = {}
inliner_resources = resources.setdefault('inliner', {})
for tt in ('css', 'js'):
existing_items = inliner_resources.setdefault(tt, [])
existing_items += [
item for item in self.inliner_resources[tt]
if item not in existing_items]
return super(ExporterInliner, self).from_notebook_node(
nb, resources, **kw)
@property
def default_config(self):
c = super(ExporterInliner, self).default_config
# import here to avoid circular import
from jupyter_contrib_nbextensions.nbconvert_support import (
templates_directory)
contrib_templates_dir = templates_directory()
template_path = c.TemplateExporter.setdefault('template_path', [])
if contrib_templates_dir not in template_path:
template_path.append(contrib_templates_dir)
return c

@ -0,0 +1,199 @@
"""PostProcessor for customizing code language css class."""
# ----------------------------------------------------------------------------
# Copyright (c) the IPython Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Imports
# ----------------------------------------------------------------------------
from __future__ import print_function
import io
import re
from nbconvert.postprocessors.base import PostProcessorBase
from traitlets import Unicode
try:
from html.parser import HTMLParser # py3
except ImportError:
from HTMLParser import HTMLParser # py2
class HtmlHighlightStripper(HTMLParser):
"""
An object that is fed with html and removes <span> tags
enclosed inside <pre> or <code> tags. This effectively removes
static highlighting, but can strip other things too. This class is
made to work with pandoc/marked/pygments type of output
"""
def __init__(self, ostream):
HTMLParser.__init__(self)
self.in_pre = False
self.in_code = False
self.ostream = ostream
self.pygments_fix = False
def handle_starttag(self, tag, attrs):
_print = True
if tag == u"pre":
if self.pygments_fix:
_print = False
self.in_pre = True
elif tag == u"code":
self.in_code = True
elif tag == u"div":
# Pygments doesn't protect raw code inside a <code> el.
# and the language is in the enclosing <div> so we must
# do some transfos.
attrs_dict = dict(attrs)
cssclass = attrs_dict.pop(u"class", None)
if cssclass and cssclass.startswith(u"hl-"):
self.pygments_fix = True
tag = u"div" + self.stringify_attrs(attrs_dict) + ">"
tag += u"<pre><code"
elif self.in_pre or self.in_code:
_print = False
if _print:
self.out(u"<%s%s>" % (tag, self.stringify_attrs(attrs)))
def handle_endtag(self, tag):
_print = True
if tag == u"pre":
if self.pygments_fix:
_print = False
self.in_pre = False
elif tag == u"code":
self.in_code = False
elif self.in_pre or self.in_code:
_print = False
elif tag == u"div" and self.pygments_fix:
tag = u"code></pre></div"
self.pygments_fix = False
if _print:
self.out(u"</" + tag + ">")
def def_handle(self, arg):
self.out(arg)
def handle_entityref(self, arg):
self.out("&" + arg + ";")
def handle_decl(self, arg):
self.out("<!" + arg + ">")
def handle_charref(self, arg):
self.out("&#" + arg + ";")
def handle_comment(self, arg):
self.out("<!--" + arg + "-->")
def handle_pi(self, arg):
self.out("<?" + arg + ">")
handle_data = unknown_decl = def_handle
def stringify_attrs(self, attrs):
if not attrs:
return ""
return " " + " ".join([k + "=" + '"%s"' % v for k, v in attrs])
def out(self, data):
self.ostream.write(data)
def rec(reg):
return re.compile(reg, re.S)
pandoc_code_markup_re = rec(r'<pre\s*class="(\w*?)">\s*<code>')
marked_code_markup_re = rec(r'<pre>\s*<code\s*class="language-(\w*)">')
pygments_code_markup_re = rec(r'<pre>\s*<code\s*class="hl-(\w*)">')
class JsHighlightPostProcessor(PostProcessorBase):
"""
Customize CSS classes of code blocks to let
your favourite JS highlighting engine pick them up.
"""
css_substitution = Unicode(default_value='{lang}', config=True,
help="""A template string to insert into the <pre>
tags' ``class`` attribute. The only substituted value
is {lang} where ``lang`` is the language of the fenced
code block.""")
def postprocess(self, input):
_html = None
with io.open(input, "r", encoding="utf-8") as f:
_html = f.read()
stripped = io.StringIO()
stripper = HtmlHighlightStripper(stripped)
stripper.feed(_html)
_html = stripped.getvalue()
# Prepare substitution string. {lang} is a placeholder
# for the language detected by the regexp, which is the first
# captured element.
css = self.css_substitution.format(lang=r"\1")
substitute = '<pre class="' + css + '"><code>'
for cre in (pandoc_code_markup_re,
marked_code_markup_re,
pygments_code_markup_re):
_html = cre.sub(substitute, _html)
with io.open(input, "w", encoding="utf-8") as f:
f.write(_html)
return
msg = """
Modify code blocks in nbconvert's HTML output so that the highlighting
is done in the browser by Javascript.
Usage:
======
python js_highlight.py file.html css_substitution
Example (to let google-prettify do the highlighting):
=====================================================
nbconvert MyNotebook.ipynb
python js_highlight.py MyNotebook.html "prettyprint lang_{lang}"
Details
=======
"""
def usage():
print(msg)
print(JsHighlightPostProcessor.class_get_help())
def main(path, substitution=None):
"""allow running the module to customize css classes of html code blocks"""
htmlClassCustomizer = JsHighlightPostProcessor()
if substitution is not None:
htmlClassCustomizer.css_substitution = substitution
htmlClassCustomizer(path)
if __name__ == '__main__':
import sys
if len(sys.argv) < 3:
usage()
sys.exit(-1)
main(*sys.argv[1:])

@ -0,0 +1,240 @@
# -*- coding: utf-8 -*-
"""nbTranslate Preprocessor Exporter class"""
# -----------------------------------------------------------------------------
# Copyright (c) 2016, J.-F. Bercher
#
# Distributed under the terms of the Modified BSD License.
#
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
from __future__ import print_function
import nbformat
from nbconvert.exporters.notebook import NotebookExporter
from nbconvert.preprocessors import Preprocessor
from traitlets import Bool, Enum, Unicode
# -----------------------------------------------------------------------------
# Preprocessor
# -----------------------------------------------------------------------------
langs = {
'auto': 'Automatic',
'af': 'Afrikaans',
'sq': 'Albanian',
'ar': 'Arabic',
'hy': 'Armenian',
'az': 'Azerbaijani',
'eu': 'Basque',
'be': 'Belarusian',
'bn': 'Bengali',
'bs': 'Bosnian',
'bg': 'Bulgarian',
'ca': 'Catalan',
'ceb': 'Cebuano',
'ny': 'Chichewa',
'zh-cn': 'Chinese Simplified',
'zh-tw': 'Chinese Traditional',
'co': 'Corsican',
'hr': 'Croatian',
'cs': 'Czech',
'da': 'Danish',
'nl': 'Dutch',
'en': 'English',
'eo': 'Esperanto',
'et': 'Estonian',
'tl': 'Filipino',
'fi': 'Finnish',
'fr': 'French',
'fy': 'Frisian',
'gl': 'Galician',
'ka': 'Georgian',
'de': 'German',
'el': 'Greek',
'gu': 'Gujarati',
'ht': 'Haitian Creole',
'ha': 'Hausa',
'haw': 'Hawaiian',
'iw': 'Hebrew',
'hi': 'Hindi',
'hmn': 'Hmong',
'hu': 'Hungarian',
'is': 'Icelandic',
'ig': 'Igbo',
'id': 'Indonesian',
'ga': 'Irish',
'it': 'Italian',
'ja': 'Japanese',
'jw': 'Javanese',
'kn': 'Kannada',
'kk': 'Kazakh',
'km': 'Khmer',
'ko': 'Korean',
'ku': 'Kurdish (Kurmanji)',
'ky': 'Kyrgyz',
'lo': 'Lao',
'la': 'Latin',
'lv': 'Latvian',
'lt': 'Lithuanian',
'lb': 'Luxembourgish',
'mk': 'Macedonian',
'mg': 'Malagasy',
'ms': 'Malay',
'ml': 'Malayalam',
'mt': 'Maltese',
'mi': 'Maori',
'mr': 'Marathi',
'mn': 'Mongolian',
'my': 'Myanmar (Burmese)',
'ne': 'Nepali',
'no': 'Norwegian',
'ps': 'Pashto',
'fa': 'Persian',
'pl': 'Polish',
'pt': 'Portuguese',
'ma': 'Punjabi',
'ro': 'Romanian',
'ru': 'Russian',
'sm': 'Samoan',
'gd': 'Scots Gaelic',
'sr': 'Serbian',
'st': 'Sesotho',
'sn': 'Shona',
'sd': 'Sindhi',
'si': 'Sinhala',
'sk': 'Slovak',
'sl': 'Slovenian',
'so': 'Somali',
'es': 'Spanish',
'su': 'Sudanese',
'sw': 'Swahili',
'sv': 'Swedish',
'tg': 'Tajik',
'ta': 'Tamil',
'te': 'Telugu',
'th': 'Thai',
'tr': 'Turkish',
'uk': 'Ukrainian',
'ur': 'Urdu',
'uz': 'Uzbek',
'vi': 'Vietnamese',
'cy': 'Welsh',
'xh': 'Xhosa',
'yi': 'Yiddish',
'yo': 'Yoruba',
'zu': 'Zulu'
}
class nbTranslatePreprocessor(Preprocessor):
def __init__(self, lang='en', **kw):
self.language = lang
def __call__(self, nb, resources, lang='en'):
if self.enabled:
self.log.debug("Applying preprocessor: %s",
self.__class__.__name__)
return self.preprocess(nb, resources)
else:
return nb, resources
def preprocess(self, nb, resources):
"""
Preprocessing to apply on each notebook.
Must return modified nb, resources.
If you wish to apply your preprocessing to each cell, you might want
to override preprocess_cell method instead.
Parameters
----------
nb : NotebookNode
Notebook being converted
resources : dictionary
Additional resources used in the conversion process. Allows
preprocessors to pass variables into the Jinja engine.
"""
filtered_cells = []
for cell in nb.cells:
if cell.cell_type == 'markdown':
if (cell.get('metadata', {}).get('lang', self.language) == self.language): # noqa
filtered_cells.append(cell)
else:
filtered_cells.append(cell)
nb.cells = filtered_cells
return super(nbTranslatePreprocessor, self).preprocess(nb, resources)
def preprocess_cell(self, cell, resources, index):
"""
Preprocess cell
Parameters
----------
cell : NotebookNode cell
Notebook cell being processed
resources : dictionary
Additional resources used in the conversion process. Allows
preprocessors to pass variables into the Jinja engine.
cell_index : int
Index of the cell being processed (see base.py)
"""
return cell, resources
# ----------------------------------------------------------------
# Exporter
# ----------------------------------------------------------------
class NotebookLangExporter(NotebookExporter):
"""Exports to an IPython notebook."""
nbformat_version = Enum(list(nbformat.versions),
default_value=nbformat.current_nbformat,
config=True,
help="""The nbformat version to write.
Use this to downgrade notebooks.
"""
)
# language = CaselessStrEnum(
# langs.keys(), help="Selected language").tag(config=True, alias="lang")
language = Unicode(
'en', help="Selected language").tag(config=True, alias="lang")
addSuffix = Bool(True, help="Use language tag as suffix")
# language = 'en'
def _file_extension_default(self):
return '.ipynb'
output_mimetype = 'application/json'
def from_notebook_node(self, nb, resources=None, **kw):
if (self.language not in langs.keys()):
raise ValueError("""Error -- {} is not a valid language abbreviation
Please select one of the abbreviations in the list\n {}""".format(self.language, langs)) # noqa
nbtranslatepreprocessor = nbTranslatePreprocessor(lang=self.language)
self.register_preprocessor(nbtranslatepreprocessor, enabled=True)
self._init_preprocessors()
nb, resources = nbtranslatepreprocessor(nb, resources)
nb_copy, resources = super(NotebookLangExporter, self).from_notebook_node(nb, resources, **kw) # noqa
if self.addSuffix:
resources['output_suffix'] = '_' + self.language
return nb_copy, resources

@ -0,0 +1,194 @@
# -*- coding: utf-8 -*-
r"""
These pre and postprocessor preserve highlights when converting the notebook to
html or LaTeX.
Preprocessor:
- for html conversion: the preprocessor replaces html tags by a "neutral" text
versions, which enables markdown conversion of text included in the data
field e.g. ::
<span class="mark"> *text* </span>
is translated into::
!oph!span class="mark"!clh! *text* !oph!/span!clh!
- for LaTeX conversion: the preprocessor replaces html tags by a "neutral" text
version of some associated LaTeX commands or environments. This, again
enables markdown conversion of text included in the command or environment.
e.g. ::
<span class="mark"> *text* </span>
is translated into::
!sl!highlighta!op! *text* !cl!
Postprocessor:
- replaces the "neutral" text versions by the destination language tags
e.g. the [html example] becomes ::
<span class="mark"> <em>text</em> </span>
(the data text have been correctly emphasized)
e.g. [LaTeX example] becomes ::
\highlighta{\emph{text}}
(the data text have been correctly emphasized)
The LaTeX commands and environments are defined in the LaTeX template
highlighter.tplx
"""
from __future__ import print_function
import re
from nbconvert.postprocessors.base import PostProcessorBase
from nbconvert.preprocessors import Preprocessor
class HighlighterPreprocessor(Preprocessor):
"""
:mod:`nbconvert` Preprocessor for the ``highlighter`` nbextension.
The preprocessor replaces highlighter html tags in markdown with a
"neutral" text version, which enables markdown conversion of text included
in the data field, command or environment. Then the neutral text is
translated into LaTeX/html output by the corresponding
:class:`HighlighterPostProcessor`.
For example the highlighter-created markdown ::
<span class="mark"> *text* </span>
is translated for html conversion into::
!oph!span class="mark"!clh! *text* !oph!/span!clh!
or for LaTeX conversion is translated into::
!sl!highlighta!op! *text* !cl!
"""
def latex_scheme_cell(self, match):
schemes = {
"mark": "highlightA",
"burk": "highlightB",
"girk": "highlightC"
}
return ("!sl!begin!op!" + schemes[match.group(1)] + '!cl!\n' +
match.group(2) + "\n!sl!end!op!" + schemes[match.group(1)] +
'!cl!\n')
def latex_scheme(self, match):
schemes = {
"mark": r"!sl!highlighta",
"burk": r"!sl!highlightb",
"girk": r"!sl!highlightc"
}
return schemes[match.group(1)] + '!op!' + match.group(2) + '!cl!'
def html_replacements(self, match):
return match.group(0).replace("<", "!oph!").replace(">", "!clh!")
def replace_highlights_with_latex(self, cell_text):
cell_text = re.sub(
"^<div class=\"(mark|burk|girk)\">([\S\s]*?)<\/div>" +
"<i class=\"fa fa-lightbulb-o \"></i>",
self.latex_scheme_cell, cell_text)
cell_text = re.sub(
"<span class=\"(mark|burk|girk)\">([\S\s]*?)<\/span>",
self.latex_scheme, cell_text)
return cell_text
def replace_highlights_in_html(self, cell_text):
cell_text = re.sub(
"^<div class=\"(mark|burk|girk)\">([\S\s]*?)<\/div>" +
"<i class=\"fa fa-lightbulb-o \"></i>",
self.html_replacements, cell_text)
cell_text = re.sub(
"<span class=\"(mark|burk|girk)\">([\S\s]*?)<\/span>",
self.html_replacements, cell_text)
return cell_text
def preprocess_cell(self, cell, resources, index):
"""
Preprocess cell
Parameters
----------
cell : NotebookNode cell
Notebook cell being processed
resources : dictionary
Additional resources used in the conversion process. Allows
preprocessors to pass variables into the Jinja engine.
cell_index : int
Index of the cell being processed (see base.py)
"""
# print("config", self.config)
if cell.cell_type == "markdown":
if self.config.NbConvertApp.export_format == "latex":
cell.source = self.replace_highlights_with_latex(cell.source)
elif self.config.NbConvertApp.export_format == "html":
cell.source = self.replace_highlights_in_html(cell.source)
return cell, resources
class HighlighterPostProcessor(PostProcessorBase):
r"""
:mod:`nbconvert` PostProcessor for the ``highlighter`` nbextension.
Replaces the "neutral" text versions created by the
:class:`HighlighterPreprocessor` by the destination language tags.
e.g. the html example becomes ::
<span class="mark"> <em>text</em> </span>
(the data text have been correctly emphasized in html markup)
e.g. the LaTeX example becomes ::
\highlighta{\emph{text}}
(the data text have been correctly emphasized using LaTeX tags)
"""
def postprocess(self, input):
print("Postprocessing...")
"""if self.config.NbConvertApp.export_format == "latex":
with open(input,'rt') as f:
nb_text=f.read()
nb_text=nb_text.replace('!op!','{')
nb_text=nb_text.replace('!cl!','}')
nb_text=nb_text.replace('!sl!','\\')
with open(input,'wt') as f:
f.write(nb_text)
elif self.config.NbConvertApp.export_format == "html":
with open(input,'rt') as f:
nb_text=f.read()
nb_text=nb_text.replace('!oph!','<')
nb_text=nb_text.replace('!clh!','>')
with open(input,'wt') as f:
f.write(nb_text)
"""
if self.config.NbConvertApp.export_format == "latex" or "html":
with open(input, 'rt') as f:
nb_text = f.read()
if self.config.NbConvertApp.export_format == "latex":
nb_text = nb_text.replace('!op!', '{')
nb_text = nb_text.replace('!cl!', '}')
nb_text = nb_text.replace('!sl!', '\\')
elif self.config.NbConvertApp.export_format == "html":
nb_text = nb_text.replace('!oph!', '<')
nb_text = nb_text.replace('!clh!', '>')
with open(input, 'wt') as f:
f.write(nb_text)

@ -0,0 +1,121 @@
# -*- coding: utf-8 -*-
"""
This preprocessor removes lines in code cells that have been marked as `folded`
by the codefolding extension
"""
from nbconvert.preprocessors import Preprocessor
from traitlets import Bool, Unicode
class CodeFoldingPreprocessor(Preprocessor):
"""
:mod:`nbconvert` Preprocessor for the code_folding nbextension.
Folds codecells as displayed in the notebook. The hidden code below the fold gets removed.
The preprocessor is installed by default. To enable codefolding with
NbConvert, you need to set the configuration parameter
`CodeFoldingPreprocessor.remove_folded_code=True`.
This can be done either in the `jupyter_nbconvert_config.py` file::
c.CodeFoldingPreprocessor.remove_folded_code=True = True
or using a command line parameter when calling NbConvert::
$ jupyter nbconvert --to html --CodeFoldingPreprocessor.remove_folded_code=True mynotebook.ipynb
The folding mark can be configured using
c.CodeFoldingPreprocessor.fold_mark = '<->'
""" # noqa: E501
remove_folded_code = Bool(
False, help="Remove code that was folded").tag(config=True)
fold_mark = Unicode(u'', help="Symbol for folded code").tag(config=True)
def fold_cell(self, cell, folded):
"""
Remove folded lines and add a '<->' at the parent line
"""
self.log.debug("CodeFoldingPreprocessor:: folding at: %s" % folded)
lines = cell.splitlines(True)
if not lines:
# no lines -> return
return cell
if folded[0] == 0 and lines[0].startswith(('#', '%')):
# fold whole cell when first line is a comment or magic
self.log.debug("fold whole cell")
return lines[0].rstrip('\n') + self.fold_mark + '\n'
foldIndent = 0
fold = False
fcell = ""
isSkipLine = False
skipped = ""
for i, line in enumerate(lines):
# fold indent level
lstrip = line.lstrip(r' \t') # strip tabs and spaces
indent = len(line) - len(lstrip)
# is it a comment or an empty line
isSkipLine = not lstrip or lstrip == "\n" or lstrip.startswith("#")
if indent <= foldIndent and not isSkipLine:
# folding finished, when we reached no skip line on an upper
# level
fold = False
fcell += skipped # add back all skipped lines
skipped = ""
if not fold:
# append the line
if i in folded:
fold = True
foldIndent = indent
fcell += line.rstrip('\n') + self.fold_mark + '\n'
else:
fcell += line
else:
# dont append the line
# when folding we track all continuous skip lines
# to add them back when we leave this scope
if not isSkipLine:
skipped = ""
else:
skipped += line
self.log.debug("%02i, %02i < %02i, %i,'%s' ", i, indent,
foldIndent, fold, line[0:indent + 10].strip("\r\n"))
return fcell
def preprocess(self, nb, resources):
"""Skip preprocessor if not enabled"""
if self.remove_folded_code:
return super(CodeFoldingPreprocessor, self).preprocess(
nb, resources)
else:
return nb, resources
def preprocess_cell(self, cell, resources, index):
"""
Read cell metadata and remove lines marked as `folded`.
Parameters
----------
cell : NotebookNode cell
Notebook cell being processed
resources : dictionary
Additional resources used in the conversion process. Allows
preprocessors to pass variables into the Jinja engine.
index : int
Index of the cell being processed (see base.py)
"""
if hasattr(cell, 'source') and cell.cell_type == 'code':
if hasattr(cell['metadata'], 'code_folding'):
folded = cell['metadata']['code_folding']
if len(folded) > 0:
self.log.debug('Removing folded code in cell')
cell.source = self.fold_cell(cell.source, folded)
return cell, resources

@ -0,0 +1,157 @@
"""Nbconvert preprocessor for the python-markdown nbextension."""
import base64
import os
import re
from ipython_genutils.ipstruct import Struct
from nbconvert.preprocessors import Preprocessor
from traitlets import Bool, Unicode
try:
from urllib.request import urlopen # py3
except ImportError:
from urllib2 import urlopen
class EmbedImagesPreprocessor(Preprocessor):
"""
:mod:`nbconvert` Preprocessor to embed images in a markdown cell as
attachment inside the notebook itself.
This :class:`~nbconvert.preprocessors.Preprocessor` replaces kernel code in
markdown cells with the results stored in the cell metadata.
The preprocessor is installed by default. To enable embedding images with
NbConvert, you need to set the configuration parameter
`EmbedImagesPreprocessor.embed_images=True`.
This can be done either in the `jupyter_nbconvert_config.py` file::
c.EmbedImagesPreprocessor.embed_images=True
or using a command line parameter when calling NbConvert::
$ jupyter nbconvert --to html --EmbedImagesPreprocessor.embed_images=True mynotebook.ipynb
Further options are::
EmbedImagesPreprocessor.embed_remote_images=True
to additionally embeds all images referenced by an url
(e.g. http://jupyter.org/assets/nav_logo.svg) instead of a local file name.
Another configuration option is::
EmbedImagesPreprocessor.resize=small
Let's you scale-down the size of an image. This is useful if you want to
save space by not embedding large images and instead use a smaller (scaled)
version. Works only for raster images (i.e. png, jpg).
Valid resize settings are: small = 500px, mid = 1000px, large = 2000px
for maximum size in length or width. No upscaling of small images will
be performed. The Python package `PIL` needs to be installed for this
option to work.
Example::
$ jupyter nbconvert --to html --EmbedImagesPreprocessor.embed_images=True
--EmbedImagesPreprocessor.resize=large mynotebook.ipynb
*Note:* To embed images after conversion to HTML you can also use the
`html_embed` exporter
"""
embed_images = Bool(False, help="Embed images as attachment").tag(config=True)
embed_remote_images = Bool(False, help="Embed images referenced by an url as attachment").tag(config=True)
resize = Unicode('', help="Resize images to save space (reduce size)").tag(config=True)
imgsizes = {'small': 500, 'mid': 1000, 'large': 2000}
def preprocess(self, nb, resources):
"""Skip preprocessor if not enabled"""
if self.embed_images:
nb, resources = super(EmbedImagesPreprocessor, self).preprocess(nb, resources)
return nb, resources
def resize_image(self, imgname, imgformat, imgdata):
"""Resize images if desired and PIL is installed
Parameters
----------
imgname: str
Name of image
imgformat: str
Format of image (JPG or PNG)
imgdata:
Binary image data
"""
if imgformat in ['png', 'jpg']:
from io import BytesIO
try:
from PIL import Image
except ImportError:
self.log.info("Pillow library not available to resize images")
return imgdata
# Only make images smaller when rescaling
im = Image.open(BytesIO(imgdata))
factor = self.imgsizes[self.resize] / max(im.size)
if factor < 1.0:
newsize = (int(im.size[0] * factor), int(im.size[1] * factor))
newim = im.resize(newsize)
fp = BytesIO()
# PIL requires JPEG instead of JPG
newim.save(fp, format=imgformat.replace('jpg', 'jpeg'))
imgdata = fp.getvalue()
fp.close()
self.log.debug("Resized %d x %d image %s to size %d x %d pixels" %
(im.size[0], im.size[1], imgname, newsize[0], newsize[1]))
return imgdata
def replfunc_md(self, match):
"""Read image and store as base64 encoded attachment"""
url = match.group(2)
imgformat = url.split('.')[-1].lower()
if url.startswith('http'):
if self.embed_remote_images:
data = urlopen(url).read()
else:
return match.group(0)
elif url.startswith('attachment'):
return match.group(0)
else:
filename = os.path.join(self.path, url)
with open(filename, 'rb') as f:
data = f.read()
if self.resize in self.imgsizes.keys():
data = self.resize_image(url, imgformat, data)
self.log.debug("Embedding url: %s, format: %s" % (url, imgformat))
b64_data = base64.b64encode(data).decode("utf-8")
self.attachments[url] = {'image/' + imgformat: b64_data}
newimg = '![' + match.group(1) + '](attachment:' + match.group(2) + ')'
return newimg
def preprocess_cell(self, cell, resources, index):
"""
Preprocess cell
Parameters
----------
cell : NotebookNode cell
Notebook cell being processed
resources : dictionary
Additional resources used in the conversion process. Allows
preprocessors to pass variables into the Jinja engine.
index : int
Index of the cell being processed (see base.py)
"""
self.path = resources['metadata']['path']
self.attachments = getattr(cell, 'attachments', Struct())
if cell.cell_type == "markdown":
regex = re.compile('!\[([^"]*)\]\(([^"]+)\)')
cell.source = regex.sub(self.replfunc_md, cell.source)
cell.attachments = self.attachments
return cell, resources

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
"""Nbconvert preprocessor for the python-markdown nbextension."""
import re
from nbconvert.preprocessors import Preprocessor
class PyMarkdownPreprocessor(Preprocessor):
"""
:mod:`nbconvert` Preprocessor for the python-markdown nbextension.
This :class:`~nbconvert.preprocessors.Preprocessor` replaces kernel code in
markdown cells with the results stored in the cell metadata.
"""
def replace_variables(self, source, variables):
"""
Replace {{variablename}} with stored value
"""
try:
replaced = re.sub(
"{{(.*?)}}", lambda m: variables.get(m.group(1), ''), source)
except TypeError:
replaced = source
return replaced
def preprocess_cell(self, cell, resources, index):
"""
Preprocess cell
Parameters
----------
cell : NotebookNode cell
Notebook cell being processed
resources : dictionary
Additional resources used in the conversion process. Allows
preprocessors to pass variables into the Jinja engine.
cell_index : int
Index of the cell being processed (see base.py)
"""
if cell.cell_type == "markdown":
if hasattr(cell['metadata'], 'variables'):
variables = cell['metadata']['variables']
if len(variables) > 0:
cell.source = self.replace_variables(
cell.source, variables)
return cell, resources

@ -0,0 +1,197 @@
# -*- coding: utf-8 -*-
"""
Preprocessor to convert svg graphics embedded in markdown to PDF.
"""
import errno
import io
import os
import re
import subprocess
import sys
from ipython_genutils.py3compat import which
from ipython_genutils.tempdir import TemporaryDirectory
from nbconvert.preprocessors import Preprocessor
from traitlets import Unicode
try:
from urllib.request import urlopen # py3
except ImportError:
from urllib2 import urlopen # py2
def get_inkscape_executable_path():
"""
Return the path of the system inkscape_ exectuable.
.. _inkscape: https://inkscape.org/en
"""
inkscape = which('inkscape')
if inkscape is not None:
return inkscape
if sys.platform == 'darwin':
default_darwin_inkscape_path = (
'/Applications/Inkscape.app/Contents/Resources/bin/inkscape')
if os.path.isfile(default_darwin_inkscape_path):
return default_darwin_inkscape_path
elif sys.platform == 'win32':
try:
import winreg # py3 stdlib on windows
except ImportError:
import _winreg as winreg # py2 stdlib on windows
win32_inkscape_reg_key = "SOFTWARE\\Classes\\inkscape.svg\\DefaultIcon"
wr_handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
try:
rkey = winreg.OpenKey(wr_handle, win32_inkscape_reg_key)
inkscape = winreg.QueryValueEx(rkey, "")[0]
except OSError as ex:
if ex.errno == errno.ENOENT:
return None
raise
return inkscape
return None
class SVG2PDFPreprocessor(Preprocessor):
"""
Preprocessor to convert svg graphics embedded in notebook markdown to PDF.
Example for a markdown cell image::
![My graphic](graphics.svg)
Because LaTeX can't use SVG graphics, they are converted to PDF using
inkscape_. This preprocessor is for SVG graphics in markdown only. For SVG
outputs from codecells, there is already the built-in nbconvert
preprocessor.
Configuration::
c.Exporter.preprocessors.append(
"jupyter_contrib_nbextensions.nbconvert_support.SVG2PDFPreprocessor"
)
.. _inkscape: https://inkscape.org/en
""" # noqa: E501
def _from_format_default(self):
return 'image/svg+xml'
def _to_format_default(self):
return 'application/pdf'
output_filename_template = Unicode(
"{unique_key}_{cell_index}_{index}{extension}", config=True)
command = Unicode(
config=True,
help="""The command to use for converting SVG to PDF
This string is a template, which will be formatted with the keys
to_filename and from_filename.
The conversion call must read the SVG from {from_flename},
and write a PDF to {to_filename}.
""")
def _command_default(self):
return (
self.inkscape +
' --without-gui --export-pdf="{to_filename}" "{from_filename}"'
)
inkscape = Unicode(config=True, help="The path to Inkscape, if necessary")
def _inkscape_default(self):
return get_inkscape_executable_path()
def convert_figure(self, name, data):
"""Convert a single SVG figure to PDF. Returns converted data."""
# self.log.info(name, data)
if not self.inkscape:
raise OSError('Inkscape executable not found')
# self.log.info('Inkscape:', self.inkscape)
# Work in a temporary directory
with TemporaryDirectory() as tmpdir:
# Write fig to temp file
input_filename = os.path.join(tmpdir, 'figure' + '.svg')
# SVG data is unicode text
with io.open(input_filename, 'w', encoding='utf8') as f:
f.write(data.decode('utf-8'))
# f.write(cast_unicode_py2(data))
# Call conversion application
output_filename = os.path.join(tmpdir, 'figure.pdf')
shell = self.command.format(
from_filename=input_filename, to_filename=output_filename)
# Shell=True okay since input is trusted.
subprocess.call(shell, shell=True)
# Read output from drive
# return value expects a filename
if os.path.isfile(output_filename):
with open(output_filename, 'rb') as f:
# PDF is a nb supported binary data type, so base64 encode
return f.read()
# return base64.encodestring(f.read())
else:
raise TypeError("Inkscape svg to pdf conversion failed")
def replfunc(self, match):
"""
Transform a regex match for an svg image into a markdown pdf image tag.
Parameters
----------
match : re.MatchObject
Match object containing the markdown image tag with svg images
Returns
-------
str
New markdown image tag using the converted-to-pdf image
"""
url = match.group(2) + '.svg'
if url.startswith('http'):
data = urlopen(url).read()
else:
with open(url, 'rb') as f:
data = f.read()
if (self.output_files_dir is not None and
not os.path.exists(self.output_files_dir)):
os.makedirs(self.output_files_dir)
else:
self.output_files_dir = ''
output_filename = os.path.join(
self.output_files_dir, match.group(2) + '.pdf')
pdf_data = self.convert_figure(match.group(2), data)
self.log.info('Writing PDF image %s' % output_filename)
with open(output_filename, 'wb') as f:
f.write(pdf_data)
new_img = "[" + match.group(1) + "](" + output_filename + ")"
return new_img
def preprocess_cell(self, cell, resources, index):
"""
Find SVG links and convert to PDF.
Parameters
----------
cell : NotebookNode cell
Notebook cell being processed
resources : dictionary
Additional resources used in the conversion process. Allows
preprocessors to pass variables into the Jinja engine.
index : int
Index of the cell being processed (see
nbconvert.preprocessors.base for details)
"""
self.output_files_dir = resources.get('output_files_dir', None)
if (cell.cell_type == 'markdown' and
self.config.NbConvertApp.export_format in ('latex', 'pdf')):
cell.source = re.sub(
'\[(.*)\]\((.+).svg\)', self.replfunc, cell.source,
flags=re.IGNORECASE)
return cell, resources

@ -0,0 +1,60 @@
"""Toc2 exporter class, TocExporter"""
# -----------------------------------------------------------------------------
# Copyright (c) 2016, the IPython IPython-Contrib Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
from nbconvert.exporters.html import HTMLExporter
from traitlets.config import Config
# -----------------------------------------------------------------------------
# Classes
# -----------------------------------------------------------------------------
class TocExporter(HTMLExporter):
"""
:mod:`nbconvert` HTMLExporter which embeds the toc2 nbextension.
Export table of contents nbextension functionality to html. The idea is to
link a relevant part of the javascript nbextension and the css, and add a
small script in the html file.
Example usage::
jupyter nbconvert --to html_toc FILE.ipynb
"""
def _file_extension_default(self):
return '.html'
def _template_file_default(self):
return 'toc2'
output_mimetype = 'text/html'
def _raw_mimetypes_default(self):
return ['text/markdown', 'text/html', '']
@property
def default_config(self):
c = Config({'ExtractOutputPreprocessor': {'enabled': True}})
# import here to avoid circular import
from jupyter_contrib_nbextensions.nbconvert_support import (
templates_directory)
c.merge(super(TocExporter, self).default_config)
c.TemplateExporter.template_path = [
'.',
templates_directory(),
]
return c

@ -0,0 +1,7 @@
Type: IPython Notebook Extension
Name: AddBefore
Description: This extension enables the Add Cell before button (from iPython 1)
Link: readme.md
Icon: icon.png
Main: main.js
Compatibility: 4.x

@ -0,0 +1,42 @@
define([
'base/js/namespace',
'jquery',
'require',
'base/js/events',
'base/js/utils',
], function(Jupyter, $, requirejs, events, configmod, utils) {
"use strict";
var load_extension = function() {
Jupyter.toolbar.add_buttons_group([
Jupyter.keyboard_manager.actions.register ({
'help' : 'Insert Cell Above',
'icon' : 'fa-arrow-circle-o-up',
'handler': function () {
Jupyter.notebook.insert_cell_above('code');
Jupyter.notebook.select_prev();
Jupyter.notebook.focus_cell();
}
}, 'insert-cell-above', 'addbefore'),
Jupyter.keyboard_manager.actions.register ({
'help' : 'Insert Cell Below',
'icon' : 'fa-arrow-circle-o-down',
'handler': function () {
Jupyter.notebook.insert_cell_below('code');
Jupyter.notebook.select_next();
Jupyter.notebook.focus_cell();
}
}, 'insert-cell-below', 'addbefore'),
]);
$('#insert_above_below').remove()
};
var extension = {
load_jupyter_extension : load_extension,
load_ipython_extension : load_extension
};
return extension;
});

@ -0,0 +1,12 @@
Addbefore
=========
This extension adds a button to add a empty cell before the currently active cell.
As was present in IPython 1.0.
It is with a circled up arrow.
The plus signed "Add Cell After button" is moved to be next to Add Cell Before,
and given matching circled down arrow icon.
The functionality of the buttons are as per in the Insert Menu,
for Insert Cell Above, and Insert Cell Below.
A empty cell is added, and it takes the cursor focus.

@ -0,0 +1,20 @@
autosavetime
============
Description
-----------
Optionally set the notebook autosave interval, and/or add a selector to the
toolbar to set it.
Parameters
----------
* `autosavetime_set_starting_interval` -
Set an autosave interval on notebook load. If false, the default is unchanged.
* `autosavetime_starting_interval` -
Autosave interval (in minutes) which would be set on notebook load.
* `autosavetime_show_selector` -
Add a selector to the toolbar to change the autosave interval

@ -0,0 +1,22 @@
Type: IPython Notebook Extension
Compatibility: 3.x, 4.x, 5.x
Name: AutoSaveTime
Main: main.js
Icon: icon.png
Link: README.md
Description: Optionally set the notebook autosave interval, and/or add a selector to the toolbar to set it
Parameters:
- name: autosavetime_set_starting_interval
description: Set an autosave interval on notebook load. If false, the default is unchanged.
input_type: checkbox
default: false
- name: autosavetime_starting_interval
description: Autosave interval (in minutes) which would be set on notebook load.
input_type: number
min: 0
step: 1
default: 2
- name: autosavetime_show_selector
description: add a selector to the toolbar to change the autosave interval
input_type: checkbox
default: true

@ -0,0 +1,81 @@
define([
'jquery',
'base/js/namespace',
'base/js/events'
], function(
$,
IPython,
events
) {
"use strict";
// define default values for config parameters
var params = {
autosavetime_set_starting_interval : false,
autosavetime_starting_interval : 2,
autosavetime_show_selector : true
};
// update params with any specified in the server's config file
var update_params = function() {
var config = IPython.notebook.config;
for (var key in params) {
if (config.data.hasOwnProperty(key))
params[key] = config.data[key];
}
};
var initialize = function () {
update_params();
var si = params.autosavetime_starting_interval;
var set_si = params.autosavetime_set_starting_interval;
if (params.autosavetime_show_selector) {
var select = $('<select class="ui-widget-content"/>');
select.change(function() {
var interval = parseInt($(this).val(), 10) * 60 * 1000;
IPython.notebook.set_autosave_interval(interval);
});
var thresholds = [0,2,5,10,15,20,30,60];
if (set_si && thresholds.indexOf(si) < 0) thresholds.push(si);
thresholds.sort(function(a, b) { return a-b; });
for (var i in thresholds) {
var thr = thresholds[i];
select.append($('<option/>').attr('value', thr).text(thr));
}
select.find('option[value="2"]').text('2 (default)');
select.find('option[value="0"]').text('off');
if (set_si) select.val(si);
IPython.toolbar.element.append(
$('<label class="navbar-text"/>').text('Autosave interval (min):')
).append(select);
}
events.on("autosave_enabled.Notebook", function(event, value) {
if (set_si) {
IPython.notebook.set_autosave_interval(si * 60 * 1000);
}
else {
if (params.autosavetime_show_selector) {
select.val(parseInt(value, 10) / 60 / 1000);
}
}
});
};
var load_ipython_extension = function() {
return IPython.notebook.config.loaded.then(initialize);
};
return {
load_ipython_extension : load_ipython_extension
};
});

@ -0,0 +1,22 @@
autoscroll
==========
Description
-----------
Optionally set the output autoscroll threshold, and/or add a selector to the
toolbar to set it, and/or add a toolbar button to enable/disable it.
Parameters
----------
* `autoscroll_set_on_load` -
Set an autoscroll threshold on notebook load. If false, the default is unchanged.
* `autoscroll_starting_threshold` -
Autoscroll threshold which would be set on notebook load. `-1` disables autoscrolling.
* `autoscroll_show_selector` -
Add a selector to the toolbar to change the autoscroll threshold
* `autoscroll_show_button` -
Add a button to the toolbar to disable/enable autoscrolling

@ -0,0 +1,26 @@
Type: IPython Notebook Extension
Compatibility: 3.x, 4.x
Name: Autoscroll
Main: main.js
Icon: icon.png
Link: README.md
Description: Optionally set the output autoscroll threshold, and/or add a selector to the toolbar to set it, and/or add a toolbar button to enable/disable it
Parameters:
- name: autoscroll_set_on_load
description: Set an autoscroll threshold on notebook load. If false, the default is unchanged.
input_type: checkbox
default: false
- name: autoscroll_starting_threshold
description: Autoscroll threshold which would be set on notebook load. -1 disables autoscrolling.
input_type: number
min: -1
step: 1
default: 100
- name: autoscroll_show_selector
description: add a selector to the toolbar to change the autoscroll threshold
input_type: checkbox
default: true
- name: autoscroll_show_button
description: add a button to the toolbar to disable/enable autoscrolling
input_type: checkbox
default: false

@ -0,0 +1,130 @@
define([
'jquery',
'base/js/namespace',
'base/js/events',
'notebook/js/outputarea',
'notebook/js/codecell'
], function (
$,
IPython,
events,
oa,
codecell
) {
"use strict";
var prev_threshold = 0;
var action_full_name; // will be set when registering the action
// define default values for config parameters
var params = {
autoscroll_set_on_load : false,
autoscroll_starting_threshold : 100,
autoscroll_show_selector : true,
autoscroll_show_button : false
};
// update params with any specified in the server's config file
var update_params = function() {
var config = IPython.notebook.config;
for (var key in params) {
if (config.data.hasOwnProperty(key))
params[key] = config.data[key];
}
};
var initAutoScroll = function() {
if (IPython.notebook === undefined) return;
var cells = IPython.notebook.get_cells();
var ncells = IPython.notebook.ncells();
for (var i=0; i<ncells; i++) {
var cell = cells[i];
if ((cell instanceof codecell.CodeCell)) {
cell.scroll_output()
}
}
};
var toggle_output_autoscroll = function() {
if (oa.OutputArea.auto_scroll_threshold > 0) {
prev_threshold = oa.OutputArea.auto_scroll_threshold;
oa.OutputArea.auto_scroll_threshold = -1;
}
else {
var new_thr = prev_threshold <= 0 ? 1 : prev_threshold;
prev_threshold = oa.OutputArea.auto_scroll_threshold;
oa.OutputArea.auto_scroll_threshold = new_thr;
}
$('#autoscroll_selector').val(oa.OutputArea.auto_scroll_threshold);
$('.btn[data-jupyter-action="' + action_full_name + '"]')
.toggleClass('active', oa.OutputArea.auto_scroll_threshold <= 0)
.blur();
initAutoScroll();
};
var initialize = function() {
update_params();
var thresholds = [-1, 1, 10, 20, 50, 100, 200, 500, 1000];
if (params.autoscroll_set_on_load) {
var st = params.autoscroll_starting_threshold;
oa.OutputArea.auto_scroll_threshold = st;
if (thresholds.includes(st) === false) thresholds.push(st);
}
thresholds.sort(function(a, b){ return a-b; });
if (params.autoscroll_show_selector) {
var select = $('<select id="autoscroll_selector"/>')
.addClass("form-control select-xs");
select.change(function() {
oa.OutputArea.auto_scroll_threshold = parseInt($(this).val(), 10);
$('.btn[data-jupyter-action="' + action_full_name + '"]')
.toggleClass('active', oa.OutputArea.auto_scroll_threshold <= 0);
$(this).blur();
});
for (var i in thresholds) {
var thr = thresholds[i];
select.append($('<option/>').attr('value', thr).text(thr));
}
select.find('option[value="100"]').text('100 (default)');
select.find('option[value="-1"]').text('no-scroll');
IPython.toolbar.element.append(
$('<label class="navbar-text"/>').text('auto-scroll threshold:')
).append(select);
select.val(oa.OutputArea.auto_scroll_threshold);
}
if (params.autoscroll_show_button) {
IPython.toolbar.add_buttons_group([action_full_name]);
}
initAutoScroll();
};
var load_ipython_extension = function () {
var prefix = 'auto';
var action_name = 'toggle-output-autoscroll';
var action = {
icon: 'fa-close',
help: 'Toggle output auto-scrolling',
help_index : 'zz',
handler : toggle_output_autoscroll
};
action_full_name = IPython.keyboard_manager.actions.register(action, action_name, prefix);
IPython.notebook.config.loaded.then(initialize);
events.on("notebook_loaded.Notebook", function(){
initAutoScroll();
});
};
return {
load_ipython_extension : load_ipython_extension
};
});

@ -0,0 +1,4 @@
Cell filter
===========
An extension that allows you to filter cells by tags. Keywords entered into the search bar separated by spaces joins them with logical AND.

@ -0,0 +1,133 @@
/**
* cell_filter.js
* An extension that allows you to filter cells by tags. Keywords entered into the search bar separated by spaces joins them with logical AND.
*
*
* @version 0.1.0
* @author Benjamin Ellenberger, https://github.com/benelot
* @updated 2018-02-16
*
*
*/
define([
'require',
'jqueryui',
'base/js/namespace',
'base/js/utils',
'services/config'
], function (
requirejs,
$,
Jupyter,
utils
) {
'use strict';
function filterRows (filterText, caseSensitive, useRegex) {
var input = $('#filterkeyword');
var btnRegex = $('#filterisreg');
filterText = filterText !== undefined ? filterText : input.val();
useRegex = useRegex !== undefined ? useRegex : btnRegex.attr('aria-pressed') === 'true';
caseSensitive = caseSensitive !== undefined ? caseSensitive : $('#filtercase').attr('aria-pressed') === 'true';
if (!useRegex) {
// escape any regex special chars
filterText = filterText.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
var keywords = filterText.split(' '); // get all space separated keywords
filterText = '.*'; // catch all stuff before the keywords
keywords.forEach(function(keyword){ // find all keywords we are looking for with regex (?=.*keyword)
filterText += '(?=.*' + keyword + ')';
});
filterText += '.*'; // catch all stuff after the keywords
}
var matchExpr;
try {
matchExpr = new RegExp(filterText, caseSensitive ? '' : 'i'); // prepare regex
}
catch (err) {
// do nothing, error is handled based on undefined matchExpr
}
var invalidRegex = matchExpr === undefined; // indicate invalid regex
btnRegex.toggleClass('btn-danger', invalidRegex);
btnRegex.toggleClass('btn-default', !invalidRegex);
btnRegex.closest('.form-group').toggleClass('has-error has-feedback', invalidRegex);
Jupyter.notebook.get_cells().forEach(function (cell, idx, cells) { // toggle visibility of cells depending on their tags
var tags = cell.metadata.tags || [];
tags = tags.join(' ');
if(filterText === ".*(?=.*).*" || filterText === "" || tags.search(matchExpr) !== -1 && tags.length > 0){ // empty filter or match expression on non-zero tags
cell.element.show(); // cell.element.style.display = '';
//cell.element.find("div.inner_cell").show();
}
else{
cell.element.hide(); // cell.element.style.display = 'none';
//cell.element.find("div.inner_cell").hide();
}
});
}
function filterRowsDefaultParams () {
return filterRows();
}
function load_ipython_extension () {
var form_tgrp = $('<div/>')
.addClass('btn-group') // insert a top form-group to make the form appear next to the buttons
.appendTo('#maintoolbar-container');
var frm_grp = $('<div/>')
.addClass('form-group') // insert a form-group
.css('margin-bottom', 0)
.appendTo(form_tgrp);
var grp = $('<div/>')
.addClass('input-group') // insert an input-group
.appendTo(frm_grp);
$('<input/>') // insert search bar
.attr('type', 'text')
.addClass('form-control input-sm')
.attr('title', 'Keyword for filtering cells by tags')
.attr('id', 'filterkeyword')
.attr('placeholder', 'Cell Tag Filter')
.css('font-weight', 'bold')
.css('width', '70%')
.css('height', '24px')
.on('focus', function (evt) { Jupyter.notebook.keyboard_manager.disable();})
.on('blur', function (evt) { Jupyter.notebook.keyboard_manager.enable();})
.appendTo(grp);
$('<button/>')
.attr('type', 'button') // insert regex button
.attr('id', 'filterisreg')
.addClass('btn btn-default btn-sm')
.attr('data-toggle', 'button')
.css('font-weight', 'bold')
.attr('title', 'Use regex (JavaScript regex syntax)')
.text('.*')
.on('click', function (evt) { setTimeout(filterRowsDefaultParams); })
.appendTo(grp);
$('<button/>') // insert case sensitive button
.attr('type', 'button')
.attr('id', 'filtercase')
.addClass('btn btn-default btn-sm')
.attr('data-toggle', 'button')
.attr('tabindex', '0')
.attr('title', 'Match case')
.css('font-weight', 'bold')
.text('Aa')
.on('click', function (evt) { setTimeout(filterRowsDefaultParams); })
.appendTo(grp);
$('#filterkeyword').on('keyup', filterRowsDefaultParams); // trigger filtering right with typing
}
return {
load_ipython_extension : load_ipython_extension
};
});

@ -0,0 +1,7 @@
Type: Jupyter Notebook Extension
Compatibility: 4.x, 5.x
Name: Cell Filter
Main: cell_filter.js
Link: README.md
Description: |
An extension that allows you to filter cells by tags. Keywords entered into the search bar separated by spaces joins them with logical AND.

@ -0,0 +1,4 @@
Code Font Size
==============
Adds toolbar buttons to increase and decrease code's font size. This is useful, for example, when projecting the notebook.

@ -0,0 +1,70 @@
// Increase/decrease code font size
define([
'base/js/namespace',
'base/js/events'
], function(Jupyter, events) {
var code_change_fontsize = function(doIncrease) {
var pre_css = null;
var pre_style = null;
for(i = 0; i < document.styleSheets.length; i++){
//if style sheet is custom.css
if(/localhost.*\/custom\/custom\.css/.test(document.styleSheets[i].href)){
//pre_css now contains the style sheet custom.css
pre_css = document.styleSheets[i];
break;
}
}
for(i = 0; i < pre_css.cssRules.length; i++){
if(/\.CodeMirror pre/.test(pre_css.cssRules[i].selectorText)){
pre_style = pre_css.cssRules[i].style;
break;
}
}
if(pre_style == null){
pre_css.insertRule(".CodeMirror pre { font-size: \"14px\"; padding-bottom: \"0px\"; }", 0);
pre_style = pre_css.cssRules[0];
}
var font_size = pre_style.fontSize || "";
if(font_size == "")
font_size = 14;
else
font_size = +/\d+/.exec(font_size)[0];
font_size += (doIncrease ? +3 : -3);
font_size = (font_size < 8 ? 8 : font_size);
var padding_size = (font_size <= 14 ? 0 : (font_size - 14));
pre_style.paddingBottom = padding_size + "px";
pre_style.fontSize = font_size + "px";
};
var load_ipython_extension = function () {
Jupyter.toolbar.add_buttons_group([
/*
* Buttons to increase/decrease code font size
*/
Jupyter.keyboard_manager.actions.register ({
'help' : 'Increase code font size',
'icon' : 'fa-search-plus',
'handler': function () {
$( document ).ready(code_change_fontsize(true));
}
}, 'increase-code-font-size', 'code_font_size'),
Jupyter.keyboard_manager.actions.register ({
'help' : 'Decrease code font size',
'icon' : 'fa-search-minus',
'handler': function () {
$( document ).ready(code_change_fontsize(false));
}
}, 'decrease-code-font-size', 'code_font_size'),
]);
};
return {
load_ipython_extension : load_ipython_extension
};
});

@ -0,0 +1,7 @@
Type: IPython Notebook Extension
Name: Code Font Size
Link: README.md
Description: Adds toolbar buttons to increase and decrease code's font size.
This is useful, for example, when projecting the notebook.
Main: code_font_size.js
Compatibility: 4.x, 5.x

@ -0,0 +1,49 @@
// Copyright (c) Jupyter-Contrib Team.
// Distributed under the terms of the Modified BSD License.
// Authors: @EWouters, @jfbercher and @jcb91
// Based on: https://github.com/jfbercher/code_prettify and
// https://gist.github.com/takluyver/c8839593c615bb2f6e80
define(['./kernel_exec_on_cell'], function(kernel_exec_on_cell) {
'use strict';
var mod_name = '2to3';
// gives default settings
var cfg = {
add_toolbar_button: true,
hotkeys: {
process_selected: 'Ctrl-M',
process_all: 'Ctrl-Shift-M',
},
register_hotkey: true,
show_alerts_for_errors: true,
button_icon: 'fa-space-shuttle',
button_label: 'Convert Python 2 to 3',
kbd_shortcut_text: 'Convert Python 2 to 3 in' // ' current cell(s)'
};
cfg.kernel_config_map = { // map of parameters for supported kernels
"python": {
"library": [
"import lib2to3.refactor, json",
"_2to3_refactoring_tool = lib2to3.refactor.RefactoringTool(",
" set(lib2to3.refactor.get_fixers_from_package('lib2to3.fixes')))",
"def _2to3_refactor_cell(src):",
" try:",
" tree = _2to3_refactoring_tool.refactor_string(src+'\\n', '<dummy_name>')",
" except (lib2to3.pgen2.parse.ParseError, lib2to3.pgen2.tokenize.TokenError):",
" return src ",
" else:",
" return str(tree)[:-1]",
].join('\n'),
"prefix": "print(json.dumps(_2to3_refactor_cell(u",
"postfix": ")))"
}
};
var converter = new kernel_exec_on_cell.define_plugin(mod_name, cfg);
converter.load_ipython_extension = converter.initialize_plugin;
return converter;
});

@ -0,0 +1,60 @@
Type: Jupyter Notebook Extension
Name: 2to3 Converter
Description: Converts python2 code in a notebook's code cell to python3 code
Link: README_2to3.md
Main: 2to3.js
Compatibility: Jupyter 4.x, 5.x
Parameters:
- name: 2to3.add_toolbar_button
description: Add a toolbar button to convert the selected cell(s)
input_type: checkbox
default: true
- name: 2to3.button_icon
description: |
Toolbar button icon: a font-awesome class defining the icon used for the
toolbar button. See https://fontawesome.com/icons for available icons.
input_type: text
default: 'fa-space-shuttle'
- name: 2to3.button_label
description: Toolbar button label text
input_type: text
default: 'Code converter'
- name: 2to3.register_hotkey
description: Register a hotkey to convert the selected cell(s)
input_type: checkbox
default: true
- name: 2to3.hotkeys.process_selected
description: Hotkey to convert the selected cell(s) from python2 to python3
input_type: hotkey
default: 'Ctrl-M'
- name: 2to3.hotkeys.process_all
description: Hotkey to convert the whole notebook
input_type: hotkey
default: 'Ctrl-Shift-M'
- name: 2to3.show_alerts_for_errors
description: Show alerts for errors in the kernel converting calls
input_type: checkbox
default: true
- name: 2to3.kernel_config_map_json
description: |
kernel_config_map_json:
json defining library calls required to load the kernel-specific
converting modules, and the prefix & postfix for the json-format string
required to make the converting call.
input_type: textarea
default: |
{
"python": {
"library": "import lib2to3.refactor, json\n_2to3_refactoring_tool = lib2to3.refactor.RefactoringTool(\n set(lib2to3.refactor.get_fixers_from_package('lib2to3.fixes')))\ndef _2to3_refactor_cell(src):\n try:\n tree = _2to3_refactoring_tool.refactor_string(src+'\\n', '<dummy_name>')\n except (lib2to3.pgen2.parse.ParseError, lib2to3.pgen2.tokenize.TokenError):\n return src \n else:\n return str(tree)[:-1]",
"prefix": "print(json.dumps(refactor_cell(u",
"postfix": ")))"
}
}

@ -0,0 +1,300 @@
KernelExecOnCells library and nbextensions
==========================================
The KernelExecOnCells library is a shared library for creating Jupyter
nbextensions which transform code cell text using calls to the active kernel.
This scheme has been applied to create several nbextensions which are also
included in the repository.
For instance, to prettify code, see the [code-prettify] nbextension, or to
refactor python 2 code for python 3, see the [2to3] extension.
These nbextensions are defined as simple plugins of the main KernelExecOnCells
library. Defining such a plugin, [jupyter-autopep8], is described in the last section below.
Compatible Kernels
------------------
The library is kernel-language agnostic, as described in the [internals]
section below. Essentially any kernel capable of interpreting and creating
json-formatted strings, and sending them to the stream output (where print
statements in most languages go) should be easy to integrate.
Hopefully, that covers pretty much all languages!
Options
-------
The library uses a series of options, describing the configuration of the
plugin. Default values for these options are specified as an object in the
plugin source file, and can be overriden by values loaded from config.
There are a few nbextension-wide options, configurable using the
[jupyter_nbextensions_configurator] or by editing the `notebook` section config
file directly.
If `mod_name` is the name of the plugin module (e.g. `code_prettify`, `2to3`,
...) and `LANG` the lowercased kernel language (eg julia, python, r ...), then
the options are as follows:
- `mod_name.add_toolbar_button`:
Whether to add a toolbar button to transform the selected cell(s).
Defaults to `true`.
- `mod_name.button_icon`:
A font-awesome class defining the icon used for the toolbar button and
actions. See [fontawesome] for available icon classes.
Defaults to `fa-legal`.
- `mod_name.button_label`:
Toolbar button label text. Also used in the actions' help text.
Defaults to `mod_name`.
- `mod_name.register_hotkey`:
Whether to register hotkeys to transform the selected cell(s)/whole notebook.
Defaults to `true`.
- `mod_name.hotkeys.process_all`:
Hotkey to use to transform all the code cells in the notebook.
Defaults to `Ctrl-Shift-L`.
- `mod_name.hotkeys.process_selected`:
Hotkey to use to transform the selected cell(s).
Defaults to `Ctrl-L`.
- `mod_name.show_alerts_for_errors`:
Whether to show alerts for errors in the kernel calls.
Defaults to `true`.
- `mod_name.kernel_config_map_json`:
The value of this key is a string which can be parsed into a json object
giving the config for each kernel language.
The following give the per-kernel options of the parsed json, using the
language key `LANG`, to be replaced as appropriate:
* `mod_name.kernel_config_map_json.LANG.library`:
String to execute in the kernel in order to load any necessary kernel
libraries.
* `mod_name.kernel_config_map_json.LANG.replacements_json_to_kernel`:
a list of pairs of strings, used as arguments to javascript's
`String.replace(from, to)` to translate from a json string into a valid
representation of the same string in the kernel language. Since json
strings are particularly simple, this can often (as with the python
language) be left as the default, an empty list.
* `mod_name.kernel_config_map_json.LANG.prefix` and
`mod_name.kernel_config_map_json.LANG.postfix`:
strings added as bookends to the kernel string (translated from the json
string using the replacements above) to make up the kernel prettifier call
kernel's prettifier libraries.
* `mod_name.kernel_config_map_json.LANG.trim_formatted_text`:
Whether to trim whitespace from the transformed cell text. Since jupyter
cells don't usually have leading or trailing whitespace, the default
behaviour is to trim the transformed text, in order to prevent the
transform adding extra newlines at the end (a common behaviour for source
files, where having a trailing newline is often considered good practice).
Internals
---------
The model is essentially:
1. The cell text is grabbed by client-side javascript, then turned into a json
string using javascript `JSON.stringify`. Since json-compatible strings are
a particularly simple string format, which is compatible with many other
programming languages without much modification (e.g. a valid json string
is also a valid string in python 3, and also in python 2 when prefixed with
a `u`), and easily converted for use in others (because of its simplicity).
2. Optional regex replacements are used to translate the json-format string
into a valid kernel string. Python, R and javascript don't require this
step, but other languages may do, so it's implemented for flexibility
using the per-kernel config key `replacements_json_to_kernel`, which is a
list of pairs of arguments to javascript `String.replace`.
3. The kernel-specific prettifier call is then composed from
`kernel_config.prefix` + `kernel_text_string` + `kernel_config.postfix` and
sent to the kernel for execution. This kernel call is expected to get the
formatted cell text _printed_ as a json-compatible string. Since most
kernel languages have json packages, this should hopefully be easy to
arrange. The reason for the printing text rather than simply displaying it,
is that it prevents us having to translate from a kernel string
representing a json string.
4. The callback for the kernel execution in client-side javascript parses the
printed json-format string, optionally trims trailing whitespace according
to the `trim_formatted_text` key (which defaults to `true`) in the
per-kernel config, and then sets the cell text using the result.
The process is probably best illustrated using an example for the python
implementation in `code_prettify`:
1. **At nbextension load**, the `code_prettify.kernel_config_map_json` config
option is parsed to give the json object
```json
{
"python": {
"library": "import json\nimport yapf.yapflib.yapf_api",
"prefix": "print(json.dumps(yapf.yapflib.yapf_api.FormatCode(u",
"postfix": ")[0]))"
}
}
```
(other kernel languages are omitted for clarity).
2. **On kernel becoming ready**, the nbextension looks up the config for the
kernel's language (in our example, this is the `python` key of the kernel
config json object above). It then sends the kernel config's `library`
string to the kernel for execution. Thus the python implementation above
executes
```python
import json
import yapf.yapflib.yapf_api
```
3. **On requesting a cell be prettified** which can happen by clicking the
toolbar, or with a (configurable) hotkey, the following happens:
Say the cell to be formatted contains the following ugly python code:
```python
msg= 'hello '+"world"
print (
msg )
```
Then the result of the `JSON.stringify` call will be a string containing
```json
"msg= 'hello '+\"world\"\nprint (\n msg )"
```
(note the opening and closing quotes). Concatenating this with the prefix &
postfix strings from the python kernel config above, gives us the kernel
code to execute. The call sent to the python kernel is therefore
```python
print(json.dumps(yapf.yapflib.yapf_api.FormatCode(u"msg= 'hello '+\"world\"\nprint (\n msg )")[0]))
```
4. What gets 'printed' by the kernel (i.e. returned to the javascript stream
callback) is the following json-format string:
```json
"msg = 'hello ' + \"world\"\nprint(msg)\n"
```
The default is to trim whitepace from the returned prettified text, which
results in the final prettified python code for the cell:
```python
msg = 'hello ' + "world"
print(msg)
```
Defining a new plugin
---------------------
As an example, we will add a new plugin which reformats code using the
[autopep8] module in python, rather than the [yapf] library used by
`code_prettify`. Such a plugin, [jupyter-autopep8] was developed by [@kenkoooo]
as a fork of an old version of `code_prettify`. Redefining it here has the
advantage of using the updated and more-robust architecture, in addition to
making it possible to reformat the whole notebook in one go.
For this new nbextension, we just have to run `import autopep8` as the kernel
library code, and then call the `autopep8.fix_code` function on cells' text.
Hence what we have to do is:
- copy `code_prettify.js` to `autopep8.js`
- update `mod_name`, `hotkeys`, `button_icon` default config values in the new
`autopep8.js`. Also update the `cfg.kernel_config_map` value to use the
correct kernel code:
```javascript
cfg.kernel_config_map = { // map of options for supported kernels
"python": {
"library": "import json\nimport autopep8",
"prefix": "print(json.dumps(autopep8.fix_code(u",
"postfix": ")))"
}
};
```
- copy `code_prettify.yaml` to `autopep8.yaml`, and update its values (name,
require, readme, plus the new defaults for hotkeys, icon, and
kernel_config_map
- that's all :-)
Of course, for this simple case, one could equally have just updated the
configuration of `code_prettify` using the [jupyter_nbextensions_configurator]
to use [autopep8] instead of [yapf] to reformat the python code.
But, if you want two alternative prettifiers available for the same kernel
language, we need to define separate plugins.
Custom Yapf Styles
------------------
Using the default `yapf` engine, one may define a custom formatting style according to the [package documentation](https://github.com/google/yapf#formatting-style).
The `code_prettify` extension is configured to follow the default `yapf` ordering (minus the command line option) and will search for the formatting style in the following manner:
> 1. In the [style] section of a .style.yapf file in either the current directory or one of its parent directories.
> 2. In the [yapf] section of a setup.cfg file in either the current directory or one of its parent directories.
> 3. In the ~/.config/yapf/style file in your home directory.
>
> If none of those files are found, the default style is used (PEP8).
This means that one can set up a globa custom yapf style using `~/.config/yapf/style` or a project-specific one using the project directory.
History
-------
- [@jfbercher], august 14, 2016, first version, named `yapf_ext`
- [@jfbercher], august 19, 2016, second version `code_prettify`
- introduced support for R and javascript.
- changed extension name from `yapf_ext` to `code_prettify`
- [@jcb91], december 2016
- made addition of toolbar button & hotkey configurable
- reworked to avoid regex replacements for conversion to/from kernel string
formats, in favour of json-string interchange
- made kernel-specific prettifier calls configurable, allowing support for
different prettifiers & arbitrary kernels
- improved documentation
- [@jfbercher], december 2016-january 2017
- added a configurable shortkey to reflow the whole notebook
- extracted most of the code to build a general library of functions,
`kernel_exec_on_cell.js`, which can be used for all nbextensions which
needs to exec some code (via the current kernel) on the text from cells.
- added 2to3 as a plugin to the shared library
- [@jcb91], january 2017
- library: Use actions to avoid problems with auto-generated actions
generated by keyboard_manager, which were overwriting each other.
Also fix toolbar button removal.
- [@jfbercher], january 2017
- updated documentation
- added autopep8 nbextension as a plugin using the shared library
- [@artificialsoph], Jan 2018
- updated documentation
- changed default behavior to load custom yapf styles
[2to3]: README_2to3.md
[@jcb91]: https://github.com/jcb91
[@jfbercher]: https://github.com/jfbercher
[@kenkoooo]: https://github.com/kenkoooo
[autopep8]: https://github.com/hhatto/autopep8
[code-prettify]: README_code_prettify.md
[jupyter-autopep8]: README_autopep8.md
[fontawesome]: https://fontawesome.com/icons
[internals]: #Internals
[jupyter-autopep8]: https://github.com/kenkoooo/jupyter-autopep8
[jupyter_nbextensions_configurator]: https://github.com/Jupyter-contrib/jupyter_nbextensions_configurator
[yapf]: https://github.com/google/yapf

@ -0,0 +1,135 @@
A 2to3 converter
================
This nbextension converts python2 code in notebook code cells to python3 code.
Under the hood, it uses a call to the current notebook kernel to reformat the
code.
The conversion run by the kernel uses Python's standard-library [lib2to3]
module.
The nbextension provides
- a toolbar button (configurable to be added or not)
- a keyboard shortcut for reformatting the current code-cell (default shortcut
is `Ctrl-M`, can also be configured not to add the keyboard shortcut).
- a keyboard shortcut for reformatting the whole notebook (default shortcut
is `Ctrl-Shift-M`, can also be configured not to add the keyboard shortcut).
Syntax needs to be correct, but the nbextension may be able to point out basic
syntax errors.
![](demo_2to3.gif)
Options
-------
All options are provided by the [KerneExecOnCells library] - see the
[internals] section below for details.
There are a few nbextension-wide options, configurable using the
[jupyter_nbextensions_configurator] or by editing the `notebook` section config
file directly.
The options are as follows:
- `2to3.add_toolbar_button`:
Whether to add a toolbar button to transform the selected cell(s).
Defaults to `true`.
- `2to3.button_icon`:
A font-awesome class defining the icon used for the toolbar button and
actions. See [fontawesome] for available icon classes.
Defaults to `fa-legal`.
- `2to3.button_label`:
Toolbar button label text. Also used in the actions' help text.
Defaults to `Convert Python 2 to 3`.
- `2to3.register_hotkey`:
Whether to register hotkeys to transform the selected cell(s)/whole notebook.
Defaults to `true`.
- `2to3.hotkeys.process_all`:
Hotkey to use to transform all the code cells in the notebook.
Defaults to `Ctrl-Shift-L`.
- `2to3.hotkeys.process_selected`:
Hotkey to use to transform the selected cell(s).
Defaults to `Ctrl-L`.
- `2to3.show_alerts_for_errors`:
Whether to show alerts for errors in the kernel calls.
Defaults to `true`.
- `2to3.kernel_config_map_json`:
The value of this key is a string which can be parsed into a json object
giving the config for each kernel language.
The following give the per-kernel options of the parsed json, using the
language key `python `:
* `2to3.kernel_config_map_json.python.library`:
String to execute in the kernel in order to load any necessary kernel
libraries.
* `2to3.kernel_config_map_json.python.replacements_json_to_kernel`:
a list of pairs of strings, used as arguments to javascript's
`String.replace(from, to)` to translate from a json string into a valid
representation of the same string in the kernel language. Since json
strings are particularly simple, this can often (as with the python
language) be left as the default, an empty list.
* `2to3.kernel_config_map_json.python.prefix` and
`2to3.kernel_config_map_json.python.postfix`:
Strings added as bookends to the kernel string (translated from the json
string using the replacements above) to make up the kernel prettifier call
kernel's prettifier libraries.
* `2to3.kernel_config_map_json.python.trim_formatted_text`:
Whether to trim whitespace from the transformed cell text. Since jupyter
cells don't usually have leading or trailing whitespace, the default
behaviour is to trim the transformed text, in order to prevent the
transform adding extra newlines at the end (a common behaviour for source
files, where having a trailing newline is often considered good practice).
Internals
---------
Under the hood, this nbextension uses the [KerneExecOnCells library], a shared
library for creating Jupyter nbextensions which transform code cell text using
calls to the active kernel.
See the [shared README] for the internal model used by the nbextension.
History
-------
The project was forked by [@EWouters] from [@jfbercher]'s [code_prettify],
retaining most of the code.
It has since been altered to use the [KerneExecOnCells library], a shared
library for creating Jupyter nbextensions which transform code cell text using
calls to the active kernel.
The 2to3 conversion's kernel-side python code is based on [2to3_nb.py] by
[@takluyver] and [@fperez].
It could be extended to use the [futurize] functions so it can convert both
ways.
[2to3_nb.py]: https://gist.github.com/takluyver/c8839593c615bb2f6e80
[@EWouters]: https://github.com/EWouters
[@fperez]: https://github.com/fperez
[@jfbercher]: https://github.com/jfbercher
[@takluyver]: https://github.com/takluyver
[code_prettify]: https://github.com/jfbercher/code_prettify
[futurize]: http://python-future.org/automatic_conversion.html
[fontawesome]: https://fontawesome.com/icons
[internals]: #Internals
[jupyter_nbextensions_configurator]: https://github.com/Jupyter-contrib/jupyter_nbextensions_configurator
[KerneExecOnCells library]: README.md
[lib2to3]: https://docs.python.org/3/library/2to3.html#module-lib2to3
[shared README]: README.md

@ -0,0 +1,132 @@
jupyter-autopep8
================
This nbextension reformats/prettifies code in notebook python code cells.
Under the hood, it uses a call to the current notebook kernel to reformat the
code.
The conversion run by the kernel uses the python [autopep8] package, and thus is compatible only with python kernels.
The nbextension provides
- a toolbar button (configurable to be added or not)
- a keyboard shortcut for reformatting the current code-cell (default shortcut
is `Alt-A`, can also be configured not to add the keyboard shortcut).
- a keyboard shortcut for reformatting the whole notebook (default shortcut
is `Alt-Shift-A`, can also be configured not to add the keyboard shortcut).
Syntax needs to be correct, but the nbextension may be able to point out basic
syntax errors.
Prerequisites
-------------
Of course, you must have the necessary kernel-specific package installed for
the prettifier call to work:
pip install autopep8
Options
-------
All options are provided by the [KerneExecOnCells library] - see the
[internals] section below for details.
There are a few nbextension-wide options, configurable using the
[jupyter_nbextensions_configurator] or by editing the `notebook` section config
file directly.
The options are as follows:
- `autopep8.add_toolbar_button`:
Whether to add a toolbar button to transform the selected cell(s).
Defaults to `true`.
- `autopep8.button_icon`:
A font-awesome class defining the icon used for the toolbar button and actions.
See [fontawesome] for available icon classes.
Defaults to `fa-cog`.
- `autopep8.button_label`:
Toolbar button label text. Also used in the actions' help text.
Defaults to `Prettify (using autopep8)`.
- `autopep8.register_hotkey`:
Whether to register hotkeys to transform the selected cell(s)/whole notebook.
Defaults to `true`.
- `autopep8.hotkeys.process_all`:
Hotkey to use to transform all the code cells in the notebook.
Defaults to `Alt-Shift-A`.
- `autopep8.hotkeys.process_selected`:
Hotkey to use to transform the selected cell(s).
Defaults to `Alt-A`.
- `autopep8.show_alerts_for_errors`:
Whether to show alerts for errors in the kernel calls.
Defaults to `true`.
- `autopep8.kernel_config_map_json`:
The value of this key is a string which can be parsed into a json object
giving the config for each kernel language.
The following give the per-kernel options of the parsed json, using the
language key `python `:
* `autopep8.kernel_config_map_json.python.library`:
String to execute in the kernel in order to load any necessary kernel
libraries.
* `autopep8.kernel_config_map_json.python.replacements_json_to_kernel`:
a list of pairs of strings, used as arguments to javascript's
`String.replace(from, to)` to translate from a json string into a valid
representation of the same string in the kernel language. Since json
strings are particularly simple, this can often (as with the python
language) be left as the default, an empty list.
* `autopep8.kernel_config_map_json.python.prefix` and
`autopep8.kernel_config_map_json.python.postfix`:
Strings added as bookends to the kernel string (translated from the json
string using the replacements above) to make up the kernel prettifier call
kernel's prettifier libraries.
* `autopep8.kernel_config_map_json.python.trim_formatted_text`:
Whether to trim whitespace from the transformed cell text. Since jupyter
cells don't usually have leading or trailing whitespace, the default
behaviour is to trim the transformed text, in order to prevent the
transform adding extra newlines at the end (a common behaviour for source
files, where having a trailing newline is often considered good practice).
Internals
---------
Under the hood, this nbextension uses the [KerneExecOnCells library], a shared
library for creating Jupyter nbextensions which transform code cell text using
calls to the active kernel.
See the [shared README] for the internal model used by the nbextension.
History
-------
The project was forked by [@kenkoooo] from [@jfbercher]'s [code_prettify],
retaining most of the code.
It has since been altered to use the [KerneExecOnCells library], a shared
library for creating Jupyter nbextensions which transform code cell text using
calls to the active kernel.
[@jfbercher]: https://github.com/jfbercher
[@kenkoooo]: https://github.com/kenkoooo
[autopep8]: https://github.com/hhatto/autopep8
[code_prettify]: https://github.com/jfbercher/code_prettify
[fontawesome]: https://fontawesome.com/icons
[internals]: #Internals
[jupyter_nbextensions_configurator]: https://github.com/Jupyter-contrib/jupyter_nbextensions_configurator
[KerneExecOnCells library]: README.md
[shared README]: README.md

@ -0,0 +1,296 @@
A Code Prettifier
=================
This nbextension reformats/prettifies code in notebook code cells.
Under the hood, it uses a call to the current notebook kernel to reformat the
code.
Thus the actual prettifier package has to be callable from the current kernel
language.
With an appropriately-configured prettifier for the kernel in use, the
nbextension provides
- a toolbar button (configurable to be added or not)
- a keyboard shortcut for reformatting the current code-cell (default shortcut
is `Ctrl-L`, can also be configured not to add the keyboard shortcut).
- a keyboard shortcut for reformatting the whole notebook (default shortcut
is `Ctrl-Shift-L`, can also be configured not to add the keyboard shortcut).
Syntax shall be correct. The nbextension may also point out basic syntax errors.
![](demo-py.gif)
![](demo-R.gif)
![](demo-jv.gif)
Compatible Kernels
------------------
Example implementations are provided for prettifiers for ipython, ir and
ijavascript kernels which should work out of the box (assuming availability of
the relevant kernel-specific [prerequisites] mentioned below), but the
kernel-specific prettifier calls are configurable, so the model is applicable
to essentially any kernel language and prettifier library.
Other languages may be added as defaults in the future, but given that there
are more than 50 [kernels] available for Jupyter, it is not easily possible to
support all of them out of the box, unless people with experience in the
relevant kernels have the time to contribute code. For information on how the
reformatting takes place, and how to adapt it for your particular
kernel/prettifier, see the [options] and [internals] sections below.
If you implement a language that isn't yet provided by default, please submit a
PR or let us know to add it to the repo :)
Under the hood, this nbextension's functionality is provided by the
[KerneExecOnCells library], a shared library for creating Jupyter nbextensions
which transform code cell text using calls to the active kernel.
Prerequisites
-------------
Of course, you must have the necessary kernel-specific packages installed for
the prettifier call to work:
- for the default python implementation, the [yapf] module is required:
pip install yapf
Others you might consider using include [autopep8] - see [README_autopep8.md].
- for R, the default implementation uses the [formatR] and [jsonlite] packages:
```r
install.packages(c("formatR", "jsonlite"), repos="http://cran.rstudio.com")
```
- for [ijavascript], the [js-beautify] package is used:
(*Under linux, in the root of your user tree = ~*)
npm install js-beautify
Under Windows, you may then need to set the `NODE_PATH` environment variable
(see [this question on stackoverflow]) to it to `%AppData%\npm\node_modules`
(Windows 7/8/10).
To be done with it once and for all, add this as a System variable in the
Advanced tab of the System Properties dialog.
Options
-------
All options are provided by the [KerneExecOnCells library]. - see the
[internals] section below for details.
There are a few nbextension-wide options, configurable using the
[jupyter_nbextensions_configurator] or by editing the `notebook` section config
file directly.
The options are as follows:
- `code_prettify.add_toolbar_button`:
Whether to add a toolbar button to transform the selected cell(s).
Defaults to `true`.
- `code_prettify.button_icon`:
A font-awesome class defining the icon used for the toolbar button and
actions. See [fontawesome] for available icon classes.
Defaults to `fa-legal`.
- `code_prettify.button_label`:
Toolbar button label text. Also used in the actions' help text.
Defaults to `Code prettify`.
- `code_prettify.register_hotkey`:
Whether to register hotkeys to transform the selected cell(s)/whole notebook.
Defaults to `true`.
- `code_prettify.hotkeys.process_all`:
Hotkey to use to transform all the code cells in the notebook.
Defaults to `Ctrl-Shift-L`.
- `code_prettify.hotkeys.process_selected`:
Hotkey to use to transform the selected cell(s).
Defaults to `Ctrl-L`.
- `code_prettify.show_alerts_for_errors`:
Whether to show alerts for errors in the kernel calls.
Defaults to `true`.
- `code_prettify.kernel_config_map_json`:
The value of this key is a string which can be parsed into a json object
giving the config for each kernel language.
The following give the per-kernel options of the parsed json, using the
language key `python `:
* `code_prettify.kernel_config_map_json.python.library`:
String to execute in the kernel in order to load any necessary kernel
libraries.
* `code_prettify.kernel_config_map_json.python.replacements_json_to_kernel`:
a list of pairs of strings, used as arguments to javascript's
`String.replace(from, to)` to translate from a json string into a valid
representation of the same string in the kernel language. Since json
strings are particularly simple, this can often (as with the python
language) be left as the default, an empty list.
* `code_prettify.kernel_config_map_json.python.prefix` and
`code_prettify.kernel_config_map_json.python.postfix`:
Strings added as bookends to the kernel string (translated from the json
string using the replacements above) to make up the kernel prettifier call
kernel's prettifier libraries.
* `code_prettify.kernel_config_map_json.python.trim_formatted_text`:
Whether to trim whitespace from the transformed cell text. Since jupyter
cells don't usually have leading or trailing whitespace, the default
behaviour is to trim the transformed text, in order to prevent the
transform adding extra newlines at the end (a common behaviour for source
files, where having a trailing newline is often considered good practice).
Internals
---------
Under the hood, this nbextension uses the [KerneExecOnCells library], a shared
library for creating Jupyter nbextensions which transform code cell text using
calls to the active kernel.
The model is essentially:
1. The cell text is grabbed by client-side javascript, then turned into a json
string using javascript `JSON.stringify`. Since json-compatible strings are
a particularly simple string format, which is compatible with many other
programming languages without much modification (e.g. a valid json string
is also a valid string in python 3, and also in python 2 when prefixed with
a `u`), and easily converted for use in others (because of its simplicity).
2. Optional regex replacements are used to translate the json-format string
into a valid kernel string. Python, R and javascript don't require this
step, but other languages may do, so it's implemented for flexibility
using the per-kernel config key `replacements_json_to_kernel`, which is a
list of pairs of arguments to javascript `String.replace`.
3. The kernel-specific prettifier call is then composed from
`kernel_config.prefix` + `kernel_text_string` + `kernel_config.postfix` and
sent to the kernel for execution. This kernel call is expected to get the
formatted cell text _printed_ as a json-compatible string. Since most
kernel languages have json packages, this should hopefully be easy to
arrange. The reason for the printing text rather than simply displaying it,
is that it prevents us having to translate from a kernel string
representing a json string.
4. The callback for the kernel execution in client-side javascript parses the
printed json-format string, optionally trims trailing whitespace according
to the `trim_formatted_text` key (which defaults to `true`) in the
per-kernel config, and then sets the cell text using the result.
The process is probably best illustrated using an example for the python
implementation:
1. **At nbextension load**, the `code_prettify.kernel_config_map_json` config
option is parsed to give the json object
```json
{
"python": {
"library": "import json\nimport yapf.yapflib.yapf_api",
"prefix": "print(json.dumps(yapf.yapflib.yapf_api.FormatCode(u",
"postfix": ")[0]))"
}
}
```
(other kernel languages are omitted for clarity).
2. **On kernel becoming ready**, the nbextension looks up the config for the
kernel's language (in our example, this is the `python` key of the kernel
config json object above). It then sends the kernel config's `library`
string to the kernel for execution. Thus the python implementation above
executes
```python
import json
import yapf.yapflib.yapf_api
```
3. **On requesting a cell be prettified** which can happen by clicking the
toolbar, or with a (configurable) hotkey, the following happens:
Say the cell to be formatted contains the following ugly python code:
```python
msg= 'hello '+"world"
print (
msg )
```
Then the result of the `JSON.stringify` call will be a string containing
```json
"msg= 'hello '+\"world\"\nprint (\n msg )"
```
(note the opening and closing quotes). Concatenating this with the prefix &
postfix strings from the python kernel config above, gives us the kernel
code to execute. The call sent to the python kernel is therefore
```python
print(json.dumps(yapf.yapflib.yapf_api.FormatCode(u"msg= 'hello '+\"world\"\nprint (\n msg )")[0]))
```
4. What gets 'printed' by the kernel (i.e. returned to the javascript stream
callback) is the following json-format string:
```json
"msg = 'hello ' + \"world\"\nprint(msg)\n"
```
The default is to trim whitepace from the returned prettified text, which
results in the final prettified python code for the cell:
```python
msg = 'hello ' + "world"
print(msg)
```
History
-------
- [@jfbercher], august 14, 2016, first version, named `yapf_ext`
- [@jfbercher], august 19, 2016, second version `code_prettify`
- introduced support for R and javascript.
- changed extension name from `yapf_ext` to `code_prettify`
- [@jcb91], december 2016
- made addition of toolbar button & hotkey configurable
- reworked to avoid regex replacements for conversion to/from kernel string
formats, in favour of json-string interchange
- made kernel-specific prettifier calls configurable, allowing support for
different prettifiers & arbitrary kernels
- improved documentation
- [@jfbercher], december 2016-january 2017
- added a configurable shortkey to reflow the whole notebook
- extracted most of the code to build a general library of functions,
`kernel_exec_on_cell.js`, which can be used for all nbextensions which
needs to exec some code (via the current kernel) on the text from cells.
[@jcb91]: https://github.com/jcb91
[@jfbercher]: https://github.com/jfbercher
[autopep8]: https://github.com/hhatto/autopep8
[formatR]: https://yihui.name/formatr
[fontawesome]: https://fontawesome.com/icons
[ijavascript]: https://n-riesco.github.io/ijavascript
[internals]: #Internals
[js-beautify]: https://github.com/beautify-web/js-beautify
[jsonlite]: https://github.com/jeroen/jsonlite
[jupyter_nbextensions_configurator]: https://github.com/Jupyter-contrib/jupyter_nbextensions_configurator
[KerneExecOnCells library]: README.md
[kernels]: https://github.com/ipython/ipython/wiki/IPython-kernels-for-other-languages
[options]: #Options
[prerequisites]: #Prerequisites
[README_autopep8.md]: README_autopep8.md
[this question on stackoverflow]: https://stackoverflow.com/questions/9587665/nodejs-cannot-find-installed-module-on-windows
[yapf]: https://github.com/google/yapf

@ -0,0 +1,40 @@
# Sort imports using isort
This nbextension sorts imports in notebook code cells.
Under the hood, it uses a call to the current notebook kernel to reformat the code. The conversion run by the kernel uses Python's package [isort](https://github.com/timothycrosley/isort) by [Timothy Edmund Crosley](https://github.com/timothycrosley).
The nbextension provides
- a toolbar button (configurable to be added or not)
**pre-requisites:** of course, you must have the corresponding package installed:
```
pip install isort [--user]
```
## Options
All options are provided by the [KerneExecOnCells library](kernel_exec_on_cell.js). There are a few nbextension-wide options, configurable using the [jupyter_nbextensions_configurator](https://github.com/Jupyter-contrib/jupyter_nbextensions_configurator) or by editing the `notebook` section config file directly. The options are as follows:
- `isort.add_toolbar_button`: Whether to add a toolbar button to transform the selected cell(s). Defaults to `true`.
- `isort.button_icon`:
A font-awesome class defining the icon used for the toolbar button and actions.
See [fontawesome] for available icon classes.
Defaults to `fa-sort`.
- `isort.show_alerts_for_errors`: Whether to show alerts for errors in the kernel calls. Defaults to `false`.
- `isort.button_label`: Toolbar button label text. Also used in the actions' help text. Defaults to `Sort imports with isort`.
- `isort.kernel_config_map_json`: The value of this key is a string which can be parsed into a json object giving the config for each kernel language.
## Internals
Under the hood, this nbextension uses the [kerneexeconcells library](kernel_exec_on_cell.js), a shared library for creating Jupyter nbextensions which transform code cell text using calls to the active kernel.
See the [shared README](README.md) and [kerneexeconcells library](kernel_exec_on_cell.js) for the internal model used by the nbextension.
[fontawesome]: https://fontawesome.com/icons

@ -0,0 +1,36 @@
// Copyright (c) Jupyter-Contrib Team.
// Distributed under the terms of the Modified BSD License.
// Authors: @kenkoooo, @jfbercher and @jcb91
define(['./kernel_exec_on_cell'], function(kernel_exec_on_cell) {
'use strict';
var mod_name = 'autopep8';
// gives default settings
var cfg = {
add_toolbar_button: true,
hotkeys: {
process_selected: 'Alt-A',
process_all: 'Alt-Shift-A',
},
register_hotkey: true,
show_alerts_for_errors: true,
button_icon: 'fa-cog',
button_label: 'Prettify (using autopep8)',
kbd_shortcut_text: 'Prettify' // ' current cell(s)'
};
cfg.kernel_config_map = { // map of parameters for supported kernels
"python": {
"library": "import json\nimport autopep8",
"prefix": "print(json.dumps(autopep8.fix_code(u",
"postfix": ")))"
}
};
var prettifier = new kernel_exec_on_cell.define_plugin(mod_name, cfg);
prettifier.load_ipython_extension = prettifier.initialize_plugin;
return prettifier;
});

@ -0,0 +1,62 @@
Type: Jupyter Notebook Extension
Name: Autopep8
Description: Use kernel-specific code to reformat/prettify the contents of code cells
Link: README_autopep8.md
Main: autopep8.js
Compatibility: Jupyter 4.x, 5.x
Parameters:
- name: autopep8.add_toolbar_button
description: Add a toolbar button to prettify the selected cell(s)
input_type: checkbox
default: true
- name: autopep8.button_icon
description: |
Toolbar button icon: a font-awesome class defining the icon used for the
toolbar button and actions.
See https://fontawesome.com/icons for available icons.
input_type: text
default: 'fa-cog'
- name: autopep8.button_label
description: Toolbar button label text
input_type: text
default: 'Code prettify'
- name: autopep8.register_hotkey
description: |
Register hotkeys to prettify the selected code cell(s), or all code cells
in the notebook
input_type: checkbox
default: true
- name: autopep8.hotkeys.process_selected
description: Hotkey to use to prettify the selected cell(s)
input_type: hotkey
default: 'Alt-A'
- name: autopep8.hotkeys.process_all
description: Hotkey to use to prettify the whole notebook
input_type: hotkey
default: 'Alt-Shift-A'
- name: autopep8.show_alerts_for_errors
description: Show alerts for errors in the kernel prettifying calls
input_type: checkbox
default: true
- name: autopep8.kernel_config_map_json
description: |
json defining library calls required to load the kernel-specific
prettifying modules, and the prefix & postfix for the json-format string
required to make the prettifying call.
input_type: textarea
default: |
{
"python": {
"library": "import json\nimport autopep8",
"prefix": "print(json.dumps(autopep8.fix_code(u",
"postfix": ")))"
}
}

@ -0,0 +1,56 @@
// Copyright (c) Jupyter-Contrib Team.
// Distributed under the terms of the Modified BSD License.
// Authors: @jfbercher and @jcb91
define(['./kernel_exec_on_cell'], function(kernel_exec_on_cell) {
'use strict';
var mod_name = 'code_prettify';
// gives default settings
var cfg = {
add_toolbar_button: true,
hotkeys: {
process_selected: 'Ctrl-L',
process_all: 'Ctrl-Shift-L',
},
register_hotkey: true,
show_alerts_for_errors: true,
button_label: 'Code prettify',
button_icon: 'fa-legal',
kbd_shortcut_text: 'Code prettify',
};
cfg.kernel_config_map = { // map of parameters for supported kernels
"python": {
"library": ["import json",
"def yapf_reformat(cell_text):",
" import yapf.yapflib.yapf_api",
" from yapf import file_resources",
" import os",
" import re",
" style_config = file_resources.GetDefaultStyleForDir(os.getcwd())",
" cell_text = re.sub('^%', '#%#', cell_text, flags=re.M)",
" reformated_text = yapf.yapflib.yapf_api.FormatCode(cell_text, style_config=style_config)[0]",
" return re.sub('^#%#', '%', reformated_text, flags=re.M)"].join("\n"),
"prefix": "print(json.dumps(yapf_reformat(u",
"postfix": ")))"
},
"r": {
"library": "library(formatR)\nlibrary(jsonlite)",
"prefix": "cat(toJSON(paste(tidy_source(text=",
"postfix": ", output=FALSE)[['text.tidy']], collapse='\n')))"
},
"javascript": {
"library": "jsbeautify = require(" + "'js-beautify')",
// we do this + trick to prevent require.js attempting to load js-beautify when processing the AMI-style load for this module
"prefix": "console.log(JSON.stringify(jsbeautify.js_beautify(",
"postfix": ")));"
}
};
var prettifier = new kernel_exec_on_cell.define_plugin(mod_name, cfg);
prettifier.load_ipython_extension = prettifier.initialize_plugin;
return prettifier;
});

@ -0,0 +1,72 @@
Type: Jupyter Notebook Extension
Name: Code prettify
Description: Use kernel-specific code to reformat/prettify the contents of code cells
Link: README_code_prettify.md
Main: code_prettify.js
Compatibility: Jupyter 4.x, 5.x
Parameters:
- name: code_prettify.add_toolbar_button
description: Add a toolbar button to prettify the selected cell(s)
input_type: checkbox
default: true
- name: code_prettify.button_icon
description: |
Toolbar button icon: a font-awesome class defining the icon used for the
toolbar button and actions.
See https://fontawesome.com/icons for available icons.
input_type: text
default: 'fa-legal'
- name: code_prettify.button_label
description: Toolbar button label text
input_type: text
default: 'Code prettify'
- name: code_prettify.register_hotkey
description: |
Register hotkeys to prettify the selected code cell(s), or all code cells
in the notebook
input_type: checkbox
default: true
- name: code_prettify.hotkeys.process_selected
description: Hotkey to use to prettify the selected cell(s)
input_type: hotkey
default: 'Ctrl-L'
- name: code_prettify.hotkeys.process_all
description: Hotkey to use to prettify the whole notebook
input_type: hotkey
default: 'Ctrl-Shift-L'
- name: code_prettify.show_alerts_for_errors
description: Show alerts for errors in the kernel prettifying calls
input_type: checkbox
default: true
- name: code_prettify.kernel_config_map_json
description: |
json defining library calls required to load the kernel-specific
prettifying modules, and the prefix & postfix for the json-format string
required to make the prettifying call.
input_type: textarea
default: |
{
"python": {
"library": "import json\ndef yapf_reformat(cell_text):\n import yapf.yapflib.yapf_api\n import re\n cell_text = re.sub('^%', '#%#', cell_text, flags=re.M)\n reformated_text = yapf.yapflib.yapf_api.FormatCode(cell_text)[0]\n return re.sub('^#%#', '%', reformated_text, flags=re.M)",
"prefix": "print(json.dumps(yapf_reformat(u",
"postfix": ")))"
},
"r": {
"library": "library(formatR)\nlibrary(jsonlite)",
"prefix": "cat(toJSON(paste(tidy_source(text=",
"postfix": ", output=FALSE)[['text.tidy']], collapse='\n')))"
},
"javascript": {
"library": "jsbeautify = require('js-beautify')",
"prefix": "console.log(JSON.stringify(jsbeautify.js_beautify(",
"postfix": ")));"
}
}

@ -0,0 +1,43 @@
// Copyright (c) Jupyter-Contrib Team.
// Distributed under the terms of the Modified BSD License.
// Authors: @benjaminabel
// Based on: code_prettify extension
define(['./kernel_exec_on_cell'], function(kernel_exec_on_cell) {
'use strict';
var mod_name = 'isort';
// gives default settings
var cfg = {
add_toolbar_button: true,
register_hotkey: false,
show_alerts_for_errors: false,
button_icon: 'fa-sort',
button_label: 'Sort imports with isort',
kbd_shortcut_text: 'Sort imports in' // ' current cell(s)'
};
cfg.kernel_config_map = { // map of parameters for supported kernels
"python": {
"library": [
"import isort",
"import json",
"def _isort_refactor_cell(src):",
" try:",
" tree = isort.SortImports(file_contents=src).output",
" except Exception:",
" return src ",
" else:",
" return str(tree)[:-1]",
].join('\n'),
"prefix": "print(json.dumps(_isort_refactor_cell(u",
"postfix": ")))"
}
};
var converter = new kernel_exec_on_cell.define_plugin(mod_name, cfg);
converter.load_ipython_extension = converter.initialize_plugin;
return converter;
});

@ -0,0 +1,40 @@
Type: Jupyter Notebook Extension
Name: isort formatter
Description: Sort imports in python files using isort
Link: README_isort.md
Main: isort.js
Compatibility: Jupyter 4.x, 5.x
Parameters:
- name: isort.add_toolbar_button
description: Add a toolbar button to convert the selected cell(s)
input_type: checkbox
default: true
- name: isort.button_icon
description: |
Toolbar button icon: a font-awesome class defining the icon used for the
toolbar button. See https://fontawesome.com/icons for available icons.
input_type: text
default: 'fa-sort'
- name: isort.button_label
description: Toolbar button label text
input_type: text
default: 'Sort imports with isort'
- name: isort.kernel_config_map_json
description: |
kernel_config_map_json:
json defining library calls required to load the kernel-specific
converting modules, and the prefix & postfix for the json-format string
required to make the converting call.
input_type: textarea
default: |
{
"python": {
"library": "import json, isort\ndef _isort_refactor_cell(src):\n try:\n tree = isort.SortImports(file_contents=src).output\n except Exception:\n return src \n else:\n return str(tree)[:-1]",
"prefix": "print(json.dumps(_isort_refactor_cell(u",
"postfix": ")))"
}
}

@ -0,0 +1,349 @@
// Copyright (c) Jupyter-Contrib Team.
// Distributed under the terms of the Modified BSD License.
define([
'jquery',
'base/js/namespace',
'base/js/events',
'notebook/js/codecell',
], function(
$,
Jupyter,
events,
codecell
) {
'use strict';
var CodeCell = codecell.CodeCell;
// this wrapper function allows config & hotkeys to be per-plugin
function KernelExecOnCells(mod_name, cfg) {
this.mod_name = mod_name;
this.mod_log_prefix = '[' + this.mod_name + ']';
this.mod_edit_shortcuts = {};
this.mod_cmd_shortcuts = {};
this.default_kernel_config = {
library: '',
prefix: '',
postfix: '',
replacements_json_to_kernel: [],
trim_formatted_text: true
};
// gives default settings
var default_cfg = {
add_toolbar_button: true,
hotkeys: {
process_selected: 'Ctrl-L',
process_all: 'Ctrl-Shift-L',
},
register_hotkey: true,
show_alerts_for_errors: true,
button_icon: 'fa-legal',
button_label: mod_name,
kbd_shortcut_text: mod_name,
kernel_config_map: {},
actions: null, // to be filled by register_actions
};
// extend a new object, to avoid interference with other nbextensions
// derived from the same base class
this.cfg = $.extend(true, {}, cfg, default_cfg);
// set default json string, will later be updated from config
// before it is parsed into an object
this.cfg.kernel_config_map_json = JSON.stringify(this.cfg.kernel_config_map);
} // end per-plugin wrapper define_plugin_functions
// Prototypes
// ----------
/**
* return a Promise which will resolve/reject based on the kernel message
* type.
* The returned promise will be
* - resolved if the message was not an error
* - rejected using the message's error text if msg.msg_type is "error"
*/
KernelExecOnCells.prototype.convert_error_msg_to_broken_promise = function(msg) {
var that = this;
return new Promise(function(resolve, reject) {
if (msg.msg_type == 'error') {
return reject(that.mod_log_prefix + '\n Error: ' + msg.content.ename + '\n' + msg.content.evalue);
}
return resolve(msg);
});
};
KernelExecOnCells.prototype.convert_loading_library_error_msg_to_broken_promise = function(msg) {
var that = this;
return new Promise(function(resolve, reject) {
if (msg.msg_type == 'error') {
return reject(that.mod_log_prefix + '\n Error loading library for ' +
Jupyter.notebook.metadata.kernelspec.language + ':\n' +
msg.content.ename + msg.content.evalue +
'\n\nCheck that the appropriate library/module is correctly installed (read ' +
that.mod_name + '\'s documentation for details)');
}
return resolve(msg);
});
};
KernelExecOnCells.prototype.get_kernel_config = function() {
var kernelLanguage = Jupyter.notebook.metadata.kernelspec.language.toLowerCase();
var kernel_config = this.cfg.kernel_config_map[kernelLanguage];
// true => deep
return $.extend(true, {}, this.default_kernel_config, kernel_config);
};
KernelExecOnCells.prototype.transform_json_string_to_kernel_string = function(str, kernel_config) {
for (var ii = 0; ii < kernel_config.replacements_json_to_kernel.length; ii++) {
var from = kernel_config.replacements_json_to_kernel[ii][0];
var to = kernel_config.replacements_json_to_kernel[ii][1];
str = str.replace(from, to);
}
return str;
};
/**
* construct functions as callbacks for the autoformat cell promise. This
* is necessary because javascript lacks loop scoping, so if we don't use
* this IIFE pattern, cell_index & cell are passed by reference, and every
* callback ends up using the same value
*/
KernelExecOnCells.prototype.construct_cell_callbacks = function(cell_index, cell) {
var that = this;
var on_success = function(formatted_text) {
cell.set_text(formatted_text);
};
var on_failure = function(reason) {
console.warn(
that.mod_log_prefix,
'error processing cell', cell_index + ':\n',
reason
);
if (that.cfg.show_alerts_for_errors) {
alert(reason);
}
};
return [on_success, on_failure];
};
KernelExecOnCells.prototype.autoformat_cells = function(indices) {
if (indices === undefined) {
indices = Jupyter.notebook.get_selected_cells_indices();
}
var kernel_config = this.get_kernel_config();
for (var ii = 0; ii < indices.length; ii++) {
var cell_index = indices[ii];
var cell = Jupyter.notebook.get_cell(cell_index);
if (!(cell instanceof CodeCell)) {
continue;
}
// IIFE because otherwise cell_index & cell are passed by reference
var callbacks = this.construct_cell_callbacks(cell_index, cell);
this.autoformat_text(cell.get_text(), kernel_config).then(callbacks[0], callbacks[1]);
}
};
KernelExecOnCells.prototype.autoformat_text = function(text, kernel_config) {
var that = this;
return new Promise(function(resolve, reject) {
kernel_config = kernel_config || that.get_kernel_config();
var kernel_str = that.transform_json_string_to_kernel_string(
JSON.stringify(text), kernel_config);
Jupyter.notebook.kernel.execute(
kernel_config.prefix + kernel_str + kernel_config.postfix, {
iopub: {
output: function(msg) {
return resolve(that.convert_error_msg_to_broken_promise(msg).then(
function on_success(msg) {
// print goes to stream text => msg.content.text
// but for some kernels (eg nodejs) can be called as result of exec
if (msg.content.text !== undefined) {
var formatted_text;
try {
formatted_text = String(JSON.parse(msg.content.text));
}
catch (err) {
return Promise.reject(err);
}
if (kernel_config.trim_formatted_text) {
formatted_text = formatted_text.trim();
}
return formatted_text;
}
}
));
}
}
}, { silent: false }
);
});
};
KernelExecOnCells.prototype.add_toolbar_button = function() {
if ($('#' + this.mod_name + '_button').length < 1) {
var button_group_id = this.mod_name + '_button';
var that = this;
Jupyter.toolbar.add_buttons_group([{
label: ' ', //space otherwise add_buttons fails -- This label is inserted as a button description AND bubble help
icon: this.cfg.button_icon,
callback: function(evt) {
that.autoformat_cells(
evt.shiftKey ? Jupyter.notebook.get_cells().map(function (cell, idx) { return idx; }) : undefined
);
},
}], button_group_id);
// Correct add_buttons_group default
// Change title --> inserts bubble help
// redefine icon to remove spurious space
var w = $('#'+ button_group_id +' > .btn')[0];
w.title = this.cfg.kbd_shortcut_text + ' selected cell(s) (add shift for all cells)'
w.innerHTML = '<i class="' + this.cfg.button_icon + ' fa"></i>'
}
}
KernelExecOnCells.prototype.add_keyboard_shortcuts = function() {
var new_shortcuts = {};
new_shortcuts[this.cfg.hotkeys.process_selected] = this.cfg.actions.process_selected.name;
new_shortcuts[this.cfg.hotkeys.process_all] = this.cfg.actions.process_all.name;
Jupyter.keyboard_manager.edit_shortcuts.add_shortcuts(new_shortcuts);
Jupyter.keyboard_manager.command_shortcuts.add_shortcuts(new_shortcuts);
};
KernelExecOnCells.prototype.register_actions = function() {
/**
* it's important that the actions created by registering keyboard
* shortcuts get different names, as otherwise a default action is
* created, whose name is a string representation of the handler
* function.
* Since this library uses the same handler function for all plugins,
* just with different contexts (different values of cfg), their
* string representations are the same, and the last one to be
* registered overwrites all previous versions.
* This is essentially an issue with notebook, but it encourages us to
* use actions, which is where notebook is going anyway.
*/
var actions = this.cfg.actions = {};
var that = this;
actions.process_selected = {
help: that.cfg.kbd_shortcut_text + ' selected cell(s)',
help_index: 'yf',
icon: that.cfg.button_icon,
handler: function(evt) { that.autoformat_cells(); },
};
actions.process_all = {
help: that.cfg.kbd_shortcut_text + " the whole notebook",
help_index: 'yf',
icon: that.cfg.button_icon,
handler: function(evt) {
that.autoformat_cells(Jupyter.notebook.get_cells().map(function (cell, idx) { return idx; }));
},
};
actions.process_selected.name = Jupyter.keyboard_manager.actions.register(
actions.process_selected, 'process_selected_cells', that.mod_name);
actions.process_all.name = Jupyter.keyboard_manager.actions.register(
actions.process_all, 'process_all_cells', that.mod_name);
};
KernelExecOnCells.prototype.setup_for_new_kernel = function() {
var that = this;
var kernelLanguage = Jupyter.notebook.metadata.kernelspec.language.toLowerCase();
var kernel_config = this.cfg.kernel_config_map[kernelLanguage];
if (kernel_config === undefined) {
$('#' + this.mod_name + '_button').remove();
alert(this.mod_log_prefix + " Sorry, can't use kernel language " + kernelLanguage + ".\n" +
"Configurations are currently only defined for the following languages:\n" +
Object.keys(this.cfg.kernel_config_map).join(', ') + "\n" +
"See readme for more details.");
// also remove keyboard shortcuts
if (this.cfg.register_hotkey) {
try {
Jupyter.keyboard_manager.edit_shortcuts.remove_shortcut(this.cfg.hotkeys.process_selected);
Jupyter.keyboard_manager.edit_shortcuts.remove_shortcut(this.cfg.hotkeys.process_all);
Jupyter.keyboard_manager.command_shortcuts.remove_shortcut(this.cfg.hotkeys.process_all);
} catch (err) {}
}
} else { // kernel language is supported
if (this.cfg.add_toolbar_button) {
this.add_toolbar_button();
}
if (this.cfg.register_hotkey) {
this.add_keyboard_shortcuts();
}
Jupyter.notebook.kernel.execute(
kernel_config.library, {
iopub: {
output: function(msg) {
return that.convert_loading_library_error_msg_to_broken_promise(msg)
.catch(
function on_failure(err) {
if (that.cfg.show_alerts_for_errors) {
alert(err);
}
else {
console.error(err);
}
}
);
}
}
}, { silent: false }
);
}
};
KernelExecOnCells.prototype.initialize_plugin = function() {
var that = this;
// first, load config
Jupyter.notebook.config.loaded
// now update default config with that loaded from server
.then(function on_success() {
$.extend(true, that.cfg, Jupyter.notebook.config.data[that.mod_name]);
}, function on_error(err) {
console.warn(that.mod_log_prefix, 'error loading config:', err);
})
// next parse json config values
.then(function on_success() {
var parsed_kernel_cfg = JSON.parse(that.cfg.kernel_config_map_json);
$.extend(that.cfg.kernel_config_map, parsed_kernel_cfg);
})
// if we failed to parse the json values in the config
// using catch pattern, we attempt to continue anyway using defaults
.catch(function on_error(err) {
console.warn(
that.mod_log_prefix, 'error parsing config variable',
that.mod_name + '.kernel_config_map_json to a json object:',
err
);
})
// now do things which required the config to be loaded
.then(function on_success() {
that.register_actions(); // register actions
// kernel may already have been loaded before we get here, in which
// case we've missed the kernel_ready.Kernel event, so try ctx
if (typeof Jupyter.notebook.kernel !== "undefined" && Jupyter.notebook.kernel !== null) {
that.setup_for_new_kernel();
}
// on kernel_ready.Kernel, a new kernel has been started
events.on("kernel_ready.Kernel", function(evt, data) {
console.log(that.mod_log_prefix, 'restarting for new kernel_ready.Kernel event');
that.setup_for_new_kernel();
});
}).catch(function on_error(err) {
console.error(that.mod_log_prefix, 'error loading:', err);
});
};
return {define_plugin: KernelExecOnCells};
});

@ -0,0 +1,17 @@
Type: Jupyter Notebook Extension
Name: Codefolding
Description: This extension enables the CodeMirror feature to allow codefolding in code cells
Link: readme.md
Icon: icon.png
Main: main.js
Compatibility: 4.x, 5.x
Parameters:
- name: codefolding_hotkey
description: Hotkey to fold/unfold code
input_type: hotkey
default: Alt-F
- name: init_delay
description: Add a delay before initializing the extension. Useful when the gutter is not being initialized correctly.
input_type: number
min: 0
default: 0

@ -0,0 +1,18 @@
Type: Jupyter Notebook Extension
Name: Codefolding in Editor
Description: |
Enables the CodeMirror feature to allow codefolding in the Jupyter file
editor view.
Note that this also uses the codefolding hotkey from the codefolding
nbextension for the notebook view.
Link: readme.md
Icon: codefolding_editor.png
Main: edit.js
Compatibility: 4.x, 5.x
Parameters:
- name: init_delay
description: Add a delay before initializing the extension. Useful when the gutter is not being initialized correctly.
input_type: number
min: 0
default: 1000
Section: edit

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save