{"id":50785178,"url":"https://github.com/confarg/pytest-markdown-console","last_synced_at":"2026-06-12T07:05:15.101Z","repository":{"id":362364886,"uuid":"1241776550","full_name":"confarg/pytest-markdown-console","owner":"confarg","description":"A pytest extension to test console code blocks in markdown files.","archived":false,"fork":false,"pushed_at":"2026-06-03T21:05:41.000Z","size":75,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-03T23:06:12.879Z","etag":null,"topics":["console","markdown-codeblock","pytest-plugin"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/confarg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-17T19:57:32.000Z","updated_at":"2026-06-03T21:05:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/confarg/pytest-markdown-console","commit_stats":null,"previous_names":["confarg/pytest-markdown-console"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/confarg/pytest-markdown-console","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/confarg%2Fpytest-markdown-console","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/confarg%2Fpytest-markdown-console/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/confarg%2Fpytest-markdown-console/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/confarg%2Fpytest-markdown-console/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/confarg","download_url":"https://codeload.github.com/confarg/pytest-markdown-console/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/confarg%2Fpytest-markdown-console/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34232853,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-12T02:00:06.859Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["console","markdown-codeblock","pytest-plugin"],"created_at":"2026-06-12T07:05:14.382Z","updated_at":"2026-06-12T07:05:15.096Z","avatar_url":"https://github.com/confarg.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# A pytest plugin to test console code blocks in Markdown files\n\n\n## Installation\n\nIn your project, run:\n\n```bash\npip install pytest-markdown-console\n```\n\nIf you are using `uv`, install it as a development dependency:\n\n```bash\nuv add --dev pytest-markdown-console\n```\n\nThe plugin self-registers and will run in each subsequent `pytest` invocation.\n\n\n## How does it work?\n\nEach `console` code block in Markdown files collected by the plugin generates a test case.\n\nThe test runs each command in the block and compares its actual output to the expected output written in the block.\n\nTake this Markdown file:\n\n````markdown\n# README.md\n\nHere is an example of running my app:\n\n```console\n$ uv run myapp.py\nHello, world!\n```\n````\n\nRunning pytest with this plugin creates a test case that passes if the app actually prints \"Hello, world!\".\n\n### Match partial output\n\nUse `...` anywhere in the expected output to match any text in its place, including multiple lines:\n\n````markdown\n```console\n$ python -c \"print(object())\"\n\u003cobject object at 0x...\u003e\n```\n````\n\nThis is useful when part of the output is non-deterministic, such as memory addresses or timestamps, or when the output is very long.\n\n\n### Signal expected failures\n\nSometimes you want to illustrate expected failures. To convey this to both the reader and the plugin, place a `# Error: `comment at the end of the failing command, or on the line preceding it:\n\n````markdown\n```console\n$ uv run myapp.py --bad_option  # Error: this will fail\n...\n$ # Error: this will also most definitely fail\n$ uv run myapp.py --still_bad\n...\n```\n````\n\nTo the test case to pass, the command line must fail and the error message produced by the application, if any, must match.\n\n### Filter by platform\n\nTo restrict a test to specific platforms, use the `platform:` directive in an HTML comment immediately before the fence:\n\n````markdown\n\u003c!-- pytest-markdown-console: platform:linux,macos --\u003e\n```console\n$ echo \"This will generate a test case on Linux and macOS\"\n```\n````\n\nTo exclude a platform, prefix its name with `!`:\n\n````markdown\n\u003c!-- pytest-markdown-console: platform:!windows --\u003e\n```console\n$ echo \"This will not generate a test case on Windows\"\n```\n````\n\n### Change the working directory\n\nBy default, all commands run in the same directory as the Markdown file. To use a different directory, use the `cwd:` directive:\n\n````markdown\n\u003c!-- pytest-markdown-console: cwd:../ --\u003e\n```console\n$ uv run myapp.py\n...\n```\n````\n\nRelative paths are resolved relative to the Markdown file's location.\n\n\n### Use a temporary directory\n\nEach console block test automatically gets an isolated temporary directory, available as the `tmpdir` environment variable. This is useful when your app writes files during testing:\n\n````markdown\n```console\n$ uv run myapp.py --logdir \"${tmpdir}/logs\"\nDone.\n```\n````\n\nYou can also use `${tmpdir}` in the `cwd:` directive to run the block's commands inside the temporary directory:\n\n````markdown\n\u003c!-- pytest-markdown-console: cwd:${tmpdir} --\u003e\n```console\n$ uv run myapp.py\n$ cat output.txt\nHello, world!\n```\n````\n\nEach block gets its own dedicated directory, so blocks do not share state through the filesystem.\n\n\u003e **Note for PowerShell users:** In `pwsh` command lines, environment variables use the `$env:` prefix. Reference the directory as `$env:tmpdir` instead of `${tmpdir}`. The `${tmpdir}` syntax in `cwd:` always works regardless of the target shell, since it is expanded by the plugin before the shell runs.\n\n\n### Use your own fixtures\n\nFor more complex setup — seeding a config file, creating a mock, or running any other preparation logic — you can declare pytest fixtures and name them in a `fixtures:` directive. The fixtures run before the block's commands.\n\nThe plugin provides a `markdown_console_tmpdir` fixture that returns the block's `tmpdir` as a `pathlib.Path`, so your fixtures can write files that the block can read via `${tmpdir}`:\n\n```python\n# conftest.py\nimport pytest\n\n@pytest.fixture\ndef write_config(markdown_console_tmpdir):\n    (markdown_console_tmpdir / \"config.ini\").write_text(\"[settings]\\nkey=value\\n\")\n```\n\n````markdown\n\u003c!-- pytest-markdown-console: fixtures:write_config --\u003e\n```console\n$ uv run myapp.py --config \"${tmpdir}/config.ini\"\nDone.\n```\n````\n\nA fixture can also return a `dict[str, str]` to inject additional environment variables into the block's subprocess. If it returns `None` (or nothing), the return value is ignored:\n\n```python\n@pytest.fixture\ndef inject_env(markdown_console_tmpdir):\n    (markdown_console_tmpdir / \"seed.db\").write_bytes(b\"...\")\n    return {\"DB_PATH\": str(markdown_console_tmpdir / \"seed.db\")}\n```\n\nMultiple fixtures can be listed, comma-separated:\n\n````markdown\n\u003c!-- pytest-markdown-console: fixtures:write_config,inject_env --\u003e\n```console\n$ uv run myapp.py\nDone.\n```\n````\n\n`yield` fixtures work normally — teardown runs after the block completes.\n\n### Exclude a block from testing\n\nTo exclude a block from being collected as a test at all, use the `notest` directive:\n\n````markdown\n\u003c!-- pytest-markdown-console: notest --\u003e\n```console\n$ echo \"This block will not be tested\"\n```\n````\n\n### Run hidden blocks\n\nWrapping a fence in an HTML comment hides it from rendered output (e.g. on GitHub) while\nthe plugin still finds and runs it. This is useful for setup steps that would clutter the\ndocumentation:\n\n````markdown\n\u003c!-- pytest-markdown-console: notest --\u003e\n\u003c!--\n```console\n$ mkdir -p tmp\n```\n--\u003e\n````\n\nTo attach a directive to a hidden block, place it on the line immediately before the `\u003c!--`\nopener:\n\n````markdown\n\u003c!-- pytest-markdown-console: cwd:tmp --\u003e\n\u003c!--\n```console\n$ echo hi\nhi\n```\n--\u003e\n````\n\n### Customise the directive tag\n\nBy default, directive comments use the `pytest-markdown-console` tag:\n\n````markdown\n\u003c!-- pytest-markdown-console: notest --\u003e\n```console\n$ echo \"This block will not be tested\"\n```\n````\n\nYou can change this tag via `pyproject.toml`, for example to keep your Markdown source shorter:\n\n```toml\n[tool.pytest.ini_options]\nmarkdown_console_directive = \"console-test\"\n```\n\nWith the above setting you would write `\u003c!-- console-test: notest --\u003e` instead.\n\n### Control test case runs globally\n\nBy default, test cases generated by this plugin are run whenever pytest is invoked. To exclude them entirely:\n\n```bash\npytest -p no:markdown-console\n```\n\nTo run only the plugin's tests:\n\n```bash\npytest -m markdown_console\n```\n\n\n## Why this plugin?\n\nThis plugin makes your documentation testable — specifically `console` blocks — within the same pytest suite you use for the rest of your Python code.\n\nOther tools can test `console` blocks in Markdown files, but we couldn't find one that is simple, supports Windows, integrates with pytest, and requires no boilerplate.\n\n### Does it make sense to test `console` blocks?\n\nTesting `console` blocks is admittedly niche. They often contain installation instructions or shell-specific commands that don't translate across platforms.\n\nHowever, if you are building a CLI app, you likely already showcase commands and their output in your docs. Testing those snippets ensures they stay up-to-date.\n\nLaunching a Python app on Windows, Linux, or macOS is the same one-liner when using `uv`. That is the sweet spot motivating this small plugin.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconfarg%2Fpytest-markdown-console","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fconfarg%2Fpytest-markdown-console","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconfarg%2Fpytest-markdown-console/lists"}