jupyter_sphinx-0.2.3/0000755000175000017500000000000013565524063015100 5ustar antonanton00000000000000jupyter_sphinx-0.2.3/LICENSE0000644000175000017500000000305513471762764016120 0ustar antonanton00000000000000Copyright (c) 2015-2016, Brian E. Granger and Jake Vanderplas Copyright (c) 2016-2019, Project Jupyter Contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jupyter_sphinx-0.2.3/MANIFEST.in0000644000175000017500000000007413544104026016625 0ustar antonanton00000000000000include LICENSE recursive-include jupyter_sphinx/thebelab/* jupyter_sphinx-0.2.3/PKG-INFO0000644000175000017500000000077213565524063016203 0ustar antonanton00000000000000Metadata-Version: 1.2 Name: jupyter_sphinx Version: 0.2.3 Summary: Jupyter Sphinx Extensions Home-page: https://github.com/jupyter/jupyter-sphinx/ Author: Jupyter Development Team Author-email: jupyter@googlegroups.com License: BSD Project-URL: Bug Tracker, https://github.com/jupyter/jupyter-sphinx/issues/ Project-URL: Documentation, https://jupyter-sphinx.readthedocs.io Project-URL: Source Code, https://github.com/jupyter/jupyter-sphinx/ Description: UNKNOWN Platform: UNKNOWN Requires-Python: >= 3.5 jupyter_sphinx-0.2.3/README.md0000644000175000017500000000131213471762764016364 0ustar antonanton00000000000000# Jupyter Sphinx Extensions ``jupyter-sphinx`` enables running code embedded in Sphinx documentation and embedding output of that code into the resulting document. It has support for rich output such as images and even Jupyter interactive widgets. ## Installation With pip: ```bash pip install jupyter_sphinx ``` with conda: ```bash conda install jupyter_sphinx -c conda-forge ``` ## Usage You can check out the documentation on https://jupyter-sphinx.readthedocs.io for up to date usage information and examples. ## License We use a shared copyright model that enables all contributors to maintain the copyright on their contributions. All code is licensed under the terms of the revised BSD license. jupyter_sphinx-0.2.3/jupyter_sphinx/0000755000175000017500000000000013565524063020173 5ustar antonanton00000000000000jupyter_sphinx-0.2.3/jupyter_sphinx/__init__.py0000644000175000017500000000006013335344153022273 0ustar antonanton00000000000000from ._version import version_info, __version__ jupyter_sphinx-0.2.3/jupyter_sphinx/_version.py0000644000175000017500000000042613565523633022375 0ustar antonanton00000000000000version_info = (0, 2, 3, 'final') _specifier_ = {'alpha': 'a', 'beta': 'b', 'candidate': 'rc', 'final': ''} __version__ = '%s.%s.%s%s'%(version_info[0], version_info[1], version_info[2], '' if version_info[3]=='final' else _specifier_[version_info[3]]+str(version_info[4])) jupyter_sphinx-0.2.3/jupyter_sphinx/css/0000755000175000017500000000000013565524063020763 5ustar antonanton00000000000000jupyter_sphinx-0.2.3/jupyter_sphinx/css/jupyter-sphinx.css0000644000175000017500000000545513564057607024523 0ustar antonanton00000000000000/* Stylesheet for jupyter-sphinx These styles mimic the Jupyter HTML styles. The default CSS (Cascading Style Sheet) class structure of jupyter-sphinx is the following: jupyter_container code_cell (optional) stderr (optional) output (optional) If the code_cell is not displayed, then there is not a jupyter_container, and the output is provided without CSS. This stylesheet attempts to override the defaults of all packaged Sphinx themes to display jupter-sphinx cells in a Jupyter-like style. If you want to adjust the styles, add additional custom CSS to override these styles. After a build, this stylesheet is loaded from ./_static/jupyter-sphinx.css . */ div.jupyter_container { padding: .4em; margin: 0 0 .4em 0; background-color: #FFFF; border: 1px solid #CCC; -moz-box-shadow: 2px 2px 4px rgba(87, 87, 87, 0.2); -webkit-box-shadow: 2px 2px 4px rgba(87, 87, 87, 0.2); box-shadow: 2px 2px 4px rgba(87, 87, 87, 0.2); } .jupyter_container div.code_cell { border: 1px solid #cfcfcf; border-radius: 2px; background-color: #f7f7f7; margin: 0 0; overflow: auto; } .jupyter_container div.code_cell pre { padding: 4px; margin: 0 0; background-color: #f7f7f7; border: none; background: none; -webkit-box-shadow: none; /* for nature */ -moz-box-shadow: none; /* for nature */ } .jupyter_container div.code_cell * { margin: 0 0; } div.jupyter_container div.highlight { background-color: #f7f7f7; /* for haiku */ } div.jupyter_container * { padding: 0; margin: 0; } /* overrides for sphinx_rtd_theme */ .rst-content .jupyter_container div[class^='highlight'], .document .jupyter_container div[class^='highlight'], .rst-content .jupyter_container pre.literal-block { border:none; margin: 0; padding: 0; background: none; padding: 3px; background-color: transparent; } /* restore Mathjax CSS, as it assumes a vertical margin. */ .jupyter_container .MathJax_Display { margin: 1em 0em; text-align: center; } .jupyter_container .stderr { background-color: #FCC; border: none; padding: 3px; } .jupyter_container .output { border: none; } .jupyter_container div.output pre { background-color: white; background: none; padding: 4px; border: none; -webkit-box-shadow: none; /* for nature */ -moz-box-shadow: none; /* for nature */ } .jupyter_container .code_cell td.linenos { align: right; padding: 4px 4px 4px 8px; border-right: 1px solid #cfcfcf; color: #999; } .jupyter_container .output .highlight { background-color: #ffffff; } /* combine sequential jupyter cells, by moving sequential ones up higher on y-axis */ div.jupyter_container + div.jupyter_container { margin: -.5em 0 .4em 0; } /* Fix for sphinx_rtd_theme spacing after jupyter_container #91 */ .rst-content .jupyter_container { margin: 0 0 24px 0; } jupyter_sphinx-0.2.3/jupyter_sphinx/execute.py0000644000175000017500000010345413565523615022220 0ustar antonanton00000000000000"""Simple sphinx extension that executes code in jupyter and inserts output.""" import os from itertools import groupby, count from operator import itemgetter import json import sphinx from sphinx.util import logging from sphinx.util.fileutil import copy_asset from sphinx.transforms import SphinxTransform from sphinx.errors import ExtensionError from sphinx.addnodes import download_reference import docutils from IPython.lib.lexers import IPythonTracebackLexer, IPython3Lexer from docutils.parsers.rst import Directive, directives from docutils.nodes import math_block import nbconvert from nbconvert.preprocessors.execute import executenb from nbconvert.preprocessors import ExtractOutputPreprocessor from nbconvert.writers import FilesWriter from jupyter_client.kernelspec import get_kernel_spec, NoSuchKernel import nbformat from ipywidgets import Widget import ipywidgets.embed from ._version import __version__ logger = logging.getLogger(__name__) WIDGET_VIEW_MIMETYPE = 'application/vnd.jupyter.widget-view+json' WIDGET_STATE_MIMETYPE = 'application/vnd.jupyter.widget-state+json' REQUIRE_URL_DEFAULT = 'https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js' THEBELAB_URL_DEFAULT = 'https://unpkg.com/thebelab@^0.4.0' def builder_inited(app): """ 2 cases case 1: ipywidgets 7, with require case 2: ipywidgets 7, no require """ require_url = app.config.jupyter_sphinx_require_url if require_url: app.add_js_file(require_url) embed_url = app.config.jupyter_sphinx_embed_url or ipywidgets.embed.DEFAULT_EMBED_REQUIREJS_URL else: embed_url = app.config.jupyter_sphinx_embed_url or ipywidgets.embed.DEFAULT_EMBED_SCRIPT_URL if embed_url: app.add_js_file(embed_url) # add jupyter-sphinx css app.add_css_file('jupyter-sphinx.css') # Check if a thebelab config was specified if app.config.jupyter_sphinx_thebelab_config: app.add_js_file('thebelab-helper.js') app.add_css_file('thebelab.css') ### Directives and their associated doctree nodes class JupyterKernel(Directive): """Specify a new Jupyter Kernel. Arguments --------- kernel_name : str (optional) The name of the kernel in which to execute future Jupyter cells, as reported by executing 'jupyter kernelspec list' on the command line. Options ------- id : str An identifier for *this kernel instance*. Used to name any output files generated when executing the Jupyter cells (e.g. images produced by cells, or a script containing the cell inputs). Content ------- None """ optional_arguments = 1 final_argument_whitespace = False has_content = False option_spec = { 'id': directives.unchanged, } def run(self): return [JupyterKernelNode( '', kernel_name=self.arguments[0].strip() if self.arguments else '', kernel_id=self.options.get('id', '').strip(), )] class JupyterKernelNode(docutils.nodes.Element): """Inserted into doctree whenever a JupyterKernel directive is encountered. Used as a marker to signal that the following JupyterCellNodes (until the next, if any, JupyterKernelNode) should be executed in a separate kernel. """ def csv_option(s): return [p.strip() for p in s.split(',')] if s else [] class JupyterCell(Directive): """Define a code cell to be later executed in a Jupyter kernel. The content of the directive is the code to execute. Code is not executed when the directive is parsed, but later during a doctree transformation. Arguments --------- filename : str (optional) If provided, a path to a file containing code. Options ------- hide-code : bool If provided, the code will not be displayed in the output. hide-output : bool If provided, the cell output will not be displayed in the output. code-below : bool If provided, the code will be shown below the cell output. linenos : bool If provided, the code will be shown with line numbering. raises : comma separated list of exception types If provided, a comma-separated list of exception type names that the cell may raise. If one of the listed execption types is raised then the traceback is printed in place of the cell output. If an exception of another type is raised then we raise a RuntimeError when executing. Content ------- code : str A code cell. """ required_arguments = 0 optional_arguments = 1 final_argument_whitespace = True has_content = True option_spec = { 'hide-code': directives.flag, 'hide-output': directives.flag, 'code-below': directives.flag, 'linenos': directives.flag, 'raises': csv_option, 'stderr': directives.flag, } def run(self): if self.arguments: # As per 'sphinx.directives.code.LiteralInclude' env = self.state.document.settings.env rel_filename, filename = env.relfn2path(self.arguments[0]) env.note_dependency(rel_filename) if self.content: logger.warning( 'Ignoring inline code in Jupyter cell included from "{}"' .format(rel_filename) ) try: with open(filename) as f: content = [line.rstrip() for line in f.readlines()] except (IOError, OSError): raise IOError( 'File {} not found or reading it failed'.format(filename) ) else: self.assert_has_content() content = self.content return [JupyterCellNode( '', docutils.nodes.literal_block( text='\n'.join(content), ), hide_code=('hide-code' in self.options), hide_output=('hide-output' in self.options), code_below=('code-below' in self.options), linenos=('linenos' in self.options), raises=self.options.get('raises'), stderr=('stderr' in self.options), )] class ThebeButton(Directive): """Specify a button to activate thebelab on the page Arguments --------- text : str (optional) If provided, the button text to display Content ------- None """ optional_arguments = 1 final_argument_whitespace = True has_content = False def run(self): kwargs = {'text': self.arguments[0]} if self.arguments else {} return [ThebeButtonNode(**kwargs)] class JupyterCellNode(docutils.nodes.container): """Inserted into doctree whever a JupyterCell directive is encountered. Contains code that will be executed in a Jupyter kernel at a later doctree-transformation step. """ class JupyterWidgetViewNode(docutils.nodes.Element): """Inserted into doctree whenever a Jupyter cell produces a widget as output. Contains a unique ID for this widget; enough information for the widget embedding javascript to render it, given the widget state. For non-HTML outputs this doctree node is rendered generically. """ def __init__(self, rawsource='', *children, **attributes): super().__init__('', view_spec=attributes['view_spec']) def html(self): return ipywidgets.embed.widget_view_template.format( view_spec=json.dumps(self['view_spec'])) class JupyterWidgetStateNode(docutils.nodes.Element): """Appended to doctree if any Jupyter cell produced a widget as output. Contains the state needed to render a collection of Jupyter widgets. Per doctree there is 1 JupyterWidgetStateNode per kernel that produced Jupyter widgets when running. This is fine as (presently) the 'html-manager' Javascript library, which embeds widgets, loads the state from all script tags on the page of the correct mimetype. """ def __init__(self, rawsource='', *children, **attributes): super().__init__('', state=attributes['state']) def html(self): # TODO: render into a separate file if 'html-manager' starts fully # parsing script tags, and not just grabbing their innerHTML # https://github.com/jupyter-widgets/ipywidgets/blob/master/packages/html-manager/src/libembed.ts#L36 return ipywidgets.embed.snippet_template.format( load='', widget_views='', json_data=json.dumps(self['state'])) class ThebeSourceNode(docutils.nodes.container): """Container that holds the cell source when thebelab is enabled""" def __init__(self, rawsource='', *children, **attributes): super().__init__('', **attributes) def visit_html(self): code_class = 'thebelab-code' if self['hide_code']: code_class += ' thebelab-hidden' if self['code_below']: code_class += ' thebelab-below' language = self['language'] return '
'\ .format(code_class, language) def depart_html(self): return '
' class ThebeOutputNode(docutils.nodes.container): """Container that holds all the output nodes when thebelab is enabled""" def visit_html(self): return '
' def depart_html(self): return '
' class ThebeButtonNode(docutils.nodes.Element): """Appended to the doctree by the ThebeButton directive Renders as a button to enable thebelab on the page. If no ThebeButton directive is found in the document but thebelab is enabled, the node is added at the bottom of the document. """ def __init__(self, rawsource='', *children, text='Make live', **attributes): super().__init__('', text=text) def html(self): text = self['text'] return (''.format(text=text)) ### Doctree transformations class ExecuteJupyterCells(SphinxTransform): """Execute code cells in Jupyter kernels. Traverses the doctree to find JupyterKernel and JupyterCell nodes, then executes the code in the JupyterCell nodes in sequence, starting a new kernel every time a JupyterKernel node is encountered. The output from each code cell is inserted into the doctree. """ default_priority = 180 # An early transform, idk def apply(self): doctree = self.document doc_relpath = os.path.dirname(self.env.docname) # relative to src dir docname = os.path.basename(self.env.docname) default_kernel = self.config.jupyter_execute_default_kernel default_names = default_notebook_names(docname) thebe_config = self.config.jupyter_sphinx_thebelab_config linenos_config = self.config.jupyter_sphinx_linenos continue_linenos = self.config.jupyter_sphinx_continue_linenos # Check if we have anything to execute. if not doctree.traverse(JupyterCellNode): return if thebe_config: # Add the button at the bottom if it is not present if not doctree.traverse(ThebeButtonNode): doctree.append(ThebeButtonNode()) add_thebelab_library(doctree, self.env) logger.info('executing {}'.format(docname)) output_dir = os.path.join(output_directory(self.env), doc_relpath) # Start new notebook whenever a JupyterKernelNode is encountered jupyter_nodes = (JupyterCellNode, JupyterKernelNode) nodes_by_notebook = split_on( lambda n: isinstance(n, JupyterKernelNode), doctree.traverse(lambda n: isinstance(n, jupyter_nodes)) ) for first, *nodes in nodes_by_notebook: if isinstance(first, JupyterKernelNode): kernel_name = first['kernel_name'] or default_kernel file_name = first['kernel_id'] or next(default_names) else: nodes = (first, *nodes) kernel_name = default_kernel file_name = next(default_names) notebook = execute_cells( kernel_name, [nbformat.v4.new_code_cell(node.astext()) for node in nodes], self.config.jupyter_execute_kwargs, ) # Raise error if cells raised exceptions and were not marked as doing so for node, cell in zip(nodes, notebook.cells): errors = [output for output in cell.outputs if output['output_type'] == 'error'] allowed_errors = node.attributes.get('raises') or [] raises_provided = node.attributes['raises'] is not None if raises_provided and not allowed_errors: # empty 'raises': supress all errors pass elif errors and not any(e['ename'] in allowed_errors for e in errors): raise ExtensionError('Cell raised uncaught exception:\n{}' .format('\n'.join(errors[0]['traceback']))) # Raise error if cells print to stderr for node, cell in zip(nodes, notebook.cells): stderr = [output for output in cell.outputs if output['output_type'] == 'stream' and output['name'] == 'stderr'] if stderr and not node.attributes['stderr']: logger.warning('Cell printed to stderr:\n{}' .format(stderr[0]['text'])) try: lexer = notebook.metadata.language_info.pygments_lexer except AttributeError: lexer = notebook.metadata.kernelspec.language # Highlight the code cells now that we know what language they are for node in nodes: source = node.children[0] source.attributes['language'] = lexer # Add line numbers to code cells if jupyter_sphinx_linenos or # jupyter_sphinx_continue_linenos are set in the configuration, # or the linenos directive is set. # Update current line numbers from cell if jupyter_sphinx_continue_linenos # is set. linenostart = 1 for node in nodes: source = node.children[0] if linenos_config or continue_linenos or node["linenos"]: source["linenos"] = True if continue_linenos: source["highlight_args"] = {'linenostart': linenostart} linenostart += source.rawsource.count("\n") + 1 # Add code cell CSS class for node in nodes: source = node.children[0] source.attributes["classes"] = ["code_cell"] # Write certain cell outputs (e.g. images) to separate files, and # modify the metadata of the associated cells in 'notebook' to # include the path to the output file. write_notebook_output(notebook, output_dir, file_name) try: cm_language = notebook.metadata.language_info.codemirror_mode.name except AttributeError: cm_language = notebook.metadata.kernelspec.language # Add doctree nodes for cell outputs. for node, cell in zip(nodes, notebook.cells): output_nodes = cell_output_to_nodes( cell, self.config.jupyter_execute_data_priority, bool(node.attributes["stderr"]), sphinx_abs_dir(self.env), thebe_config ) attach_outputs(output_nodes, node, thebe_config, cm_language) if contains_widgets(notebook): doctree.append(JupyterWidgetStateNode(state=get_widgets(notebook))) ### Roles def jupyter_download_role(name, rawtext, text, lineno, inliner): _, filetype = name.split(':') assert filetype in ('notebook', 'script') ext = '.ipynb' if filetype == 'notebook' else '.py' output_dir = sphinx_abs_dir(inliner.document.settings.env) download_file = text + ext node = download_reference( download_file, download_file, reftarget=os.path.join(output_dir, download_file) ) return [node], [] ### Utilities def blank_nb(kernel_name): try: spec = get_kernel_spec(kernel_name) except NoSuchKernel as e: raise ExtensionError('Unable to find kernel', orig_exc=e) return nbformat.v4.new_notebook(metadata={ 'kernelspec': { 'display_name': spec.display_name, 'language': spec.language, 'name': kernel_name, } }) def split_on(pred, it): """Split an iterator wherever a predicate is True.""" counter = 0 def count(x): nonlocal counter if pred(x): counter += 1 return counter # Return iterable of lists to ensure that we don't lose our # place in the iterator return (list(x) for _, x in groupby(it, count)) def strip_latex_delimiters(source): """Remove LaTeX math delimiters that would be rendered by the math block. These are: ``\(…\)``, ``\[…\]``, ``$…$``, and ``$$…$$``. This is necessary because sphinx does not have a dedicated role for generic LaTeX, while Jupyter only defines generic LaTeX output, see https://github.com/jupyter/jupyter-sphinx/issues/90 for discussion. """ source = source.strip() delimiter_pairs = ( pair.split() for pair in r'\( \),\[ \],$$ $$,$ $'.split(',') ) for start, end in delimiter_pairs: if source.startswith(start) and source.endswith(end): return source[len(start):-len(end)] return source def cell_output_to_nodes(cell, data_priority, write_stderr, dir, thebe_config): """Convert a jupyter cell with outputs and filenames to doctree nodes. Parameters ---------- cell : jupyter cell data_priority : list of mime types Which media types to prioritize. write_stderr : bool If True include stderr in cell output dir : string Sphinx "absolute path" to the output folder, so it is a relative path to the source folder prefixed with ``/``. thebe_config: dict Thebelab configuration object or None """ to_add = [] for index, output in enumerate(cell.get('outputs', [])): output_type = output['output_type'] if ( output_type == 'stream' ): if output["name"] == "stderr": if not write_stderr: continue else: # Output a container with an unhighlighted literal block for # `stderr` messages. # # Adds a "stderr" class that can be customized by the user for both # the container and the literal_block. # # Not setting "rawsource" disables Pygment hightlighting, which # would otherwise add a
. container = docutils.nodes.container(classes=["stderr"]) container.append(docutils.nodes.literal_block( text=output['text'], rawsource='', # disables Pygment highlighting language='none', classes=["stderr"] )) to_add.append(container) else: to_add.append(docutils.nodes.literal_block( text=output['text'], rawsource=output['text'], language='none', classes=["output", "stream"] )) elif ( output_type == 'error' ): traceback = '\n'.join(output['traceback']) text = nbconvert.filters.strip_ansi(traceback) to_add.append(docutils.nodes.literal_block( text=text, rawsource=text, language='ipythontb', classes =["output", "traceback"] )) elif ( output_type in ('display_data', 'execute_result') ): try: # First mime_type by priority that occurs in output. mime_type = next( x for x in data_priority if x in output['data'] ) except StopIteration: continue data = output['data'][mime_type] if mime_type.startswith('image'): # Sphinx treats absolute paths as being rooted at the source # directory, so make a relative path, which Sphinx treats # as being relative to the current working directory. filename = os.path.basename( output.metadata['filenames'][mime_type] ) uri = os.path.join(dir, filename) to_add.append(docutils.nodes.image(uri=uri)) elif mime_type == 'text/html': to_add.append(docutils.nodes.raw( text=data, format='html', classes=["output", "text_html"] )) elif mime_type == 'text/latex': to_add.append(math_block( text=strip_latex_delimiters(data), nowrap=False, number=None, classes=["output", "text_latex"] )) elif mime_type == 'text/plain': to_add.append(docutils.nodes.literal_block( text=data, rawsource=data, language='none', classes=["output", "text_plain"] )) elif mime_type == 'application/javascript': to_add.append(docutils.nodes.raw( text='' .format(mime_type=mime_type, data=data), format='html', )) elif mime_type == WIDGET_VIEW_MIMETYPE: to_add.append(JupyterWidgetViewNode(view_spec=data)) return to_add def attach_outputs(output_nodes, node, thebe_config, cm_language): if not node.attributes["hide_code"]: # only add css if code is displayed node.attributes["classes"] = ["jupyter_container"] if thebe_config: source = node.children[0] thebe_source = ThebeSourceNode(hide_code=node.attributes['hide_code'], code_below=node.attributes['code_below'], language=cm_language) thebe_source.children = [source] node.children = [thebe_source] if not node.attributes['hide_output']: thebe_output = ThebeOutputNode() thebe_output.children = output_nodes if node.attributes['code_below']: node.children = [thebe_output] + node.children else: node.children = node.children + [thebe_output] else: if node.attributes['hide_code']: node.children = [] if not node.attributes['hide_output']: if node.attributes['code_below']: node.children = output_nodes + node.children else: node.children = node.children + output_nodes def default_notebook_names(basename): """Return an interator yielding notebook names based off 'basename'""" yield basename for i in count(1): yield '_'.join((basename, str(i))) def execute_cells(kernel_name, cells, execute_kwargs): """Execute Jupyter cells in the specified kernel and return the notebook.""" notebook = blank_nb(kernel_name) notebook.cells = cells # Modifies 'notebook' in-place try: executenb(notebook, **execute_kwargs) except Exception as e: raise ExtensionError('Notebook execution failed', orig_exc=e) return notebook def get_widgets(notebook): try: return notebook.metadata.widgets[WIDGET_STATE_MIMETYPE] except AttributeError: # Don't catch KeyError, as it's a bug if 'widgets' does # not contain 'WIDGET_STATE_MIMETYPE' return None def contains_widgets(notebook): widgets = get_widgets(notebook) return widgets and widgets['state'] def language_info(executor): # Can only run this function inside 'setup_preprocessor' assert hasattr(executor, 'kc') info_msg = executor._wait_for_reply(executor.kc.kernel_info()) return info_msg['content']['language_info'] def write_notebook_output(notebook, output_dir, notebook_name): """Extract output from notebook cells and write to files in output_dir. This also modifies 'notebook' in-place, adding metadata to each cell that maps output mime-types to the filenames the output was saved under. """ resources = dict( unique_key=os.path.join(output_dir, notebook_name), outputs={} ) # Modifies 'resources' in-place ExtractOutputPreprocessor().preprocess(notebook, resources) # Write the cell outputs to files where we can (images and PDFs), # as well as the notebook file. FilesWriter(build_directory=output_dir).write( nbformat.writes(notebook), resources, os.path.join(output_dir, notebook_name + '.ipynb') ) # Write a script too. ext = notebook.metadata.language_info.file_extension contents = '\n\n'.join(cell.source for cell in notebook.cells) with open(os.path.join(output_dir, notebook_name + ext), 'w') as f: f.write(contents) def output_directory(env): # Put output images inside the sphinx build directory to avoid # polluting the current working directory. We don't use a # temporary directory, as sphinx may cache the doctree with # references to the images that we write # Note: we are using an implicit fact that sphinx output directories are # direct subfolders of the build directory. return os.path.abspath(os.path.join( env.app.outdir, os.path.pardir, 'jupyter_execute' )) def sphinx_abs_dir(env): # We write the output files into # output_directory / jupyter_execute / path relative to source directory # Sphinx expects download links relative to source file or relative to # source dir and prepended with '/'. We use the latter option. return '/' + os.path.relpath( os.path.abspath(os.path.join( output_directory(env), os.path.dirname(env.docname), )), os.path.abspath(env.app.srcdir) ) def add_thebelab_library(doctree, env): """Adds the thebelab configuration and library to the doctree""" thebe_config = env.config.jupyter_sphinx_thebelab_config if isinstance(thebe_config, dict): pass elif isinstance(thebe_config, str): if os.path.isabs(thebe_config): filename = thebe_config else: filename = os.path.join(os.path.abspath(env.app.srcdir), thebe_config) if not os.path.exists(filename): logger.warning('The supplied thebelab configuration file does not exist') return with open(filename, 'r') as config_file: try: thebe_config = json.load(config_file) except ValueError: logger.warning('The supplied thebelab configuration file is not in JSON format.') return else: logger.warning('The supplied thebelab configuration should be either a filename or a dictionary.') return # Force config values to make thebelab work correctly thebe_config['predefinedOutput'] = True thebe_config['requestKernel'] = True # Specify the thebelab config inline, a separate file is not supported doctree.append(docutils.nodes.raw( text='\n' .format(json.dumps(thebe_config)), format='html' )) # Add thebelab library after the config is specified doctree.append(docutils.nodes.raw( text='\n' .format(env.config.jupyter_sphinx_thebelab_url), format='html' )) def build_finished(app, env): if app.builder.format != 'html': return # Copy stylesheet src = os.path.join(os.path.dirname(__file__), 'css') dst = os.path.join(app.outdir, '_static') copy_asset(src, dst) thebe_config = app.config.jupyter_sphinx_thebelab_config if not thebe_config: return # Copy all thebelab related assets src = os.path.join(os.path.dirname(__file__), 'thebelab') dst = os.path.join(app.outdir, '_static') copy_asset(src, dst) def setup(app): # Configuration app.add_config_value( 'jupyter_execute_kwargs', dict(timeout=-1, allow_errors=True, store_widget_state=True), 'env' ) app.add_config_value( 'jupyter_execute_default_kernel', 'python3', 'env' ) app.add_config_value( 'jupyter_execute_data_priority', [ WIDGET_VIEW_MIMETYPE, 'application/javascript', 'text/html', 'image/svg+xml', 'image/png', 'image/jpeg', 'text/latex', 'text/plain' ], 'env', ) # ipywidgets config app.add_config_value('jupyter_sphinx_require_url', REQUIRE_URL_DEFAULT, 'html') app.add_config_value('jupyter_sphinx_embed_url', None, 'html') # thebelab config, can be either a filename or a dict app.add_config_value('jupyter_sphinx_thebelab_config', None, 'html') app.add_config_value('jupyter_sphinx_thebelab_url', THEBELAB_URL_DEFAULT, 'html') # linenos config app.add_config_value('jupyter_sphinx_linenos', False, 'env') app.add_config_value('jupyter_sphinx_continue_linenos', False, 'env') # Used for nodes that do not need to be rendered def skip(self, node): raise docutils.nodes.SkipNode # Renders the children of a container render_container = ( lambda self, node: self.visit_container(node), lambda self, node: self.depart_container(node), ) # Used to render the container and its children as HTML def visit_container_html(self, node): self.body.append(node.visit_html()) self.visit_container(node) def depart_container_html(self, node): self.depart_container(node) self.body.append(node.depart_html()) # Used to render an element node as HTML def visit_element_html(self, node): self.body.append(node.html()) raise docutils.nodes.SkipNode # Used to render the ThebeSourceNode conditionally for non-HTML builders def visit_thebe_source(self, node): if node['hide_code']: raise docutils.nodes.SkipNode else: self.visit_container(node) render_thebe_source = ( visit_thebe_source, lambda self, node: self.depart_container(node) ) # JupyterKernelNode is just a doctree marker for the # ExecuteJupyterCells transform, so we don't actually render it. app.add_node( JupyterKernelNode, html=(skip, None), latex=(skip, None), textinfo=(skip, None), text=(skip, None), man=(skip, None), ) # JupyterCellNode is a container that holds the input and # any output, so we render it as a container. app.add_node( JupyterCellNode, html=render_container, latex=render_container, textinfo=render_container, text=render_container, man=render_container, ) # JupyterWidgetViewNode holds widget view JSON, # but is only rendered properly in HTML documents. app.add_node( JupyterWidgetViewNode, html=(visit_element_html, None), latex=(skip, None), textinfo=(skip, None), text=(skip, None), man=(skip, None), ) # JupyterWidgetStateNode holds the widget state JSON, # but is only rendered in HTML documents. app.add_node( JupyterWidgetStateNode, html=(visit_element_html, None), latex=(skip, None), textinfo=(skip, None), text=(skip, None), man=(skip, None), ) # ThebeSourceNode holds the source code and is rendered if # hide-code is not specified. For HTML it is always rendered, # but hidden using the stylesheet app.add_node( ThebeSourceNode, html=(visit_container_html, depart_container_html), latex=render_thebe_source, textinfo=render_thebe_source, text=render_thebe_source, man=render_thebe_source, ) # ThebeOutputNode holds the output of the Jupyter cells # and is rendered if hide-output is not specified. app.add_node( ThebeOutputNode, html=(visit_container_html, depart_container_html), latex=render_container, textinfo=render_container, text=render_container, man=render_container, ) # ThebeButtonNode is the button that activates thebelab # and is only rendered for the HTML builder app.add_node( ThebeButtonNode, html=(visit_element_html, None), latex=(skip, None), textinfo=(skip, None), text=(skip, None), man=(skip, None), ) app.add_directive('jupyter-execute', JupyterCell) app.add_directive('jupyter-kernel', JupyterKernel) app.add_directive('thebe-button', ThebeButton) app.add_role('jupyter-download:notebook', jupyter_download_role) app.add_role('jupyter-download:script', jupyter_download_role) app.add_transform(ExecuteJupyterCells) # For syntax highlighting app.add_lexer('ipythontb', IPythonTracebackLexer()) app.add_lexer('ipython', IPython3Lexer()) app.connect('builder-inited', builder_inited) app.connect('build-finished', build_finished) return { 'version': __version__, 'parallel_read_safe': True, } jupyter_sphinx-0.2.3/jupyter_sphinx/thebelab/0000755000175000017500000000000013565524063021741 5ustar antonanton00000000000000jupyter_sphinx-0.2.3/jupyter_sphinx/thebelab/thebelab-helper.js0000644000175000017500000000154213544104024025310 0ustar antonanton00000000000000function initThebelab() { let activateButton = document.getElementById("thebelab-activate-button"); if (activateButton.classList.contains('thebelab-active')) { return; } // Place all outputs below the source where this was not the case // to make them recognizable by thebelab let codeBelows = document.getElementsByClassName('thebelab-below'); for(var i = 0; i < codeBelows.length; i++) { let prev = codeBelows[i] // Find previous sibling element, compatible with IE8 do prev = prev.previousSibling; while(prev && prev.nodeType !== 1); swapSibling(prev, codeBelows[i]) } thebelab.bootstrap(); activateButton.classList.add('thebelab-active') } function swapSibling(node1, node2) { node1.parentNode.replaceChild(node1, node2); node1.parentNode.insertBefore(node2, node1); } jupyter_sphinx-0.2.3/jupyter_sphinx/thebelab/thebelab.css0000644000175000017500000000135413544104022024206 0ustar antonanton00000000000000.thebelab-cell .thebelab-input pre { z-index: 0; } .thebelab-hidden { display: none; } .thebelab-button { position: relative; display: inline-block; box-sizing: border-box; border: none; border-radius: .1rem; padding: 0 2rem; margin: .5rem .1rem; min-width: 64px; height: 1.6rem; vertical-align: middle; text-align: center; font-size: 0.8rem; color: rgba(0, 0, 0, 0.8); background-color: rgba(0, 0, 0, 0.07); overflow: hidden; outline: none; cursor: pointer; transition: background-color 0.2s; } .thebelab-button:hover { background-color: rgba(0, 0, 0, 0.12); } .thebelab-button:active { background-color: rgba(0, 0, 0, 0.15); color: rgba(0, 0, 0, 1) }jupyter_sphinx-0.2.3/jupyter_sphinx.egg-info/0000755000175000017500000000000013565524063021665 5ustar antonanton00000000000000jupyter_sphinx-0.2.3/jupyter_sphinx.egg-info/PKG-INFO0000644000175000017500000000077213565524063022770 0ustar antonanton00000000000000Metadata-Version: 1.2 Name: jupyter-sphinx Version: 0.2.3 Summary: Jupyter Sphinx Extensions Home-page: https://github.com/jupyter/jupyter-sphinx/ Author: Jupyter Development Team Author-email: jupyter@googlegroups.com License: BSD Project-URL: Bug Tracker, https://github.com/jupyter/jupyter-sphinx/issues/ Project-URL: Documentation, https://jupyter-sphinx.readthedocs.io Project-URL: Source Code, https://github.com/jupyter/jupyter-sphinx/ Description: UNKNOWN Platform: UNKNOWN Requires-Python: >= 3.5 jupyter_sphinx-0.2.3/jupyter_sphinx.egg-info/SOURCES.txt0000644000175000017500000000066313565524063023556 0ustar antonanton00000000000000LICENSE MANIFEST.in README.md setup.cfg setup.py jupyter_sphinx/__init__.py jupyter_sphinx/_version.py jupyter_sphinx/execute.py jupyter_sphinx.egg-info/PKG-INFO jupyter_sphinx.egg-info/SOURCES.txt jupyter_sphinx.egg-info/dependency_links.txt jupyter_sphinx.egg-info/requires.txt jupyter_sphinx.egg-info/top_level.txt jupyter_sphinx/css/jupyter-sphinx.css jupyter_sphinx/thebelab/thebelab-helper.js jupyter_sphinx/thebelab/thebelab.cssjupyter_sphinx-0.2.3/jupyter_sphinx.egg-info/dependency_links.txt0000644000175000017500000000000113565524063025733 0ustar antonanton00000000000000 jupyter_sphinx-0.2.3/jupyter_sphinx.egg-info/requires.txt0000644000175000017500000000007613565524063024270 0ustar antonanton00000000000000Sphinx>=1.8 ipywidgets>=7.0.0 IPython nbconvert>=5.5 nbformat jupyter_sphinx-0.2.3/jupyter_sphinx.egg-info/top_level.txt0000644000175000017500000000001713565524063024415 0ustar antonanton00000000000000jupyter_sphinx jupyter_sphinx-0.2.3/setup.cfg0000644000175000017500000000011113565524063016712 0ustar antonanton00000000000000[metadata] license_file = LICENSE [egg_info] tag_build = tag_date = 0 jupyter_sphinx-0.2.3/setup.py0000644000175000017500000000177413557577054016634 0ustar antonanton00000000000000from setuptools import setup import os here = os.path.abspath(os.path.dirname(__file__)) name = 'jupyter_sphinx' version_ns = {} with open(os.path.join(here, name, '_version.py')) as f: exec(f.read(), {}, version_ns) setup( name = name, version = version_ns['__version__'], author = 'Jupyter Development Team', author_email = 'jupyter@googlegroups.com', description = 'Jupyter Sphinx Extensions', url = 'https://github.com/jupyter/jupyter-sphinx/', project_urls = { 'Bug Tracker': 'https://github.com/jupyter/jupyter-sphinx/issues/', 'Documentation': 'https://jupyter-sphinx.readthedocs.io', 'Source Code': 'https://github.com/jupyter/jupyter-sphinx/', }, license = 'BSD', packages = ['jupyter_sphinx'], install_requires = [ 'Sphinx>=1.8', 'ipywidgets>=7.0.0', 'IPython', 'nbconvert>=5.5', 'nbformat', ], python_requires = '>= 3.5', package_data={'jupyter_sphinx': ['thebelab/*', 'css/*']}, )