Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
pytest-accept is a pytest plugin for automatically updating doctest outputs. It runs doctests, observes the generated outputs, and writes them to the doctests' documented outputs.
It's designed for a couple of audiences:
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 from normal doctests.
Here's an example of what 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 @yminsky in a Jane Street Blogpost. @matklad also has an excellent summary in his blog post How to Test.
pip install pytest-accept
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:
accept(result, "abc")
,
similar to frameworks like rust's excellent
insta (which I developed some features
for), or ocaml's ppx_expect.
assert
tests. And one of the great elegances of pytest is its
deferral to a normal assert
statement.Nothing ground-breaking! Some notes:
If a docstring uses escape characters such as \n
, python will interpret them
as the escape character rather than the literal. Use a raw string to have it
interpreted as a literal. e.g. this fails:
def raw_string():
"""
>>> "\n"
'\n'
"""
but succeeds with:
def raw_string():
- """
+ r"""
>>> "\n"
'\n'
Possibly pytest-accept could do more here — e.g. change the format of the docstring. But that would not be trivial to implement, and may be too invasive.
The library attempts to confirm the file hasn't changed between the start and
end of the test and won't overwrite the file where it detects there's been a
change. This can be helpful for workflows where the tests run repeatedly in
the background (e.g. using something like
watchexec) while a person is working
on the file, or when the tests take a long time, maybe because of --pdb
. To
be doubly careful, passing --accept-copy
will cause the plugin to instead
create a file named {file}.py.new
rather than overwriting the file on any
doctest failure.
--accept-copy
to be conservative.This is still fairly early, has mostly been used by me & xarray and there may be some small bugs. Let me know anything at all and I'll attempt to fix them.
It currently doesn't affect the printing of test results; the doctests will still print as failures.
Python's doctest library is imperfect:
.*
is an ellipsis ...
, which is also the syntax for
continuing a code line, so the beginning of a line must always be specified.pprint(x)
, which is verbose.\
is counted as one, meaning this
library will not have access to the correct line number for doctest inputs
and outputs.FAQs
A pytest-plugin for updating doctest outputs
We found that pytest-accept demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.