diff --git a/docs/_static/patch.css b/docs/_static/patch.css new file mode 100644 index 00000000..72949d9b --- /dev/null +++ b/docs/_static/patch.css @@ -0,0 +1,7 @@ +/* CSS that should eventually go in sphinx-book-theme */ + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} diff --git a/docs/api/index.rst b/docs/api/index.rst new file mode 100644 index 00000000..a4a1fcd8 --- /dev/null +++ b/docs/api/index.rst @@ -0,0 +1,18 @@ +.. _api/main: + +Python API +========== + +.. toctree:: + :maxdepth: 2 + + nodes + render_outputs + +Miscellaneous +------------- + +.. autoclass:: myst_nb.ansi_lexer.AnsiColorLexer + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/nodes.rst b/docs/api/nodes.rst new file mode 100644 index 00000000..cedde74f --- /dev/null +++ b/docs/api/nodes.rst @@ -0,0 +1,26 @@ +.. _api/nodes: + +AST Nodes +--------- + +.. automodule:: myst_nb.nodes + +.. autoclass:: myst_nb.nodes.CellNode + :members: + :undoc-members: + :show-inheritance: + +.. autoclass:: myst_nb.nodes.CellInputNode + :members: + :undoc-members: + :show-inheritance: + +.. autoclass:: myst_nb.nodes.CellOutputNode + :members: + :undoc-members: + :show-inheritance: + +.. autoclass:: myst_nb.nodes.CellOutputBundleNode + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/render_outputs.rst b/docs/api/render_outputs.rst new file mode 100644 index 00000000..f44a2f69 --- /dev/null +++ b/docs/api/render_outputs.rst @@ -0,0 +1,30 @@ +.. _api/output_renderer: + +Output Renderer +--------------- + +.. automodule:: myst_nb.render_outputs + +.. autoclass:: myst_nb.render_outputs.CellOutputsToNodes + :members: + :undoc-members: + :show-inheritance: + +.. autoexception:: myst_nb.render_outputs.MystNbEntryPointError + :members: + :undoc-members: + :show-inheritance: + +.. autofunction:: myst_nb.render_outputs.load_renderer + + +.. autoclass:: myst_nb.render_outputs.CellOutputRendererBase + :members: + :undoc-members: + :show-inheritance: + :special-members: __init__ + +.. autoclass:: myst_nb.render_outputs.CellOutputRenderer + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/conf.py b/docs/conf.py index 69e03c96..4b67576c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -34,6 +34,8 @@ "sphinx_togglebutton", "sphinx_copybutton", "sphinx.ext.intersphinx", + "sphinx.ext.autodoc", + # "sphinx.ext.viewcode" ] # Add any paths that contain templates here, relative to this directory. @@ -63,19 +65,31 @@ } intersphinx_mapping = { + "python": ("https://docs.python.org/3.8", None), "jb": ("https://jupyterbook.org/", None), "myst": ("https://myst-parser.readthedocs.io/en/latest/", None), "markdown_it": ("https://markdown-it-py.readthedocs.io/en/latest", None), "nbclient": ("https://nbclient.readthedocs.io/en/latest", None), "nbformat": ("https://nbformat.readthedocs.io/en/latest", None), + "sphinx": ("https://www.sphinx-doc.org/en/3.x", None), } intersphinx_cache_limit = 5 +nitpick_ignore = [ + ("py:class", "docutils.nodes.document"), + ("py:class", "docutils.nodes.Node"), + ("py:class", "docutils.nodes.container"), + ("py:class", "docutils.nodes.system_message"), + ("py:class", "nbformat.notebooknode.NotebookNode"), + ("py:class", "pygments.lexer.RegexLexer"), +] + # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] +html_css_files = ["patch.css"] copybutton_selector = "div:not(.output) > div.highlight pre" diff --git a/docs/index.md b/docs/index.md index 817d8de8..bb57d593 100644 --- a/docs/index.md +++ b/docs/index.md @@ -81,7 +81,9 @@ Finally, here is documentation on contributing to the development of MySt-NB ```{toctree} :titlesonly: +:maxdepth: 1 develop/contributing +api/index GitHub Repo ``` diff --git a/docs/use/formatting_outputs.md b/docs/use/formatting_outputs.md new file mode 100644 index 00000000..7e643800 --- /dev/null +++ b/docs/use/formatting_outputs.md @@ -0,0 +1,218 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: '0.8' + jupytext_version: '1.4.1' +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +(use/format)= +# Formatting code outputs + +(use/format/priority)= +## Render priority + +When Jupyter executes a code cell it can produce multiple outputs, and each of these outputs can contain multiple [MIME media types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types), for use by different output formats (like HTML or LaTeX). + +MyST-NB stores a default priority dictionary for most of the common [Sphinx builders](https://www.sphinx-doc.org/en/master/usage/builders/index.html), which you can be also update in your `conf.py`. +For example, this is the default priority list for HTML: + +```python +nb_render_priority = { + "html": ( + "application/vnd.jupyter.widget-view+json", + "application/javascript", + "text/html", + "image/svg+xml", + "image/png", + "image/jpeg", + "text/markdown", + "text/latex", + "text/plain", + ) +} +``` + +:::{seealso} +[](use/format/cutomise), for a more advanced means of customisation. +::: + +## Removing stdout and stderr + +In some cases you may not wish to display stdout/stderr outputs in your final documentation, +for example, if they are only for debugging purposes. +You can tell MyST-NB to remove these outputs using the `remove-stdout` and `remove-stderr` [cell tags](https://jupyter-notebook.readthedocs.io/en/stable/changelog.html#cell-tags), like so: + +````md +```{code-cell} ipython3 +:tags: [remove-input,remove-stdout,remove-stderr] + +import pandas, sys +print("this is some stdout") +print("this is some stderr", file=sys.stderr) +# but what I really want to show is: +pandas.DataFrame({"column 1": [1, 2, 3]}) +``` +```` + +```{code-cell} ipython3 +:tags: [remove-input,remove-stdout,remove-stderr] + +import pandas, sys +print("this is some stdout") +print("this is some stderr", file=sys.stderr) +# but what I really want to show is: +pandas.DataFrame({"column 1": [1, 2, 3]}) +``` + +(use/format/images)= +## Images + +With the default renderer, for any image types output by the code, we can apply formatting *via* cell metadata. +The keys should be placed under `myst`, then for the image we can apply all the variables of the standard [image directive](https://docutils.sourceforge.io/docs/ref/rst/directives.html#image): + +- **width**: length or percentage (%) of the current line width +- **height**: length +- **scale**: integer percentage (the "%" symbol is optional) +- **align**: "top", "middle", "bottom", "left", "center", or "right" +- **classes**: space separated strings +- **alt**: string + +Units of length are: 'em', 'ex', 'px', 'in', 'cm', 'mm', 'pt', 'pc' + +We can also set a caption (which is rendered as [CommonMark](https://commonmark.org/)) and name, by which to reference the figure: + +````md +```{code-cell} ipython3 +--- +myst: + image: + width: 200px + alt: fun-fish + classes: shadow bg-primary + figure: + caption: | + Hey everyone its **party** time! + name: fun-fish +--- +from IPython.display import Image +Image("images/fun-fish.png") +``` +```` + +```{code-cell} ipython3 +--- +myst: + image: + width: 300px + alt: fun-fish + classes: shadow bg-primary + figure: + caption: | + Hey everyone its **party** time! + name: fun-fish +--- +from IPython.display import Image +Image("images/fun-fish.png") +``` + +Now we can link to the image from anywhere in our documentation: [swim to the fish](fun-fish) + +(use/format/markdown)= +## Markdown + +Markdown output is parsed by MyST-Parser, currently with the configuration set to `myst_commonmark_only=True` (see [MyST configuration options](myst:intro/config-options)). + +The parsed Markdown is integrated into the wider documentation, and so it is possible, for example, to include internal references: + +```{code-cell} ipython3 +from IPython.display import display, Markdown +display(Markdown('**_some_ markdown** and an [internal reference](use/format/markdown)!')) +``` + +and even internal images can be rendered! + +```{code-cell} ipython3 +display(Markdown('![figure](../_static/logo.png)')) +``` + +(use/format/ansi)= +## ANSI Outputs + +By default, the standard output/error streams and text/plain MIME outputs may contain ANSI escape sequences to change the text and background colors. + +```{code-cell} ipython3 +import sys +print("BEWARE: \x1b[1;33;41mugly colors\x1b[m!", file=sys.stderr) +print("AB\x1b[43mCD\x1b[35mEF\x1b[1mGH\x1b[4mIJ\x1b[7m" + "KL\x1b[49mMN\x1b[39mOP\x1b[22mQR\x1b[24mST\x1b[27mUV") +``` + +This uses the built-in {py:class}`~myst_nb.ansi_lexer.AnsiColorLexer` [pygments lexer](https://pygments.org/). +You can change the lexer used in the `conf.py`, for example to turn off lexing: + +```python +nb_render_text_lexer = "none" +``` + +The following code[^acknowledge] shows the 8 basic ANSI colors it is based on. +Each of the 8 colors has an “intense” variation, which is used for bold text. + +[^acknowledge]: Borrowed from [nbsphinx](https://nbsphinx.readthedocs.io/en/0.7.1/code-cells.html#ANSI-Colors)! + +```{code-cell} ipython3 +text = " XYZ " +formatstring = "\x1b[{}m" + text + "\x1b[m" + +print( + " " * 6 + + " " * len(text) + + "".join("{:^{}}".format(bg, len(text)) for bg in range(40, 48)) +) +for fg in range(30, 38): + for bold in False, True: + fg_code = ("1;" if bold else "") + str(fg) + print( + " {:>4} ".format(fg_code) + + formatstring.format(fg_code) + + "".join( + formatstring.format(fg_code + ";" + str(bg)) for bg in range(40, 48) + ) + ) +``` + +:::{note} +ANSI also supports a set of 256 indexed colors. +This is currently not supported, but we hope to introduce it at a later date +(raise an issue on the repository if you require it!). +::: + +(use/format/cutomise)= +## Customise the render process + +The render process is goverened by subclasses of {py:class}`myst_nb.render_outputs.CellOutputRendererBase`, which dictate how to create the `docutils` AST nodes for a particular MIME type. the default implementation is {py:class}`~myst_nb.render_outputs.CellOutputRenderer`. + +Implementations are loaded *via* Python [entry points](https://packaging.python.org/guides/distributing-packages-using-setuptools/#entry-points), in the `myst_nb.mime_render` group. +So it is possible to inject your own subclass to handle rendering. + +For example, the renderers loaded in this package are: + +```python +entry_points={ + "myst_nb.mime_render": [ + "default = myst_nb.render_outputs:CellOutputRenderer", + "inline = myst_nb.render_outputs:CellOutputRendererInline", + ], +} +``` + +You can then select the renderer plugin in your `conf.py`: + +```python +nb_render_plugin = "default" +``` diff --git a/docs/use/hiding.md b/docs/use/hiding.md index b91a5d6f..24935b94 100644 --- a/docs/use/hiding.md +++ b/docs/use/hiding.md @@ -50,7 +50,7 @@ right to show it. # This cell has a hide-input tag fig, ax = plt.subplots() -ax.scatter(*data, c=data[0], s=data[0]) +points =ax.scatter(*data, c=data[0], s=data[0]) ``` Here's a cell with a `hide-output` tag: @@ -60,7 +60,7 @@ Here's a cell with a `hide-output` tag: # This cell has a hide-output tag fig, ax = plt.subplots() -ax.scatter(*data, c=data[0], s=data[0]) +points =ax.scatter(*data, c=data[0], s=data[0]) ``` And the following cell has a `hide-cell` tag: @@ -70,7 +70,7 @@ And the following cell has a `hide-cell` tag: # This cell has a hide-cell tag fig, ax = plt.subplots() -ax.scatter(*data, c=data[0], s=data[0]) +points =ax.scatter(*data, c=data[0], s=data[0]) ``` (use/hiding/markdown)= @@ -152,7 +152,7 @@ the page at all. # This cell has a remove-input tag fig, ax = plt.subplots() -ax.scatter(*data, c=data[0], s=data[0]) +points =ax.scatter(*data, c=data[0], s=data[0]) ``` Here's a cell with a `remove-output` tag: diff --git a/docs/use/images/fun-fish.png b/docs/use/images/fun-fish.png new file mode 100644 index 00000000..c9a49971 Binary files /dev/null and b/docs/use/images/fun-fish.png differ diff --git a/docs/use/index.md b/docs/use/index.md index 6b010848..736729d5 100644 --- a/docs/use/index.md +++ b/docs/use/index.md @@ -10,5 +10,6 @@ start myst execute hiding +formatting_outputs glue ``` diff --git a/docs/use/start.md b/docs/use/start.md index 95219eb2..d0f88a0e 100644 --- a/docs/use/start.md +++ b/docs/use/start.md @@ -26,7 +26,7 @@ To install `myst-nb`, do the following: ``` Once you do this, MyST-NB will now parse both markdown (`.md`), Jupyter notebooks (`.ipynb`), and even [text-based Notebooks](markdown.md) (`.md`) into your Sphinx site -(see also ). +(see also [custom notebook formats](examples/custom_formats)). (start/error-reporting)= diff --git a/myst_nb/__init__.py b/myst_nb/__init__.py index f63c8d3a..aac5a7dc 100644 --- a/myst_nb/__init__.py +++ b/myst_nb/__init__.py @@ -12,21 +12,15 @@ from myst_parser import setup_sphinx as setup_myst_parser -from jupyter_sphinx.ast import ( # noqa: F401 - JupyterWidgetStateNode, - JupyterWidgetViewNode, - JupyterCell, -) - from .execution import update_execution_cache -from .parser import ( - NotebookParser, +from .parser import NotebookParser +from .nodes import ( CellNode, CellInputNode, CellOutputNode, CellOutputBundleNode, ) -from .transform import CellOutputsToNodes +from .render_outputs import CellOutputsToNodes, get_default_render_priority from .nb_glue import glue # noqa: F401 from .nb_glue.domain import ( @@ -38,6 +32,7 @@ ) from .nb_glue.transform import PasteNodesToDocutils from .exec_table import setup_exec_table +from .render_outputs import load_renderer LOGGER = logging.getLogger(__name__) @@ -114,6 +109,11 @@ def visit_element_html(self, node): app.add_config_value("execution_show_tb", False, "") app.add_config_value("execution_custom_formats", {}, "env") + # render config + app.add_config_value("nb_render_priority", {}, "env") + app.add_config_value("nb_render_plugin", "default", "env") + app.add_config_value("nb_render_text_lexer", "myst-ansi", "env") + # Register our post-transform which will convert output bundles to nodes app.add_post_transform(PasteNodesToDocutils) app.add_post_transform(CellOutputsToNodes) @@ -126,6 +126,7 @@ def visit_element_html(self, node): app.connect("builder-inited", static_path) app.connect("builder-inited", set_valid_execution_paths) app.connect("builder-inited", set_up_execution_data) + app.connect("builder-inited", set_render_priority) app.connect("env-purge-doc", remove_execution_data) app.connect("env-get-outdated", update_execution_cache) app.connect("config-inited", add_exclude_patterns) @@ -133,6 +134,10 @@ def visit_element_html(self, node): app.connect("env-updated", save_glue_cache) app.connect("config-inited", add_nb_custom_formats) + from myst_nb.ansi_lexer import AnsiColorLexer + + app.add_lexer("myst-ansi", AnsiColorLexer) + # Misc app.add_css_file("mystnb.css") app.setup_extension("jupyter_sphinx") @@ -205,6 +210,8 @@ def validate_config_values(app: Sphinx, config): raise MystNbConfigError( f"`execution_custom_formats.{name}.commonmark_only` arg is not boolean" ) + # try loading notebook output renderer + load_renderer(app.config["nb_render_plugin"]) def static_path(app: Sphinx): @@ -212,6 +219,25 @@ def static_path(app: Sphinx): app.config.html_static_path.append(str(static_path)) +def set_render_priority(app: Sphinx): + """Set the render priority for the particular builder.""" + builder = app.builder.name + if app.config.nb_render_priority and builder in app.config.nb_render_priority: + app.env.nb_render_priority = app.config.nb_render_priority[builder] + else: + app.env.nb_render_priority = get_default_render_priority(builder) + + if app.env.nb_render_priority is None: + raise MystNbConfigError(f"`nb_render_priority` not set for builder: {builder}") + try: + for item in app.env.nb_render_priority: + assert isinstance(item, str) + except Exception: + raise MystNbConfigError( + f"`nb_render_priority` is not a list of str: {app.env.nb_render_priority}" + ) + + def set_valid_execution_paths(app: Sphinx): """Set files excluded from execution, and valid file suffixes diff --git a/myst_nb/_static/mystnb.css b/myst_nb/_static/mystnb.css index 108d2d69..5db6b7ff 100644 --- a/myst_nb/_static/mystnb.css +++ b/myst_nb/_static/mystnb.css @@ -121,3 +121,58 @@ span.pasted-inline img { tbody span.pasted-inline img { max-height: none; } + +/* Font colors for translated ANSI escape sequences +Color values are adapted from share/jupyter/nbconvert/templates/classic/static/style.css +*/ +div.highlight .-Color-Bold { + font-weight: bold; +} +div.highlight .-Color[class*=-Black] { + color :#3E424D +} +div.highlight .-Color[class*=-Red] { + color: #E75C58 +} +div.highlight .-Color[class*=-Green] { + color: #00A250 +} +div.highlight .-Color[class*=-Yellow] { + color: yellow +} +div.highlight .-Color[class*=-Blue] { + color: #208FFB +} +div.highlight .-Color[class*=-Magenta] { + color: #D160C4 +} +div.highlight .-Color[class*=-Cyan] { + color: #60C6C8 +} +div.highlight .-Color[class*=-White] { + color: #C5C1B4 +} +div.highlight .-Color[class*=-BGBlack] { + background-color: #3E424D +} +div.highlight .-Color[class*=-BGRed] { + background-color: #E75C58 +} +div.highlight .-Color[class*=-BGGreen] { + background-color: #00A250 +} +div.highlight .-Color[class*=-BGYellow] { + background-color: yellow +} +div.highlight .-Color[class*=-BGBlue] { + background-color: #208FFB +} +div.highlight .-Color[class*=-BGMagenta] { + background-color: #D160C4 +} +div.highlight .-Color[class*=-BGCyan] { + background-color: #60C6C8 +} +div.highlight .-Color[class*=-BGWhite] { + background-color: #C5C1B4 +} diff --git a/myst_nb/ansi_lexer.py b/myst_nb/ansi_lexer.py new file mode 100644 index 00000000..fdb485d9 --- /dev/null +++ b/myst_nb/ansi_lexer.py @@ -0,0 +1,154 @@ +# -*- coding: utf-8 -*- +"""Pygments lexer for text containing ANSI color codes. + +Adapted from https://github.com/chriskuehl/pygments-ansi-color +""" +import re + +import pygments.lexer +import pygments.token + + +_ansi_code_to_color = { + 0: "Black", + 1: "Red", + 2: "Green", + 3: "Yellow", + 4: "Blue", + 5: "Magenta", + 6: "Cyan", + 7: "White", +} + + +def _token_from_lexer_state(bold, faint, fg_color, bg_color): + """Construct a token given the current lexer state. + + We can only emit one token even though we have a multiple-tuple state. + To do work around this, we construct tokens like "Bold.Red". + """ + components = () + + if bold: + components += ("Bold",) + + if faint: + components += ("Faint",) + + if fg_color: + components += (fg_color,) + + if bg_color: + components += ("BG" + bg_color,) + + if len(components) == 0: + return pygments.token.Text + else: + token = pygments.token.Token.Color + for component in components: + token = getattr(token, component) + return token + + +class AnsiColorLexer(pygments.lexer.RegexLexer): + name = "ANSI Color" + aliases = ("myst-ansi",) + flags = re.DOTALL | re.MULTILINE + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.reset_state() + + def reset_state(self): + self.bold = False + self.faint = False + self.fg_color = None + self.bg_color = None + + @property + def current_token(self): + return _token_from_lexer_state( + self.bold, self.faint, self.fg_color, self.bg_color, + ) + + def process(self, match): + """Produce the next token and bit of text. + + Interprets the ANSI code (which may be a color code or some other + code), changing the lexer state and producing a new token. If it's not + a color code, we just strip it out and move on. + + Some useful reference for ANSI codes: + * http://ascii-table.com/ansi-escape-sequences.php + """ + # "after_escape" contains everything after the start of the escape + # sequence, up to the next escape sequence. We still need to separate + # the content from the end of the escape sequence. + after_escape = match.group(1) + + # TODO: this doesn't handle the case where the values are non-numeric. + # This is rare but can happen for keyboard remapping, e.g. + # '\x1b[0;59;"A"p' + parsed = re.match( + r"([0-9;=]*?)?([a-zA-Z])(.*)$", after_escape, re.DOTALL | re.MULTILINE, + ) + if parsed is None: + # This shouldn't ever happen if we're given valid text + ANSI, but + # people can provide us with utter junk, and we should tolerate it. + text = after_escape + else: + value, code, text = parsed.groups() + if code == "m": # "m" is "Set Graphics Mode" + # Special case \x1b[m is a reset code + if value == "": + self.reset_state() + else: + try: + values = [int(v) for v in value.split(";")] + except ValueError: + # Shouldn't ever happen, but could with invalid ANSI. + values = [] + + while len(values) > 0: + value = values.pop(0) + fg_color = _ansi_code_to_color.get(value - 30) + bg_color = _ansi_code_to_color.get(value - 40) + if fg_color: + self.fg_color = fg_color + elif bg_color: + self.bg_color = bg_color + elif value == 1: + self.bold = True + elif value == 2: + self.faint = True + elif value == 22: + self.bold = False + self.faint = False + elif value == 39: + self.fg_color = None + elif value == 49: + self.bg_color = None + elif value == 0: + self.reset_state() + elif value in (38, 48): + try: + five = values.pop(0) + color = values.pop(0) + except IndexError: + continue + else: + if five != 5: + continue + if not 0 <= color <= 255: + continue + color = "C{}".format(color) + if value == 38: + self.fg_color = color + else: + self.bg_color = color + + yield match.start(), self.current_token, text + + tokens = { + "root": [(r"\x1b\[([^\x1b]*)", process), (r"[^\x1b]+", pygments.token.Text)], + } diff --git a/myst_nb/nb_glue/domain.py b/myst_nb/nb_glue/domain.py index 06439eb4..ec2adc51 100644 --- a/myst_nb/nb_glue/domain.py +++ b/myst_nb/nb_glue/domain.py @@ -13,6 +13,7 @@ from myst_nb.nb_glue import GLUE_PREFIX from myst_nb.nb_glue.utils import find_all_keys +from myst_nb.nodes import CellOutputNode, CellOutputBundleNode SPHINX_LOGGER = logging.getLogger(__name__) @@ -20,8 +21,7 @@ class PasteNode(nodes.container): """Represent a MimeBundle in the Sphinx AST, to be transformed later.""" - def __init__(self, key, location=None, rawsource="", *children, **attributes): - self.location = location + def __init__(self, key, **attributes): attributes["key"] = key super().__init__("", **attributes) @@ -30,16 +30,17 @@ def key(self): return self.attributes["key"] def copy(self): - return self.__class__(location=self.location, **self.attributes) + return self.__class__( + self.key, **{k: v for k, v in self.attributes.items() if k != "key"} + ) def create_node(self, output: dict, document, env): """Create the output node, give the cell output.""" # the whole output chunk is deposited and rendered later # TODO move these nodes to separate module, to avoid cyclic imports - from myst_nb.parser import CellOutputNode, CellOutputBundleNode - - output_node = CellOutputBundleNode(outputs=[output]) + output_node = CellOutputBundleNode([output], "default") out_node = CellOutputNode(classes=["cell_output"]) + out_node.source, out_node.line = self.source, self.line out_node += output_node return out_node @@ -48,10 +49,9 @@ class PasteInlineNode(PasteNode): def create_node(self, output: dict, document, env): """Create the output node, give the cell output.""" # the whole output chunk is deposited and rendered later - from myst_nb.parser import CellOutputBundleNode - - bundle_node = CellOutputBundleNode(outputs=[output], inline=True) + bundle_node = CellOutputBundleNode([output], "inline") inline_node = nodes.inline("", "", bundle_node, classes=["pasted-inline"]) + inline_node.source, inline_node.line = self.source, self.line return inline_node @@ -74,7 +74,9 @@ def create_node(self, output: dict, document, env): text = f"{newtext:>{self.formatting}}" except ValueError: pass - return nodes.inline(text, text, classes=["pasted-text"]) + node = nodes.inline(text, text, classes=["pasted-text"]) + node.source, node.line = self.source, self.line + return node return None @@ -98,11 +100,9 @@ def create_node(self, output: dict, document, env): nowrap=self["math_nowrap"], label=self["math_label"], ) - node.line = self.line - node.source = self.source + node.line, node.source = self.line, self.source if "math_class" in self and self["math_class"]: node["classes"].append(self["math_class"]) - return node return None @@ -116,15 +116,9 @@ class Paste(SphinxDirective): option_spec = {"id": directives.unchanged} def run(self): - # TODO: Figure out how to report cell number in the location - # currently, line numbers in ipynb files are not reliable - path, lineno = self.state_machine.get_source_and_line(self.lineno) - # Remove line number if we have a notebook because it is unreliable - if path.endswith(".ipynb"): - lineno = None - # Remove the suffix from path so its suffix is printed properly in logs - path = str(Path(path).with_suffix("")) - return [PasteNode(self.arguments[0], location=(path, lineno))] + node = PasteNode(self.arguments[0]) + self.set_source_info(node) + return [node] class PasteMath(Paste): @@ -136,15 +130,8 @@ class PasteMath(Paste): has_content = False def run(self): - # TODO: Figure out how to report cell number in the location - # currently, line numbers in ipynb files are not reliable - path, lineno = self.state_machine.get_source_and_line(self.lineno) - # Remove line number if we have a notebook because it is unreliable - if path.endswith(".ipynb"): - lineno = None - # Remove the suffix from path so its suffix is printed properly in logs - path = str(Path(path).with_suffix("")) - paste_node = PasteMathNode(self.arguments[0], location=(path, lineno)) + paste_node = PasteMathNode(self.arguments[0]) + self.set_source_info(paste_node) paste_node["math_class"] = self.options.pop("class", None) paste_node["math_label"] = self.options.pop("label", None) paste_node["math_nowrap"] = "nowrap" in self.options diff --git a/myst_nb/nb_glue/transform.py b/myst_nb/nb_glue/transform.py index 7122ff34..7b319c18 100644 --- a/myst_nb/nb_glue/transform.py +++ b/myst_nb/nb_glue/transform.py @@ -10,7 +10,7 @@ class PasteNodesToDocutils(SphinxTransform): """Use the builder context to transform a CellOutputNode into Sphinx nodes.""" - default_priority = 699 # must be applied before CellOutputsToNodes + default_priority = 3 # must be applied before CellOutputsToNodes def apply(self): glue_domain = NbGlueDomain.from_env(self.app.env) # type: NbGlueDomain @@ -22,7 +22,7 @@ def apply(self): f"Couldn't find key `{paste_node.key}` " "in keys defined across all pages." ), - location=paste_node.location, + location=(paste_node.source, paste_node.line), ) continue @@ -38,7 +38,7 @@ def apply(self): "Couldn't find compatible output format for key " f"`{paste_node.key}`" ), - location=paste_node.location, + location=(paste_node.source, paste_node.line), ) else: paste_node.replace_self(out_node) diff --git a/myst_nb/nodes.py b/myst_nb/nodes.py new file mode 100644 index 00000000..77ab022f --- /dev/null +++ b/myst_nb/nodes.py @@ -0,0 +1,60 @@ +"""AST nodes to designate notebook components.""" +from typing import List + +from docutils import nodes +from nbformat import NotebookNode + + +class CellNode(nodes.container): + """Represent a cell in the Sphinx AST.""" + + def __init__(self, rawsource="", *children, **attributes): + super().__init__("", **attributes) + + +class CellInputNode(nodes.container): + """Represent an input cell in the Sphinx AST.""" + + def __init__(self, rawsource="", *children, **attributes): + super().__init__("", **attributes) + + +class CellOutputNode(nodes.container): + """Represent an output cell in the Sphinx AST.""" + + def __init__(self, rawsource="", *children, **attributes): + super().__init__("", **attributes) + + +class CellOutputBundleNode(nodes.container): + """Represent a MimeBundle in the Sphinx AST, to be transformed later.""" + + def __init__(self, outputs, renderer: str, metadata=None, **attributes): + self._outputs = outputs + self._renderer = renderer + self._metadata = metadata or NotebookNode() + attributes["output_count"] = len(outputs) # for debugging with pformat + super().__init__("", **attributes) + + @property + def outputs(self) -> List[NotebookNode]: + """The outputs associated with this cell.""" + return self._outputs + + @property + def metadata(self) -> NotebookNode: + """The cell level metadata for this output.""" + return self._metadata + + @property + def renderer(self) -> str: + """The cell level metadata for this output.""" + return self._renderer + + def copy(self): + return self.__class__( + outputs=self._outputs, + renderer=self._renderer, + metadata=self._metadata, + **self.attributes, + ) diff --git a/myst_nb/parser.py b/myst_nb/parser.py index b2f61d1d..708497ec 100644 --- a/myst_nb/parser.py +++ b/myst_nb/parser.py @@ -19,10 +19,11 @@ from myst_parser.sphinx_renderer import SphinxRenderer from myst_parser.sphinx_parser import MystParser -from myst_nb.execution import generate_notebook_outputs from myst_nb.converter import get_nb_converter +from myst_nb.execution import generate_notebook_outputs from myst_nb.nb_glue import GLUE_PREFIX from myst_nb.nb_glue.domain import NbGlueDomain +from myst_nb.nodes import CellNode, CellInputNode, CellOutputNode, CellOutputBundleNode SPHINX_LOGGER = logging.getLogger(__name__) @@ -73,7 +74,9 @@ def parse(self, inputstring: str, document: nodes.document): # Parse the notebook content to a list of syntax tokens and an env # containing global data like reference definitions md_parser, env, tokens = nb_to_tokens( - ntbk, self.env.myst_config if converter is None else converter.config, + ntbk, + self.env.myst_config if converter is None else converter.config, + self.env.config["nb_render_plugin"], ) # Write the notebook's output to disk @@ -88,7 +91,7 @@ def parse(self, inputstring: str, document: nodes.document): def nb_to_tokens( - ntbk: nbf.NotebookNode, config: MdParserConfig + ntbk: nbf.NotebookNode, config: MdParserConfig, renderer_plugin: str ) -> Tuple[MarkdownIt, AttrDict, List[Token]]: """Parse the notebook content to a list of syntax tokens and an env, containing global data like reference definitions. @@ -153,7 +156,6 @@ def parse_block(src, start_line): # we add the cell index to tokens, # so they can be included in the error logging, - # although note this logic isn't currently implemented in SphinxRenderer block_tokens.extend(parse_block(nb_cell["source"], start_line)) elif nb_cell["cell_type"] == "code": @@ -163,7 +165,7 @@ def parse_block(src, start_line): "nb_code_cell", "", 0, - meta={"cell": nb_cell, "lexer": lexer}, + meta={"cell": nb_cell, "lexer": lexer, "renderer": renderer_plugin}, map=[start_line, start_line], ) ) @@ -213,7 +215,8 @@ def render_jupyter_widget_state(self, token: Token): def render_nb_code_cell(self, token: Token): """Render a Jupyter notebook cell.""" - cell = token.meta["cell"] + cell = token.meta["cell"] # type: nbf.NotebookNode + # TODO logic involving tags should be deferred to a transform tags = cell.metadata.get("tags", []) @@ -225,6 +228,7 @@ def render_nb_code_cell(self, token: Token): self.current_node += sphinx_cell if ("remove_input" not in tags) and ("remove-input" not in tags): cell_input = CellInputNode(classes=["cell_input"]) + self.add_line_and_source_path(cell_input, token) sphinx_cell += cell_input # Input block @@ -244,45 +248,13 @@ def render_nb_code_cell(self, token: Token): cell_output = CellOutputNode(classes=["cell_output"]) sphinx_cell += cell_output - outputs = CellOutputBundleNode(cell["outputs"]) + outputs = CellOutputBundleNode( + cell["outputs"], token.meta["renderer"], cell.metadata + ) + self.add_line_and_source_path(outputs, token) cell_output += outputs -class CellNode(nodes.container): - """Represent a cell in the Sphinx AST.""" - - def __init__(self, rawsource="", *children, **attributes): - super().__init__("", **attributes) - - -class CellInputNode(nodes.container): - """Represent an input cell in the Sphinx AST.""" - - def __init__(self, rawsource="", *children, **attributes): - super().__init__("", **attributes) - - -class CellOutputNode(nodes.container): - """Represent an output cell in the Sphinx AST.""" - - def __init__(self, rawsource="", *children, **attributes): - super().__init__("", **attributes) - - -class CellOutputBundleNode(nodes.container): - """Represent a MimeBundle in the Sphinx AST, to be transformed later.""" - - def __init__(self, outputs, rawsource="", *children, **attributes): - self.outputs = outputs - attributes["output_count"] = len(outputs) - super().__init__("", **attributes) - - def copy(self): - return self.__class__( - rawsource=self.rawsource, outputs=self.outputs, **self.attributes - ) - - def nb_output_to_disc(ntbk: nbf.NotebookNode, document: nodes.document) -> Path: """Write the notebook's output to disk diff --git a/myst_nb/render_outputs.py b/myst_nb/render_outputs.py new file mode 100644 index 00000000..4865b82b --- /dev/null +++ b/myst_nb/render_outputs.py @@ -0,0 +1,493 @@ +"""A Sphinx post-transform, to convert notebook outpus to AST nodes.""" +from abc import ABC, abstractmethod +import os +from typing import List, Optional + +from importlib_metadata import entry_points +from docutils import nodes +from docutils.parsers.rst import directives +from sphinx.environment import BuildEnvironment +from sphinx.environment.collectors.asset import ImageCollector +from sphinx.errors import SphinxError +from sphinx.transforms.post_transforms import SphinxPostTransform +from sphinx.util import logging + +import nbconvert +from nbformat import NotebookNode + +from jupyter_sphinx.ast import ( + JupyterWidgetViewNode, + strip_latex_delimiters, +) +from jupyter_sphinx.utils import sphinx_abs_dir + +from myst_parser.main import default_parser, MdParserConfig + +from .nodes import CellOutputBundleNode + +LOGGER = logging.getLogger(__name__) + +WIDGET_VIEW_MIMETYPE = "application/vnd.jupyter.widget-view+json" +MYST_META_KEY = "myst" + + +def get_default_render_priority(builder: str) -> Optional[List[str]]: + priority = { + builder: ( + WIDGET_VIEW_MIMETYPE, + "application/javascript", + "text/html", + "image/svg+xml", + "image/png", + "image/jpeg", + "text/markdown", + "text/latex", + "text/plain", + ) + for builder in ( + "html", + "readthedocs", + "singlehtml", + "dirhtml", + "linkcheck", + "readthedocsdirhtml", + "readthedocssinglehtml", + "readthedocssinglehtmllocalmedia", + "epub", + ) + } + # TODO: add support for "image/svg+xml" + priority["latex"] = ( + "application/pdf", + "image/png", + "image/jpeg", + "text/latex", + "text/markdown", + "text/plain", + ) + return priority.get(builder, None) + + +class MystNbEntryPointError(SphinxError): + category = "MyST NB Renderer Load" + + +def load_renderer(name) -> "CellOutputRendererBase": + """Load a renderer, + given a name within the ``myst_nb.mime_render`` entry point group + """ + ep_list = set(ep for ep in entry_points()["myst_nb.mime_render"] if ep.name == name) + if len(ep_list) == 1: + klass = ep_list.pop().load() + if not issubclass(klass, CellOutputRendererBase): + raise MystNbEntryPointError( + f"Entry Point for myst_nb.mime_render:{name} " + f"is not a subclass of `CellOutputRendererBase`: {klass}" + ) + return klass + elif not ep_list: + raise MystNbEntryPointError( + f"No Entry Point found for myst_nb.mime_render:{name}" + ) + raise MystNbEntryPointError( + f"Multiple Entry Points found for myst_nb.mime_render:{name}: {ep_list}" + ) + + +class CellOutputsToNodes(SphinxPostTransform): + """Use the builder context to transform a CellOutputNode into Sphinx nodes.""" + + # process very early, before CitationReferenceTransform (5), ReferencesResolver (10) + # https://www.sphinx-doc.org/en/master/extdev/appapi.html#sphinx.application.Sphinx.add_transform + default_priority = 4 + + def run(self): + abs_dir = sphinx_abs_dir(self.env) + renderers = {} # cache renderers + for node in self.document.traverse(CellOutputBundleNode): + try: + renderer_cls = renderers[node.renderer] + except KeyError: + renderer_cls = load_renderer(node.renderer) + renderers[node.renderer] = renderer_cls + renderer = renderer_cls(self.document, node, abs_dir) + output_nodes = renderer.cell_output_to_nodes(self.env.nb_render_priority) + node.replace_self(output_nodes) + + # Image collect extra nodes from cell outputs that we need to process + # this normally gets called as a `doctree-read` event + for node in self.document.traverse(nodes.image): + # If the image node has `candidates` then it's already been processed + # as in-line markdown, so skip it + if "candidates" in node: + continue + col = ImageCollector() + col.process_doc(self.app, node) + + +class CellOutputRendererBase(ABC): + """An abstract base class for rendering Notebook outputs to docutils nodes. + + Subclasses should implement the ``render`` method. + """ + + def __init__( + self, document: nodes.document, node: CellOutputBundleNode, sphinx_dir: str + ): + """ + :param sphinx_dir: Sphinx "absolute path" to the output folder, + so it is a relative path to the source folder prefixed with ``/``. + """ + self.document = document + self.env = document.settings.env # type: BuildEnvironment + self.node = node + self.sphinx_dir = sphinx_dir + + def cell_output_to_nodes(self, data_priority: List[str]) -> List[nodes.Node]: + """Convert a jupyter cell with outputs and filenames to doctree nodes. + + :param outputs: a list of outputs from a Jupyter cell + :param data_priority: media type by priority. + + :returns: list of docutils nodes + + """ + output_nodes = [] + for idx, output in enumerate(self.node.outputs): + output_type = output["output_type"] + if output_type == "stream": + if output["name"] == "stderr": + output_nodes.extend(self.render("stderr", output, idx)) + else: + output_nodes.extend(self.render("stdout", output, idx)) + elif output_type == "error": + print("traceback", idx) + output_nodes.extend(self.render("traceback", output, idx)) + + 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: + # TODO this is incompatible with glue outputs + # perhaps have sphinx config to turn on/off this error reporting? + # and/or only warn if "scrapbook" not in output.metadata + # (then enable tests/test_render_outputs.py::test_unknown_mimetype) + # LOGGER.warning( + # "MyST-NB: output contains no MIME type in priority list: %s", + # list(output["data"].keys()), + # location=location, + # ) + continue + output_nodes.extend(self.render(mime_type, output, idx)) + + return output_nodes + + def add_source_and_line(self, *nodes: List[nodes.Node]): + """Add the source and line recursively to all nodes.""" + location = self.node.source, self.node.line + for node in nodes: + node.source, node.line = location + for child in node.traverse(): + child.source, child.line = location + + def make_error(self, error_msg: str) -> nodes.system_message: + """Raise an exception or generate a warning if appropriate, + and return a system_message node""" + return self.document.reporter.error( + "output render: {}".format(error_msg), line=self.node.line, + ) + + def add_name(self, node: nodes.Node, name: str): + """Append name to node['names']. + + Also normalize the name string and register it as explicit target. + """ + name = nodes.fully_normalize_name(name) + if "name" in node: + del node["name"] + node["names"].append(name) + self.document.note_explicit_target(node, node) + return name + + def parse_markdown( + self, text: str, parent: Optional[nodes.Node] = None + ) -> List[nodes.Node]: + """Parse text as CommonMark, in a new document.""" + parser = default_parser(MdParserConfig(commonmark_only=True)) + parent = parent or nodes.container() + parser.options["current_node"] = parent + parser.render(text) + # TODO is there any transforms we should retroactively carry out? + return parent.children + + @abstractmethod + def render( + self, mime_type: str, output: NotebookNode, index: int + ) -> List[nodes.Node]: + """Take a MIME bundle and MIME type, and return zero or more nodes.""" + pass + + +class CellOutputRenderer(CellOutputRendererBase): + def __init__( + self, document: nodes.document, node: CellOutputBundleNode, sphinx_dir: str + ): + """ + :param sphinx_dir: Sphinx "absolute path" to the output folder, + so it is a relative path to the source folder prefixed with ``/``. + """ + super().__init__(document, node, sphinx_dir) + self._render_map = { + "stderr": self.render_stderr, + "stdout": self.render_stdout, + "traceback": self.render_traceback, + "text/plain": self.render_text_plain, + "text/markdown": self.render_text_markdown, + "text/html": self.render_text_html, + "text/latex": self.render_text_latex, + "application/javascript": self.render_application_javascript, + WIDGET_VIEW_MIMETYPE: self.render_widget, + } + + def render( + self, mime_type: str, output: NotebookNode, index: int + ) -> List[nodes.Node]: + """Take a MIME bundle and MIME type, and return zero or more nodes.""" + if mime_type.startswith("image"): + nodes = self.create_render_image(mime_type)(output, index) + self.add_source_and_line(*nodes) + return nodes + if mime_type in self._render_map: + nodes = self._render_map[mime_type](output, index) + self.add_source_and_line(*nodes) + return nodes + + LOGGER.warning( + "MyST-NB: No renderer found for output MIME: %s", + mime_type, + location=(self.node.source, self.node.line), + ) + return [] + + def render_stderr(self, output: NotebookNode, index: int): + """Output a container with an unhighlighted literal block.""" + + if "remove-stderr" in self.node.metadata.get("tags", []): + return [] + + container = nodes.container(classes=["stderr"]) + container.append( + nodes.literal_block( + text=output["text"], + rawsource=output["text"], + language=self.env.config.nb_render_text_lexer, + classes=["stderr"], + ) + ) + return [container] + + def render_stdout(self, output: NotebookNode, index: int): + + if "remove-stdout" in self.node.metadata.get("tags", []): + return [] + + return [ + nodes.literal_block( + text=output["text"], + rawsource=output["text"], + language=self.env.config.nb_render_text_lexer, + classes=["output", "stream"], + ) + ] + + def render_traceback(self, output: NotebookNode, index: int): + traceback = "\n".join(output["traceback"]) + text = nbconvert.filters.strip_ansi(traceback) + return [ + nodes.literal_block( + text=text, + rawsource=text, + language="ipythontb", + classes=["output", "traceback"], + ) + ] + + def render_text_markdown(self, output: NotebookNode, index: int): + text = output["data"]["text/markdown"] + return self.parse_markdown(text) + + def render_text_html(self, output: NotebookNode, index: int): + text = output["data"]["text/html"] + return [nodes.raw(text=text, format="html", classes=["output", "text_html"])] + + def render_text_latex(self, output: NotebookNode, index: int): + text = output["data"]["text/latex"] + return [ + nodes.math_block( + text=strip_latex_delimiters(text), + nowrap=False, + number=None, + classes=["output", "text_latex"], + ) + ] + + def render_text_plain(self, output: NotebookNode, index: int): + text = output["data"]["text/plain"] + return [ + nodes.literal_block( + text=text, + rawsource=text, + language=self.env.config.nb_render_text_lexer, + classes=["output", "text_plain"], + ) + ] + + def render_application_javascript(self, output: NotebookNode, index: int): + data = output["data"]["application/javascript"] + return [ + nodes.raw( + text=''.format( + mime_type="application/javascript", data=data + ), + format="html", + ) + ] + + def render_widget(self, output: NotebookNode, index: int): + data = output["data"][WIDGET_VIEW_MIMETYPE] + return [JupyterWidgetViewNode(view_spec=data)] + + def create_render_image(self, mime_type: str): + def _render_image(output: NotebookNode, index: int): + # 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]) + + # checks if file dir path is inside a subdir of dir + filedir = os.path.dirname(output.metadata["filenames"][mime_type]) + subpaths = filedir.split(self.sphinx_dir) + final_dir = self.sphinx_dir + if subpaths and len(subpaths) > 1: + subpath = subpaths[1] + final_dir += subpath + + uri = os.path.join(final_dir, filename) + # TODO I'm not quite sure why, but as soon as you give it a width, + # it becomes clickable?! (i.e. will open the image in the browser) + image_node = nodes.image(uri=uri) + + myst_meta_img = self.node.metadata.get(MYST_META_KEY, {}).get("image", {}) + + for key, spec in [ + ("classes", directives.class_option), + ("alt", directives.unchanged), + ("height", directives.length_or_unitless), + ("width", directives.length_or_percentage_or_unitless), + ("scale", directives.percentage), + ("align", align), + ]: + if key in myst_meta_img: + value = myst_meta_img[key] + try: + image_node[key] = spec(value) + except (ValueError, TypeError) as error: + error_msg = ( + "Invalid image attribute: " + "(key: '{}'; value: {})\n{}".format(key, value, error) + ) + return [self.make_error(error_msg)] + + myst_meta_fig = self.node.metadata.get(MYST_META_KEY, {}).get("figure", {}) + if "caption" not in myst_meta_fig: + return [image_node] + + figure_node = nodes.figure("", image_node) + caption = nodes.caption(myst_meta_fig["caption"], "") + figure_node += caption + # TODO only contents of one paragraph? (and second should be a legend) + self.parse_markdown(myst_meta_fig["caption"], caption) + if "name" in myst_meta_fig: + name = myst_meta_fig["name"] + self.add_source_and_line(figure_node) + self.add_name(figure_node, name) + # The target should have already been processed by now, with + # sphinx.transforms.references.SphinxDomains, which calls + # sphinx.domains.std.StandardDomain.process_doc, + # so we have to replicate that here + std = self.env.get_domain("std") + nametypes = self.document.nametypes.items() + self.document.nametypes = {name: True} + try: + std.process_doc(self.env, self.env.docname, self.document) + finally: + self.document.nametypes = nametypes + + return [figure_node] + + return _render_image + + +def align(argument): + return directives.choice(argument, ("left", "center", "right")) + + +class CellOutputRendererInline(CellOutputRenderer): + """Replaces literal/math blocks with non-block versions""" + + def render_stderr(self, output: NotebookNode, index: int): + """Output a container with an unhighlighted literal""" + return [ + nodes.literal( + text=output["text"], + rawsource="", # disables Pygment highlighting + language="none", + classes=["stderr"], + ) + ] + + def render_stdout(self, output: NotebookNode, index: int): + """Output a container with an unhighlighted literal""" + return [ + nodes.literal( + text=output["text"], + rawsource="", # disables Pygment highlighting + language="none", + classes=["output", "stream"], + ) + ] + + def render_traceback(self, output: NotebookNode, index: int): + traceback = "\n".join(output["traceback"]) + text = nbconvert.filters.strip_ansi(traceback) + return [ + nodes.literal( + text=text, + rawsource=text, + language="ipythontb", + classes=["output", "traceback"], + ) + ] + + def render_text_latex(self, output: NotebookNode, index: int): + data = output["data"]["text/latex"] + return [ + nodes.math( + text=strip_latex_delimiters(data), + nowrap=False, + number=None, + classes=["output", "text_latex"], + ) + ] + + def render_text_plain(self, output: NotebookNode, index: int): + data = output["data"]["text/plain"] + return [ + nodes.literal( + text=data, + rawsource=data, + language="none", + classes=["output", "text_plain"], + ) + ] diff --git a/myst_nb/transform.py b/myst_nb/transform.py deleted file mode 100644 index 8b714ea3..00000000 --- a/myst_nb/transform.py +++ /dev/null @@ -1,211 +0,0 @@ -"""Defines the MIMEtype docutils node.""" -from docutils import nodes -from sphinx.transforms import SphinxTransform -from sphinx.util import logging - -from jupyter_sphinx.ast import ( - cell_output_to_nodes, - JupyterWidgetViewNode, - strip_latex_delimiters, -) -from jupyter_sphinx.utils import sphinx_abs_dir -from .parser import CellOutputBundleNode -from sphinx.environment.collectors.asset import ImageCollector - -logger = logging.getLogger(__name__) - -WIDGET_VIEW_MIMETYPE = "application/vnd.jupyter.widget-view+json" -RENDER_PRIORITY = { - builder: ( - WIDGET_VIEW_MIMETYPE, - "application/javascript", - "text/html", - "image/svg+xml", - "image/png", - "image/jpeg", - "text/latex", - "text/plain", - ) - for builder in ( - "html", - "readthedocs", - "singlehtml", - "dirhtml", - "linkcheck", - "readthedocsdirhtml", - "readthedocssinglehtml", - "readthedocssinglehtmllocalmedia", - "epub", - ) -} -# TODO: add support for "image/svg+xml" -RENDER_PRIORITY["latex"] = ( - "application/pdf", - "image/png", - "image/jpeg", - "text/latex", - "text/plain", -) - - -class CellOutputsToNodes(SphinxTransform): - """Use the builder context to transform a CellOutputNode into Sphinx nodes.""" - - default_priority = 700 - - def apply(self): - builder = self.app.builder.name - output_dir = sphinx_abs_dir(self.env) - for node in self.document.traverse(CellOutputBundleNode): - cell = {"outputs": node.outputs} - outputs = cell.get("outputs", []) - if node.get("inline", False): - output_nodes = cell_output_to_nodes_inline( - outputs, RENDER_PRIORITY[builder], True, output_dir, None - ) - else: - output_nodes = cell_output_to_nodes( - outputs, RENDER_PRIORITY[builder], True, output_dir, None - ) - # TODO add warning if output_nodes is empty - node.replace_self(output_nodes) - - # Image collect extra nodes from cell outputs that we need to process - for node in self.document.traverse(nodes.image): - # If the image node has `candidates` then it's already been processed - # as in-line markdown, so skip it - if "candidates" in node: - continue - col = ImageCollector() - col.process_doc(self.app, node) - - -# TODO this needs to be upstreamed to jupyter-sphinx -def cell_output_to_nodes_inline( - outputs, data_priority, write_stderr, dir, thebe_config -): - """Convert jupyter cell outputs and filenames to doctree nodes. - - Parameters - ---------- - outputs : jupyter cell outputs - 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 - """ - import os - import docutils - import nbconvert - - to_add = [] - for _, output in enumerate(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"]) - literal = docutils.nodes.literal( - text=output["text"], - rawsource="", # disables Pygment highlighting - language="none", - classes=["stderr"], - ) - - to_add.append(literal) - else: - - to_add.append( - docutils.nodes.literal( - 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( - 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]) - - # checks if path in cell has a subpath inside of dir - filedir = os.path.dirname(output.metadata["filenames"][mime_type]) - subpaths = filedir.split(dir) - if subpaths and len(subpaths) > 1: - subpath = subpaths[1] - dir += subpath - - 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( - docutils.nodes.math( - text=strip_latex_delimiters(data), - nowrap=False, - number=None, - classes=["output", "text_latex"], - ) - ) - elif mime_type == "text/plain": - to_add.append( - docutils.nodes.literal( - 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 diff --git a/setup.py b/setup.py index f92a3e2b..10bc8e52 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,15 @@ author_email="choldgraf@berkeley.edu", license="BSD-3", packages=find_packages(), - entry_points={"console_scripts": []}, + entry_points={ + "myst_nb.mime_render": [ + "default = myst_nb.render_outputs:CellOutputRenderer", + "inline = myst_nb.render_outputs:CellOutputRendererInline", + ], + # 'pygments.lexers': [ + # 'myst_ansi = myst_nb.ansi_lexer:AnsiColorLexer', + # ], + }, classifiers=[ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", @@ -51,6 +59,7 @@ "nbconvert~=5.6", "pyyaml", "sphinx-togglebutton~=0.2.2", + "importlib_metadata", ], extras_require={ "code_style": ["flake8<3.8.0,>=3.7.0", "black", "pre-commit==1.17.0"], diff --git a/tests/conftest.py b/tests/conftest.py index 388f0ab1..a4636e97 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,12 +1,10 @@ import json import os from pathlib import Path -import pickle import uuid import pytest -from docutils.utils import Reporter from nbdime.diffing.notebooks import ( diff_notebooks, set_notebook_diff_targets, @@ -77,17 +75,17 @@ def invalidate_files(self): for name, _ in self.files: self.env.all_docs.pop(name) - def get_doctree(self, index=0): + def get_resolved_doctree(self, docname): + """Load and return the built docutils.document, after post-transforms.""" + doctree = self.env.get_and_resolve_doctree(docname, self.app.builder) + doctree["source"] = docname + return doctree + + def get_doctree(self, docname=None): """Load and return the built docutils.document.""" - name = self.files[index][0] - _path = self.app.doctreedir / (name + ".doctree") - if not _path.exists(): - pytest.fail("doctree not output") - doctree = pickle.loads(_path.bytes()) - doctree["source"] = name - doctree.reporter = Reporter(name, 1, 5) - self.app.env.temp_data["docname"] = name - doctree.settings.env = self.app.env + docname = docname or self.files[0][0] + doctree = self.env.get_doctree(docname) + doctree["source"] = docname return doctree def get_html(self, index=0): diff --git a/tests/notebooks/complex_outputs.ipynb b/tests/notebooks/complex_outputs.ipynb index 9b563c64..c47a0288 100644 --- a/tests/notebooks/complex_outputs.ipynb +++ b/tests/notebooks/complex_outputs.ipynb @@ -509,6 +509,29 @@ "f = y(n)-2*y(n-1/sym.pi)-5*y(n-2)\n", "sym.rsolve(f,y(n),[1,4])" ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "**_some_ markdown**" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import display, Markdown\n", + "display(Markdown('**_some_ markdown**'))" + ] } ], "metadata": { diff --git a/tests/notebooks/complex_outputs_unrun.ipynb b/tests/notebooks/complex_outputs_unrun.ipynb index ef470a41..4b1903ea 100644 --- a/tests/notebooks/complex_outputs_unrun.ipynb +++ b/tests/notebooks/complex_outputs_unrun.ipynb @@ -339,6 +339,16 @@ "import ipywidgets as widgets\n", "widgets.Layout(model_id=\"1337h4x0R\")" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.display import display, Markdown\n", + "display(Markdown('**_some_ markdown**'))" + ] } ], "metadata": { diff --git a/tests/notebooks/metadata_image.ipynb b/tests/notebooks/metadata_image.ipynb new file mode 100644 index 00000000..24090926 --- /dev/null +++ b/tests/notebooks/metadata_image.ipynb @@ -0,0 +1,71 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Formatting code outputs" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "myst": { + "figure": { + "caption": "Hey everyone its **party** time!\n", + "name": "fun-fish" + }, + "image": { + "alt": "fun-fish", + "classes": "shadow bg-primary", + "width": "300px" + } + } + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "image/png": "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\n", + "text/plain": "" + }, + "metadata": {}, + "execution_count": 3 + } + ], + "source": [ + "from IPython.display import Image\n", + "Image(\"fun-fish.png\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Link: [swim to the fish](fun-fish)" + ] + } + ], + "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.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/tests/notebooks/unknown_mimetype.ipynb b/tests/notebooks/unknown_mimetype.ipynb new file mode 100644 index 00000000..31ebe5ba --- /dev/null +++ b/tests/notebooks/unknown_mimetype.ipynb @@ -0,0 +1,45 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "source": [ + "a=1\n", + "print(a)" + ], + "outputs": [ + { + "output_type": "display_data", + "metadata": {}, + "execution_count": 1, + "data": { + "unknown": "" + } + } + ] + } + ], + "metadata": { + "test_name": "notebook1", + "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.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tests/test_ansi_lexer.py b/tests/test_ansi_lexer.py new file mode 100644 index 00000000..7c9c6047 --- /dev/null +++ b/tests/test_ansi_lexer.py @@ -0,0 +1,99 @@ +from pygments.token import Text, Token +import pytest + +from myst_nb import ansi_lexer + + +@pytest.mark.parametrize( + ("bold", "faint", "fg_color", "bg_color", "expected"), + ( + (False, False, False, False, Text), + (True, False, False, False, Token.Color.Bold), + (True, False, "Red", False, Token.Color.Bold.Red), + (True, False, "Red", "Blue", Token.Color.Bold.Red.BGBlue), + (True, True, "Red", "Blue", Token.Color.Bold.Faint.Red.BGBlue), + ), +) +def test_token_from_lexer_state(bold, faint, fg_color, bg_color, expected): + ret = ansi_lexer._token_from_lexer_state(bold, faint, fg_color, bg_color) + assert ret == expected + + +def _highlight(text): + return tuple(ansi_lexer.AnsiColorLexer().get_tokens(text)) + + +def test_plain_text(): + assert _highlight("hello world\n") == ((Text, "hello world\n"),) + + +def test_simple_colors(): + assert _highlight( + "plain text\n" + "\x1b[31mred text\n" + "\x1b[1;32mbold green text\n" + "\x1b[39mfg color turned off\n" + "\x1b[0mplain text after reset\n" + "\x1b[1mbold text\n" + "\x1b[43mbold from previous line with yellow bg\n" + "\x1b[49mbg color turned off\n" + "\x1b[2mfaint turned on\n" + "\x1b[22mbold turned off\n" + ) == ( + (Text, "plain text\n"), + (Token.Color.Red, "red text\n"), + (Token.Color.Bold.Green, "bold green text\n"), + (Token.Color.Bold, "fg color turned off\n"), + (Text, "plain text after reset\n"), + (Token.Color.Bold, "bold text\n"), + (Token.Color.Bold.BGYellow, "bold from previous line with yellow bg\n"), + (Token.Color.Bold, "bg color turned off\n"), + (Token.Color.Bold.Faint, "faint turned on\n"), + (Text, "bold turned off\n"), + ) + + +def test_highlight_empty_end_specifier(): + ret = _highlight("plain\x1b[31mred\x1b[mplain\n") + assert ret == ((Text, "plain"), (Token.Color.Red, "red"), (Text, "plain\n")) + + +def test_ignores_unrecognized_ansi_color_codes(): + """It should just strip and ignore any unrecognized color ANSI codes.""" + assert _highlight( + # unknown int code + "\x1b[99m" + "plain text\n" + # invalid non-int code + "\x1b[=m" + "plain text\n" + ) == ((Text, "plain text\n"), (Text, "plain text\n"),) + + +def test_ignores_valid_ansi_non_color_codes(): + """It should just strip and ignore any non-color ANSI codes. + + These include things like moving the cursor position, erasing lines, etc. + """ + assert _highlight( + # restore cursor position + "\x1b[u" + "plain " + # move cursor backwards 55 steps + "\x1b[55C" + "text\n" + ) == ( + # Ideally these would be just one token, but our regex isn't smart + # enough yet. + (Text, "plain "), + (Text, "text\n"), + ) + + +def test_ignores_completely_invalid_escapes(): + """It should strip and ignore invalid escapes. + + This shouldn't happen in valid ANSI text, but we could have an escape + followed by garbage. + """ + assert _highlight("plain \x1b[%text\n") == ((Text, "plain "), (Text, "%text\n"),) diff --git a/tests/test_execute/test_complex_outputs_unrun_auto.ipynb b/tests/test_execute/test_complex_outputs_unrun_auto.ipynb index 23c8384f..9d258516 100644 --- a/tests/test_execute/test_complex_outputs_unrun_auto.ipynb +++ b/tests/test_execute/test_complex_outputs_unrun_auto.ipynb @@ -4,12 +4,6 @@ "cell_type": "code", "execution_count": 1, "metadata": { - "execution": { - "iopub.execute_input": "2020-06-09T20:58:00.136549Z", - "iopub.status.busy": "2020-06-09T20:58:00.135499Z", - "iopub.status.idle": "2020-06-09T20:58:01.000390Z", - "shell.execute_reply": "2020-06-09T20:58:01.000658Z" - }, "init_cell": true, "slideshow": { "slide_type": "skip" @@ -164,12 +158,6 @@ "cell_type": "code", "execution_count": 2, "metadata": { - "execution": { - "iopub.execute_input": "2020-06-09T20:58:01.003529Z", - "iopub.status.busy": "2020-06-09T20:58:01.003122Z", - "iopub.status.idle": "2020-06-09T20:58:01.005552Z", - "shell.execute_reply": "2020-06-09T20:58:01.005184Z" - }, "ipub": { "text": { "format": { @@ -259,12 +247,6 @@ "cell_type": "code", "execution_count": 3, "metadata": { - "execution": { - "iopub.execute_input": "2020-06-09T20:58:01.010731Z", - "iopub.status.busy": "2020-06-09T20:58:01.010410Z", - "iopub.status.idle": "2020-06-09T20:58:01.021093Z", - "shell.execute_reply": "2020-06-09T20:58:01.020829Z" - }, "ipub": { "code": { "asfloat": true, @@ -378,12 +360,6 @@ "cell_type": "code", "execution_count": 4, "metadata": { - "execution": { - "iopub.execute_input": "2020-06-09T20:58:01.024117Z", - "iopub.status.busy": "2020-06-09T20:58:01.023659Z", - "iopub.status.idle": "2020-06-09T20:58:01.026242Z", - "shell.execute_reply": "2020-06-09T20:58:01.025992Z" - }, "ipub": { "equation": { "label": "eqn:example_ipy" @@ -424,12 +400,6 @@ "cell_type": "code", "execution_count": 5, "metadata": { - "execution": { - "iopub.execute_input": "2020-06-09T20:58:01.040077Z", - "iopub.status.busy": "2020-06-09T20:58:01.039754Z", - "iopub.status.idle": "2020-06-09T20:58:01.681565Z", - "shell.execute_reply": "2020-06-09T20:58:01.681305Z" - }, "ipub": { "code": { "asfloat": true, @@ -447,7 +417,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/latex": [ "$\\displaystyle \\left(\\sqrt{5} i\\right)^{\\alpha} \\left(\\frac{1}{2} - \\frac{2 \\sqrt{5} i}{5}\\right) + \\left(- \\sqrt{5} i\\right)^{\\alpha} \\left(\\frac{1}{2} + \\frac{2 \\sqrt{5} i}{5}\\right)$" ], @@ -460,7 +430,7 @@ "execution_count": 5, "metadata": { "filenames": { - "image/png": "/tmp/pytest-of-choldgraf/pytest-170/test_complex_outputs_unrun_nbc0/source/_build/jupyter_execute/complex_outputs_unrun_22_0.png" + "image/png": "/private/var/folders/t2/xbl15_3n4tsb1vr_ccmmtmbr0000gn/T/pytest-of-chrisjsewell/pytest-679/test_complex_outputs_unrun_aut0/source/_build/jupyter_execute/complex_outputs_unrun_22_0.png" } }, "output_type": "execute_result" @@ -485,14 +455,7 @@ { "cell_type": "code", "execution_count": 6, - "metadata": { - "execution": { - "iopub.execute_input": "2020-06-09T20:58:01.684186Z", - "iopub.status.busy": "2020-06-09T20:58:01.683879Z", - "iopub.status.idle": "2020-06-09T20:58:01.707915Z", - "shell.execute_reply": "2020-06-09T20:58:01.708169Z" - } - }, + "metadata": {}, "outputs": [ { "data": { @@ -513,6 +476,29 @@ "import ipywidgets as widgets\n", "widgets.Layout(model_id=\"1337h4x0R\")" ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "**_some_ markdown**" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import display, Markdown\n", + "display(Markdown('**_some_ markdown**'))" + ] } ], "metadata": { @@ -574,7 +560,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.3" + "version": "3.7.8" }, "latex_envs": { "LaTeX_envs_menu_present": true, diff --git a/tests/test_execute/test_complex_outputs_unrun_auto.xml b/tests/test_execute/test_complex_outputs_unrun_auto.xml index 57e402c2..a36063d8 100644 --- a/tests/test_execute/test_complex_outputs_unrun_auto.xml +++ b/tests/test_execute/test_complex_outputs_unrun_auto.xml @@ -155,4 +155,11 @@ widgets.Layout(model_id="1337h4x0R") + + + + from IPython.display import display, Markdown + display(Markdown('**_some_ markdown**')) + + diff --git a/tests/test_execute/test_complex_outputs_unrun_cache.ipynb b/tests/test_execute/test_complex_outputs_unrun_cache.ipynb index 3ed6820c..c5bbe655 100644 --- a/tests/test_execute/test_complex_outputs_unrun_cache.ipynb +++ b/tests/test_execute/test_complex_outputs_unrun_cache.ipynb @@ -417,7 +417,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/latex": [ "$\\displaystyle \\left(\\sqrt{5} i\\right)^{\\alpha} \\left(\\frac{1}{2} - \\frac{2 \\sqrt{5} i}{5}\\right) + \\left(- \\sqrt{5} i\\right)^{\\alpha} \\left(\\frac{1}{2} + \\frac{2 \\sqrt{5} i}{5}\\right)$" ], @@ -430,7 +430,7 @@ "execution_count": 5, "metadata": { "filenames": { - "image/png": "/tmp/pytest-of-choldgraf/pytest-173/test_complex_outputs_unrun0/source/_build/jupyter_execute/complex_outputs_unrun_22_0.png" + "image/png": "/private/var/folders/t2/xbl15_3n4tsb1vr_ccmmtmbr0000gn/T/pytest-of-chrisjsewell/pytest-679/test_complex_outputs_unrun_cac0/source/_build/jupyter_execute/complex_outputs_unrun_22_0.png" } }, "output_type": "execute_result" @@ -476,6 +476,29 @@ "import ipywidgets as widgets\n", "widgets.Layout(model_id=\"1337h4x0R\")" ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "**_some_ markdown**" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import display, Markdown\n", + "display(Markdown('**_some_ markdown**'))" + ] } ], "metadata": { @@ -537,7 +560,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.3" + "version": "3.7.8" }, "latex_envs": { "LaTeX_envs_menu_present": true, diff --git a/tests/test_execute/test_complex_outputs_unrun_cache.xml b/tests/test_execute/test_complex_outputs_unrun_cache.xml index 37e711e2..820413ca 100644 --- a/tests/test_execute/test_complex_outputs_unrun_cache.xml +++ b/tests/test_execute/test_complex_outputs_unrun_cache.xml @@ -155,4 +155,11 @@ widgets.Layout(model_id="1337h4x0R") + + + + from IPython.display import display, Markdown + display(Markdown('**_some_ markdown**')) + + diff --git a/tests/test_glue.py b/tests/test_glue.py index 1b8128f2..bb856f36 100644 --- a/tests/test_glue.py +++ b/tests/test_glue.py @@ -1,11 +1,12 @@ import pytest from IPython.core.interactiveshell import InteractiveShell from IPython.core.displaypub import DisplayPublisher -from docutils.transforms import Transformer -from myst_nb.nb_glue import glue, transform, utils +from myst_nb.nb_glue import glue, utils from myst_nb.nb_glue.domain import NbGlueDomain -from myst_nb.transform import CellOutputsToNodes + +from myst_nb.render_outputs import CellOutputsToNodes +from myst_nb.nb_glue.transform import PasteNodesToDocutils class MockDisplayPublisher(DisplayPublisher): @@ -26,6 +27,11 @@ def mock_ipython(): InteractiveShell.clear_instance() +def test_check_priority(): + """Assert that the default transform priority is less than CellOutputsToNodes""" + assert PasteNodesToDocutils.default_priority < CellOutputsToNodes.default_priority + + def test_glue_func_text(mock_ipython): glue("a", "b") assert mock_ipython.publish_calls == [ @@ -104,11 +110,8 @@ def test_parser(sphinx_run, file_regression): sphinx_run.build() # print(sphinx_run.status()) assert sphinx_run.warnings() == "" - document = sphinx_run.get_doctree() - transformer = Transformer(document) - transformer.add_transforms([CellOutputsToNodes, transform.PasteNodesToDocutils]) - transformer.apply_transforms() - file_regression.check(document.pformat(), extension=".xml") + doctree = sphinx_run.get_resolved_doctree("with_glue") + file_regression.check(doctree.pformat(), extension=".xml") glue_domain = NbGlueDomain.from_env(sphinx_run.app.env) assert set(glue_domain.cache) == { "key_text1", diff --git a/tests/test_glue/test_parser.xml b/tests/test_glue/test_parser.xml index 9a8d1141..b95d8c23 100644 --- a/tests/test_glue/test_parser.xml +++ b/tests/test_glue/test_parser.xml @@ -4,26 +4,26 @@ Glue Tests - + from myst_nb import glue - + glue("key_text1", "text1") glue("key_float", 3.14159) - + 'text1' - + 3.14159 - + glue("key_undisplayed", "undisplayed", display=False) - + import pandas as pd df = pd.DataFrame({"header": [1, 2, 3]}) glue("key_df", df) @@ -68,7 +68,7 @@
- + import matplotlib.pyplot as plt plt.plot([1, 2, 3]) glue("key_plt", plt.gcf(), display=False) @@ -154,7 +154,7 @@ Math - + import sympy as sym f = sym.Function('f') y = sym.Function('y') diff --git a/tests/test_nb_render.py b/tests/test_nb_render.py index 06b6b754..98e4c475 100644 --- a/tests/test_nb_render.py +++ b/tests/test_nb_render.py @@ -22,7 +22,7 @@ def test_render(line, title, input, expected): dct = yaml.safe_load(input) dct.setdefault("metadata", {}) ntbk = nbformat.from_dict(dct) - md, env, tokens = nb_to_tokens(ntbk, MdParserConfig()) + md, env, tokens = nb_to_tokens(ntbk, MdParserConfig(), "default") document = make_document() with mock_sphinx_env(document=document): tokens_to_docutils(md, env, tokens, document) @@ -40,7 +40,7 @@ def test_reporting(line, title, input, expected): dct = yaml.safe_load(input) dct.setdefault("metadata", {}) ntbk = nbformat.from_dict(dct) - md, env, tokens = nb_to_tokens(ntbk, MdParserConfig()) + md, env, tokens = nb_to_tokens(ntbk, MdParserConfig(), "default") document = make_document("source/path") messages = [] diff --git a/tests/test_parser.py b/tests/test_parser.py index b5b37a91..e2d09d8a 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -78,5 +78,7 @@ def test_toctree_in_ipynb(sphinx_run, file_regression): sphinx_run.build() print(sphinx_run.status()) print(sphinx_run.warnings()) - file_regression.check(sphinx_run.get_doctree(1).pformat(), extension=".xml") + file_regression.check( + sphinx_run.get_doctree("latex_build/other").pformat(), extension=".xml" + ) assert sphinx_run.warnings() == "" diff --git a/tests/test_parser/test_complex_outputs.xml b/tests/test_parser/test_complex_outputs.xml index a5f0b43d..577e65dc 100644 --- a/tests/test_parser/test_complex_outputs.xml +++ b/tests/test_parser/test_complex_outputs.xml @@ -156,3 +156,10 @@ sym.rsolve(f,y(n),[1,4]) + + + + from IPython.display import display, Markdown + display(Markdown('**_some_ markdown**')) + + diff --git a/tests/test_render_outputs.py b/tests/test_render_outputs.py new file mode 100644 index 00000000..0f51887e --- /dev/null +++ b/tests/test_render_outputs.py @@ -0,0 +1,71 @@ +from unittest.mock import patch + +from importlib_metadata import EntryPoint +import pytest + +from myst_nb.render_outputs import load_renderer, MystNbEntryPointError + + +def test_load_renderer_not_found(): + with pytest.raises(MystNbEntryPointError): + load_renderer("other") + + +@patch.object(EntryPoint, "load", lambda self: EntryPoint) +def test_load_renderer_not_subclass(): + with pytest.raises(MystNbEntryPointError): + load_renderer("default") + + +@pytest.mark.sphinx_params("basic_run.ipynb", conf={"jupyter_execute_notebooks": "off"}) +def test_basic_run(sphinx_run, file_regression): + sphinx_run.build() + assert sphinx_run.warnings() == "" + doctree = sphinx_run.get_resolved_doctree("basic_run") + file_regression.check(doctree.pformat(), extension=".xml") + + +@pytest.mark.sphinx_params( + "complex_outputs.ipynb", conf={"jupyter_execute_notebooks": "off"} +) +def test_complex_outputs(sphinx_run, file_regression): + sphinx_run.build() + assert sphinx_run.warnings() == "" + doctree = sphinx_run.get_resolved_doctree("complex_outputs") + file_regression.check(doctree.pformat().replace(".jpeg", ".jpg"), extension=".xml") + + +@pytest.mark.sphinx_params( + "complex_outputs.ipynb", + conf={"jupyter_execute_notebooks": "off"}, + buildername="latex", +) +def test_complex_outputs_latex(sphinx_run, file_regression): + sphinx_run.build() + assert sphinx_run.warnings() == "" + doctree = sphinx_run.get_resolved_doctree("complex_outputs") + file_regression.check(doctree.pformat().replace(".jpeg", ".jpg"), extension=".xml") + + +@pytest.mark.sphinx_params( + "metadata_image.ipynb", conf={"jupyter_execute_notebooks": "off"}, +) +def test_metadata_image(sphinx_run, file_regression): + sphinx_run.build() + assert sphinx_run.warnings() == "" + doctree = sphinx_run.get_resolved_doctree("metadata_image") + file_regression.check(doctree.pformat().replace(".jpeg", ".jpg"), extension=".xml") + + +# @pytest.mark.sphinx_params( +# "unknown_mimetype.ipynb", conf={"jupyter_execute_notebooks": "off"} +# ) +# def test_unknown_mimetype(sphinx_run, file_regression): +# sphinx_run.build() +# warning = ( +# "unknown_mimetype.ipynb.rst:10002: WARNING: MyST-NB: " +# "output contains no MIME type in priority list" +# ) +# assert warning in sphinx_run.warnings() +# doctree = sphinx_run.get_resolved_doctree("unknown_mimetype") +# file_regression.check(doctree.pformat(), extension=".xml") diff --git a/tests/test_transform/test_basic_run.xml b/tests/test_render_outputs/test_basic_run.xml similarity index 76% rename from tests/test_transform/test_basic_run.xml rename to tests/test_render_outputs/test_basic_run.xml index 2e63236b..d6523606 100644 --- a/tests/test_transform/test_basic_run.xml +++ b/tests/test_render_outputs/test_basic_run.xml @@ -6,9 +6,9 @@ some text - + a=1 print(a) - + 1 diff --git a/tests/test_transform/test_complex_outputs.xml b/tests/test_render_outputs/test_complex_outputs.xml similarity index 87% rename from tests/test_transform/test_complex_outputs.xml rename to tests/test_render_outputs/test_complex_outputs.xml index f961e838..384f7a65 100644 --- a/tests/test_transform/test_complex_outputs.xml +++ b/tests/test_render_outputs/test_complex_outputs.xml @@ -1,7 +1,7 @@ - + import matplotlib.pyplot as plt import pandas as pd pd.set_option('display.latex.repr', True) @@ -89,13 +89,13 @@ Text Output - + print(""" This is some printed text, with a nicely formatted output. """) - + This is some printed text, with a nicely formatted output. @@ -105,7 +105,7 @@ Images and Figures - + Image('example.jpg',height=400) @@ -118,7 +118,7 @@ The plotting code for a matplotlib figure (\cref{fig:example_mpl}). - + plt.scatter(np.random.rand(10), np.random.rand(10), label='data label') plt.ylabel(r'a y label with latex $\alpha$') @@ -132,7 +132,7 @@ The plotting code for a pandas Dataframe table (\cref{tbl:example}). - + df = pd.DataFrame(np.random.rand(3,4),columns=['a','b','c','d']) df.a = ['$\delta$','x','y'] df.b = ['l','m','n'] @@ -194,7 +194,7 @@ Equations (with ipython or sympy) - + Latex('$$ a = b+c $$') @@ -203,10 +203,21 @@ The plotting code for a sympy equation (=@eqn:example_sympy). - + y = sym.Function('y') n = sym.symbols(r'\alpha') f = y(n)-2*y(n-1/sym.pi)-5*y(n-2) sym.rsolve(f,y(n),[1,4]) + + + + from IPython.display import display, Markdown + display(Markdown('**_some_ markdown**')) + + + + + some + markdown diff --git a/tests/test_transform/test_complex_outputs_latex.xml b/tests/test_render_outputs/test_complex_outputs_latex.xml similarity index 85% rename from tests/test_transform/test_complex_outputs_latex.xml rename to tests/test_render_outputs/test_complex_outputs_latex.xml index fd348d39..b15aaa00 100644 --- a/tests/test_transform/test_complex_outputs_latex.xml +++ b/tests/test_render_outputs/test_complex_outputs_latex.xml @@ -1,7 +1,7 @@ - + import matplotlib.pyplot as plt import pandas as pd pd.set_option('display.latex.repr', True) @@ -89,13 +89,13 @@ Text Output - + print(""" This is some printed text, with a nicely formatted output. """) - + This is some printed text, with a nicely formatted output. @@ -105,7 +105,7 @@ Images and Figures - + Image('example.jpg',height=400) @@ -118,7 +118,7 @@ The plotting code for a matplotlib figure (\cref{fig:example_mpl}). - + plt.scatter(np.random.rand(10), np.random.rand(10), label='data label') plt.ylabel(r'a y label with latex $\alpha$') @@ -132,7 +132,7 @@ The plotting code for a pandas Dataframe table (\cref{tbl:example}). - + df = pd.DataFrame(np.random.rand(3,4),columns=['a','b','c','d']) df.a = ['$\delta$','x','y'] df.b = ['l','m','n'] @@ -154,7 +154,7 @@ Equations (with ipython or sympy) - + Latex('$$ a = b+c $$') @@ -163,10 +163,21 @@ The plotting code for a sympy equation (=@eqn:example_sympy). - + y = sym.Function('y') n = sym.symbols(r'\alpha') f = y(n)-2*y(n-1/sym.pi)-5*y(n-2) sym.rsolve(f,y(n),[1,4]) + + + + from IPython.display import display, Markdown + display(Markdown('**_some_ markdown**')) + + + + + some + markdown diff --git a/tests/test_render_outputs/test_metadata_image.xml b/tests/test_render_outputs/test_metadata_image.xml new file mode 100644 index 00000000..7a7147aa --- /dev/null +++ b/tests/test_render_outputs/test_metadata_image.xml @@ -0,0 +1,23 @@ + +
+ + Formatting code outputs + <CellNode cell_type="code" classes="cell"> + <CellInputNode classes="cell_input"> + <literal_block language="ipython3" linenos="False" xml:space="preserve"> + from IPython.display import Image + Image("fun-fish.png") + <CellOutputNode classes="cell_output"> + <figure ids="fun-fish" names="fun-fish"> + <image alt="fun-fish" candidates="{'*': '_build/jupyter_execute/metadata_image_1_0.png'}" classes="shadow bg-primary" uri="_build/jupyter_execute/metadata_image_1_0.png" width="300px"> + <caption> + <paragraph> + Hey everyone its + <strong> + party + time! + <paragraph> + Link: + <reference internal="True" refid="fun-fish"> + <inline classes="std std-ref"> + swim to the fish diff --git a/tests/test_render_outputs/test_unknown_mimetype.xml b/tests/test_render_outputs/test_unknown_mimetype.xml new file mode 100644 index 00000000..1064a756 --- /dev/null +++ b/tests/test_render_outputs/test_unknown_mimetype.xml @@ -0,0 +1,7 @@ +<document source="unknown_mimetype"> + <CellNode cell_type="code" classes="cell"> + <CellInputNode classes="cell_input"> + <literal_block language="ipython3" linenos="False" xml:space="preserve"> + a=1 + print(a) + <CellOutputNode classes="cell_output"> diff --git a/tests/test_transform.py b/tests/test_transform.py deleted file mode 100644 index 5f5ec414..00000000 --- a/tests/test_transform.py +++ /dev/null @@ -1,39 +0,0 @@ -import pytest - -from myst_nb.transform import CellOutputsToNodes - - -@pytest.mark.sphinx_params("basic_run.ipynb", conf={"jupyter_execute_notebooks": "off"}) -def test_basic_run(sphinx_run, file_regression): - sphinx_run.build() - assert sphinx_run.warnings() == "" - document = sphinx_run.get_doctree() - transform = CellOutputsToNodes(document) - transform.apply() - file_regression.check(document.pformat(), extension=".xml") - - -@pytest.mark.sphinx_params( - "complex_outputs.ipynb", conf={"jupyter_execute_notebooks": "off"} -) -def test_complex_outputs(sphinx_run, file_regression): - sphinx_run.build() - assert sphinx_run.warnings() == "" - document = sphinx_run.get_doctree() - transform = CellOutputsToNodes(document) - transform.apply() - file_regression.check(document.pformat().replace(".jpeg", ".jpg"), extension=".xml") - - -@pytest.mark.sphinx_params( - "complex_outputs.ipynb", - conf={"jupyter_execute_notebooks": "off"}, - buildername="latex", -) -def test_complex_outputs_latex(sphinx_run, file_regression): - sphinx_run.build() - assert sphinx_run.warnings() == "" - document = sphinx_run.get_doctree() - transform = CellOutputsToNodes(document) - transform.apply() - file_regression.check(document.pformat().replace(".jpeg", ".jpg"), extension=".xml")