<div align="center">
# docspec_test — Docstring tests as documentation, spec and CI
[](https://github.com/alexsukhrin/docspec_test/actions/workflows/ci.yml)
[](https://pypi.org/project/docspec-test/)
[](https://pypi.org/project/docspec-test/)
[](LICENSE)
[](https://github.com/alexsukhrin/docspec_test)
Turn examples in your docstrings into executable tests — without leaving your code.
</div>
Why
---
- Keep tests next to the API they validate — examples never drift from reality.
- Examples become living documentation and a precise specification.
- Perfect for TDD and quick feedback while coding.
Features
--------
- Docstring fenced blocks executed as tests: ```python test ...```
- Directives: `name`, `raises=Exception`, `skip[="reason"]`, `xfail[="reason"]`
- Optional `setup` / `teardown` blocks per object
- Pytest integration (auto-discovered plugin) and a standalone CLI
- Runtime helpers to validate directly in an interpreter or on call
Install
-------
```bash
pip install docspec-test
```
Quickstart
----------
```python
def add(a: int, b: int) -> int:
"""
Adds two numbers.
```python test
assert add(1, 2) == 3
```
"""
return a + b
```
Run pytest (the plugin is discovered via `pytest11`):
```bash
pytest
```
Directives
----------
Add options to the test block header:
```markdown
```python test name="custom-name" raises=ValueError skip="reason" xfail
# test code
```
```
- name: custom test name
- raises: assert that an exception is raised (e.g. `raises=KeyError`)
- skip: skip test, with optional reason
- xfail: expected failure, with optional reason
Setup / Teardown
----------------
One optional `setup` and `teardown` block per object:
```markdown
```python setup
state = {"x": 0}
```
```python test name="increments"
state["x"] += 1
assert state["x"] == 1
```
```python teardown
state.clear()
```
```
Runtime validation (no pytest)
------------------------------
```python
from docspec_test import validate_module, execute_docstring_tests_for_object, validate_on_call
# validate an entire module by path or module object
validate_module("path/to/module.py")
# validate a single function/class
execute_docstring_tests_for_object(add)
# validate on first call (or on every call with mode="always")
@validate_on_call
def inc(x: int) -> int:
"""
```python test
assert inc(1) == 2
```
"""
return x + 1
```
CLI
---
Validate all Python files in the current directory:
```bash
docspec-test
```
Validate a specific path (file or directory):
```bash
docspec-test path/to/src
```
Ignore directories:
```bash
docspec-test . --ignore .venv --ignore build
```
Pytest defaults
---------------
By default, only docspec-marked tests run (`-m docspec`). To run everything:
```bash
pytest -m 'not docspec'
```
Contributing
------------
We’d love your help! Great first issues: docs, new directives, better error reporting, CI workflows.
Dev setup:
```bash
git clone https://github.com/alexsukhrin/docspec_test
cd docspec_test
python -m venv venv && source venv/bin/activate
pip install -e .[dev] # or: pip install -e . && pip install black isort pytest build twine
```
Run checks:
```bash
isort . && black . && pytest -m 'not docspec' && pytest
```
Roadmap
-------
- Parametrized examples (table-driven)
- Inline output matching (like doctest) alongside code blocks
- Jupyter notebooks support
- VSCode/IDE integration for quick-run
Requirements
------------
- Python >= 3.8
- pytest >= 7.0.0
License
-------
MIT
Raw data
{
"_id": null,
"home_page": null,
"name": "docspec-test",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "pytest, plugin, doctest, docstring, markdown",
"author": "Alexandr Sukhryn",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/c7/93/4913f9728de38a8117d0dfcfd7b1ada7b88013ab5c0eb69a0f052bb4e0db/docspec_test-0.1.6.tar.gz",
"platform": null,
"description": "<div align=\"center\">\n\n# docspec_test \u2014 Docstring tests as documentation, spec and CI\n\n[](https://github.com/alexsukhrin/docspec_test/actions/workflows/ci.yml)\n[](https://pypi.org/project/docspec-test/)\n[](https://pypi.org/project/docspec-test/)\n[](LICENSE)\n[](https://github.com/alexsukhrin/docspec_test)\n\nTurn examples in your docstrings into executable tests \u2014 without leaving your code.\n\n</div>\n\nWhy\n---\n\n- Keep tests next to the API they validate \u2014 examples never drift from reality.\n- Examples become living documentation and a precise specification.\n- Perfect for TDD and quick feedback while coding.\n\nFeatures\n--------\n\n- Docstring fenced blocks executed as tests: ```python test ...```\n- Directives: `name`, `raises=Exception`, `skip[=\"reason\"]`, `xfail[=\"reason\"]`\n- Optional `setup` / `teardown` blocks per object\n- Pytest integration (auto-discovered plugin) and a standalone CLI\n- Runtime helpers to validate directly in an interpreter or on call\n\nInstall\n-------\n\n```bash\npip install docspec-test\n```\n\nQuickstart\n----------\n\n```python\ndef add(a: int, b: int) -> int:\n \"\"\"\n Adds two numbers.\n\n ```python test\n assert add(1, 2) == 3\n ```\n \"\"\"\n return a + b\n```\n\nRun pytest (the plugin is discovered via `pytest11`):\n\n```bash\npytest\n```\n\nDirectives\n----------\n\nAdd options to the test block header:\n\n```markdown\n```python test name=\"custom-name\" raises=ValueError skip=\"reason\" xfail\n# test code\n```\n```\n\n- name: custom test name\n- raises: assert that an exception is raised (e.g. `raises=KeyError`)\n- skip: skip test, with optional reason\n- xfail: expected failure, with optional reason\n\nSetup / Teardown\n----------------\n\nOne optional `setup` and `teardown` block per object:\n\n```markdown\n```python setup\nstate = {\"x\": 0}\n```\n\n```python test name=\"increments\"\nstate[\"x\"] += 1\nassert state[\"x\"] == 1\n```\n\n```python teardown\nstate.clear()\n```\n```\n\nRuntime validation (no pytest)\n------------------------------\n\n```python\nfrom docspec_test import validate_module, execute_docstring_tests_for_object, validate_on_call\n\n# validate an entire module by path or module object\nvalidate_module(\"path/to/module.py\")\n\n# validate a single function/class\nexecute_docstring_tests_for_object(add)\n\n# validate on first call (or on every call with mode=\"always\")\n@validate_on_call\ndef inc(x: int) -> int:\n \"\"\"\n ```python test\n assert inc(1) == 2\n ```\n \"\"\"\n return x + 1\n```\n\nCLI\n---\n\nValidate all Python files in the current directory:\n\n```bash\ndocspec-test\n```\n\nValidate a specific path (file or directory):\n\n```bash\ndocspec-test path/to/src\n```\n\nIgnore directories:\n\n```bash\ndocspec-test . --ignore .venv --ignore build\n```\n\nPytest defaults\n---------------\n\nBy default, only docspec-marked tests run (`-m docspec`). To run everything:\n\n```bash\npytest -m 'not docspec'\n```\n\nContributing\n------------\n\nWe\u2019d love your help! Great first issues: docs, new directives, better error reporting, CI workflows.\n\nDev setup:\n\n```bash\ngit clone https://github.com/alexsukhrin/docspec_test\ncd docspec_test\npython -m venv venv && source venv/bin/activate\npip install -e .[dev] # or: pip install -e . && pip install black isort pytest build twine\n```\n\nRun checks:\n\n```bash\nisort . && black . && pytest -m 'not docspec' && pytest\n```\n\nRoadmap\n-------\n\n- Parametrized examples (table-driven)\n- Inline output matching (like doctest) alongside code blocks\n- Jupyter notebooks support\n- VSCode/IDE integration for quick-run\n\nRequirements\n------------\n\n- Python >= 3.8\n- pytest >= 7.0.0\n\nLicense\n-------\n\nMIT\n\n\n",
"bugtrack_url": null,
"license": null,
"summary": "Pytest plugin for running docstring tests in Markdown blocks",
"version": "0.1.6",
"project_urls": {
"Homepage": "https://github.com/alexsukhrin/docspec_test",
"Source": "https://github.com/alexsukhrin/docspec_test",
"Tracker": "https://github.com/alexsukhrin/docspec_test/issues"
},
"split_keywords": [
"pytest",
" plugin",
" doctest",
" docstring",
" markdown"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "fa237f736db7adfd7658322199424d5461f99ccc641f0ccb31902771d46d9e2b",
"md5": "c75aea88267086988134736e9505519b",
"sha256": "86db2bdf9b517376079022d9fb6dce9e69ec5dc40743708ed2877c549616521a"
},
"downloads": -1,
"filename": "docspec_test-0.1.6-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c75aea88267086988134736e9505519b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 10900,
"upload_time": "2025-09-06T21:18:37",
"upload_time_iso_8601": "2025-09-06T21:18:37.638408Z",
"url": "https://files.pythonhosted.org/packages/fa/23/7f736db7adfd7658322199424d5461f99ccc641f0ccb31902771d46d9e2b/docspec_test-0.1.6-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "c7934913f9728de38a8117d0dfcfd7b1ada7b88013ab5c0eb69a0f052bb4e0db",
"md5": "a67ad603e4c4f24ca74a2129c196ed12",
"sha256": "1eec4f23d0bae511d57ab08f5dce43dc0bdaa471ef623cd85a536c3bbaf12664"
},
"downloads": -1,
"filename": "docspec_test-0.1.6.tar.gz",
"has_sig": false,
"md5_digest": "a67ad603e4c4f24ca74a2129c196ed12",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 11265,
"upload_time": "2025-09-06T21:18:38",
"upload_time_iso_8601": "2025-09-06T21:18:38.711756Z",
"url": "https://files.pythonhosted.org/packages/c7/93/4913f9728de38a8117d0dfcfd7b1ada7b88013ab5c0eb69a0f052bb4e0db/docspec_test-0.1.6.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-06 21:18:38",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "alexsukhrin",
"github_project": "docspec_test",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "docspec-test"
}