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)) # setup parent node if parent is None: parent = nodes.container() self.add_source_and_line(parent) parser.options["current_node"] = parent # setup containing document new_doc = make_document(self.node.source) new_doc.settings = self.document.settings new_doc.reporter = self.document.reporter parser.options["document"] = new_doc # use the node docname, where possible, to deal with single document builds with mock.patch.dict( self.env.temp_data, {"docname": self.env.path2doc(self.node.source)} ): parser.render(text) # TODO is there any transforms we should retroactively carry out? return parent.children
def test_render(line, title, input, expected, tmp_path): tmp_path.joinpath("other.md").write_text("a\nb\nc") tmp_path.joinpath("fmatter.md").write_text("---\na: 1\n---\nb") document = make_document(str(tmp_path / "test.md")) to_docutils(input, document=document, in_sphinx_env=True, srcdir=str(tmp_path)) output = document.pformat().replace(str(tmp_path) + os.sep, "tmpdir" + "/").rstrip() print(output) assert output == expected.rstrip()
def test_myst_mock_sphinx_env_compat(): conf = {"extensions": ["sphinxcontrib.bibtex"], "bibtex_bibfiles": ["test.bib"]} requested_extensions = set(conf.get("extensions")) with mock_sphinx_env_compat( conf=conf, srcdir=".", with_builder="html", document=make_document() ) as app: app_exts = sorted(app.extensions) assert ( requested_extensions.intersection(app_exts) == requested_extensions ), f"requested {requested_extensions}, got {app_exts}"
def test_basic(line, title, input, expected): document = make_document("source/path") messages = [] def observer(msg_node): if msg_node["level"] > 1: messages.append(msg_node.astext()) document.reporter.attach_observer(observer) to_docutils(input, MdParserConfig(renderer="docutils"), document=document) assert "\n".join(messages).rstrip() == expected.rstrip()
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(), "default") document = make_document() with mock_sphinx_env(document=document): tokens_to_docutils(md, env, tokens, document) output = document.pformat().rstrip() if output != expected.rstrip(): print(output) assert output == expected.rstrip()
def test_myst_mock_sphinx_env(): conf = {"extensions": ["sphinxcontrib.bibtex"]} requested_extensions = set(conf.get("extensions")) with mock_sphinx_env( conf=conf, srcdir=".", with_builder=True, document=make_document() ) as app, pytest.xfail( reason="See https://github.com/executablebooks/MyST-Parser/issues/327" ): app_exts = sorted(app.extensions) assert ( requested_extensions.intersection(app_exts) == requested_extensions ), f"requested {requested_extensions}, got {app_exts}"
def test_errors(line, title, input, expected, tmp_path): tmp_path.joinpath("bad.md").write_text("{a}`b`") document = make_document(str(tmp_path / "test.md")) messages = [] def observer(msg_node): if msg_node["level"] > 1: messages.append(msg_node.astext().replace(str(tmp_path), "tmpdir")) document.reporter.attach_observer(observer) document.reporter.halt_level = 6 to_docutils(input, document=document, in_sphinx_env=True, srcdir=str(tmp_path)) assert "\n".join(messages).rstrip() == expected.rstrip()
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(), "default") document = make_document("source/path") messages = [] def observer(msg_node): if msg_node["level"] > 1: messages.append(msg_node.astext()) document.reporter.attach_observer(observer) with mock_sphinx_env(document=document): tokens_to_docutils(md, env, tokens, document) assert "\n".join(messages).rstrip() == expected.rstrip()
def to_docutils( text: str, options=None, env=None, disable_syntax: List[str] = (), math_delimiters: str = "dollars", renderer="sphinx", document=None, in_sphinx_env: bool = False, conf=None, srcdir=None, ): """Render text to the docutils AST :param text: the text to render :param options: options to update the parser with :param env: The sandbox environment for the parse (will contain e.g. reference definitions) :param disable_syntax: list of syntax element names to disable :param document: the docutils root node to use (otherwise a new one will be created) :param in_sphinx_env: initialise a minimal sphinx environment (useful for testing) :param conf: the sphinx conf.py as a dictionary :param srcdir: to parse to the mock sphinc env :returns: docutils document """ from myst_parser.docutils_renderer import make_document md = default_parser( renderer=renderer, disable_syntax=disable_syntax, math_delimiters=math_delimiters, ) if options: md.options.update(options) md.options["document"] = document or make_document() if in_sphinx_env: from myst_parser.sphinx_renderer import mock_sphinx_env with mock_sphinx_env(conf=conf, srcdir=srcdir, document=md.options["document"]): return md.render(text, env) else: return md.render(text, env)
def test_errors(line, title, input, expected, tmp_path): if title.startswith("Non-existent path") and os.name == "nt": pytest.skip("tmp_path not converted correctly on Windows") tmp_path.joinpath("bad.md").write_text("{a}`b`") document = make_document(str(tmp_path / "test.md")) messages = [] def observer(msg_node): if msg_node["level"] > 1: messages.append( msg_node.astext().replace(str(tmp_path) + os.sep, "tmpdir" + "/") ) document.reporter.attach_observer(observer) document.reporter.halt_level = 6 to_docutils(input, document=document, in_sphinx_env=True, srcdir=str(tmp_path)) assert "\n".join(messages).rstrip() == expected.rstrip()
def to_sphinx( filename: Iterable[str], parser_config: Optional[MdParserConfig] = None, options=None, env=None, document=None, conf=None, srcdir=None, with_builder="singlehtml", ): """Render text to the docutils AST (before transforms) :param text: the text to render :param options: options to update the parser with :param env: The sandbox environment for the parse (will contain e.g. reference definitions) :param document: the docutils root node to use (otherwise a new one will be created) :param in_sphinx_env: initialise a minimal sphinx environment (useful for testing) :param conf: the sphinx conf.py as a dictionary :param srcdir: to parse to the mock sphinx env :returns: docutils document """ from myst_parser.docutils_renderer import make_document md = default_parser(parser_config or MdParserConfig()) if options: md.options.update(options) md.options["document"] = document or make_document() force_all = False with mock_sphinx_env_compat( conf=conf, srcdir=srcdir, document=md.options["document"], with_builder=with_builder, ) as app: app.build(force_all, (filename, )) filehtml = Path(filename).with_suffix(".html").name output = (Path(app.outdir) / filehtml).read_text() return get_div_body(output)
def to_docutils( text: str, parser_config: Optional[MdParserConfig] = None, options=None, env=None, document=None, in_sphinx_env: bool = False, conf=None, srcdir=None, ): """Render text to the docutils AST :param text: the text to render :param options: options to update the parser with :param env: The sandbox environment for the parse (will contain e.g. reference definitions) :param document: the docutils root node to use (otherwise a new one will be created) :param in_sphinx_env: initialise a minimal sphinx environment (useful for testing) :param conf: the sphinx conf.py as a dictionary :param srcdir: to parse to the mock sphinc env :returns: docutils document """ from myst_parser.docutils_renderer import make_document md = default_parser(parser_config or MdParserConfig()) if options: md.options.update(options) md.options["document"] = document or make_document() if in_sphinx_env: from myst_parser.sphinx_renderer import mock_sphinx_env with mock_sphinx_env(conf=conf, srcdir=srcdir, document=md.options["document"]): return md.render(text, env) else: return md.render(text, env)