Skip to main content

A pytest-plugin for updating doctest outputs

Project description

pytest-accept

Test Actions Status PyPI version fury.io GitHub license

pytest-accept is a pytest plugin for automatically updating doctest outputs. It observes generated outputs by running doctests, and writes these to the doctests' documented outputs.

It's designed for a couple of use cases:

  • People who work with doctests and don't enjoy manually copying and pasting generated outputs from the pytest error log into their doctests' documented outputs. pytest-accept does the copying & pasting for you.
  • People who generally find writing tests a bit annoying, and prefer to develop by "running the code and seeing whether it works". This library aims to allow testing to become a joyful part of that development loop.

pytest-accept is decoupled from the doctests it works with — it can be used with existing doctests, and the doctests it edits are no different to normal doctests.

Jesse, what the?

Here's an example of pytest-accept does: given a file like add.py containing an incorrect documented output:

def add(x, y):
    """
    Adds two values.

    >>> add(1, 1)
    3

    >>> add("ab", "c")
    'bac'
    """

    return x + y

...running doctests using pytest and passing --accept replaces the existing incorrect values with correct values:

pytest --doctest-modules examples/add.py --accept
diff --git a/examples/add.py b/examples/add.py
index 10a71fd..c2c945f 100644
--- a/examples/add.py
+++ b/examples/add.py
@@ -3,10 +3,10 @@ def add(x, y):
     Adds two values.
 
     >>> add(1, 1)
-    3
+    2
 
     >>> add("ab", "c")
-    'bac'
+    'abc'
     """
 
     return x + y

This style of testing is fairly well-developed in some languages, although still doesn't receive the attention I think it deserves, and historically hasn't had good support in python.

Confusingly, it's referred to "snapshot testing" or "regression testing" or "expect testing" or "literate testing" or "acceptance testing". The best explanation I've seen on this testing style is from Ron Minsky in a Jane Street Blogpost.

Installation

pip install pytest-accept

What about normal tests?

A previous effort in assert_plugin.py attempted to do this for assert statements, and the file contains some notes on the effort. The biggest problem is pytest stops on the first assert failure in each test, which is very limiting. (Whereas pytest can be configured to continue on doctest failures, which this library takes advantage of.)

It's probably possible to change pytest's behavior here, but it's a significant effort on the pytest codebase.

Some alternatives:

  • Use an existing library like pytest-regtest, which offers file snapshot testing (i.e. not inline).
  • We could write a specific function / fixture, like accept(result, "abc"), similar to frameworks like rust's excellent insta (which I developed some features for), or ocaml's ppx_expect.
    • But this has the disadvantage of coupling the test to the plugin: it's not possible to run tests independently of the plugin, or use the plugin on general assert tests. And one of the great elegances of pytest is its deferral to a normal assert statement.
  • Some of this testing feels like writing a notebook and testing that. pytest-notebook fully implements this.

Anything else?

Not really! Some things to watch out for:

  • It'll replace the file at the end of a test. So — to the extent there are useful changes to the file between the start and and the end of a test — it'll overwrite them. Passing --accept-copy will cause the plugin to instead create a file named {file}.py.new.
    • TODO: Should we disable the plugin on --pdb as one way of long-running tests?
    • It will overwrite the existing values, though these aren't generally useful — they're designed to match the results of the code.
  • This is early, and there are probably some small bugs. Let me know and I'll attempt to fix them.
  • It currently doesn't affect the printing of test results; the doctests will still print as failures.
    • TODO: A future version could print something about them being fixed.
  • Python's doctest library is imperfect:
    • It can't handle indents, and probably other things. (We do handle blank lines though, and TODO: check whether the output we paste is valid doctest output).
    • The syntax for .* is an ellipsis ..., which is also the syntax for continuing a code line, so it can't be at the start of a line.
    • The syntax for all the directives is arguably less than aesthetically pleasing.
    • It reports line numbers incorrectly in some cases — two docstring lines separated with continuation character \ is counted as one, meaning this library will not have access to the correct line number for doctest inputs and outputs.

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

pytest-accept-0.1.3.tar.gz (12.9 kB view details)

Uploaded Source

Built Distribution

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

pytest_accept-0.1.3-py3-none-any.whl (13.3 kB view details)

Uploaded Python 3

File details

Details for the file pytest-accept-0.1.3.tar.gz.

File metadata

  • Download URL: pytest-accept-0.1.3.tar.gz
  • Upload date:
  • Size: 12.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.6 CPython/3.8.10 Linux/5.4.0-1047-azure

File hashes

Hashes for pytest-accept-0.1.3.tar.gz
Algorithm Hash digest
SHA256 aba62c776a13c91f4a6c712e34fee09665ba016ba7ab5de8210f165d82cbcc96
MD5 5054f77b17d16d81a47b01fc9770703c
BLAKE2b-256 e5af705888a99dca9c10310e5f1e3ff6e642b8bf3e16fe04b4909f68b2648618

See more details on using hashes here.

File details

Details for the file pytest_accept-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: pytest_accept-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 13.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.6 CPython/3.8.10 Linux/5.4.0-1047-azure

File hashes

Hashes for pytest_accept-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 eb3147ef1ab01bac52407d6ba0ef75fa453bab378613f729f9eb5dc847c801f3
MD5 3fecf94b3260305fc6b96c27eb9e58f7
BLAKE2b-256 56bee60f0bd6e7f25b453c2360ffd2dc1908ad2a0c8e70eae64079c1faf5c0ee

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