Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
aleivag authored and LecrisUT committed Jun 23, 2023
1 parent 5d97244 commit 23a2195
Show file tree
Hide file tree
Showing 11 changed files with 179 additions and 85 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ repos:
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
Expand Down
2 changes: 1 addition & 1 deletion myst_nb/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""A docutils/sphinx parser for Jupyter Notebooks."""
__version__ = "0.17.2"
__version__ = "0.18.0"


def setup(app):
Expand Down
32 changes: 21 additions & 11 deletions myst_nb/core/config.py
Original file line number Diff line number Diff line change
@@ -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 (
Expand All @@ -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]]:
Expand Down Expand Up @@ -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),
},
)
Expand Down Expand Up @@ -184,7 +191,7 @@ 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),
},
)
Expand Down Expand Up @@ -220,7 +227,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),
},
)
Expand Down Expand Up @@ -387,7 +394,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,
Expand Down Expand Up @@ -454,7 +461,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": (
Expand All @@ -471,7 +478,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,
Expand Down Expand Up @@ -505,7 +512,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,
Expand Down Expand Up @@ -567,7 +574,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.
Expand All @@ -593,7 +600,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:
Expand All @@ -611,7 +618,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)
25 changes: 11 additions & 14 deletions myst_nb/core/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
38 changes: 15 additions & 23 deletions myst_nb/core/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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,
)
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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."""
Expand Down Expand Up @@ -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."""
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -832,7 +824,6 @@ def _render_markdown_base(
data.string,
data.line or 0,
inline=inline,
allow_headings=allow_headings,
)
finally:
# restore the parser
Expand Down Expand Up @@ -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)
Expand Down
36 changes: 14 additions & 22 deletions myst_nb/docutils_.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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")}
Expand Down Expand Up @@ -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."""
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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 = (
Expand All @@ -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,
)


Expand Down
1 change: 0 additions & 1 deletion myst_nb/ext/glue/directives.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 23a2195

Please sign in to comment.