Repository: executablebooks/MyST-Parser
Pull request #687 (2023-01-15 12:53:14)

👌 Change missing directive/role errors to warnings
If an unknown directive/role name is encountered,
then a warning is emitted with the `myst.directive_unknown` or `myst.role_unknown` type,
which can be suppressed.


Patch:
diff --git a/docs/live_preview.py b/docs/live_preview.py
index 474a624..ffd70b2 100644
--- a/docs/live_preview.py
+++ b/docs/live_preview.py
@@ -1,3 +1,4 @@
+import traceback
 from io import StringIO
 
 import yaml
@@ -30,7 +31,7 @@ def convert(input_config: str, input_myst: str, writer_name: str) -> dict:
             settings_overrides=settings,
         )
     except Exception as exc:
-        output = f"ERROR: conversion:\n{exc}"
+        output = f"ERROR: conversion:\n{exc}\n{traceback.format_exc()}"
     return {"output": output, "warnings": warning_stream.getvalue()}
 
 
diff --git a/myst_parser/mdit_to_docutils/base.py b/myst_parser/mdit_to_docutils/base.py
index 3f5f3cc..93639ed 100644
--- a/myst_parser/mdit_to_docutils/base.py
+++ b/myst_parser/mdit_to_docutils/base.py
@@ -1319,17 +1319,18 @@ class DocutilsRenderer(RendererProtocol):
         role_func, messages = roles.role(
             name, self.language_module_rst, lineno, self.reporter
         )
-        inliner = MockInliner(self)
-        if role_func:
-            _nodes, messages2 = role_func(name, rawsource, text, lineno, inliner)
-            # return nodes, messages + messages2
-            self.current_node += _nodes
-        else:
-            message = self.reporter.error(
-                f'Unknown interpreted text role "{name}".', line=lineno
+        if not role_func:
+            self.create_warning(
+                f'Unknown interpreted text role "{name}".',
+                MystWarnings.UNKNOWN_ROLE,
+                line=lineno,
+                append_to=self.current_node,
             )
-            problematic = inliner.problematic(text, rawsource, message)
-            self.current_node += problematic
+            self.current_node.extend(messages)
+            return
+        inliner = MockInliner(self)
+        _nodes, messages2 = role_func(name, rawsource, text, lineno, inliner)
+        self.current_node += _nodes + messages2
 
     def render_colon_fence(self, token: SyntaxTreeNode) -> None:
         """Render a code fence with ``:`` colon delimiters."""
@@ -1470,11 +1471,12 @@ class DocutilsRenderer(RendererProtocol):
         )
         directive_class, messages = output
         if not directive_class:
-            error = self.reporter.error(
-                f'Unknown directive type "{name}".\n',
+            warn_node = self.create_warning(
+                f"Unknown directive type: {name!r}",
+                MystWarnings.UNKNOWN_DIRECTIVE,
                 line=position,
             )
-            return [error] + messages
+            return ([warn_node] if warn_node else []) + messages
 
         if issubclass(directive_class, Include):
             # this is a Markdown only option,
diff --git a/myst_parser/warnings_.py b/myst_parser/warnings_.py
index 7756573..f9d498c 100644
--- a/myst_parser/warnings_.py
+++ b/myst_parser/warnings_.py
@@ -31,6 +31,10 @@ class MystWarnings(Enum):
 
     DIRECTIVE_PARSING = "directive_parse"
     """Issue parsing directive."""
+    UNKNOWN_DIRECTIVE = "directive_unknown"
+    """Unknown directive."""
+    UNKNOWN_ROLE = "role_unknown"
+    """Unknown role."""
 
     # cross-reference resolution
     XREF_AMBIGUOUS = "xref_ambiguous"


Test patch:
diff --git a/tests/test_renderers/fixtures/directive_options.md b/tests/test_renderers/fixtures/directive_options.md
index 76f9255..9b47258 100644
--- a/tests/test_renderers/fixtures/directive_options.md
+++ b/tests/test_renderers/fixtures/directive_options.md
@@ -147,9 +147,9 @@ Unknown Directive:
 ```
 .
 <document source="<src>/index.md">
-    <system_message level="3" line="1" source="<src>/index.md" type="ERROR">
+    <system_message level="2" line="1" source="<src>/index.md" type="WARNING">
         <paragraph>
-            Unknown directive type "unknown".
+            Unknown directive type: 'unknown' [myst.directive_unknown]
     <system_message level="1" line="1" source="<src>/index.md" type="INFO">
         <paragraph>
             No directive entry for "unknown" in module "docutils.parsers.rst.languages.en".
diff --git a/tests/test_renderers/fixtures/mock_include_errors.md b/tests/test_renderers/fixtures/mock_include_errors.md
index 1e5c2e9..c293be1 100644
--- a/tests/test_renderers/fixtures/mock_include_errors.md
+++ b/tests/test_renderers/fixtures/mock_include_errors.md
@@ -20,5 +20,5 @@ Error in include file:
 ```{include} bad.md
 ```
 .
-tmpdir/bad.md:2: (ERROR/3) Unknown interpreted text role "a".
+tmpdir/bad.md:2: (WARNING/2) Unknown interpreted text role "a". [myst.role_unknown]
 .
diff --git a/tests/test_renderers/fixtures/reporter_warnings.md b/tests/test_renderers/fixtures/reporter_warnings.md
index 7c3cc78..68b76b1 100644
--- a/tests/test_renderers/fixtures/reporter_warnings.md
+++ b/tests/test_renderers/fixtures/reporter_warnings.md
@@ -19,7 +19,7 @@ abc
 
 {xyz}`a`
 .
-<string>:3: (ERROR/3) Unknown interpreted text role "xyz".
+<string>:3: (WARNING/2) Unknown interpreted text role "xyz". [myst.role_unknown]
 .
 
 Unknown directive:
@@ -28,7 +28,7 @@ Unknown directive:
 ```{xyz}
 ```
 .
-<string>:2: (ERROR/3) Unknown directive type "xyz".
+<string>:2: (WARNING/2) Unknown directive type: 'xyz' [myst.directive_unknown]
 .
 
 Bad Front Matter:
@@ -174,5 +174,5 @@ Paragraph
 {unknown}`a`
 ```
 .
-<string>:7: (ERROR/3) Unknown interpreted text role "unknown".
+<string>:7: (WARNING/2) Unknown interpreted text role "unknown". [myst.role_unknown]
 .