diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index b5174d5e..dafab884 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -26,15 +26,15 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
- python-version: ["3.8", "3.9", "3.10"]
- sphinx: [">=5,<6"]
+ python-version: ["3.8", "3.9", "3.10", "3.11"]
+ sphinx: ["~=5.0","~=6.0","~=7.0"]
include:
- os: windows-latest
python-version: 3.9
- sphinx: ">=5,<6"
+ sphinx: "~=5.0"
- os: macos-latest
python-version: 3.9
- sphinx: ">=5,<6"
+ sphinx: "~=5.0"
runs-on: ${{ matrix.os }}
@@ -44,10 +44,29 @@ jobs:
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
+ cache: pip
+ - name: Install myst-nb with Sphinx ${{ matrix.sphinx }}
+ run: |
+ pip install --upgrade pip
+ pip install --upgrade "Sphinx${{ matrix.sphinx }}" -e .[testing]
+
+ - name: Run pytest
+ run: pytest --durations=10
+
+ coverage:
+ needs: [tests]
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v4
+ with:
+ python-version: 3.11
+ cache: pip
- name: Install dependencies
run: |
- python -m pip install --upgrade pip
- pip install "sphinx${{ matrix.sphinx }}"
+ pip install --upgrade pip
pip install -e .[testing]
- name: Run pytest
@@ -59,13 +78,11 @@ jobs:
# this is why we run `coverage xml` afterwards (required by codecov)
- name: Upload to Codecov
- if: github.repository == 'executablebooks/MyST-NB' && matrix.python-version == '3.9' && matrix.os == 'ubuntu-latest'
uses: codecov/codecov-action@v3
with:
name: myst-nb-pytests
flags: pytests
files: ./coverage.xml
- fail_ci_if_error: true
publish:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7896a9fc..fc8cabfb 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -20,7 +20,7 @@ repos:
- id: trailing-whitespace
- repo: https://github.com/asottile/pyupgrade
- rev: v3.3.2
+ rev: v3.7.0
hooks:
- id: pyupgrade
args: [--py37-plus]
@@ -42,13 +42,13 @@ repos:
additional_dependencies: [flake8-bugbear]
- repo: https://github.com/pre-commit/mirrors-mypy
- rev: v1.2.0
+ rev: v1.4.1
hooks:
- id: mypy
args: [--config-file=pyproject.toml]
additional_dependencies:
- importlib_metadata
- - myst-parser~=0.18.0
+ - myst-parser~=1.0.0
- "sphinx~=5.0"
- nbclient
- types-PyYAML
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d0191248..0699e778 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -92,7 +92,7 @@ WARNING: 'jupyter_execute_notebooks' is deprecated for 'nb_execution_mode' [myst
`nb_render_priority` has been removed and replaced by `nb_mime_priority_overrides`, which has a different format and is more flexible. See [Outputs MIME priority](docs/render/format_code_cells.md) for more information.
-As per the changes in [`myst_parser`](myst:develop/_changelog), the `dollarmath` syntax extension is no longer included by default.
+As per the changes in [`myst_parser`](inv:myst#develop/_changelog), the `dollarmath` syntax extension is no longer included by default.
To re-add this extension, ensure that it is specified in your `conf.py`: `myst_enable_extensions = ["dollarmath"]`.
For cell-level configuration the top-level key `render` has now been deprecated for `mystnb`.
@@ -168,7 +168,7 @@ See [Embedding outputs as variables](docs/render/glue.md) for more details.
- `nbconvert`
- Updated:
- `Python`: `3.6+ -> 3.7+`
- - `myst_parser`: [`0.15 -> 0.17`](myst:develop/_changelog)
+ - `myst_parser`: [`0.15 -> 0.17`](inv:myst#develop/_changelog)
- `jupyter-cache`: [`0.4 -> 0.5`](https://github.com/executablebooks/jupyter-cache/blob/master/CHANGELOG.md)
- `sphinx-togglebutton`: [`0.1 -> 0.3`](https://sphinx-togglebutton.readthedocs.io/en/latest/changelog.html)
diff --git a/docs/authoring/custom-formats.Rmd b/docs/authoring/custom-formats.Rmd
index c682702c..7575d250 100644
--- a/docs/authoring/custom-formats.Rmd
+++ b/docs/authoring/custom-formats.Rmd
@@ -21,7 +21,7 @@ nb_custom_formats = {
```
- The string should be a Python function that will be loaded by `import mylibrary.converter_function`
-- The function should take a file's contents (as a `str`) and return an [nbformat.NotebookNode](nbformat:api)
+- The function should take a file's contents (as a `str`) and return an [nbformat.NotebookNode](inv:nbformat#api)
If the function takes additional keyword arguments, then you can specify these as dictionary in a second argument.
For example this is what the default conversion would look like:
diff --git a/docs/authoring/jupyter-notebooks.md b/docs/authoring/jupyter-notebooks.md
index 945ab336..58b1f71a 100644
--- a/docs/authoring/jupyter-notebooks.md
+++ b/docs/authoring/jupyter-notebooks.md
@@ -16,13 +16,13 @@ Sphinx using the MyST parser.[^download]
:::{seealso}
For more information about what you can write with MyST Markdown, see the
-[MyST Parser documentation](myst:intro/get-started).
+[MyST Parser documentation](inv:myst#intro/get-started).
:::
### Configuration
-The MyST-NB parser derives from [the base MyST-Parser](myst:intro/get-started), and so all the same configuration options are available.
-See the [MyST configuration options](myst:sphinx/config-options) for the full set of options, and [MyST syntax guide](myst:syntax/core) for all the syntax options.
+The MyST-NB parser derives from [the base MyST-Parser](inv:myst#intro/get-started), and so all the same configuration options are available.
+See the [MyST configuration options](inv:myst#sphinx/config-options) for the full set of options, and [MyST syntax guide](inv:myst#syntax/core) for all the syntax options.
To build documentation from this notebook, the following options are set:
@@ -38,7 +38,7 @@ myst_url_schemes = ("http", "https", "mailto")
```
:::{note}
-Loading the `myst_nb` extension also activates the [`myst_parser`](myst:index) extension, for enabling the MyST flavour of Markdown.
+Loading the `myst_nb` extension also activates the [`myst_parser`](inv:myst#index) extension, for enabling the MyST flavour of Markdown.
It is not required to add this explicitly in the list of `extensions`.
:::
@@ -53,7 +53,7 @@ For example, here's the MyST-NB logo:
![myst-nb logo](../_static/logo-wide.svg)
-By adding `"html_image"` to the `myst_enable_extensions` list in the sphinx configuration ([see here](myst:syntax/images)), you can even add HTML `img` tags with attributes:
+By adding `"html_image"` to the `myst_enable_extensions` list in the sphinx configuration ([see here](inv:myst#syntax/images)), you can even add HTML `img` tags with attributes:
```html
@@ -66,7 +66,7 @@ For example, here's a note admonition block:
:::::{note}
**Wow**, a note!
-It was generated with this code ([as explained here](myst:syntax/admonitions)):
+It was generated with this code ([as explained here](inv:myst:std:label#syntax/admonitions)):
````md
:::{note}
@@ -77,7 +77,7 @@ It was generated with this code ([as explained here](myst:syntax/admonitions)):
:::::
If you wish to use "bare" LaTeX equations, then you should add `"amsmath"` to the `myst_enable_extensions` list in the sphinx configuration.
-This is [explained here](myst:syntax/amsmath), and works as such:
+This is [explained here](inv:myst:std:label#syntax/amsmath), and works as such:
```latex
\begin{equation}
@@ -110,7 +110,7 @@ $$e^{i\pi} + 1 = 0$$ (euler)
Euler's identity, equation {math:numref}`euler`, was elected one of the
most beautiful mathematical formulas.
-You can see the syntax used for this example [here in the MyST documentation](myst:syntax/math).
+You can see the syntax used for this example [here in the MyST documentation](inv:myst:std:label#syntax/math).
## Code cells and outputs
diff --git a/docs/index.md b/docs/index.md
index 06fef4a1..d75b9260 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -86,7 +86,7 @@ Build single or collections of documents into multiple formats (HTML, PDF, ...).
MyST-NB is a module within the [Executable Books Project](https://executablebooks.org),
an international collaboration to build open source tools that facilitate publishing computational narratives using the Jupyter ecosystem.
-It is also a core component of [Jupyter Book](jb:intro).
+It is also a core component of [Jupyter Book](inv:jb#intro).
Check out the [Gallery of Jupyter Books](https://executablebooks.org/en/latest/gallery),
for inspiration from across the community.
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 822d882b..013a5bc0 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,2 +1,2 @@
# this is only required by coconut kernel
-ipython<=7.11.0
+ipython<=8.14.0
diff --git a/myst_nb/__init__.py b/myst_nb/__init__.py
index 7fd25d88..8b156d3a 100644
--- a/myst_nb/__init__.py
+++ b/myst_nb/__init__.py
@@ -1,5 +1,5 @@
"""A docutils/sphinx parser for Jupyter Notebooks."""
-__version__ = "0.17.2"
+__version__ = "0.18.0"
def setup(app):
diff --git a/myst_nb/core/config.py b/myst_nb/core/config.py
index 1d69465a..3bf97e83 100644
--- a/myst_nb/core/config.py
+++ b/myst_nb/core/config.py
@@ -1,6 +1,7 @@
"""Configuration for myst-nb."""
import dataclasses as dc
from enum import Enum
+import sys
from typing import Any, Callable, Dict, Iterable, Optional, Sequence, Tuple
from myst_parser.config.dc_validators import (
@@ -12,7 +13,13 @@
optional,
validate_fields,
)
-from typing_extensions import Literal
+
+if sys.version_info >= (3, 8):
+ from typing import Literal
+else:
+ from typing_extensions import Literal # noqa: F401
+
+from myst_nb.warnings_ import MystNBWarnings
def custom_formats_converter(value: dict) -> Dict[str, Tuple[str, dict, bool]]:
@@ -130,7 +137,7 @@ def __post_init__(self):
default_factory=dict,
metadata={
"help": "Custom formats for reading notebook; suffix -> reader",
- "docutils_exclude": True,
+ "omit": ["docutils"],
"sections": (Section.global_lvl, Section.read),
},
)
@@ -184,10 +191,18 @@ def __post_init__(self):
"validator": deep_mapping(instance_of(str), instance_of(str)),
"help": "Mapping of kernel name regex to replacement kernel name"
"(applied before execution)",
- "docutils_exclude": True,
+ "omit": ["docutils"],
"sections": (Section.global_lvl, Section.execute),
},
)
+ eval_name_regex: str = dc.field(
+ default=r"^[a-zA-Z_][a-zA-Z0-9_]*$",
+ metadata={
+ "validator": instance_of(str),
+ "help": "Regex that matches permitted values of eval expressions",
+ "sections": (Section.global_lvl, Section.file_lvl, Section.execute),
+ },
+ )
execution_mode: Literal["off", "force", "auto", "cache", "inline"] = dc.field(
default="auto",
metadata={
@@ -220,7 +235,7 @@ def __post_init__(self):
"validator": deep_iterable(instance_of(str)),
"help": "Exclude (POSIX) glob patterns for notebooks",
"legacy_name": "execution_excludepatterns",
- "docutils_exclude": True,
+ "omit": ["docutils"],
"sections": (Section.global_lvl, Section.execute),
},
)
@@ -387,7 +402,7 @@ def __post_init__(self):
"help": "Overrides for the base render priority of mime types: "
"list of (builder name, mime type, priority)",
# TODO how to allow this in docutils?
- "docutils_exclude": True,
+ "omit": ["docutils"],
"sections": (Section.global_lvl, Section.file_lvl, Section.render),
},
repr=False,
@@ -454,7 +469,7 @@ def __post_init__(self):
metadata={
"validator": deep_mapping(instance_of(str), instance_of((str, int))),
"help": "Options for image outputs (class|alt|height|width|scale|align)",
- "docutils_exclude": True,
+ "omit": ["docutils"],
# TODO backward-compatible change to "image_options"?
"cell_key": "image",
"sections": (
@@ -471,7 +486,7 @@ def __post_init__(self):
metadata={
"validator": deep_mapping(instance_of(str), instance_of((str, int))),
"help": "Options for figure outputs (classes|name|caption|caption_before)",
- "docutils_exclude": True,
+ "omit": ["docutils"],
"cell_key": "figure",
"sections": (
Section.global_lvl,
@@ -505,7 +520,7 @@ def __post_init__(self):
instance_of(str), deep_mapping(instance_of(str), instance_of(str))
),
"help": "Javascript to be loaded on pages containing ipywidgets",
- "docutils_exclude": True,
+ "omit": ["docutils"],
"sections": (Section.global_lvl, Section.render),
},
repr=False,
@@ -567,7 +582,7 @@ def get_cell_level_config(
self,
field_name: str,
cell_metadata: Dict[str, Any],
- warning_callback: Callable[[str, str], Any],
+ warning_callback: Callable[[str, MystNBWarnings], Any],
) -> Any:
"""Get a configuration value at the cell level.
@@ -593,7 +608,7 @@ def get_cell_level_config(
warning_callback(
f"Deprecated `cell_metadata_key` 'render' "
f"found, replace with {self.cell_metadata_key!r}",
- "cell_metadata_key",
+ MystNBWarnings.CELL_METADATA_KEY,
)
cell_meta = cell_metadata["render"]
else:
@@ -611,7 +626,10 @@ def get_cell_level_config(
field.metadata["validator"](self, field, value)
return value
except Exception as exc:
- warning_callback(f"Cell metadata invalid: {exc}", "cell_config")
+ warning_callback(
+ f"Cell metadata invalid: {exc}",
+ MystNBWarnings.CELL_CONFIG,
+ )
# default/global/file level should have already been merged
return getattr(self, field.name)
diff --git a/myst_nb/core/execute/base.py b/myst_nb/core/execute/base.py
index edcfd03d..befb6d29 100644
--- a/myst_nb/core/execute/base.py
+++ b/myst_nb/core/execute/base.py
@@ -2,7 +2,6 @@
from __future__ import annotations
from pathlib import Path
-import re
from typing import Any
from nbformat import NotebookNode
@@ -39,9 +38,6 @@ class EvalNameError(Exception):
"""An exception for if an evaluation variable name is invalid."""
-EVAL_NAME_REGEX = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$")
-
-
class NotebookClientBase:
"""A base client for interacting with Jupyter notebooks.
diff --git a/myst_nb/core/execute/inline.py b/myst_nb/core/execute/inline.py
index 06b53b07..13d20786 100644
--- a/myst_nb/core/execute/inline.py
+++ b/myst_nb/core/execute/inline.py
@@ -3,6 +3,7 @@
import asyncio
from datetime import datetime
+import re
import shutil
from tempfile import mkdtemp
import time
@@ -22,7 +23,7 @@
from myst_nb.ext.glue import extract_glue_data_cell
-from .base import EVAL_NAME_REGEX, EvalNameError, ExecutionError, NotebookClientBase
+from .base import EvalNameError, ExecutionError, NotebookClientBase
class NotebookClientInline(NotebookClientBase):
@@ -148,7 +149,7 @@ def code_cell_outputs(
return cell.get("execution_count", None), cell.get("outputs", [])
def eval_variable(self, name: str) -> list[NotebookNode]:
- if not EVAL_NAME_REGEX.match(name):
+ if not re.match(self.nb_config.eval_name_regex, name):
raise EvalNameError(name)
return self._client.eval_expression(name)
diff --git a/myst_nb/core/read.py b/myst_nb/core/read.py
index ad011049..2b3dae4b 100644
--- a/myst_nb/core/read.py
+++ b/myst_nb/core/read.py
@@ -312,25 +312,22 @@ class _MockDirective:
def _read_fenced_cell(token, cell_index, cell_type):
- from myst_parser.parsers.directives import (
- DirectiveParsingError,
- parse_directive_text,
- )
+ from myst_parser.parsers.directives import parse_directive_text
- try:
- _, options, body_lines, _ = parse_directive_text(
- directive_class=_MockDirective,
- first_line="",
- content=token.content,
- validate_options=False,
- )
- except DirectiveParsingError as err:
+ result = parse_directive_text(
+ directive_class=_MockDirective,
+ first_line="",
+ content=token.content,
+ validate_options=False,
+ )
+ if result.warnings:
raise MystMetadataParsingError(
"{} cell {} at line {} could not be read: {}".format(
- cell_type, cell_index, token.map[0] + 1, err
+ cell_type, cell_index, token.map[0] + 1, result.warnings[0]
)
)
- return options, body_lines
+
+ return result.options, result.body
def _read_cell_metadata(token, cell_index):
diff --git a/myst_nb/core/render.py b/myst_nb/core/render.py
index e28b856b..54f1762d 100644
--- a/myst_nb/core/render.py
+++ b/myst_nb/core/render.py
@@ -28,8 +28,9 @@
from myst_nb.core.config import NbParserConfig
from myst_nb.core.execute import NotebookClientBase
-from myst_nb.core.loggers import DEFAULT_LOG_TYPE, LoggerType
+from myst_nb.core.loggers import LoggerType # DEFAULT_LOG_TYPE,
from myst_nb.core.utils import coalesce_streams
+from myst_nb.warnings_ import MystNBWarnings, create_warning
if TYPE_CHECKING:
from markdown_it.tree import SyntaxTreeNode
@@ -57,7 +58,6 @@ class MditRenderMixin:
# required by mypy
md_options: dict[str, Any]
document: nodes.document
- create_warning: Any
render_children: Any
add_line_and_source_path: Any
add_line_and_source_path_r: Any
@@ -95,8 +95,8 @@ def get_cell_level_config(
:param cell_metadata: the metadata for the cell
"""
- def _callback(msg: str, subtype: str):
- self.create_warning(msg, line=line, subtype=subtype)
+ def _callback(msg: str, subtype: MystNBWarnings):
+ create_warning(self.document, msg, line=line, subtype=subtype)
return self.nb_config.get_cell_level_config(field, cell_metadata, _callback)
@@ -222,10 +222,11 @@ def _get_nb_source_code_lexer(
# TODO this will create a warning for every cell, but perhaps
# it should only be a single warning for the notebook (as previously)
# TODO allow user to set default lexer?
- self.create_warning(
+ create_warning(
+ self.document,
f"No source code lexer found for notebook cell {cell_index + 1}",
- wtype=DEFAULT_LOG_TYPE,
- subtype="lexer",
+ # wtype=DEFAULT_LOG_TYPE,
+ subtype=MystNBWarnings.LEXER,
line=line,
append_to=self.current_node,
)
@@ -310,11 +311,6 @@ class MimeData:
"""Index of the output in the cell"""
line: int | None = None
"""Source line of the cell"""
- md_headings: bool = False
- """Whether to render headings in text/markdown blocks."""
- # we can only do this if know the content will be rendered into the main body
- # of the document, e.g. not inside a container node
- # (otherwise it will break the structure of the AST)
@property
def string(self) -> str:
@@ -598,9 +594,7 @@ def render_markdown(self, data: MimeData) -> list[nodes.Element]:
fmt = self.renderer.get_cell_level_config(
"render_markdown_format", data.cell_metadata, line=data.line
)
- return self._render_markdown_base(
- data, fmt=fmt, inline=False, allow_headings=data.md_headings
- )
+ return self._render_markdown_base(data, fmt=fmt, inline=False)
def render_text_plain(self, data: MimeData) -> list[nodes.Element]:
"""Render a notebook text/plain mime data output."""
@@ -753,9 +747,7 @@ def render_markdown_inline(self, data: MimeData) -> list[nodes.Element]:
fmt = self.renderer.get_cell_level_config(
"render_markdown_format", data.cell_metadata, line=data.line
)
- return self._render_markdown_base(
- data, fmt=fmt, inline=True, allow_headings=data.md_headings
- )
+ return self._render_markdown_base(data, fmt=fmt, inline=True)
def render_text_plain_inline(self, data: MimeData) -> list[nodes.Element]:
"""Render a notebook text/plain mime data output."""
@@ -796,7 +788,7 @@ def render_widget_view_inline(self, data: MimeData) -> list[nodes.Element]:
return self.render_widget_view(data)
def _render_markdown_base(
- self, data: MimeData, *, fmt: str, inline: bool, allow_headings: bool
+ self, data: MimeData, *, fmt: str, inline: bool
) -> list[nodes.Element]:
"""Base render for a notebook markdown mime output (block or inline)."""
psuedo_element = nodes.Element() # element to hold the parsed markdown
@@ -832,7 +824,6 @@ def _render_markdown_base(
data.string,
data.line or 0,
inline=inline,
- allow_headings=allow_headings,
)
finally:
# restore the parser
@@ -986,11 +977,12 @@ def create_figure_context(
caption.source = self.document["source"]
caption.line = line
elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0):
- self.create_warning(
+ create_warning(
+ self.document,
"Figure caption must be a paragraph or empty comment.",
line=line,
- wtype=DEFAULT_LOG_TYPE,
- subtype="fig_caption",
+ # wtype=DEFAULT_LOG_TYPE,
+ subtype=MystNBWarnings.FIG_CAPTION,
)
self.current_node.append(figure_node)
diff --git a/myst_nb/docutils_.py b/myst_nb/docutils_.py
index 9738a0f0..7da9c6db 100644
--- a/myst_nb/docutils_.py
+++ b/myst_nb/docutils_.py
@@ -14,14 +14,7 @@
from markdown_it.token import Token
from markdown_it.tree import SyntaxTreeNode
from myst_parser.config.main import MdParserConfig, merge_file_level
-from myst_parser.mdit_to_docutils.base import (
- DocutilsRenderer,
- create_warning,
- token_line,
-)
-from myst_parser.parsers.docutils_ import (
- DOCUTILS_EXCLUDED_ARGS as DOCUTILS_EXCLUDED_ARGS_MYST,
-)
+from myst_parser.mdit_to_docutils.base import DocutilsRenderer, token_line
from myst_parser.parsers.docutils_ import Parser as MystParser
from myst_parser.parsers.docutils_ import create_myst_config, create_myst_settings_spec
from myst_parser.parsers.mdit import create_md_parser
@@ -32,7 +25,7 @@
from myst_nb import static
from myst_nb.core.config import NbParserConfig
from myst_nb.core.execute import create_client
-from myst_nb.core.loggers import DEFAULT_LOG_TYPE, DocutilsDocLogger
+from myst_nb.core.loggers import DocutilsDocLogger # DEFAULT_LOG_TYPE,
from myst_nb.core.nb_to_tokens import nb_node_to_dict, notebook_to_tokens
from myst_nb.core.read import (
NbReader,
@@ -50,6 +43,7 @@
)
from myst_nb.ext.eval import load_eval_docutils
from myst_nb.ext.glue import load_glue_docutils
+from myst_nb.warnings_ import MystNBWarnings, create_warning
DOCUTILS_EXCLUDED_ARGS = list(
{f.name for f in NbParserConfig.get_fields() if f.metadata.get("docutils_exclude")}
@@ -81,7 +75,7 @@ class Parser(MystParser):
settings_spec = (
"MyST-NB options",
None,
- create_myst_settings_spec(DOCUTILS_EXCLUDED_ARGS, NbParserConfig, "nb_"),
+ create_myst_settings_spec(NbParserConfig, "nb_"),
*MystParser.settings_spec,
)
"""Runtime settings specification."""
@@ -116,18 +110,14 @@ def _parse(self, inputstring: str, document: nodes.document) -> None:
# get markdown parsing configuration
try:
- md_config = create_myst_config(
- document.settings, DOCUTILS_EXCLUDED_ARGS_MYST
- )
+ md_config = create_myst_config(document.settings)
except (TypeError, ValueError) as error:
logger.error(f"myst configuration invalid: {error.args[0]}")
md_config = MdParserConfig()
# get notebook rendering configuration
try:
- nb_config = create_myst_config(
- document.settings, DOCUTILS_EXCLUDED_ARGS, NbParserConfig, "nb_"
- )
+ nb_config = create_myst_config(document.settings, NbParserConfig, "nb_")
except (TypeError, ValueError) as error:
logger.error(f"myst-nb configuration invalid: {error.args[0]}")
nb_config = NbParserConfig()
@@ -310,13 +300,14 @@ def _render_nb_cell_code_outputs(
mime_type = next(x for x in mime_priority if x in output["data"])
except StopIteration:
if output["data"]:
- self.create_warning(
+ create_warning(
+ self.document,
"No output mime type found from render_priority "
f"(cell<{cell_index}>.output<{output_index}>",
line=line,
append_to=self.current_node,
- wtype=DEFAULT_LOG_TYPE,
- subtype="mime_type",
+ # wtype=DEFAULT_LOG_TYPE,
+ subtype=MystNBWarnings.MIME_TYPE,
)
else:
figure_options = (
@@ -341,12 +332,13 @@ def _render_nb_cell_code_outputs(
self.current_node.extend(_nodes)
self.add_line_and_source_path_r(_nodes, token)
else:
- self.create_warning(
+ create_warning(
+ self.document,
f"Unsupported output type: {output.output_type}",
line=line,
append_to=self.current_node,
- wtype=DEFAULT_LOG_TYPE,
- subtype="output_type",
+ # wtype=DEFAULT_LOG_TYPE,
+ subtype=MystNBWarnings.OUTPUT_TYPE,
)
diff --git a/myst_nb/ext/eval/__init__.py b/myst_nb/ext/eval/__init__.py
index 3b565c74..52c04cd2 100644
--- a/myst_nb/ext/eval/__init__.py
+++ b/myst_nb/ext/eval/__init__.py
@@ -43,11 +43,13 @@ def retrieve_eval_data(document: nodes.document, key: str) -> list[VariableOutpu
except NotImplementedError:
raise RetrievalError("This document does not have a running kernel")
except EvalNameError:
- raise RetrievalError(f"The variable {key!r} is not a valid name")
+ raise RetrievalError(
+ f"The expression {key!r} is not valid according to the configured pattern"
+ )
except Exception as exc:
raise RetrievalError(f"variable evaluation error: {exc}")
if not outputs:
- raise RetrievalError(f"variable {key!r} does not return any outputs")
+ raise RetrievalError(f"expression {key!r} does not return any outputs")
# the returned outputs could be one of the following:
# https://nbformat.readthedocs.io/en/latest/format_description.html#code-cell-outputs
diff --git a/myst_nb/ext/glue/directives.py b/myst_nb/ext/glue/directives.py
index fc63376c..4d42c15a 100644
--- a/myst_nb/ext/glue/directives.py
+++ b/myst_nb/ext/glue/directives.py
@@ -106,7 +106,6 @@ def run(self) -> List[nodes.Node]:
},
output_metadata=result.metadata,
line=self.line,
- md_headings=True,
)
_nodes = result.nb_renderer.render_markdown(mime)
self.set_source_info(_nodes)
diff --git a/myst_nb/sphinx_.py b/myst_nb/sphinx_.py
index 62bd9a7c..dba36531 100644
--- a/myst_nb/sphinx_.py
+++ b/myst_nb/sphinx_.py
@@ -13,7 +13,7 @@
from markdown_it.tree import SyntaxTreeNode
from myst_parser.config.main import MdParserConfig, merge_file_level
from myst_parser.mdit_to_docutils.base import token_line
-from myst_parser.mdit_to_docutils.sphinx_ import SphinxRenderer, create_warning
+from myst_parser.mdit_to_docutils.sphinx_ import SphinxRenderer
from myst_parser.parsers.mdit import create_md_parser
from myst_parser.parsers.sphinx_ import MystParser
import nbformat
@@ -38,6 +38,7 @@
get_mime_priority,
load_renderer,
)
+from myst_nb.warnings_ import MystNBWarnings, create_warning
SPHINX_LOGGER = sphinx_logging.getLogger(__name__)
@@ -301,12 +302,13 @@ def _render_nb_cell_code_outputs(
self.add_line_and_source_path_r([mime_bundle], token)
self.current_node.append(mime_bundle)
else:
- self.create_warning(
+ create_warning(
+ self.document,
f"Unsupported output type: {output.output_type}",
line=line,
append_to=self.current_node,
- wtype=DEFAULT_LOG_TYPE,
- subtype="output_type",
+ # wtype=DEFAULT_LOG_TYPE,
+ subtype=MystNBWarnings.OUTPUT_TYPE,
)
diff --git a/myst_nb/warnings_.py b/myst_nb/warnings_.py
new file mode 100644
index 00000000..de8e66ce
--- /dev/null
+++ b/myst_nb/warnings_.py
@@ -0,0 +1,103 @@
+"""Central handling of warnings for the myst-nb extension."""
+from __future__ import annotations
+
+from enum import Enum
+from typing import Sequence
+
+from docutils import nodes
+from myst_parser.warnings_ import MystWarnings
+from myst_parser.warnings_ import create_warning as myst_parser_create_warnings
+
+__all__ = [
+ "MystWarnings",
+ "MystNBWarnings",
+ "create_warning",
+]
+
+
+class MystNBWarnings(Enum):
+ """MySTNB warning types."""
+
+ LEXER = "lexer"
+ """Issue resolving lexer"""
+
+ FIG_CAPTION = "fig_caption"
+ """Issue resoliving figure caption"""
+
+ MIME_TYPE = "mime_type"
+ """Issue resolving MIME type"""
+ OUTPUT_TYPE = "output_type"
+ """Issue resolving Output type"""
+
+ CELL_METADATA_KEY = "cell_metadata_key"
+ """Issue with a key in a cell's `metadata` dictionary."""
+ CELL_CONFIG = "cell_config"
+ """Issue with a cell's configuration or metadata."""
+
+
+def _is_suppressed_warning(
+ type: str, subtype: str, suppress_warnings: Sequence[str]
+) -> bool:
+ """Check whether the warning is suppressed or not.
+
+ Mirrors:
+ https://github.com/sphinx-doc/sphinx/blob/47d9035bca9e83d6db30a0726a02dc9265bd66b1/sphinx/util/logging.py
+ """
+ if type is None:
+ return False
+
+ subtarget: str | None
+
+ for warning_type in suppress_warnings:
+ if "." in warning_type:
+ target, subtarget = warning_type.split(".", 1)
+ else:
+ target, subtarget = warning_type, None
+
+ if target == type and subtarget in (None, subtype, "*"):
+ return True
+
+ return False
+
+
+def create_warning(
+ document: nodes.document,
+ message: str,
+ subtype: MystNBWarnings | MystWarnings,
+ *,
+ line: int | None = None,
+ append_to: nodes.Element | None = None,
+) -> nodes.system_message | None:
+ """Generate a warning, logging if it is necessary.
+
+ If the warning type is listed in the ``suppress_warnings`` configuration,
+ then ``None`` will be returned and no warning logged.
+ """
+ # Pass off Myst Parser warnings to that package
+ if isinstance(subtype, MystWarnings):
+ myst_parser_create_warnings(
+ document=document,
+ message=message,
+ subtype=subtype,
+ line=line,
+ append_to=append_to,
+ )
+
+ wtype = "myst-nb"
+ # figure out whether to suppress the warning, if sphinx is available,
+ # it will have been set up by the Sphinx environment,
+ # otherwise we will use the configuration set by docutils
+ suppress_warnings: Sequence[str] = []
+ try:
+ suppress_warnings = document.settings.env.app.config.suppress_warnings
+ except AttributeError:
+ suppress_warnings = document.settings.myst_suppress_warnings or []
+ if _is_suppressed_warning(wtype, subtype.value, suppress_warnings):
+ return None
+
+ kwargs = {"line": line} if line is not None else {}
+ message = f"{message} [{wtype}.{subtype.value}]"
+ msg_node = document.reporter.warning(message, **kwargs)
+ if append_to is not None:
+ append_to.append(msg_node)
+ return msg_node
diff --git a/pyproject.toml b/pyproject.toml
index 1d759b32..fc27f2c9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -38,10 +38,10 @@ dependencies = [
"ipython",
"jupyter-cache>=0.5,<0.7",
"nbclient", # nbclient version pinned by jupyter-client
- "myst-parser~=0.18.0",
+ "myst-parser>=0.18.0",
"nbformat~=5.0",
"pyyaml",
- "sphinx>=4,<6",
+ "sphinx>=4",
"typing-extensions",
# ipykernel is not a requirement of the library,
# but is a common requirement for users (registers the python3 kernel)
@@ -71,7 +71,7 @@ rtd = [
"alabaster",
"altair",
"bokeh",
- "coconut>=1.4.3,<2.3.0",
+ "coconut>=1.4.3,<3.1.0",
"ipykernel~=5.5",
"ipywidgets",
"jupytext>=1.11.2,<1.15.0",
@@ -79,7 +79,7 @@ rtd = [
"numpy",
"pandas",
"plotly",
- "sphinx-book-theme>=0.3,<1.1",
+ "sphinx-book-theme>=0.3",
"sphinx-copybutton",
"sphinx-design~=0.4.0",
"sphinxcontrib-bibtex",
@@ -92,7 +92,7 @@ testing = [
# for issue with 8.1.0 see https://github.com/ipython/ipython/issues/13554
# TODO ipython 8.5 subtly changes output of test regressions
# see https://ipython.readthedocs.io/en/stable/whatsnew/version8.html#restore-line-numbers-for-input
- "ipython!=8.1.0,<8.5",
+ "ipython!=8.1.0,<8.15",
"ipywidgets>=8",
"jupytext>=1.11.2,<1.15.0",
"matplotlib>=3.5.3,<3.6", # TODO mpl 3.6 subtly changes output of test regressions
diff --git a/tests/nb_fixtures/reporter_warnings.txt b/tests/nb_fixtures/reporter_warnings.txt
index 813d082c..1e226162 100644
--- a/tests/nb_fixtures/reporter_warnings.txt
+++ b/tests/nb_fixtures/reporter_warnings.txt
@@ -10,10 +10,9 @@ cells:
source: |
{unknown}`a`
.
-:20002: (ERROR/3) Unknown interpreted text role "unknown".
+:20002: (WARNING/2) Unknown interpreted text role "unknown". [myst.role_unknown]
.
-
Unknown directive:
.
cells:
@@ -24,7 +23,7 @@ cells:
```{xyz}
```
.
-:10003: (ERROR/3) Unknown directive type "xyz".
+:10003: (WARNING/2) Unknown directive type: 'xyz' [myst.directive_unknown]
.
Directive parsing error:
@@ -66,5 +65,5 @@ cells:
[a]: c
.
-:20004: (WARNING/2) Duplicate reference definition: A [myst.ref]
-.
\ No newline at end of file
+:20004: (WARNING/2) Duplicate reference definition: A [myst.duplicate_def]
+.
diff --git a/tests/test_execute/test_allow_errors_auto.ipynb b/tests/test_execute/test_allow_errors_auto.ipynb
index 70acbc69..3606ee95 100644
--- a/tests/test_execute/test_allow_errors_auto.ipynb
+++ b/tests/test_execute/test_allow_errors_auto.ipynb
@@ -21,7 +21,7 @@
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mException\u001b[0m Traceback (most recent call last)",
- "Input \u001b[0;32mIn [1]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124moopsie!\u001b[39m\u001b[38;5;124m'\u001b[39m)\n",
+ "Cell \u001b[0;32mIn[1], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124moopsie!\u001b[39m\u001b[38;5;124m'\u001b[39m)\n",
"\u001b[0;31mException\u001b[0m: oopsie!"
]
}
@@ -47,7 +47,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.8.13"
+ "version": "3.9.7"
},
"test_name": "notebook1"
},
diff --git a/tests/test_execute/test_allow_errors_auto.xml b/tests/test_execute/test_allow_errors_auto.xml
index f06308ac..c8d1d104 100644
--- a/tests/test_execute/test_allow_errors_auto.xml
+++ b/tests/test_execute/test_allow_errors_auto.xml
@@ -12,7 +12,7 @@
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
- Input In [1], in ()
+ Cell In[1], line 1
----> 1 raise Exception('oopsie!')
Exception: oopsie!
diff --git a/tests/test_execute/test_allow_errors_cache.ipynb b/tests/test_execute/test_allow_errors_cache.ipynb
index 70acbc69..3606ee95 100644
--- a/tests/test_execute/test_allow_errors_cache.ipynb
+++ b/tests/test_execute/test_allow_errors_cache.ipynb
@@ -21,7 +21,7 @@
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mException\u001b[0m Traceback (most recent call last)",
- "Input \u001b[0;32mIn [1]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124moopsie!\u001b[39m\u001b[38;5;124m'\u001b[39m)\n",
+ "Cell \u001b[0;32mIn[1], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124moopsie!\u001b[39m\u001b[38;5;124m'\u001b[39m)\n",
"\u001b[0;31mException\u001b[0m: oopsie!"
]
}
@@ -47,7 +47,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.8.13"
+ "version": "3.9.7"
},
"test_name": "notebook1"
},
diff --git a/tests/test_execute/test_allow_errors_cache.xml b/tests/test_execute/test_allow_errors_cache.xml
index f06308ac..c8d1d104 100644
--- a/tests/test_execute/test_allow_errors_cache.xml
+++ b/tests/test_execute/test_allow_errors_cache.xml
@@ -12,7 +12,7 @@
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
- Input In [1], in ()
+ Cell In[1], line 1
----> 1 raise Exception('oopsie!')
Exception: oopsie!
diff --git a/tests/test_execute/test_basic_failing_auto.ipynb b/tests/test_execute/test_basic_failing_auto.ipynb
index 70acbc69..3606ee95 100644
--- a/tests/test_execute/test_basic_failing_auto.ipynb
+++ b/tests/test_execute/test_basic_failing_auto.ipynb
@@ -21,7 +21,7 @@
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mException\u001b[0m Traceback (most recent call last)",
- "Input \u001b[0;32mIn [1]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124moopsie!\u001b[39m\u001b[38;5;124m'\u001b[39m)\n",
+ "Cell \u001b[0;32mIn[1], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124moopsie!\u001b[39m\u001b[38;5;124m'\u001b[39m)\n",
"\u001b[0;31mException\u001b[0m: oopsie!"
]
}
@@ -47,7 +47,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.8.13"
+ "version": "3.9.7"
},
"test_name": "notebook1"
},
diff --git a/tests/test_execute/test_basic_failing_auto.xml b/tests/test_execute/test_basic_failing_auto.xml
index f06308ac..c8d1d104 100644
--- a/tests/test_execute/test_basic_failing_auto.xml
+++ b/tests/test_execute/test_basic_failing_auto.xml
@@ -12,7 +12,7 @@
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
- Input In [1], in ()
+ Cell In[1], line 1
----> 1 raise Exception('oopsie!')
Exception: oopsie!
diff --git a/tests/test_execute/test_basic_failing_cache.ipynb b/tests/test_execute/test_basic_failing_cache.ipynb
index 70acbc69..3606ee95 100644
--- a/tests/test_execute/test_basic_failing_cache.ipynb
+++ b/tests/test_execute/test_basic_failing_cache.ipynb
@@ -21,7 +21,7 @@
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mException\u001b[0m Traceback (most recent call last)",
- "Input \u001b[0;32mIn [1]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124moopsie!\u001b[39m\u001b[38;5;124m'\u001b[39m)\n",
+ "Cell \u001b[0;32mIn[1], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124moopsie!\u001b[39m\u001b[38;5;124m'\u001b[39m)\n",
"\u001b[0;31mException\u001b[0m: oopsie!"
]
}
@@ -47,7 +47,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.8.13"
+ "version": "3.9.7"
},
"test_name": "notebook1"
},
diff --git a/tests/test_execute/test_basic_failing_cache.xml b/tests/test_execute/test_basic_failing_cache.xml
index f06308ac..c8d1d104 100644
--- a/tests/test_execute/test_basic_failing_cache.xml
+++ b/tests/test_execute/test_basic_failing_cache.xml
@@ -12,7 +12,7 @@
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
- Input In [1], in ()
+ Cell In[1], line 1
----> 1 raise Exception('oopsie!')
Exception: oopsie!
diff --git a/tests/test_execute/test_basic_failing_inline.ipynb b/tests/test_execute/test_basic_failing_inline.ipynb
index 70acbc69..3606ee95 100644
--- a/tests/test_execute/test_basic_failing_inline.ipynb
+++ b/tests/test_execute/test_basic_failing_inline.ipynb
@@ -21,7 +21,7 @@
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mException\u001b[0m Traceback (most recent call last)",
- "Input \u001b[0;32mIn [1]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124moopsie!\u001b[39m\u001b[38;5;124m'\u001b[39m)\n",
+ "Cell \u001b[0;32mIn[1], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124moopsie!\u001b[39m\u001b[38;5;124m'\u001b[39m)\n",
"\u001b[0;31mException\u001b[0m: oopsie!"
]
}
@@ -47,7 +47,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.8.13"
+ "version": "3.9.7"
},
"test_name": "notebook1"
},
diff --git a/tests/test_execute/test_basic_failing_inline.xml b/tests/test_execute/test_basic_failing_inline.xml
index f06308ac..c8d1d104 100644
--- a/tests/test_execute/test_basic_failing_inline.xml
+++ b/tests/test_execute/test_basic_failing_inline.xml
@@ -12,7 +12,7 @@
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
- Input In [1], in ()
+ Cell In[1], line 1
----> 1 raise Exception('oopsie!')
Exception: oopsie!
diff --git a/tox.ini b/tox.ini
index 5cc43a9a..3bfcea70 100644
--- a/tox.ini
+++ b/tox.ini
@@ -11,7 +11,7 @@
# then then deleting compiled files has been found to fix it: `find . -name \*.pyc -delete`
[tox]
-envlist = py38-sphinx5
+envlist = py39-sphinx5
[testenv]
usedevelop = true
| | | | | | | | | |