@ -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"
|
||||
}
|
@ -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 @@
|
||||
pip
|
@ -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 @@
|
||||
jupyter_contrib_core
|
@ -0,0 +1 @@
|
||||
|
@ -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 @@
|
||||
pip
|
@ -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 @@
|
||||
jupyter_contrib_nbextensions
|
@ -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
|
After Width: | Height: | Size: 5.6 KiB |
@ -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
|
After Width: | Height: | Size: 18 KiB |
@ -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
|
After Width: | Height: | Size: 32 KiB |
@ -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": ")));"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 229 KiB |
After Width: | Height: | Size: 119 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 118 KiB |
@ -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
|
After Width: | Height: | Size: 23 KiB |
@ -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
|
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 4.0 KiB |