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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds pytest_markdown_docs_markdown_it for custom markdownit parser #47

Merged
merged 3 commits into from
Apr 9, 2025
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
]
9 changes: 9 additions & 0 deletions src/pytest_markdown_docs/hooks.py
Original file line number Diff line number Diff line change
@@ -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."""
20 changes: 16 additions & 4 deletions src/pytest_markdown_docs/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -294,8 +293,11 @@ def find_object_tests_recursive(
or "<Unnamed obj>"
)
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,
Expand All @@ -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,
Expand Down Expand Up @@ -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")
40 changes: 40 additions & 0 deletions tests/plugin_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)