PK4O&H„•g^WW nbsphinx.py# Copyright (c) 2015-2016 Matthias Geier # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. """Jupyter Notebook Tools for Sphinx. http://nbsphinx.rtfd.org/ """ __version__ = '0.2.2' import docutils from docutils.parsers import rst import jinja2 import nbconvert import nbformat import os import sphinx _ipynbversion = 4 RST_TEMPLATE = """ {% extends 'rst.tpl' %} {% macro insert_empty_lines(text) %} {%- set before, after = resources.get_empty_lines(text) %} {%- if before %} :empty-lines-before: {{ before }} {%- endif %} {%- if after %} :empty-lines-after: {{ after }} {%- endif %} {%- endmacro %} {% block input -%} .. nbinput:: {% if nb.metadata.language_info -%} {{ nb.metadata.language_info.pygments_lexer }} {%- endif -%} {{ insert_empty_lines(cell.source) }} {%- if cell.execution_count %} :execution-count: {{ cell.execution_count }} {%- endif %} {%- if not cell.outputs %} :no-output: {%- endif %} {%- if cell.source.strip() %} {{ cell.source.strip('\n') | indent }} {%- endif %} {% endblock input %} {% block nboutput -%} {%- if output.output_type == 'stream' %} {%- set datatype = 'text/plain' %} {%- set outputdata = output.text[:-1] %}{# trailing \n is stripped #} {%- elif output.output_type == 'error' %} {%- set datatype = 'ansi' %} {%- set outputdata = '\n'.join(output.traceback) %} {%- else %} {%- set datatype = (output.data | filter_data_type)[0] %} {%- set outputdata = output.data[datatype] %} {%- endif %} .. nboutput:: {%- if datatype == 'text/plain' %}{# nothing #} {%- else %} rst {%- endif %} {%- if output.output_type == 'execute_result' and cell.execution_count %} :execution-count: {{ cell.execution_count }} {%- endif %} {%- if output != cell.outputs[-1] %} :more-to-come: {%- endif %} {%- if output.name == 'stderr' %} :class: output_stderr {%- endif %} {%- if datatype == 'text/plain' -%} {{ insert_empty_lines(outputdata) }} {{ outputdata.strip(\n) | indent }} {%- elif datatype in ['image/svg+xml', 'image/png', 'image/jpeg'] %} .. image:: {{ output.metadata.filenames[datatype] | urlencode }} {%- elif datatype in ['text/markdown'] %} {{ output.data['text/markdown'] | markdown2rst | indent }} {%- elif datatype in ['text/latex'] %} .. math:: {{ output.data['text/latex'] | strip_dollars | indent | indent }} {%- elif datatype == 'text/html' %} .. raw:: html {{ output.data['text/html'] | indent | indent }} {%- elif datatype == 'ansi' %} .. raw:: html
{{ outputdata | ansi2html | indent | indent }}
        
.. raw:: latex \\begin{OriginalVerbatim}[commandchars=\\\\\\{\\}] {{ outputdata | ansi2latex | indent | indent }} \\end{OriginalVerbatim} {%- else %} WARNING! Data type not implemented: {{ datatype }} {%- endif %} {% endblock nboutput %} {% block execute_result %}{{ self.nboutput() }}{% endblock execute_result %} {% block display_data %}{{ self.nboutput() }}{% endblock display_data %} {% block stream %}{{ self.nboutput() }}{% endblock stream %} {% block error %}{{ self.nboutput() }}{% endblock error %} {% block rawcell %} {%- set raw_mimetype = cell.metadata.get('raw_mimetype', '').lower() %} {%- if raw_mimetype == '' %} .. raw:: html {{ cell.source | indent }} .. raw:: latex {{ cell.source | indent }} {%- elif raw_mimetype == 'text/html' %} .. raw:: html {{ cell.source | indent }} {%- elif raw_mimetype == 'text/latex' %} .. raw:: latex {{ cell.source | indent }} {%- elif raw_mimetype == 'text/markdown' %} {{ cell.source | markdown2rst }} {%- elif raw_mimetype == 'text/restructuredtext' %} {{ cell.source }} {% endif %} {% endblock rawcell %} """ LATEX_PREAMBLE = r""" % Notebook prompt colors \definecolor{nbsphinxin}{rgb}{0.0, 0.0, 0.5} \definecolor{nbsphinxout}{rgb}{0.545, 0.0, 0.0} % ANSI colors for traceback highlighting \definecolor{red}{rgb}{.6,0,0} \definecolor{green}{rgb}{0,.65,0} \definecolor{brown}{rgb}{0.6,0.6,0} \definecolor{blue}{rgb}{0,.145,.698} \definecolor{purple}{rgb}{.698,.145,.698} \definecolor{cyan}{rgb}{0,.698,.698} \definecolor{lightgray}{gray}{0.5} \definecolor{darkgray}{gray}{0.25} \definecolor{lightred}{rgb}{1.0,0.39,0.28} \definecolor{lightgreen}{rgb}{0.48,0.99,0.0} \definecolor{lightblue}{rgb}{0.53,0.81,0.92} \definecolor{lightpurple}{rgb}{0.87,0.63,0.87} \definecolor{lightcyan}{rgb}{0.5,1.0,0.83} """ CSS_STRING = """ /* CSS for nbsphinx extension */ /* remove conflicting styling from Sphinx themes */ div.nbinput, div.nbinput div, div.nbinput div pre, div.nboutput, div.nboutput div, div.nboutput div pre { background: none; border: none; padding: 0 0; margin: 0; box-shadow: none; } /* remove negative margin from cloud theme */ div.nbinput div[class|="highlight"], div.nboutput div[class|="highlight"] { margin: 0; } /* input/output containers */ div.nbinput, div.nboutput { display: -webkit-flex; display: flex; align-items: flex-start; margin: 0; } /* input container */ div.nbinput { padding-top: 5px; } /* last container */ div.nblast { padding-bottom: 5px; } /* input prompt */ div.nbinput > :first-child pre { color: navy; } /* output prompt */ div.nboutput > :first-child pre { color: darkred; } /* all prompts */ div.nbinput > :first-child, div.nboutput > :first-child { min-width: 11ex; padding-top: 0.4em; padding-right: 0.4em; text-align: right; flex: 0; } /* input/output area */ div.nbinput > :nth-child(2), div.nboutput > :nth-child(2) { padding: 0.4em; -webkit-flex: 1; flex: 1; } /* input area */ div.nbinput > :nth-child(2) { border: 1px solid #cfcfcf; border-radius: 2px; background: #f7f7f7; } /* override MathJax center alignment in output cells */ div.nboutput div[class*=MathJax] { text-align: left !important; } /* override sphinx.ext.pngmath center alignment in output cells */ div.nboutput div.math p { text-align: left; } /* standard error */ div.nboutput > :nth-child(2).output_stderr { background: #fdd; } /* ANSI colors */ .ansired { color: darkred; } .ansigreen { color: darkgreen; } .ansicyan { color: steelblue; } .ansiblue { color: darkblue; } .ansiyellow { color: #c4a000; } .ansiblack { color: black; } .ansipurple { color: darkviolet; } .ansigray { color: gray; } /* nbconvert CSS */ .ansigrey { color: gray; } /* nbconvert HTML output */ .ansibold { font-weight: bold; } """ class NotebookParser(rst.Parser): """Sphinx source parser for Jupyter notebooks. Uses nbconvert to convert the notebook content to reStructuredText, which is then parsed by Sphinx's built-in reST parser. An extended Jinja2 template is provided that uses custom reST directives for input and output cells. Notebooks without output cells are automatically executed before conversion. """ def get_transforms(self): """List of transforms for documents parsed by this parser.""" return rst.Parser.get_transforms(self) + [RewriteNotebookLinks, CreateSectionLabels] def parse(self, inputstring, document): """Parse `inputstring`, write results to `document`.""" nb = nbformat.reads(inputstring, as_version=_ipynbversion) nbsphinx_metadata = nb.metadata.get('nbsphinx', {}) resources = {} env = document.settings.env srcdir = os.path.dirname(env.doc2path(env.docname)) auxdir = os.path.join(env.doctreedir, 'nbsphinx') sphinx.util.ensuredir(auxdir) # Execute notebook only if there are no outputs: if not any(c.outputs for c in nb.cells if 'outputs' in c): resources.setdefault('metadata', {})['path'] = srcdir allow_errors = nbsphinx_metadata.get('allow_errors', False) pp = nbconvert.preprocessors.ExecutePreprocessor( allow_errors=allow_errors) nb, resources = pp.preprocess(nb, resources) # Remove hidden cells nb.cells[:] = (cell for cell in nb.cells if cell.metadata.get('nbsphinx') != 'hidden') # Sphinx doesn't accept absolute paths in images etc. resources['output_files_dir'] = os.path.relpath(auxdir, srcdir) resources['unique_key'] = env.docname.replace(os.sep, '_') def get_empty_lines(s): """Get number of empty lines before and after code.""" before = 0 lines = s.split('\n') for line in lines: if line.strip(): break before += 1 after = 0 for line in reversed(lines[before:]): if line.strip(): break after += 1 return before, after resources['get_empty_lines'] = get_empty_lines loader = jinja2.DictLoader({'nbsphinx-rst.tpl': RST_TEMPLATE}) exporter = nbconvert.RSTExporter(template_file='nbsphinx-rst', extra_loaders=[loader]) rststring, resources = exporter.from_notebook_node(nb, resources) if nbsphinx_metadata.get('orphan', False): rststring = ':orphan:\n\n' + rststring # Create additional output files (figures etc.), # see nbconvert.writers.FilesWriter.write() for filename, data in resources.get('outputs', {}).items(): dest = os.path.normpath(os.path.join(srcdir, filename)) with open(dest, 'wb') as f: f.write(data) rst.Parser.parse(self, rststring, document) class CodeNode(docutils.nodes.Element): """A custom node that contains a literal_block node.""" @classmethod def create(cls, text, language='none', classes=[]): """Create a new CodeNode containing a literal_block node. Apparently, this cannot be done in CodeNode.__init__(), see: https://groups.google.com/forum/#!topic/sphinx-dev/0chv7BsYuW0 """ node = docutils.nodes.literal_block(text, text, language=language, classes=classes) return cls(text, node) # See http://docutils.sourceforge.net/docs/howto/rst-directives.html class NbInput(rst.Directive): """A notebook input cell with prompt and code area.""" required_arguments = 0 optional_arguments = 1 # lexer name final_argument_whitespace = False option_spec = { 'execution-count': rst.directives.positive_int, 'empty-lines-before': rst.directives.nonnegative_int, 'empty-lines-after': rst.directives.nonnegative_int, 'no-output': rst.directives.flag, } has_content = True def run(self): """This is called by the reST parser.""" execution_count = self.options.get('execution-count') classes = ['nbinput'] if 'no-output' in self.options: classes.append('nblast') container = docutils.nodes.container(classes=classes) # Input prompt text = 'In [{}]:'.format(execution_count if execution_count else ' ') container += CodeNode.create(text) latex_prompt = text + ' ' # Input code area text = '\n'.join(self.content.data) node = CodeNode.create( text, language=self.arguments[0] if self.arguments else 'none') _set_emtpy_lines(node, self.options) node.attributes['latex_prompt'] = latex_prompt container += node return [container] class NbOutput(rst.Directive): """A notebook output cell with optional prompt.""" required_arguments = 0 optional_arguments = 1 # 'rst' or nothing (which means literal text) final_argument_whitespace = False option_spec = { 'execution-count': rst.directives.positive_int, 'more-to-come': rst.directives.flag, 'empty-lines-before': rst.directives.nonnegative_int, 'empty-lines-after': rst.directives.nonnegative_int, 'class': rst.directives.unchanged, } has_content = True def run(self): """This is called by the reST parser.""" outputtype = self.arguments[0] if self.arguments else '' execution_count = self.options.get('execution-count') classes = ['nboutput'] if 'more-to-come' not in self.options: classes.append('nblast') container = docutils.nodes.container(classes=classes) # Optional output prompt if execution_count: text = 'Out[{}]:'.format(execution_count) container += CodeNode.create(text) latex_prompt = text + ' ' else: container += rst.nodes.container() # empty container for HTML latex_prompt = '' # Output area if outputtype == 'rst': output_area = docutils.nodes.container() self.state.nested_parse(self.content, self.content_offset, output_area) container += output_area else: text = '\n'.join(self.content.data) classes = [] if 'class' in self.options: classes.append(self.options['class']) node = CodeNode.create(text, classes=classes) _set_emtpy_lines(node, self.options) node.attributes['latex_prompt'] = latex_prompt container += node return [container] def _set_emtpy_lines(node, options): """Set "empty lines" attributes on a CodeNode. See http://stackoverflow.com/q/34050044/500098. """ for attr in 'empty-lines-before', 'empty-lines-after': value = options.get(attr, 0) if value: node.attributes[attr] = value class RewriteNotebookLinks(docutils.transforms.Transform): """Turn links to local notebooks into ``:doc:``/``:ref:`` links. Links to subsections are possible with ``...#Subsection-Title``. These links use the labels created by CreateSectionLabels. Links to subsections use ``:ref:``, links to whole notebooks use ``:doc:``. Latter can be useful if you have an ``index.rst`` but also want a distinct ``index.ipynb`` for use with Jupyter. In this case you can use such a link in a notebook:: [Back to main page](index.ipynb) In Jupyter, this will create a "normal" link to ``index.ipynb``, but in the files generated by Sphinx, this will become a link to the main page created from ``index.rst``. """ default_priority = 400 # Should probably be adjusted? def apply(self): env = self.document.settings.env for node in self.document.traverse(docutils.nodes.reference): uri = node.get('refuri', '') if '://' not in uri: if uri.lower().endswith('.ipynb'): target = uri[:-len('.ipynb')] target_ext = '' reftype = 'doc' refdomain = None elif '.ipynb#' in uri.lower(): idx = uri.lower().find('.ipynb#') target = uri[:idx] target_ext = uri[idx:] reftype = 'ref' refdomain = 'std' else: continue # Not a local notebook target_docname = os.path.normpath( os.path.join(os.path.dirname(env.docname), target)) if target_docname in env.found_docs: if target_ext: target = target_docname + target_ext target = target.lower() linktext = node.astext() xref = sphinx.addnodes.pending_xref( reftype=reftype, reftarget=target, refdomain=refdomain, refwarn=True, refexplicit=True, refdoc=env.docname) xref += docutils.nodes.Text(linktext, linktext) node.replace_self(xref) class CreateSectionLabels(docutils.transforms.Transform): """Make labels for each notebook and each section thereof. These labels are referenced in RewriteNotebookLinks. Note: Sphinx lower-cases the HTML section IDs, Jupyter doesn't. """ default_priority = 250 # Before references.PropagateTargets (260) def apply(self): env = self.document.settings.env i_still_have_to_create_the_notebook_label = True for section in self.document.traverse(docutils.nodes.section): assert section.children assert isinstance(section.children[0], docutils.nodes.title) title = section.children[0].astext() link_id = title.replace(' ', '-') section['ids'] = [link_id] label = env.docname + '.ipynb#' + link_id label = label.lower() env.domaindata['std']['labels'][label] = ( env.docname, link_id, title) env.domaindata['std']['anonlabels'][label] = ( env.docname, link_id) # Create a label for the whole notebook using the first section: if i_still_have_to_create_the_notebook_label: label = env.docname.lower() + '.ipynb' env.domaindata['std']['labels'][label] = ( env.docname, '', title) env.domaindata['std']['anonlabels'][label] = ( env.docname, '') i_still_have_to_create_the_notebook_label = False def builder_inited(app): """Add color definitions to LaTeX preamble.""" latex_elements = app.builder.config.latex_elements latex_elements['preamble'] = '\n'.join([ LATEX_PREAMBLE, latex_elements.get('preamble', ''), ]) def html_page_context(app, pagename, templatename, context, doctree): """Add CSS string to HTML page.""" body = context.get('body', '') if body: style = '\n\n' context['body'] = style + body def depart_code_html(self, node): """Add empty lines before and after the code.""" text = self.body[-1] text = text.replace('
\n
', '
')
    text = text.replace('
',
                        '
\n' + '\n' * node.get('empty-lines-before', 0))
    text = text.replace('
', '\n' * node.get('empty-lines-after', 0) + '
') self.body[-1] = text def visit_code_latex(self, node): """Avoid creating a separate prompt node. The prompt will be pre-pended in the main code node. """ if 'latex_prompt' not in node.attributes: raise docutils.nodes.SkipNode() def depart_code_latex(self, node): """Some changes to code blocks. * Remove the frame (by changing Verbatim -> OriginalVerbatim) * Add empty lines before and after the code * Add prompt to the first line, emtpy space to the following lines """ lines = self.body[-1].split('\n') out = [] assert lines[0] == '' out.append(lines[0]) assert lines[1].startswith(r'\begin{Verbatim}') out.append(lines[1].replace('Verbatim', 'OriginalVerbatim')) code_lines = ( [''] * node.get('empty-lines-before', 0) + lines[2:-2] + [''] * node.get('empty-lines-after', 0) ) prompt = node.get('latex_prompt') color = 'nbsphinxin' if prompt.startswith('In') else 'nbsphinxout' prefix = r'\textcolor{' + color + '}{' + prompt + '}' if prompt else '' for line in code_lines[:1]: out.append(prefix + line) prefix = ' ' * len(prompt) for line in code_lines[1:]: out.append(prefix + line) assert lines[-2].startswith(r'\end{Verbatim}') out.append(lines[-2].replace('Verbatim', 'OriginalVerbatim')) assert lines[-1] == '' out.append(lines[-1]) self.body[-1] = '\n'.join(out) def do_nothing(self, node): pass def _add_notebook_parser(app): """Ugly hack to modify source_suffix and source_parsers. Once https://github.com/sphinx-doc/sphinx/pull/2209 is merged (and some additional time has passed), this should be replaced by :: app.add_source_parser('.ipynb', NotebookParser) See also https://github.com/sphinx-doc/sphinx/issues/2162. """ source_suffix = app.config._raw_config.get('source_suffix', ['.rst']) if isinstance(source_suffix, sphinx.config.string_types): source_suffix = [source_suffix] if '.ipynb' not in source_suffix: source_suffix.append('.ipynb') app.config._raw_config['source_suffix'] = source_suffix source_parsers = app.config._raw_config.get('source_parsers', {}) if '.ipynb' not in source_parsers and 'ipynb' not in source_parsers: source_parsers['.ipynb'] = NotebookParser app.config._raw_config['source_parsers'] = source_parsers def setup(app): """Initialize Sphinx extension.""" _add_notebook_parser(app) app.add_directive('nbinput', NbInput) app.add_directive('nboutput', NbOutput) app.add_node(CodeNode, html=(do_nothing, depart_code_html), latex=(visit_code_latex, depart_code_latex)) app.connect('builder-inited', builder_inited) app.connect('html-page-context', html_page_context) return {'version': __version__, 'parallel_read_safe': True} PK[O&H&ÏWrr(nbsphinx-0.2.2.dist-info/DESCRIPTION.rstJupyter Notebook Tools for Sphinx ================================= ``nbsphinx`` is a Sphinx_ extension that provides a source parser for ``*.ipynb`` files. Custom Sphinx directives are used to show `Jupyter Notebook`_ code cells (and of course their results) in both HTML and LaTeX output. Un-evaluated notebooks -- i.e. notebooks without stored output cells -- will be automatically executed during the Sphinx build process. .. _Sphinx: http://sphinx-doc.org/ .. _Jupyter Notebook: http://jupyter.org/ Documentation (and example of use): http://nbsphinx.rtfd.org/ Code: http://github.com/spatialaudio/nbsphinx/ Python Package Index: https://pypi.python.org/pypi/nbsphinx/ License: MIT -- see the file ``LICENSE`` for details. Quick Start: #. Install ``nbsphinx`` with pip_:: pip install nbsphinx --user #. Edit your ``conf.py`` and add ``'nbsphinx'`` to ``extensions``. #. Edit your ``index.rst`` and add the names of your ``*.ipynb`` files (without the ``.ipynb`` extension) to the ``toctree`` directive. #. Run Sphinx! .. _pip: https://pip.pypa.io/en/latest/installing/ PK[O&Hõ§ê¸žž&nbsphinx-0.2.2.dist-info/metadata.json{"classifiers": ["Development Status :: 2 - Pre-Alpha", "Framework :: Sphinx", "Intended Audience :: Education", "Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Topic :: Documentation :: Sphinx"], "extensions": {"python.details": {"contacts": [{"email": "Matthias.Geier@gmail.com", "name": "Matthias Geier", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "http://nbsphinx.rtfd.org/"}}}, "extras": [], "generator": "bdist_wheel (0.26.0)", "keywords": ["Sphinx", "Jupyter", "notebook"], "license": "MIT", "metadata_version": "2.0", "name": "nbsphinx", "platform": "any", "run_requires": [{"requires": ["docutils", "jinja2", "nbconvert", "nbformat", "sphinx"]}], "summary": "Jupyter Notebook Tools for Sphinx", "version": "0.2.2"}PK[O&HæVÒœ &nbsphinx-0.2.2.dist-info/top_level.txtnbsphinx PK[O&Hìndªnnnbsphinx-0.2.2.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.26.0) Root-Is-Purelib: true Tag: py2-none-any Tag: py3-none-any PK[O&H<ã~~!nbsphinx-0.2.2.dist-info/METADATAMetadata-Version: 2.0 Name: nbsphinx Version: 0.2.2 Summary: Jupyter Notebook Tools for Sphinx Home-page: http://nbsphinx.rtfd.org/ Author: Matthias Geier Author-email: Matthias.Geier@gmail.com License: MIT Keywords: Sphinx,Jupyter,notebook Platform: any Classifier: Development Status :: 2 - Pre-Alpha Classifier: Framework :: Sphinx Classifier: Intended Audience :: Education Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Documentation :: Sphinx Requires-Dist: docutils Requires-Dist: jinja2 Requires-Dist: nbconvert Requires-Dist: nbformat Requires-Dist: sphinx Jupyter Notebook Tools for Sphinx ================================= ``nbsphinx`` is a Sphinx_ extension that provides a source parser for ``*.ipynb`` files. Custom Sphinx directives are used to show `Jupyter Notebook`_ code cells (and of course their results) in both HTML and LaTeX output. Un-evaluated notebooks -- i.e. notebooks without stored output cells -- will be automatically executed during the Sphinx build process. .. _Sphinx: http://sphinx-doc.org/ .. _Jupyter Notebook: http://jupyter.org/ Documentation (and example of use): http://nbsphinx.rtfd.org/ Code: http://github.com/spatialaudio/nbsphinx/ Python Package Index: https://pypi.python.org/pypi/nbsphinx/ License: MIT -- see the file ``LICENSE`` for details. Quick Start: #. Install ``nbsphinx`` with pip_:: pip install nbsphinx --user #. Edit your ``conf.py`` and add ``'nbsphinx'`` to ``extensions``. #. Edit your ``index.rst`` and add the names of your ``*.ipynb`` files (without the ``.ipynb`` extension) to the ``toctree`` directive. #. Run Sphinx! .. _pip: https://pip.pypa.io/en/latest/installing/ PK[O&Hz*GÎ99nbsphinx-0.2.2.dist-info/RECORDnbsphinx.py,sha256=_HPIcJVAKwMJYTJwQyFyxp1F9O4cVe4dgDaGFzFy-F4,22275 nbsphinx-0.2.2.dist-info/DESCRIPTION.rst,sha256=WY_escZzI5Ns3dMMzozQ7MsysvjUxFsw0lWJ47vXVtE,1138 nbsphinx-0.2.2.dist-info/METADATA,sha256=5f5RnSDQ6v-BhMgz6qzt7P3cQ4JGpAPu52Ivn1HiOI8,1918 nbsphinx-0.2.2.dist-info/RECORD,, nbsphinx-0.2.2.dist-info/WHEEL,sha256=GrqQvamwgBV4nLoJe0vhYRSWzWsx7xjlt74FT0SWYfE,110 nbsphinx-0.2.2.dist-info/metadata.json,sha256=L-4AJ_NVWpqm3UqJMgMr6leeyXGugOSQkYaVDDy8SYg,926 nbsphinx-0.2.2.dist-info/top_level.txt,sha256=8pI5VGWd8bJqLYLT9B5JAwaaAeWYKEeya-iW-mw8iC4,9 PK4O&H„•g^WW nbsphinx.pyPK[O&H&ÏWrr(,Wnbsphinx-0.2.2.dist-info/DESCRIPTION.rstPK[O&Hõ§ê¸žž&ä[nbsphinx-0.2.2.dist-info/metadata.jsonPK[O&HæVÒœ &Æ_nbsphinx-0.2.2.dist-info/top_level.txtPK[O&Hìndªnn`nbsphinx-0.2.2.dist-info/WHEELPK[O&H<ã~~!½`nbsphinx-0.2.2.dist-info/METADATAPK[O&Hz*GÎ99zhnbsphinx-0.2.2.dist-info/RECORDPKðj