pytest-markdown-docs


Namepytest-markdown-docs JSON
Version 0.7.1 PyPI version JSON
download
home_pageNone
SummaryRun markdown code fences through pytest
upload_time2024-11-28 14:37:29
maintainerNone
docs_urlNone
authorModal Labs
requires_python>=3.8
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Pytest Markdown Docs

A plugin for [pytest](https://docs.pytest.org) that uses markdown code snippets from markdown files and docstrings as tests.

Detects Python code fences (triple backtick escaped blocks) in markdown files as
well as inline Python docstrings (similar to doctests) and runs them as tests.

Python file example:

````python
# mymodule.py
class Foo:
    def bar(self):
        """Bar the foo

        This is a sample docstring for the bar method

        Usage:
        ```python
        import mymodule
        result = mymodule.Foo().bar()
        assert result == "hello"
        ```
        """
        return "hello"
````

Markdown file examples:

````markdown
# Title

Lorem ipsum yada yada yada

```python
import mymodule
result = mymodule.Foo().bar()
assert result == "hello"
```
````

## Usage

First, make sure to install the plugin:

```shell
pip install pytest-markdown-docs
```

To enable markdown python tests, pass the `--markdown-docs` flag to `pytest`:

```shell
pytest --markdown-docs
```

You can also use the `markdown-docs` flag to filter *only* markdown-docs tests:

```shell
pytest --markdown-docs -m markdown-docs
```

### Detection conditions

Fence blocks (` ``` `) starting with the `python`, `python3` or `py` language definitions are detected as tests in:

* Python (.py) files, within docstrings of classes and functions
* `.md`, `.mdx` and `.svx` files

## Skipping tests

To exclude a Python code fence from testing, add a `notest` info string to the
code fence, e.g:

````markdown
```python notest
print("this will not be run")
```
````

## Code block dependencies

Sometimes you might wish to run code blocks that depend on entities to already
be declared in the scope of the code, without explicitly declaring them. There
are currently two ways you can do this with pytest-markdown:

### Injecting global/local variables

If you have some common imports or other common variables that you want to make
use of in snippets, you can add them by creating a `pytest_markdown_docs_globals`
hook in your `conftest.py`:

```python
def pytest_markdown_docs_globals():
    import math
    return {"math": math, "myvar": "hello"}
```

With this conftest, you would be able to run the following markdown snippet as a
test, without causing an error:

````markdown
```python
print(myvar, math.pi)
```
````

### Fixtures

You can use both `autouse=True` pytest fixtures in a conftest.py or named fixtures with
your markdown tests. To specify named fixtures, add `fixture:<name>` markers to the code
fence info string, e.g.,

````markdown
```python fixture:capsys
print("hello")
captured = capsys.readouterr()
assert captured.out == "hello\n"
```
````

As you can see above, the fixture value will be injected as a global. For `autouse=True` fixtures, the value is only injected as a global if it's explicitly added using a `fixture:<name>` marker.

### Depending on previous snippets

If you have multiple snippets following each other and want to keep the side
effects from the previous snippets, you can do so by adding the `continuation`
info string to your code fence:

````markdown
```python
a = "hello"
```

```python continuation
assert a + " world" == "hello world"
```
````

### Compatibility with Material for MkDocs

Material for Mkdocs is not compatible with the default syntax.

But if the extension `pymdownx.superfences` is configured for mkdocs, the brace format can be used:
````markdown
```{.python continuation}
````

You will need to call pytest with the `--markdown-docs-syntax` option:
```shell
pytest --markdown-docs --markdown-docs-syntax=superfences
```

## MDX Comments for Metadata Options
In .mdx files, you can use MDX comments to provide additional options for code blocks. These comments should be placed immediately before the code block and take the following form:

```mdx
{/* pmd-metadata: notest fixture:capsys */}
```python
print("hello")
captured = capsys.readouterr()
assert captured.out == "hello\n"
```

The following options can be specified using MDX comments:

* notest: Exclude the code block from testing.
* fixture:<name>: Apply named pytest fixtures to the code block.
* continuation: Continue from the previous code block, allowing you to carry over state.

This approach allows you to add metadata to the code block without modifying the code fence itself, making it particularly useful in MDX environments.

## Testing of this plugin

You can test this module itself (sadly not using markdown tests at the moment) using pytest:

```shell
> poetry run pytest
```

Or for fun, you can use this plugin to include testing of the validity of snippets in this README.md file:

```shell
> poetry run pytest --markdown-docs
```

## Known issues
* Code for docstring-inlined test discovery can probably be done better (similar to how doctest does it). Currently, seems to sometimes traverse into Python's standard library which isn't great...
* Traceback logic is extremely hacky, wouldn't be surprised if the tracebacks look weird sometimes
  * Line numbers are "wrong" for docstring-inlined snippets (since we don't know where in the file the docstring starts)
  * Line numbers are "wrong" for continuation blocks even in pure markdown files (can be worked out with some refactoring)
* There are probably more appropriate ways to use pytest internal APIs to get more features "for free" - current state of the code is a bit "patch it til' it works".
* Assertions are not rewritten w/ pretty data structure inspection like they are with regular pytest tests by default

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "pytest-markdown-docs",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": null,
    "author": "Modal Labs",
    "author_email": "Elias Freider <elias@modal.com>",
    "download_url": "https://files.pythonhosted.org/packages/38/02/e326c6ade977f473f7a6b592531cc811ac8b384fe2d2148ec7ff32b7762c/pytest_markdown_docs-0.7.1.tar.gz",
    "platform": null,
    "description": "# Pytest Markdown Docs\n\nA plugin for [pytest](https://docs.pytest.org) that uses markdown code snippets from markdown files and docstrings as tests.\n\nDetects Python code fences (triple backtick escaped blocks) in markdown files as\nwell as inline Python docstrings (similar to doctests) and runs them as tests.\n\nPython file example:\n\n````python\n# mymodule.py\nclass Foo:\n    def bar(self):\n        \"\"\"Bar the foo\n\n        This is a sample docstring for the bar method\n\n        Usage:\n        ```python\n        import mymodule\n        result = mymodule.Foo().bar()\n        assert result == \"hello\"\n        ```\n        \"\"\"\n        return \"hello\"\n````\n\nMarkdown file examples:\n\n````markdown\n# Title\n\nLorem ipsum yada yada yada\n\n```python\nimport mymodule\nresult = mymodule.Foo().bar()\nassert result == \"hello\"\n```\n````\n\n## Usage\n\nFirst, make sure to install the plugin:\n\n```shell\npip install pytest-markdown-docs\n```\n\nTo enable markdown python tests, pass the `--markdown-docs` flag to `pytest`:\n\n```shell\npytest --markdown-docs\n```\n\nYou can also use the `markdown-docs` flag to filter *only* markdown-docs tests:\n\n```shell\npytest --markdown-docs -m markdown-docs\n```\n\n### Detection conditions\n\nFence blocks (` ``` `) starting with the `python`, `python3` or `py` language definitions are detected as tests in:\n\n* Python (.py) files, within docstrings of classes and functions\n* `.md`, `.mdx` and `.svx` files\n\n## Skipping tests\n\nTo exclude a Python code fence from testing, add a `notest` info string to the\ncode fence, e.g:\n\n````markdown\n```python notest\nprint(\"this will not be run\")\n```\n````\n\n## Code block dependencies\n\nSometimes you might wish to run code blocks that depend on entities to already\nbe declared in the scope of the code, without explicitly declaring them. There\nare currently two ways you can do this with pytest-markdown:\n\n### Injecting global/local variables\n\nIf you have some common imports or other common variables that you want to make\nuse of in snippets, you can add them by creating a `pytest_markdown_docs_globals`\nhook in your `conftest.py`:\n\n```python\ndef pytest_markdown_docs_globals():\n    import math\n    return {\"math\": math, \"myvar\": \"hello\"}\n```\n\nWith this conftest, you would be able to run the following markdown snippet as a\ntest, without causing an error:\n\n````markdown\n```python\nprint(myvar, math.pi)\n```\n````\n\n### Fixtures\n\nYou can use both `autouse=True` pytest fixtures in a conftest.py or named fixtures with\nyour markdown tests. To specify named fixtures, add `fixture:<name>` markers to the code\nfence info string, e.g.,\n\n````markdown\n```python fixture:capsys\nprint(\"hello\")\ncaptured = capsys.readouterr()\nassert captured.out == \"hello\\n\"\n```\n````\n\nAs you can see above, the fixture value will be injected as a global. For `autouse=True` fixtures, the value is only injected as a global if it's explicitly added using a `fixture:<name>` marker.\n\n### Depending on previous snippets\n\nIf you have multiple snippets following each other and want to keep the side\neffects from the previous snippets, you can do so by adding the `continuation`\ninfo string to your code fence:\n\n````markdown\n```python\na = \"hello\"\n```\n\n```python continuation\nassert a + \" world\" == \"hello world\"\n```\n````\n\n### Compatibility with Material for MkDocs\n\nMaterial for Mkdocs is not compatible with the default syntax.\n\nBut if the extension `pymdownx.superfences` is configured for mkdocs, the brace format can be used:\n````markdown\n```{.python continuation}\n````\n\nYou will need to call pytest with the `--markdown-docs-syntax` option:\n```shell\npytest --markdown-docs --markdown-docs-syntax=superfences\n```\n\n## MDX Comments for Metadata Options\nIn .mdx files, you can use MDX comments to provide additional options for code blocks. These comments should be placed immediately before the code block and take the following form:\n\n```mdx\n{/* pmd-metadata: notest fixture:capsys */}\n```python\nprint(\"hello\")\ncaptured = capsys.readouterr()\nassert captured.out == \"hello\\n\"\n```\n\nThe following options can be specified using MDX comments:\n\n* notest: Exclude the code block from testing.\n* fixture:<name>: Apply named pytest fixtures to the code block.\n* continuation: Continue from the previous code block, allowing you to carry over state.\n\nThis approach allows you to add metadata to the code block without modifying the code fence itself, making it particularly useful in MDX environments.\n\n## Testing of this plugin\n\nYou can test this module itself (sadly not using markdown tests at the moment) using pytest:\n\n```shell\n> poetry run pytest\n```\n\nOr for fun, you can use this plugin to include testing of the validity of snippets in this README.md file:\n\n```shell\n> poetry run pytest --markdown-docs\n```\n\n## Known issues\n* Code for docstring-inlined test discovery can probably be done better (similar to how doctest does it). Currently, seems to sometimes traverse into Python's standard library which isn't great...\n* Traceback logic is extremely hacky, wouldn't be surprised if the tracebacks look weird sometimes\n  * Line numbers are \"wrong\" for docstring-inlined snippets (since we don't know where in the file the docstring starts)\n  * Line numbers are \"wrong\" for continuation blocks even in pure markdown files (can be worked out with some refactoring)\n* There are probably more appropriate ways to use pytest internal APIs to get more features \"for free\" - current state of the code is a bit \"patch it til' it works\".\n* Assertions are not rewritten w/ pretty data structure inspection like they are with regular pytest tests by default\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Run markdown code fences through pytest",
    "version": "0.7.1",
    "project_urls": null,
    "split_keywords": [],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "166e64ce9f2bdbc193929383b751c0816de4d3356de8f11c00b3083d16303f97",
                "md5": "6327a9fe4dae8d65d1ea16f09e3e28a0",
                "sha256": "916ffa0911892c439773fd363b3bc64afc7e819925bfaec859afdcff2f587cc6"
            },
            "downloads": -1,
            "filename": "pytest_markdown_docs-0.7.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "6327a9fe4dae8d65d1ea16f09e3e28a0",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 9473,
            "upload_time": "2024-11-28T14:37:28",
            "upload_time_iso_8601": "2024-11-28T14:37:28.256752Z",
            "url": "https://files.pythonhosted.org/packages/16/6e/64ce9f2bdbc193929383b751c0816de4d3356de8f11c00b3083d16303f97/pytest_markdown_docs-0.7.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "3802e326c6ade977f473f7a6b592531cc811ac8b384fe2d2148ec7ff32b7762c",
                "md5": "f90553cecce2e6c55922c5e70780f311",
                "sha256": "20c27d5946601d5b45306685059612396fa737e931c0d28cb28aa0ae97f4e71b"
            },
            "downloads": -1,
            "filename": "pytest_markdown_docs-0.7.1.tar.gz",
            "has_sig": false,
            "md5_digest": "f90553cecce2e6c55922c5e70780f311",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 12816,
            "upload_time": "2024-11-28T14:37:29",
            "upload_time_iso_8601": "2024-11-28T14:37:29.352886Z",
            "url": "https://files.pythonhosted.org/packages/38/02/e326c6ade977f473f7a6b592531cc811ac8b384fe2d2148ec7ff32b7762c/pytest_markdown_docs-0.7.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-28 14:37:29",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "pytest-markdown-docs"
}
        
Elapsed time: 0.37840s