Skip to content

Repository files navigation

mktestdocs

Run pytest against markdown files/docstrings.

Installation

pip install mktestdocs

Usage

Let's say that you're using mkdocs for your documentation. Then you're writing down markdown to explain how your Python packages work. It'd be a shame if a codeblock had an error in it, so it'd be great if you could run your unit tests against them.

This package allows you to do just that. Here's an example:

importpathlibimportpytestfrommktestdocsimportcheck_md_file# Note the use of `str`, makes for pretty output@pytest.mark.parametrize('fpath', pathlib.Path("docs").glob("**/*.md"), ids=str)deftest_files_good(fpath):
check_md_file(fpath=fpath)

This will take any codeblock that starts with ```python and run it, checking for any errors that might happen. This means that if your docs contain asserts, that you get some unit-tests for free!

Multiple Code Blocks

Let's suppose that you have the following markdown file:

This is a code block
```python
from operator import add
a = 1
b = 2
```
This code-block should run fine.
```python
assert add(a, b) == 3
```

Then in this case the second code-block depends on the first code-block. The standard settings of check_md_file assume that each code-block needs to run independently. If you'd like to test markdown files with these sequential code-blocks be sure to set memory=True.

importpathlibfrommktestdocsimportcheck_md_filefpath=pathlib.Path("docs") /"multiple-code-blocks.md"try:
# Assume that cell-blocks are independent.check_md_file(fpath=fpath)
exceptNameError:
# But they weren'tpass# Assumes that cell-blocks depend on each other.check_md_file(fpath=fpath, memory=True)

Markdown in Docstrings

You might also have docstrings written in markdown. Those can be easily checked as well.

# I'm assuming that we've got a library called dinosaurfromdinosaurimportroar, super_roarimportpytestfrommktestdocsimportcheck_docstring# Note the use of `__name__`, makes for pretty output@pytest.mark.parametrize('func', [roar, super_roar], ids=lambdad: d.__name__)deftest_docstring(func):
check_docstring(obj=func)

There's even some utilities for grab all the docstrings from classes that you've defined.

# I'm assuming that we've got a library called dinosaurfromdinosaurimportDinosaurimportpytestfrommktestdocsimportcheck_docstring, get_codeblock_members# This retrieves all methods/properties that have a docstring.members=get_codeblock_members(Dinosaur)
# Note the use of `__qualname__`, makes for pretty output@pytest.mark.parametrize("obj", members, ids=lambdad: d.__qualname__)deftest_member(obj):
check_docstring(obj)

When you run these commands via pytest --verbose you should see informative test info being run.

If you're wondering why you'd want to write markdown in a docstring feel free to check out mkdocstrings.

Bash Support

Be default, bash code blocks are also supported. A markdown file that contains both python and bash code blocks can have each executed separately.

This will print the python version to the terminal
```bash
python --version
```
This will print the exact same version string
```python
import sys
print(f"Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")
```

This markdown could be fully tested like this

importpathlibfrommktestdocsimportcheck_md_filefpath=pathlib.Path("docs") /"bash-support.md"check_md_file(fpath=fpath, lang="python")
check_md_file(fpath=fpath, lang="bash")

Additional Language Support

You can add support for languages other than python and bash by first registering a new executor for that language. The register_executor function takes a tag to specify the code block type supported, and a function that will be passed any code blocks found in markdown files.

For example if you have a markdown file like this

This is an example REST response
```json
{"body": {"results": ["spam", "eggs"]}, "errors": []}
```

You could create a json validator that tested the example was always valid json like this

importjsonimportpathlibfrommktestdocsimportcheck_md_file, register_executordefparse_json(json_text):
json.loads(json_text)
register_executor("json", parse_json)
check_md_file(fpath=pathlib.Path("docs") /"additional-language-support.md", lang="json")

About

Run pytest against markdown files/docstrings.

Resources

Stars

160 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages