Skip to main content

Validate Python code blocks in Markdown README files.

Project description

readme-example-tester

ci test codecov PyPI pyversions Current version on PyPI

Do not let your README/documentation examples become invalid: unit test them!

Install

pip install readme-example-tester

Usage

Mark the code blocks that you want to test.

Check out this crazy snippet:

<!-- example-id: tests/sample_pump_it_up.py -->
```python
def pump_it_up(input):
    return input + 100
```

Then create a unit test for that README, such as:

from pathlib import Path

from readme_example_tester import ReadmeTestCase


class TestReadme(ReadmeTestCase):
    # assuming test is in tests/ and README.md in root
    README_PATH = Path(__file__).parent.parent / 'README.md'
    TESTS_DIR = Path(__file__).parent

Whenever this test case runs, 3 tests are executed:

  • test_readme_example_targets_have_tests: ensures every snippet is covered by a test case
  • test_readme_code_blocks_match_example_targets: ensures every snippet matches an existing file
  • test_examples_are_still_in_use: ensures all files inside TESTS_DIR matching SAMPLE_FILE_GLOB (sample_*) are still being used in the README

These tests, plus the sample-file coverage checks, keep README examples honest.

Dogfooding

This project README is actually covered by tests/test_dogfood.py

And the inner example is in tests/sample_one.md and covered by tests/test_sample_one_readme.py

Advanced usage

Custom marker

class DemoReadme(ReadmeTestCase):
    README_PATH = Path(__file__).parent / 'README.md'
    TESTS_DIR = Path(__file__).parent
    README_MARKER = 'demo-id'
<!-- demo-id: tests/some_sample.py -->
```python
def pump_it_up(input):
    return input + 100
```

Assert snippet outputs

Use <!-- example-id-output: ... --> (or README_MARKER-output if customized) to compare/validate outputs from an executable sample script.

Expanding the previous example to be executable

#!/usr/bin/env python3


def pump_it_up(input):
    return input + 100


def main(argv):
    if not argv:
        print('No pump')
    else:
        print(pump_it_up(int(argv[0])))


if __name__ == '__main__':
    import sys

    main(sys.argv[1:])
<!-- example-id-output: tests/sample_pump_it_up_cli.py 2 -->
```text
$ tests/sample_pump_it_up_cli.py 2
102
```

Partial snippets

Use # README+++ / # README--- in a sample file to narrow the excerpt that matches the README block when the source file has extra boilerplate.

If one sample file feeds multiple README blocks, use # README:<id>+++ / # README:<id>--- to split the source into named sections and then use <!-- example-id:<id> tests/... --> in the code snippets

Non-sample sample files

If you have a test file that matches SAMPLE_FILE_GLOB but it is not expected to be used in README, you can add # README-EXCLUDE

Development

Project setup and local checks live in CONTRIBUTING.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

readme_example_tester-0.0.2.tar.gz (8.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

readme_example_tester-0.0.2-py3-none-any.whl (7.0 kB view details)

Uploaded Python 3

File details

Details for the file readme_example_tester-0.0.2.tar.gz.

File metadata

  • Download URL: readme_example_tester-0.0.2.tar.gz
  • Upload date:
  • Size: 8.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for readme_example_tester-0.0.2.tar.gz
Algorithm Hash digest
SHA256 1195c7bef26e53d3ad779b540ed5009e981d8ad6eac3f2b8b4081997b6b8405e
MD5 fa1de5a6c94877e4e02b2a07aca2a310
BLAKE2b-256 b728d48f9eecc0114386d8529a2f45d520024d2016011852ea198acf8f5de9a6

See more details on using hashes here.

File details

Details for the file readme_example_tester-0.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for readme_example_tester-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 6f7a8f41e3ade82f05d2fdba364c01f346263e7a5f64a2af13a1b17dc7c73342
MD5 8f2309721d3f6ab3cce58ae930f5b2ea
BLAKE2b-256 f58283e227cc1939de0651957536151f17d8c17e326676c439605b41bdacd2cc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page