From ae299209691e50f3ce594789cc10ae2829a3f8ac Mon Sep 17 00:00:00 2001 From: Matthias Geier Date: Mon, 5 Nov 2018 12:57:11 +0100 Subject: [PATCH] Change nbsphinx_contents_manager to nbsphinx_custom_formats --- doc/conf.py | 8 ++--- doc/contents-manager.ipynb | 70 ------------------------------------- doc/custom-formats.ipynb | 71 ++++++++++++++++++++++++++++++++++++++ doc/index.rst | 2 +- src/nbsphinx.py | 43 +++++++++++++---------- 5 files changed, 100 insertions(+), 94 deletions(-) delete mode 100644 doc/contents-manager.ipynb create mode 100644 doc/custom-formats.ipynb diff --git a/doc/conf.py b/doc/conf.py index 574178e2..74e7e531 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -86,10 +86,10 @@ # Output prompt for code cells. "%s" is replaced by the execution count. #nbsphinx_output_prompt = 'Out[%s]:' -#nbsphinx_contents_manager = 'jupytext.TextFileContentsManager' -#source_suffix = { -# '.Rmd': 'jupyter_notebook', -# '.rst': 'restructuredtext', +# Specify conversion functions for custom notebook formats: +#import jupytext +#nbsphinx_custom_formats = { +# '.Rmd': lambda s: jupytext.reads(s, '.Rmd'), #} # -- The settings below this line are not specific to nbsphinx ------------ diff --git a/doc/contents-manager.ipynb b/doc/contents-manager.ipynb deleted file mode 100644 index ec89caa0..00000000 --- a/doc/contents-manager.ipynb +++ /dev/null @@ -1,70 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Custom Notebook Formats\n", - "\n", - "The Jupyter Notebook application allows extensions to use a custom notebook format\n", - "other than the native Jupyter format used in `*.ipynb` files.\n", - "Such extensions can customize the so-called \"contents manager\"\n", - "which is responsible for reading and writing the files used by Jupyter.\n", - "\n", - "One example for such an extension is [jupytext](https://github.com/mwouts/jupytext),\n", - "which allows the use of Markdown, R-Markdown as well as plain Julia, Python and R files.\n", - "\n", - "If it provides the necessary metadata, such a \"contents manager\" can also be used by `nbsphinx`.\n", - "To use a custom \"contents manager\", you have to select it in your `conf.py` file\n", - "(and of course you have to install the extension, too):\n", - "\n", - "```python\n", - "nbsphinx_contents_manager = 'jupytext.TextFileContentsManager'\n", - "```\n", - "\n", - "In addition, you have to register the file extension(s) you want to use\n", - "(for example `.Rmd`) as having the type `jupyter_notebook`:\n", - "\n", - "```python\n", - "source_suffix = {\n", - " '.Rmd': 'jupyter_notebook',\n", - " '.rst': 'restructuredtext',\n", - "}\n", - "```\n", - "\n", - "With such a setup you should be able to use notebooks with custom formats\n", - "just like `*.ipynb` files.\n", - "\n", - "
\n", - "\n", - "**Note:**\n", - "\n", - "Using `nbsphinx_contents_manager` makes it impossible to use\n", - "the Sphinx translation machinery at the same time.\n", - "\n", - "
" - ] - } - ], - "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.6.7" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/doc/custom-formats.ipynb b/doc/custom-formats.ipynb new file mode 100644 index 00000000..a334164b --- /dev/null +++ b/doc/custom-formats.ipynb @@ -0,0 +1,71 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Custom Notebook Formats\n", + "\n", + "By default, Jupyter notebooks are stored in files with the suffix `.ipynb`,\n", + "which use the JSON format for storage.\n", + "\n", + "However, there are libraries available which allow storing notebooks in different formats,\n", + "using different file suffixes.\n", + "\n", + "To use a custom format in `nbsphinx`, you can specify the\n", + "`nbsphinx_custom_formats` option in your `conf.py` file.\n", + "You have to provide the file extension\n", + "and a conversion function that takes the contents of a file (as a string)\n", + "and returns a Jupyter notebook object.\n", + "\n", + "```python\n", + "nbsphinx_custom_formats = {\n", + " '.mysuffix': 'mylibrary.converter_function',\n", + "}\n", + "```\n", + "\n", + "The converter function can be given as a string or as a function object.\n", + "\n", + "One example for such library is [jupytext](https://github.com/mwouts/jupytext),\n", + "which allows storing the contents of Jupyter notebooks in \n", + "Markdown and R-Markdown, as well as plain Julia, Python and R files.\n", + "\n", + "Since its conversion function takes more than a single string argument,\n", + "just using the function name `'jupytext.reads'` will not work.\n", + "We have to create a function object,\n", + "and one way to do that is using a `lambda` function like this:\n", + "\n", + "```python\n", + "import jupytext\n", + "\n", + "nbsphinx_custom_formats = {\n", + " '.Rmd': lambda s: jupytext.reads(s, '.Rmd'),\n", + "}\n", + "```\n", + "\n", + "You can of course use multiple formats by specifying multiple conversion functions." + ] + } + ], + "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.6.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/doc/index.rst b/doc/index.rst index 043346b1..6f02b104 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -15,7 +15,7 @@ was generated from Jupyter notebooks. hidden-cells.ipynb executing-notebooks.ipynb prolog-and-epilog.ipynb - contents-manager.ipynb + custom-formats.ipynb subdir/* a-normal-rst-file.rst links.ipynb diff --git a/src/nbsphinx.py b/src/nbsphinx.py index 4ceef725..90c7cbb3 100644 --- a/src/nbsphinx.py +++ b/src/nbsphinx.py @@ -783,27 +783,29 @@ def parse(self, inputstring, document): that, the translated strings will most likely be parsed as CommonMark. - If the configuration value "nbsphinx_contents_manager" is - specified, the translation mechansim will not work! + If the configuration value "nbsphinx_custom_formats" is + specified, the input string is converted to the Jupyter notebook + format with the given conversion function. """ env = document.settings.env - cm = env.config.nbsphinx_contents_manager - if cm is None: - try: - nb = nbformat.reads(inputstring, as_version=_ipynbversion) - except Exception: - # NB: The use of the RST parser is temporary! - rst.Parser.parse(self, inputstring, document) - return - else: - relative_doc = env.doc2path( - env.docname, base=os.path.relpath(env.srcdir, os.getcwd())) - if isinstance(cm, str): - cm = sphinx.util.import_object(cm)() - model = cm.get(relative_doc) - assert model['type'] == 'notebook' - nb = model['content'] + formats = env.config.nbsphinx_custom_formats + formats.setdefault( + '.ipynb', lambda s: nbformat.reads(s, as_version=_ipynbversion)) + suffix = os.path.splitext(env.doc2path(env.docname))[1] + try: + converter = formats[suffix] + except KeyError: + raise NotebookError('No converter for suffix {!r}'.format(suffix)) + if isinstance(converter, str): + converter = sphinx.util.import_object(converter) + try: + nb = converter(inputstring) + except Exception: + # NB: The use of the RST parser is temporary! + rst.Parser.parse(self, inputstring, document) + return + srcdir = os.path.dirname(env.doc2path(env.docname)) auxdir = os.path.join(env.doctreedir, 'nbsphinx') sphinx.util.ensuredir(auxdir) @@ -1479,6 +1481,9 @@ def builder_inited(app): 'traditional': '4ex', }.get(app.config.html_theme, '7ex') + for suffix in app.config.nbsphinx_custom_formats: + app.add_source_suffix(suffix, 'jupyter_notebook') + def html_page_context(app, pagename, templatename, context, doctree): """Add CSS string to HTML pages that contain code cells.""" @@ -1683,7 +1688,7 @@ def setup(app): app.add_config_value('nbsphinx_epilog', None, rebuild='env') app.add_config_value('nbsphinx_input_prompt', '[%s]:', rebuild='env') app.add_config_value('nbsphinx_output_prompt', '[%s]:', rebuild='env') - app.add_config_value('nbsphinx_contents_manager', None, rebuild='env') + app.add_config_value('nbsphinx_custom_formats', {}, rebuild='env') app.add_directive('nbinput', NbInput) app.add_directive('nboutput', NbOutput)