Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

馃敡 MAINTAIN: Implement MockInliner.parse #504

Merged
merged 2 commits into from Jan 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/conf.py
Expand Up @@ -161,6 +161,7 @@ def run_apidoc(app):
("py:class", "docutils.nodes.document"),
("py:class", "docutils.nodes.docinfo"),
("py:class", "docutils.nodes.Element"),
("py:class", "docutils.nodes.Node"),
("py:class", "docutils.nodes.field_list"),
("py:class", "docutils.nodes.problematic"),
("py:class", "docutils.nodes.pending"),
Expand Down
2 changes: 1 addition & 1 deletion myst_parser/docutils_renderer.py
Expand Up @@ -1046,7 +1046,7 @@ def render_myst_role(self, token: SyntaxTreeNode) -> None:
role_func, messages = roles.role(
name, self.language_module_rst, lineno, self.reporter
)
inliner = MockInliner(self, lineno)
inliner = MockInliner(self)
if role_func:
nodes, messages2 = role_func(name, rawsource, text, lineno, inliner)
# return nodes, messages + messages2
Expand Down
47 changes: 32 additions & 15 deletions myst_parser/mocking.py
Expand Up @@ -5,7 +5,7 @@
import re
import sys
from pathlib import Path
from typing import TYPE_CHECKING, List, Optional, Tuple, Type
from typing import TYPE_CHECKING, Any, List, Optional, Tuple, Type

from docutils import nodes
from docutils.parsers.rst import Directive, DirectiveError
Expand All @@ -31,28 +31,50 @@ class MockInliner:
This is parsed to role functions.
"""

def __init__(self, renderer: "DocutilsRenderer", lineno: int):
def __init__(self, renderer: "DocutilsRenderer"):
"""Initialize the mock inliner."""
self._renderer = renderer
# here we mock that the `parse` method has already been called
# which is where these attributes are set (via the RST state Memo)
self.document = renderer.document
self.reporter = renderer.document.reporter
self.language = renderer.language_module_rst
self.parent = renderer.current_node

if not hasattr(self.reporter, "get_source_and_line"):
# TODO this is called by some roles,
# but I can't see how that would work in RST?
# In docutils this is set by `RSTState.runtime_init`
self.reporter.get_source_and_line = lambda l: (self.document["source"], l)
self.parent = renderer.current_node
self.language = renderer.language_module_rst

self.rfc_url = "rfc%d.html"

def problematic(
self, text: str, rawsource: str, message: nodes.system_message
) -> nodes.problematic:
"""Record a system message from parsing."""
msgid = self.document.set_id(message, self.parent)
problematic = nodes.problematic(rawsource, rawsource, refid=msgid)
problematic = nodes.problematic(rawsource, text, refid=msgid)
prbid = self.document.set_id(problematic)
message.add_backref(prbid)
return problematic

# TODO add parse method
def parse(
self, text: str, lineno: int, memo: Any, parent: nodes.Node
) -> Tuple[List[nodes.Node], List[nodes.system_message]]:
"""Parse the text and return a list of nodes."""
# note the only place this is normally called,
# is by `RSTState.inline_text`, or in directives: `self.state.inline_text`,
# and there the state parses its own parent
# self.reporter = memo.reporter
# self.document = memo.document
# self.language = memo.language
with self._renderer.current_node_context(parent):
# the parent is never actually appended to though,
# so we make a temporary parent to parse into
container = nodes.Element()
with self._renderer.current_node_context(container):
self._renderer.nested_render_text(text, lineno, inline=True)

return container.children, []

def __getattr__(self, name: str):
"""This method is only be called if the attribute requested has not
Expand Down Expand Up @@ -87,7 +109,7 @@ def __init__(
self.document = renderer.document
self.reporter = renderer.document.reporter
self.state_machine = state_machine
self.inliner = MockInliner(renderer, lineno)
self.inliner = MockInliner(renderer)

class Struct:
document = self.document
Expand Down Expand Up @@ -172,12 +194,7 @@ def inline_text(

:returns: (list of nodes, list of messages)
"""
container = nodes.Element()
with self._renderer.current_node_context(container):
self._renderer.nested_render_text(text, lineno, inline=True)

# TODO return messages?
return container.children, []
return self.inliner.parse(text, lineno, self.memo, self._renderer.current_node)

# U+2014 is an em-dash:
attribution_pattern = re.compile("^((?:---?(?!-)|\u2014) *)(.+)")
Expand Down