pytest-codeblock **************** Test your documentation code blocks. [image: PyPI Version][image][image: Supported Python versions][image][image: Build Status][image][image: Documentation Status][image][image: llms.txt - documentation for LLMs][image][image: MIT][image][image: Coverage][image] pytest-codeblock is a Pytest plugin that discovers Python code examples in your reStructuredText and Markdown documentation files and runs them as part of your test suite. This ensures your docs stay correct and up-to-date. Features ======== * **reStructuredText and Markdown support**: Automatically find and test code blocks in reStructuredText (".rst") and Markdown (".md") files. Async code snippets are supported as well. * **Grouping**: Split a single example across multiple code blocks; the plugin concatenates them into one test. * **Pytest markers support**: Add existing or custom pytest markers to the code blocks and hook into the tests life-cycle using "conftest.py". * **Pytest fixtures support**: Request existing or custom pytest fixtures for the code blocks. Prerequisites ============= * Python 3.10+ * pytest is the only required dependency (on Python 3.11+; for Python 3.10 tomli is also required). Documentation ============= * Documentation is available on Read the Docs. * For *reStructuredText*, see a dedicated reStructuredText docs. * For *Markdown*, see a dedicated Markdown docs. * Both reStructuredText docs and Markdown docs have extensive documentation on pytest markers and corresponding "conftest.py" hooks. * For guidelines on contributing check the Contributor guidelines. Installation ============ Install with pip: pip install pytest-codeblock Or install with uv: uv pip install pytest-codeblock Configuration ============= For most use cases, no configuration needed. By default, all code blocks with a name starting with "test_" will be collected and executed as tests. This allows you to have both test and non-test code blocks in your documentation, giving you flexibility in how you structure your examples. However, if you want to test all code blocks, you can set "test_nameless_codeblocks" to "true" in your *pyproject.toml*: *Filename: pyproject.toml* [tool.pytest-codeblock] test_nameless_codeblocks = true If you still want to skip some code blocks, you can use built-in or custom pytest markers. See the dedicated reStructuredText docs and Markdown docs to learn more about *pytestmark* directive. Note, that nameless code blocks have limitations when it comes to grouping. ====================================================================== By default, all code *.rst* and *.md* files shall be picked automatically. However, if you need to add another file extension or use or another language identifier for python in codeblock, you could configure that. See the following example of *pyproject.toml* configuration: *Filename: pyproject.toml* [tool.pytest-codeblock] rst_user_codeblocks = ["c_py"] rst_user_extensions = [".rst.txt"] md_user_codeblocks = ["c_py"] md_user_extensions = [".md.txt"] See customisation docs for more. Usage ===== Note: It's highly recommended to use doc8 for catching possible markup errors, that otherwise would be difficult to spot. reStructruredText usage ----------------------- Any code directive, such as ".. code-block:: python", ".. code:: python", or literal blocks with a preceding ".. codeblock-name: ", will be collected and executed automatically by pytest. "code-block" directive example ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Note: Note that ":name:" value has a "test_" prefix. *Filename: README.rst* .. code-block:: python :name: test_basic_example import math result = math.pow(3, 2) assert result == 9 "literalinclude" directive example ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Note: Note that ":name:" value has a "test_" prefix. *Filename: README.rst* .. literalinclude:: examples/python/basic_example.py :name: test_li_basic_example See a dedicated reStructuredText docs for more. Markdown usage -------------- Any fenced code block with a recognized Python language tag (e.g., "python", "py") will be collected and executed automatically by pytest. Note: Note that "name" value has a "test_" prefix. *Filename: README.md* ```python name=test_basic_example import math result = math.pow(3, 2) assert result == 9 ``` See a dedicated Markdown docs for more. Tests ===== Run the tests with pytest: pytest Troubleshooting =============== If something doesn't work, try to add this to your pyproject.toml: *Filename: pyproject.toml* [tool.pytest.ini_options] testpaths = [ "**/*.rst", "**/*.md", ] Writing documentation ===================== Keep the following hierarchy. ===== title ===== header ====== sub-header ---------- sub-sub-header ~~~~~~~~~~~~~~ sub-sub-sub-header ^^^^^^^^^^^^^^^^^^ sub-sub-sub-sub-header ++++++++++++++++++++++ sub-sub-sub-sub-sub-header ************************** License ======= MIT Support ======= For security issues contact me at the e-mail given in the Author section. For overall issues, go to GitHub. Author ====== Artur Barseghyan Project documentation ===================== Contents: Table of Contents ^^^^^^^^^^^^^^^^^ * pytest-codeblock * Features * Prerequisites * Documentation * Installation * Configuration * Usage * reStructruredText usage * "code-block" directive example * "literalinclude" directive example * Markdown usage * Tests * Troubleshooting * Writing documentation * License * Support * Author * Project documentation * Quick-start reference * Naming rules * RST syntax * Markdown syntax * Async support * pyproject.toml configuration * testpaths troubleshooting * conftest.py hook integration * reStructuredText * Usage examples * Customisation/hooks * Markdown * Usage examples * Customisation/hooks * Customisation * Languages * Extensions * reStructuredText cheatsheet * Marking code-block as xfailed * Requesting specific pytest fixtures for a code-block * Markdown cheatsheet * Marking code-block as xfailed * Requesting specific pytest fixtures for a code-block * Security Policy * Reporting a Vulnerability * Supported Versions * Contributor guidelines * Developer prerequisites * Code standards * Virtual environment * Documentation * Testing * Pull requests * GitHub Actions * Questions * Issues * Contributor Covenant Code of Conduct * Our Pledge * Our Standards * Enforcement Responsibilities * Scope * Enforcement * Enforcement Guidelines * Attribution * Release history and notes * 0.5.9 * 0.5.8 * 0.5.7 * 0.5.6 * 0.5.5 * 0.5.4 * 0.5.3 * 0.5.2 * 0.5.1 * 0.5 * 0.4 * 0.3.5 * 0.3.4 * 0.3.3 * 0.3.2 * 0.3.1 * 0.3 * 0.2 * 0.1.8 * 0.1.7 * 0.1.6 * 0.1.5 * 0.1.4 * 0.1.3 * 0.1.2 * 0.1.1 * 0.1 * Package * Indices and tables * Project source-tree * README.rst * CONTRIBUTING.rst * docs/quick_start_ref.rst * docs/restructured_text.rst * docs/markdown.rst * docs/cheatsheet_restructured_text.rst * docs/cheatsheet_markdown.rst * docs/customisation.rst * conftest.py * docs/conf.py * pyproject.toml * src/pytest_codeblock/__init__.py * src/pytest_codeblock/collector.py * src/pytest_codeblock/config.py * src/pytest_codeblock/constants.py * src/pytest_codeblock/helpers.py * src/pytest_codeblock/md.py * src/pytest_codeblock/pytestrun.py * src/pytest_codeblock/rst.py * src/pytest_codeblock/tests/__init__.py * src/pytest_codeblock/tests/test_customisation.py * src/pytest_codeblock/tests/test_integration.py * src/pytest_codeblock/tests/test_nameless_codeblocks.py * src/pytest_codeblock/tests/test_pytest_codeblock.py * src/pytest_codeblock/tests/test_pytestrun_marker.py * src/pytest_codeblock/tests/tests.md * src/pytest_codeblock/tests/tests.rst