diff --git a/README.md b/README.md index cbf55a1..9aacd37 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,21 @@ The following options can be specified using MDX comments: This approach allows you to add metadata to the code block without modifying the code fence itself, making it particularly useful in MDX environments. +## Customizing your own custom MarkdownIt parser + +You can configure your own [Markdown-it-py](https://pypi.org/project/markdown-it-py/) parser used by `pytest-markdown-docs` by defining a `pytest_markdown_docs_markdown_it`. For example, you can support +`mkdocs`'s admonitions with: + +```python +def pytest_markdown_docs_markdown_it(): + import markdown_it + from mdit_py_plugins.admon import admon_plugin + + mi = markdown_it.MarkdownIt(config="commonmark") + mi.use(admon_plugin) + return mi +``` + ## Testing of this plugin You can test this module itself (sadly not using markdown tests at the moment) using pytest: diff --git a/pyproject.toml b/pyproject.toml index 174f2fd..44eeca4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,4 +29,5 @@ dev-dependencies = [ "pre-commit>=3.5.0", "pytest~=8.1.0", "ruff~=0.9.10", + "mdit-py-plugins~=0.4.2" ] diff --git a/src/pytest_markdown_docs/hooks.py b/src/pytest_markdown_docs/hooks.py index c5e5a32..a473711 100644 --- a/src/pytest_markdown_docs/hooks.py +++ b/src/pytest_markdown_docs/hooks.py @@ -1,5 +1,14 @@ +import pytest import typing +if typing.TYPE_CHECKING: + from markdown_it import MarkdownIt + def pytest_markdown_docs_globals() -> typing.Dict[str, typing.Any]: return {} + + +@pytest.hookspec(firstresult=True) +def pytest_markdown_docs_markdown_it() -> "MarkdownIt": + """Configure a custom markdown_it.MarkdownIt parser.""" diff --git a/src/pytest_markdown_docs/plugin.py b/src/pytest_markdown_docs/plugin.py index d8c9066..2cb321c 100644 --- a/src/pytest_markdown_docs/plugin.py +++ b/src/pytest_markdown_docs/plugin.py @@ -24,6 +24,7 @@ if typing.TYPE_CHECKING: from markdown_it.token import Token + from markdown_it import MarkdownIt logger = logging.getLogger("pytest-markdown-docs") @@ -123,16 +124,14 @@ def get_prefixed_strings( def extract_fence_tests( + markdown_it_parser: "MarkdownIt", markdown_string: str, start_line_offset: int, source_path: pathlib.Path, markdown_type: str = "md", fence_syntax: FenceSyntax = FenceSyntax.default, ) -> typing.Generator[FenceTestDefinition, None, None]: - import markdown_it - - mi = markdown_it.MarkdownIt(config="commonmark") - tokens = mi.parse(markdown_string) + tokens = markdown_it_parser.parse(markdown_string) prev = "" for i, block in enumerate(tokens): @@ -294,8 +293,11 @@ def find_object_tests_recursive( or "" ) fence_syntax = FenceSyntax(self.config.option.markdowndocs_syntax) + markdown_it_parser = self.config.hook.pytest_markdown_docs_markdown_it() + for i, fence_test in enumerate( extract_fence_tests( + markdown_it_parser, docstr, docstring_offset, source_path=self.path, @@ -317,8 +319,11 @@ def collect(self): markdown_content = self.path.read_text("utf8") fence_syntax = FenceSyntax(self.config.option.markdowndocs_syntax) + markdown_it_parser = self.config.hook.pytest_markdown_docs_markdown_it() + for i, fence_test in enumerate( extract_fence_tests( + markdown_it_parser, markdown_content, source_path=self.path, start_line_offset=0, @@ -374,3 +379,10 @@ def pytest_addoption(parser: Parser) -> None: def pytest_addhooks(pluginmanager): pluginmanager.add_hookspecs(hooks) + + +@pytest.hookimpl +def pytest_markdown_docs_markdown_it() -> "MarkdownIt": + from markdown_it import MarkdownIt + + return MarkdownIt(config="commonmark") diff --git a/tests/plugin_test.py b/tests/plugin_test.py index 8d050d2..1ed61a2 100644 --- a/tests/plugin_test.py +++ b/tests/plugin_test.py @@ -470,3 +470,43 @@ def runtest(self, test, args): ], consecutive=True, ) + + +def test_admonition_markdown_text_file(testdir): + testdir.makeconftest( + """ + def pytest_markdown_docs_globals(): + return {"a": "hello"} + + def pytest_markdown_docs_markdown_it(): + import markdown_it + from mdit_py_plugins.admon import admon_plugin + + mi = markdown_it.MarkdownIt(config="commonmark") + mi.use(admon_plugin) + return mi + """ + ) + + testdir.makefile( + ".md", + """ + ??? quote + + ```python + assert a + " world" == "hello world" + ``` + + !!! info + ```python + assert False + ``` + + ???+ note + ```python + **@ # this is a syntax error + ``` + """, + ) + result = testdir.runpytest("--markdown-docs") + result.assert_outcomes(passed=1, failed=2)