Compare commits
207 Commits
6.0.x
...
6.2.0.dev0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0ea00a70d | ||
|
|
19c78ab574 | ||
|
|
0b327cc75b | ||
|
|
d3c746eb8e | ||
|
|
d3f47bf346 | ||
|
|
3db24893b4 | ||
|
|
8215625135 | ||
|
|
5cfd7c0ddd | ||
|
|
a99ca879e7 | ||
|
|
050c2df737 | ||
|
|
cdfdb3a25d | ||
|
|
8eefe4eaf5 | ||
|
|
b031a7cecf | ||
|
|
027415502a | ||
|
|
9f164b7227 | ||
|
|
4e460cdd9e | ||
|
|
89305e7b09 | ||
|
|
c4ce5f2c98 | ||
|
|
9bfd14a443 | ||
|
|
895a8cf296 | ||
|
|
98608c439f | ||
|
|
9ceb4e6efc | ||
|
|
da21fc5883 | ||
|
|
7470270f20 | ||
|
|
cdf2024070 | ||
|
|
f42c0cd1ec | ||
|
|
4b46db8ae5 | ||
|
|
7f7e383daf | ||
|
|
a5fd2895b6 | ||
|
|
bc0020ad96 | ||
|
|
e04bc05e7e | ||
|
|
51752108b8 | ||
|
|
24c26a046e | ||
|
|
d18cb961cf | ||
|
|
35350e11cd | ||
|
|
634cde9506 | ||
|
|
ec58ae5bae | ||
|
|
96a17b1683 | ||
|
|
389e30283c | ||
|
|
e0dd2111a0 | ||
|
|
e36adbaadc | ||
|
|
c00fe960ba | ||
|
|
78ed3e48db | ||
|
|
9c0e0c756a | ||
|
|
6ae0f741ef | ||
|
|
7da6ebede0 | ||
|
|
e503c9a9f8 | ||
|
|
4df39e3a1d | ||
|
|
5bdfd719e6 | ||
|
|
1df2471f17 | ||
|
|
54f7a87ea8 | ||
|
|
db12d79c2a | ||
|
|
44fc0192bc | ||
|
|
5371be4cf6 | ||
|
|
0ca2327069 | ||
|
|
48a8c373a0 | ||
|
|
885d969484 | ||
|
|
0d0b798663 | ||
|
|
62e249a1f9 | ||
|
|
a346028006 | ||
|
|
3085c99e47 | ||
|
|
19e99ab413 | ||
|
|
9f672c85c5 | ||
|
|
91dbdb6093 | ||
|
|
877c62166a | ||
|
|
21aa6c42b7 | ||
|
|
ceea6000ba | ||
|
|
12de92cd2b | ||
|
|
daca174c98 | ||
|
|
2fcf763d7e | ||
|
|
98891a5947 | ||
|
|
8730a7bb14 | ||
|
|
a267a622eb | ||
|
|
00996adeb8 | ||
|
|
ff41e7ad5d | ||
|
|
c1f975668e | ||
|
|
023f0510af | ||
|
|
c867452488 | ||
|
|
d0e8b71404 | ||
|
|
eec13ba57e | ||
|
|
c4fd461617 | ||
|
|
c2256189ae | ||
|
|
841521fedb | ||
|
|
0c6b2f39b2 | ||
|
|
a2c919d350 | ||
|
|
adaec2da90 | ||
|
|
1b2de81404 | ||
|
|
5356a0979a | ||
|
|
0b41b79dcb | ||
|
|
57aca11d4a | ||
|
|
4b8e1a1771 | ||
|
|
32edc4655c | ||
|
|
d121d7c917 | ||
|
|
1dad5c6433 | ||
|
|
172b6e15c5 | ||
|
|
bb38ae9c52 | ||
|
|
6cf89338d3 | ||
|
|
b47b488e3d | ||
|
|
143e3ab846 | ||
|
|
837687c21a | ||
|
|
b1354608cc | ||
|
|
75af2bfa06 | ||
|
|
5e39cd5e71 | ||
|
|
d69abff2c7 | ||
|
|
372a094005 | ||
|
|
7605150eaa | ||
|
|
ef946d557c | ||
|
|
b32c48ee05 | ||
|
|
52b0cc4f19 | ||
|
|
457d351941 | ||
|
|
345a59dd53 | ||
|
|
6ecbd008c4 | ||
|
|
73e06373dc | ||
|
|
c747dc5248 | ||
|
|
98530184a5 | ||
|
|
c98525bd21 | ||
|
|
afa4760cb8 | ||
|
|
0d5a65091d | ||
|
|
b426bb3443 | ||
|
|
2213016e40 | ||
|
|
3f0abcc6a5 | ||
|
|
eddd993cf4 | ||
|
|
f76b162263 | ||
|
|
d426a79a90 | ||
|
|
f28af14457 | ||
|
|
2c5403b951 | ||
|
|
8056a677b4 | ||
|
|
02c6e4455c | ||
|
|
10f98e1d2f | ||
|
|
82181fde3e | ||
|
|
36c8bb492e | ||
|
|
15d8293241 | ||
|
|
4c92584364 | ||
|
|
acc9310c17 | ||
|
|
8a66f0a96d | ||
|
|
bee72e1925 | ||
|
|
a27c539a85 | ||
|
|
384b6f6866 | ||
|
|
f8c4e038fd | ||
|
|
70f3ad1c1f | ||
|
|
9e55288ba4 | ||
|
|
e0d0951945 | ||
|
|
aa9905d72e | ||
|
|
67cb7ef673 | ||
|
|
a64298ff5e | ||
|
|
44cd8a3a86 | ||
|
|
2bd0d97fcc | ||
|
|
fbf251f11d | ||
|
|
f0eb82f7d4 | ||
|
|
62ddf7a0e5 | ||
|
|
303030c141 | ||
|
|
0d65e4b454 | ||
|
|
84c4b64354 | ||
|
|
d688fefecb | ||
|
|
9ab14c6d9c | ||
|
|
1c9b84756f | ||
|
|
0dd5e169d0 | ||
|
|
9a18b57c7c | ||
|
|
b8471aa527 | ||
|
|
701998bf2c | ||
|
|
be354b36f3 | ||
|
|
be656dd4e4 | ||
|
|
d1fa749b83 | ||
|
|
d7ad55bb2a | ||
|
|
1e9c638468 | ||
|
|
a2d562d369 | ||
|
|
49827adcb9 | ||
|
|
cbec0f8c6a | ||
|
|
0242de4f56 | ||
|
|
6882c0368b | ||
|
|
07f7372aff | ||
|
|
d5a49100cf | ||
|
|
4f0793a462 | ||
|
|
09265eb7c7 | ||
|
|
a1ba8dfe2a | ||
|
|
8d98de8f8a | ||
|
|
96a48f0c66 | ||
|
|
e49f1d6f60 | ||
|
|
645cbc91fc | ||
|
|
924e466c98 | ||
|
|
d756b4a543 | ||
|
|
1e66ed0b1c | ||
|
|
49628786f0 | ||
|
|
22acbaf393 | ||
|
|
e691d3ee52 | ||
|
|
095bf191e2 | ||
|
|
cefe064bb0 | ||
|
|
d3267bc49d | ||
|
|
0e0275d8d9 | ||
|
|
422685d0bd | ||
|
|
b473e515bc | ||
|
|
20a3a28815 | ||
|
|
54e08b7230 | ||
|
|
f9837f953c | ||
|
|
c755840793 | ||
|
|
f86e4516eb | ||
|
|
1653c49b1b | ||
|
|
6ea6f0dac8 | ||
|
|
27a4c6cd6d | ||
|
|
b36bcd13e9 | ||
|
|
88cc636c18 | ||
|
|
c7216ae0f6 | ||
|
|
df09a31646 | ||
|
|
109b6cb32c | ||
|
|
70764bef4f | ||
|
|
3633b691d8 | ||
|
|
c15bb5d3de |
@@ -27,3 +27,4 @@ exclude_lines =
|
||||
^\s*assert False(,|$)
|
||||
|
||||
^\s*if TYPE_CHECKING:
|
||||
^\s*@overload( |$)
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
---
|
||||
name: 🐛 Bug Report
|
||||
about: Report errors and problems
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Thanks for submitting an issue!
|
||||
|
||||
Here's a quick checklist for what to provide:
|
||||
Quick check-list while reporting bugs:
|
||||
-->
|
||||
|
||||
- [ ] a detailed description of the bug or suggestion
|
||||
- [ ] a detailed description of the bug or problem you are having
|
||||
- [ ] output of `pip list` from the virtual environment you are using
|
||||
- [ ] pytest and operating system versions
|
||||
- [ ] minimal example if possible
|
||||
5
.github/ISSUE_TEMPLATE/2_feature_request.md
vendored
Normal file
5
.github/ISSUE_TEMPLATE/2_feature_request.md
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
name: 🚀 Feature Request
|
||||
about: Ideas for new features and improvements
|
||||
|
||||
---
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: ❓ Support Question
|
||||
url: https://github.com/pytest-dev/pytest/discussions
|
||||
about: Use GitHub's new Discussions feature for questions
|
||||
8
.github/workflows/main.yml
vendored
8
.github/workflows/main.yml
vendored
@@ -41,6 +41,7 @@ jobs:
|
||||
|
||||
"docs",
|
||||
"doctesting",
|
||||
"plugins",
|
||||
]
|
||||
|
||||
include:
|
||||
@@ -111,6 +112,11 @@ jobs:
|
||||
tox_env: "py38-xdist"
|
||||
use_coverage: true
|
||||
|
||||
- name: "plugins"
|
||||
python: "3.7"
|
||||
os: ubuntu-latest
|
||||
tox_env: "plugins"
|
||||
|
||||
- name: "docs"
|
||||
python: "3.7"
|
||||
os: ubuntu-latest
|
||||
@@ -131,7 +137,7 @@ jobs:
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
- name: Set up Python ${{ matrix.python }} (deadsnakes)
|
||||
uses: deadsnakes/action@v1.0.0
|
||||
uses: deadsnakes/action@v2.0.0
|
||||
if: matrix.python == '3.9-dev'
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
|
||||
@@ -25,7 +25,9 @@ repos:
|
||||
hooks:
|
||||
- id: flake8
|
||||
language_version: python3
|
||||
additional_dependencies: [flake8-typing-imports==1.9.0]
|
||||
additional_dependencies:
|
||||
- flake8-typing-imports==1.9.0
|
||||
- flake8-docstrings==1.5.0
|
||||
- repo: https://github.com/asottile/reorder_python_imports
|
||||
rev: v2.3.0
|
||||
hooks:
|
||||
@@ -70,9 +72,11 @@ repos:
|
||||
_code\.|
|
||||
builtin\.|
|
||||
code\.|
|
||||
io\.(BytesIO|saferepr|TerminalWriter)|
|
||||
io\.|
|
||||
path\.local\.sysfind|
|
||||
process\.|
|
||||
std\.
|
||||
std\.|
|
||||
error\.|
|
||||
xml\.
|
||||
)
|
||||
types: [python]
|
||||
|
||||
12
.readthedocs.yml
Normal file
12
.readthedocs.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
version: 2
|
||||
|
||||
python:
|
||||
version: 3.7
|
||||
install:
|
||||
- requirements: doc/en/requirements.txt
|
||||
- method: pip
|
||||
path: .
|
||||
|
||||
formats:
|
||||
- epub
|
||||
- pdf
|
||||
1
AUTHORS
1
AUTHORS
@@ -151,6 +151,7 @@ Joshua Bronson
|
||||
Jurko Gospodnetić
|
||||
Justyna Janczyszyn
|
||||
Kale Kundert
|
||||
Kamran Ahmad
|
||||
Karl O. Pinc
|
||||
Katarzyna Jachim
|
||||
Katarzyna Król
|
||||
|
||||
@@ -89,6 +89,38 @@ without using a local copy. This can be convenient for small fixes.
|
||||
The built documentation should be available in ``doc/en/_build/html``,
|
||||
where 'en' refers to the documentation language.
|
||||
|
||||
Pytest has an API reference which in large part is
|
||||
`generated automatically <https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html>`_
|
||||
from the docstrings of the documented items. Pytest uses the
|
||||
`Sphinx docstring format <https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html>`_.
|
||||
For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def my_function(arg: ArgType) -> Foo:
|
||||
"""Do important stuff.
|
||||
|
||||
More detailed info here, in separate paragraphs from the subject line.
|
||||
Use proper sentences -- start sentences with capital letters and end
|
||||
with periods.
|
||||
|
||||
Can include annotated documentation:
|
||||
|
||||
:param short_arg: An argument which determines stuff.
|
||||
:param long_arg:
|
||||
A long explanation which spans multiple lines, overflows
|
||||
like this.
|
||||
:returns: The result.
|
||||
:raises ValueError:
|
||||
Detailed information when this can happen.
|
||||
|
||||
.. versionadded:: 6.0
|
||||
|
||||
Including types into the annotations above is not necessary when
|
||||
type-hinting is being used (as in this example).
|
||||
"""
|
||||
|
||||
|
||||
.. _submitplugin:
|
||||
|
||||
Submitting Plugins to pytest-dev
|
||||
@@ -99,8 +131,6 @@ in repositories living under the ``pytest-dev`` organisations:
|
||||
|
||||
- `pytest-dev on GitHub <https://github.com/pytest-dev>`_
|
||||
|
||||
- `pytest-dev on Bitbucket <https://bitbucket.org/pytest-dev>`_
|
||||
|
||||
All pytest-dev Contributors team members have write access to all contained
|
||||
repositories. Pytest core and plugins are generally developed
|
||||
using `pull requests`_ to respective repositories.
|
||||
@@ -116,16 +146,17 @@ You can submit your plugin by subscribing to the `pytest-dev mail list
|
||||
mail pointing to your existing pytest plugin repository which must have
|
||||
the following:
|
||||
|
||||
- PyPI presence with a ``setup.py`` that contains a license, ``pytest-``
|
||||
- PyPI presence with packaging metadata that contains a ``pytest-``
|
||||
prefixed name, version number, authors, short and long description.
|
||||
|
||||
- a ``tox.ini`` for running tests using `tox <https://tox.readthedocs.io>`_.
|
||||
- a `tox configuration <https://tox.readthedocs.io/en/latest/config.html#configuration-discovery>`_
|
||||
for running tests using `tox <https://tox.readthedocs.io>`_.
|
||||
|
||||
- a ``README.txt`` describing how to use the plugin and on which
|
||||
- a ``README`` describing how to use the plugin and on which
|
||||
platforms it runs.
|
||||
|
||||
- a ``LICENSE.txt`` file or equivalent containing the licensing
|
||||
information, with matching info in ``setup.py``.
|
||||
- a ``LICENSE`` file containing the licensing information, with
|
||||
matching info in its packaging metadata.
|
||||
|
||||
- an issue tracker for bug reports and enhancement requests.
|
||||
|
||||
@@ -375,6 +406,27 @@ actual latest release). The procedure for this is:
|
||||
* Delete the PR body, it usually contains a duplicate commit message.
|
||||
|
||||
|
||||
Who does the backporting
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
As mentioned above, bugs should first be fixed on ``master`` (except in rare occasions
|
||||
that a bug only happens in a previous release). So who should do the backport procedure described
|
||||
above?
|
||||
|
||||
1. If the bug was fixed by a core developer, it is the main responsibility of that core developer
|
||||
to do the backport.
|
||||
2. However, often the merge is done by another maintainer, in which case it is nice of them to
|
||||
do the backport procedure if they have the time.
|
||||
3. For bugs submitted by non-maintainers, it is expected that a core developer will to do
|
||||
the backport, normally the one that merged the PR on ``master``.
|
||||
4. If a non-maintainers notices a bug which is fixed on ``master`` but has not been backported
|
||||
(due to maintainers forgetting to apply the *needs backport* label, or just plain missing it),
|
||||
they are also welcome to open a PR with the backport. The procedure is simple and really
|
||||
helps with the maintenance of the project.
|
||||
|
||||
All the above are not rules, but merely some guidelines/suggestions on what we should expect
|
||||
about backports.
|
||||
|
||||
Handling stale issues/PRs
|
||||
-------------------------
|
||||
|
||||
|
||||
16
README.rst
16
README.rst
@@ -22,8 +22,8 @@
|
||||
.. image:: https://travis-ci.org/pytest-dev/pytest.svg?branch=master
|
||||
:target: https://travis-ci.org/pytest-dev/pytest
|
||||
|
||||
.. image:: https://dev.azure.com/pytest-dev/pytest/_apis/build/status/pytest-CI?branchName=master
|
||||
:target: https://dev.azure.com/pytest-dev/pytest
|
||||
.. image:: https://github.com/pytest-dev/pytest/workflows/main/badge.svg
|
||||
:target: https://github.com/pytest-dev/pytest/actions?query=workflow%3Amain
|
||||
|
||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/psf/black
|
||||
@@ -77,21 +77,21 @@ Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` stat
|
||||
Features
|
||||
--------
|
||||
|
||||
- Detailed info on failing `assert statements <https://docs.pytest.org/en/stable/assert.html>`_ (no need to remember ``self.assert*`` names);
|
||||
- Detailed info on failing `assert statements <https://docs.pytest.org/en/stable/assert.html>`_ (no need to remember ``self.assert*`` names)
|
||||
|
||||
- `Auto-discovery
|
||||
<https://docs.pytest.org/en/stable/goodpractices.html#python-test-discovery>`_
|
||||
of test modules and functions;
|
||||
of test modules and functions
|
||||
|
||||
- `Modular fixtures <https://docs.pytest.org/en/stable/fixture.html>`_ for
|
||||
managing small or parametrized long-lived test resources;
|
||||
managing small or parametrized long-lived test resources
|
||||
|
||||
- Can run `unittest <https://docs.pytest.org/en/stable/unittest.html>`_ (or trial),
|
||||
`nose <https://docs.pytest.org/en/stable/nose.html>`_ test suites out of the box;
|
||||
`nose <https://docs.pytest.org/en/stable/nose.html>`_ test suites out of the box
|
||||
|
||||
- Python 3.5+ and PyPy3;
|
||||
- Python 3.5+ and PyPy3
|
||||
|
||||
- Rich plugin architecture, with over 850+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community;
|
||||
- Rich plugin architecture, with over 850+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community
|
||||
|
||||
|
||||
Documentation
|
||||
|
||||
@@ -5,37 +5,85 @@ Our current policy for releasing is to aim for a bug-fix release every few weeks
|
||||
is to get fixes and new features out instead of trying to cram a ton of features into a release and by consequence
|
||||
taking a lot of time to make a new one.
|
||||
|
||||
The git commands assume the following remotes are setup:
|
||||
|
||||
* ``origin``: your own fork of the repository.
|
||||
* ``upstream``: the ``pytest-dev/pytest`` official repository.
|
||||
|
||||
Preparing: Automatic Method
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
We have developed an automated workflow for releases, that uses GitHub workflows and is triggered
|
||||
by opening an issue or issuing a comment one.
|
||||
by opening an issue.
|
||||
|
||||
The comment must be in the form::
|
||||
Bug-fix releases
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
@pytestbot please prepare release from BRANCH
|
||||
A bug-fix release is always done from a maintenance branch, so for example to release bug-fix
|
||||
``5.1.2``, open a new issue and add this comment to the body::
|
||||
|
||||
Where ``BRANCH`` is ``master`` or one of the maintenance branches.
|
||||
@pytestbot please prepare release from 5.1.x
|
||||
|
||||
For major releases the comment must be in the form::
|
||||
Where ``5.1.x`` is the maintenance branch for the ``5.1`` series.
|
||||
|
||||
@pytestbot please prepare major release from master
|
||||
The automated workflow will publish a PR for a branch ``release-5.1.2``
|
||||
and notify it as a comment in the issue.
|
||||
|
||||
After that, the workflow should publish a PR and notify that it has done so as a comment
|
||||
in the original issue.
|
||||
Minor releases
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
1. Create a new maintenance branch from ``master``::
|
||||
|
||||
git fetch --all
|
||||
git branch 5.2.x upstream/master
|
||||
git push upstream 5.2.x
|
||||
|
||||
2. Open a new issue and add this comment to the body::
|
||||
|
||||
@pytestbot please prepare release from 5.2.x
|
||||
|
||||
The automated workflow will publish a PR for a branch ``release-5.2.0`` and
|
||||
notify it as a comment in the issue.
|
||||
|
||||
Major and release candidates
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
1. Create a new maintenance branch from ``master``::
|
||||
|
||||
git fetch --all
|
||||
git branch 6.0.x upstream/master
|
||||
git push upstream 6.0.x
|
||||
|
||||
2. For a **major release**, open a new issue and add this comment in the body::
|
||||
|
||||
@pytestbot please prepare major release from 6.0.x
|
||||
|
||||
For a **release candidate**, the comment must be (TODO: `#7551 <https://github.com/pytest-dev/pytest/issues/7551>`__)::
|
||||
|
||||
@pytestbot please prepare release candidate from 6.0.x
|
||||
|
||||
The automated workflow will publish a PR for a branch ``release-6.0.0`` and
|
||||
notify it as a comment in the issue.
|
||||
|
||||
At this point on, this follows the same workflow as other maintenance branches: bug-fixes are merged
|
||||
into ``master`` and ported back to the maintenance branch, even for release candidates.
|
||||
|
||||
**A note about release candidates**
|
||||
|
||||
During release candidates we can merge small improvements into
|
||||
the maintenance branch before releasing the final major version, however we must take care
|
||||
to avoid introducing big changes at this stage.
|
||||
|
||||
Preparing: Manual Method
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. important::
|
||||
|
||||
pytest releases must be prepared on **Linux** because the docs and examples expect
|
||||
to be executed on that platform.
|
||||
**Important**: pytest releases must be prepared on **Linux** because the docs and examples expect
|
||||
to be executed on that platform.
|
||||
|
||||
To release a version ``MAJOR.MINOR.PATCH``, follow these steps:
|
||||
|
||||
#. For major and minor releases, create a new branch ``MAJOR.MINOR.x`` from the
|
||||
latest ``master`` and push it to the ``pytest-dev/pytest`` repo.
|
||||
#. For major and minor releases, create a new branch ``MAJOR.MINOR.x`` from
|
||||
``upstream/master`` and push it to ``upstream``.
|
||||
|
||||
#. Create a branch ``release-MAJOR.MINOR.PATCH`` from the ``MAJOR.MINOR.x`` branch.
|
||||
|
||||
@@ -56,9 +104,10 @@ Releasing
|
||||
Both automatic and manual processes described above follow the same steps from this point onward.
|
||||
|
||||
#. After all tests pass and the PR has been approved, tag the release commit
|
||||
in the ``MAJOR.MINOR.x`` branch and push it. This will publish to PyPI::
|
||||
in the ``release-MAJOR.MINOR.PATCH`` branch and push it. This will publish to PyPI::
|
||||
|
||||
git tag MAJOR.MINOR.PATCH
|
||||
git fetch --all
|
||||
git tag MAJOR.MINOR.PATCH upstream/release-MAJOR.MINOR.PATCH
|
||||
git push git@github.com:pytest-dev/pytest.git MAJOR.MINOR.PATCH
|
||||
|
||||
Wait for the deploy to complete, then make sure it is `available on PyPI <https://pypi.org/project/pytest>`_.
|
||||
@@ -69,9 +118,9 @@ Both automatic and manual processes described above follow the same steps from t
|
||||
|
||||
git fetch --all --prune
|
||||
git checkout origin/master -b cherry-pick-release
|
||||
git cherry-pick --no-commit -m1 origin/MAJOR.MINOR.x
|
||||
git checkout origin/master -- changelog
|
||||
git commit # no arguments
|
||||
git cherry-pick -x -m1 upstream/MAJOR.MINOR.x
|
||||
|
||||
#. Open a PR for ``cherry-pick-release`` and merge it once CI passes. No need to wait for approvals if there were no conflicts on the previous step.
|
||||
|
||||
#. Send an email announcement with the contents from::
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
Fix pylint ``not-callable`` lint on ``pytest.mark.parametrize()`` and the other builtin marks:
|
||||
``skip``, ``skipif``, ``xfail``, ``usefixtures``, ``filterwarnings``.
|
||||
@@ -1 +0,0 @@
|
||||
Fix regression in plugins using ``TestReport.longreprtext`` (such as ``pytest-html``) when ``TestReport.longrepr`` is not a string.
|
||||
@@ -45,7 +45,7 @@ Partner projects, sign up here! (by 22 March)
|
||||
What does it mean to "adopt pytest"?
|
||||
-----------------------------------------
|
||||
|
||||
There can be many different definitions of "success". Pytest can run many `nose and unittest`_ tests by default, so using pytest as your testrunner may be possible from day 1. Job done, right?
|
||||
There can be many different definitions of "success". Pytest can run many nose_ and unittest_ tests by default, so using pytest as your testrunner may be possible from day 1. Job done, right?
|
||||
|
||||
Progressive success might look like:
|
||||
|
||||
@@ -63,7 +63,8 @@ Progressive success might look like:
|
||||
|
||||
It may be after the month is up, the partner project decides that pytest is not right for it. That's okay - hopefully the pytest team will also learn something about its weaknesses or deficiencies.
|
||||
|
||||
.. _`nose and unittest`: faq.html#how-does-pytest-relate-to-nose-and-unittest
|
||||
.. _nose: nose.html
|
||||
.. _unittest: unittest.html
|
||||
.. _assert: assert.html
|
||||
.. _pycmd: https://bitbucket.org/hpk42/pycmd/overview
|
||||
.. _`setUp/tearDown methods`: xunit_setup.html
|
||||
|
||||
@@ -6,6 +6,9 @@ Release announcements
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
release-6.1.0
|
||||
release-6.0.2
|
||||
release-6.0.1
|
||||
release-6.0.0
|
||||
release-6.0.0rc1
|
||||
release-5.4.3
|
||||
|
||||
@@ -94,7 +94,7 @@ Changes between 2.2.4 and 2.3.0
|
||||
- pluginmanager.register(...) now raises ValueError if the
|
||||
plugin has been already registered or the name is taken
|
||||
|
||||
- fix issue159: improve http://pytest.org/en/stable/faq.html
|
||||
- fix issue159: improve https://docs.pytest.org/en/6.0.1/faq.html
|
||||
especially with respect to the "magic" history, also mention
|
||||
pytest-django, trial and unittest integration.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.5.1: fixes and new home page styling
|
||||
===========================================================================
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1000 tests
|
||||
pytest is a mature Python testing tool with more than 1000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
The 2.5.1 release maintains the "zero-reported-bugs" promise by fixing
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.5.2: fixes
|
||||
===========================================================================
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1000 tests
|
||||
pytest is a mature Python testing tool with more than 1000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
The 2.5.2 release fixes a few bugs with two maybe-bugs remaining and
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.6.0: shorter tracebacks, new warning system, test runner compat
|
||||
===========================================================================
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1000 tests
|
||||
pytest is a mature Python testing tool with more than 1000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
The 2.6.0 release should be drop-in backward compatible to 2.5.2 and
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.6.1: fixes and new xfail feature
|
||||
===========================================================================
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
The 2.6.1 release is drop-in compatible to 2.5.2 and actually fixes some
|
||||
regressions introduced with 2.6.0. It also brings a little feature
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.6.2: few fixes and cx_freeze support
|
||||
===========================================================================
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
This release is drop-in compatible to 2.5.2 and 2.6.X. It also
|
||||
brings support for including pytest with cx_freeze or similar
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.6.3: fixes and little improvements
|
||||
===========================================================================
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
This release is drop-in compatible to 2.5.2 and 2.6.X.
|
||||
See below for the changes and see docs at:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.7.0: fixes, features, speed improvements
|
||||
===========================================================================
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
This release is supposed to be drop-in compatible to 2.6.X.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.7.1: bug fixes
|
||||
=======================
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
This release is supposed to be drop-in compatible to 2.7.0.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.7.2: bug fixes
|
||||
=======================
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
This release is supposed to be drop-in compatible to 2.7.1.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.8.2: bug fixes
|
||||
=======================
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
This release is supposed to be drop-in compatible to 2.8.1.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.8.3: bug fixes
|
||||
=======================
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
This release is supposed to be drop-in compatible to 2.8.2.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.8.4
|
||||
============
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
This release is supposed to be drop-in compatible to 2.8.2.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.8.5
|
||||
============
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
This release is supposed to be drop-in compatible to 2.8.4.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.8.6
|
||||
============
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
This release is supposed to be drop-in compatible to 2.8.5.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ pytest-2.8.7
|
||||
This is a hotfix release to solve a regression
|
||||
in the builtin monkeypatch plugin that got introduced in 2.8.6.
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
This release is supposed to be drop-in compatible to 2.8.5.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.9.0
|
||||
============
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
See below for the changes and see docs at:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.9.1
|
||||
============
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
See below for the changes and see docs at:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pytest-2.9.2
|
||||
============
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1100 tests
|
||||
pytest is a mature Python testing tool with more than 1100 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
See below for the changes and see docs at:
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-3.0.0
|
||||
|
||||
The pytest team is proud to announce the 3.0.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1600 tests
|
||||
pytest is a mature Python testing tool with more than 1600 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a lot of bugs fixes and improvements, and much of
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-3.1.0
|
||||
|
||||
The pytest team is proud to announce the 3.1.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1600 tests
|
||||
pytest is a mature Python testing tool with more than 1600 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-3.10.0
|
||||
|
||||
The pytest team is proud to announce the 3.10.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-3.2.0
|
||||
|
||||
The pytest team is proud to announce the 3.2.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1600 tests
|
||||
pytest is a mature Python testing tool with more than 1600 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-3.3.0
|
||||
|
||||
The pytest team is proud to announce the 3.3.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1600 tests
|
||||
pytest is a mature Python testing tool with more than 1600 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-3.4.0
|
||||
|
||||
The pytest team is proud to announce the 3.4.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1600 tests
|
||||
pytest is a mature Python testing tool with more than 1600 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-3.5.0
|
||||
|
||||
The pytest team is proud to announce the 3.5.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1600 tests
|
||||
pytest is a mature Python testing tool with more than 1600 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-3.6.0
|
||||
|
||||
The pytest team is proud to announce the 3.6.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 1600 tests
|
||||
pytest is a mature Python testing tool with more than 1600 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-3.7.0
|
||||
|
||||
The pytest team is proud to announce the 3.7.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-3.8.0
|
||||
|
||||
The pytest team is proud to announce the 3.8.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-3.9.0
|
||||
|
||||
The pytest team is proud to announce the 3.9.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-4.0.0
|
||||
|
||||
The pytest team is proud to announce the 4.0.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-4.1.0
|
||||
|
||||
The pytest team is proud to announce the 4.1.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-4.2.0
|
||||
|
||||
The pytest team is proud to announce the 4.2.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-4.3.0
|
||||
|
||||
The pytest team is proud to announce the 4.3.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-4.4.0
|
||||
|
||||
The pytest team is proud to announce the 4.4.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-4.5.0
|
||||
|
||||
The pytest team is proud to announce the 4.5.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-4.6.0
|
||||
|
||||
The pytest team is proud to announce the 4.6.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-5.0.0
|
||||
|
||||
The pytest team is proud to announce the 5.0.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-5.1.0
|
||||
|
||||
The pytest team is proud to announce the 5.1.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-5.2.0
|
||||
|
||||
The pytest team is proud to announce the 5.2.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-5.3.0
|
||||
|
||||
The pytest team is proud to announce the 5.3.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
|
||||
@@ -3,7 +3,7 @@ pytest-5.4.0
|
||||
|
||||
The pytest team is proud to announce the 5.4.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
pytest is a mature Python testing tool with more than 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bug fixes and improvements, so users are encouraged
|
||||
|
||||
21
doc/en/announce/release-6.0.1.rst
Normal file
21
doc/en/announce/release-6.0.1.rst
Normal file
@@ -0,0 +1,21 @@
|
||||
pytest-6.0.1
|
||||
=======================================
|
||||
|
||||
pytest 6.0.1 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Bruno Oliveira
|
||||
* Mattreex
|
||||
* Ran Benita
|
||||
* hp310780
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
19
doc/en/announce/release-6.0.2.rst
Normal file
19
doc/en/announce/release-6.0.2.rst
Normal file
@@ -0,0 +1,19 @@
|
||||
pytest-6.0.2
|
||||
=======================================
|
||||
|
||||
pytest 6.0.2 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Bruno Oliveira
|
||||
* Ran Benita
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
44
doc/en/announce/release-6.1.0.rst
Normal file
44
doc/en/announce/release-6.1.0.rst
Normal file
@@ -0,0 +1,44 @@
|
||||
pytest-6.1.0
|
||||
=======================================
|
||||
|
||||
The pytest team is proud to announce the 6.1.0 release!
|
||||
|
||||
This release contains new features, improvements, bug fixes, and breaking changes, so users
|
||||
are encouraged to take a look at the CHANGELOG carefully:
|
||||
|
||||
https://docs.pytest.org/en/stable/changelog.html
|
||||
|
||||
For complete documentation, please visit:
|
||||
|
||||
https://docs.pytest.org/en/stable/
|
||||
|
||||
As usual, you can upgrade from PyPI via:
|
||||
|
||||
pip install -U pytest
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Anthony Sottile
|
||||
* Bruno Oliveira
|
||||
* C. Titus Brown
|
||||
* Drew Devereux
|
||||
* Faris A Chugthai
|
||||
* Florian Bruhin
|
||||
* Hugo van Kemenade
|
||||
* Hynek Schlawack
|
||||
* Joseph Lucas
|
||||
* Kamran Ahmad
|
||||
* Mattreex
|
||||
* Maximilian Cosmo Sitter
|
||||
* Ran Benita
|
||||
* Rüdiger Busche
|
||||
* Sam Estep
|
||||
* Sorin Sbarnea
|
||||
* Thomas Grainger
|
||||
* Vipul Kumar
|
||||
* Yutaro Ikeda
|
||||
* hp310780
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -23,7 +23,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
cache.get(key, default)
|
||||
cache.set(key, value)
|
||||
|
||||
Keys must be a ``/`` separated value, where the first part is usually the
|
||||
Keys must be ``/`` separated strings, where the first part is usually the
|
||||
name of your plugin or application to avoid clashes with other cache users.
|
||||
|
||||
Values can be any object handled by the json stdlib module.
|
||||
@@ -57,7 +57,8 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
``out`` and ``err`` will be ``byte`` objects.
|
||||
|
||||
doctest_namespace [session scope]
|
||||
Fixture that returns a :py:class:`dict` that will be injected into the namespace of doctests.
|
||||
Fixture that returns a :py:class:`dict` that will be injected into the
|
||||
namespace of doctests.
|
||||
|
||||
pytestconfig [session scope]
|
||||
Session-scoped fixture that returns the :class:`_pytest.config.Config` object.
|
||||
@@ -89,8 +90,10 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
automatically XML-encoded.
|
||||
|
||||
record_testsuite_property [session scope]
|
||||
Records a new ``<property>`` tag as child of the root ``<testsuite>``. This is suitable to
|
||||
writing global information regarding the entire test suite, and is compatible with ``xunit2`` JUnit family.
|
||||
Record a new ``<property>`` tag as child of the root ``<testsuite>``.
|
||||
|
||||
This is suitable to writing global information regarding the entire test
|
||||
suite, and is compatible with ``xunit2`` JUnit family.
|
||||
|
||||
This is a ``session``-scoped fixture which is called with ``(name, value)``. Example:
|
||||
|
||||
@@ -102,6 +105,12 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
|
||||
``name`` must be a string, ``value`` will be converted to a string and properly xml-escaped.
|
||||
|
||||
.. warning::
|
||||
|
||||
Currently this fixture **does not work** with the
|
||||
`pytest-xdist <https://github.com/pytest-dev/pytest-xdist>`__ plugin. See issue
|
||||
`#7767 <https://github.com/pytest-dev/pytest/issues/7767>`__ for details.
|
||||
|
||||
caplog
|
||||
Access and control log capturing.
|
||||
|
||||
@@ -114,8 +123,10 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
* caplog.clear() -> clear captured records and formatted log output string
|
||||
|
||||
monkeypatch
|
||||
The returned ``monkeypatch`` fixture provides these
|
||||
helper methods to modify objects, dictionaries or os.environ::
|
||||
A convenient fixture for monkey-patching.
|
||||
|
||||
The fixture provides these methods to modify objects, dictionaries or
|
||||
os.environ::
|
||||
|
||||
monkeypatch.setattr(obj, name, value, raising=True)
|
||||
monkeypatch.delattr(obj, name, raising=True)
|
||||
@@ -126,10 +137,9 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
monkeypatch.syspath_prepend(path)
|
||||
monkeypatch.chdir(path)
|
||||
|
||||
All modifications will be undone after the requesting
|
||||
test function or fixture has finished. The ``raising``
|
||||
parameter determines if a KeyError or AttributeError
|
||||
will be raised if the set/deletion operation has no target.
|
||||
All modifications will be undone after the requesting test function or
|
||||
fixture has finished. The ``raising`` parameter determines if a KeyError
|
||||
or AttributeError will be raised if the set/deletion operation has no target.
|
||||
|
||||
recwarn
|
||||
Return a :class:`WarningsRecorder` instance that records all warnings emitted by test functions.
|
||||
@@ -140,30 +150,28 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
tmpdir_factory [session scope]
|
||||
Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session.
|
||||
|
||||
|
||||
tmp_path_factory [session scope]
|
||||
Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session.
|
||||
|
||||
|
||||
tmpdir
|
||||
Return a temporary directory path object
|
||||
which is unique to each test function invocation,
|
||||
created as a sub directory of the base temporary
|
||||
directory. The returned object is a `py.path.local`_
|
||||
path object.
|
||||
Return a temporary directory path object which is unique to each test
|
||||
function invocation, created as a sub directory of the base temporary
|
||||
directory.
|
||||
|
||||
The returned object is a `py.path.local`_ path object.
|
||||
|
||||
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
|
||||
|
||||
tmp_path
|
||||
Return a temporary directory path object
|
||||
which is unique to each test function invocation,
|
||||
created as a sub directory of the base temporary
|
||||
directory. The returned object is a :class:`pathlib.Path`
|
||||
object.
|
||||
Return a temporary directory path object which is unique to each test
|
||||
function invocation, created as a sub directory of the base temporary
|
||||
directory.
|
||||
|
||||
The returned object is a :class:`pathlib.Path` object.
|
||||
|
||||
.. note::
|
||||
|
||||
in python < 3.6 this is a pathlib2.Path
|
||||
In python < 3.6 this is a pathlib2.Path.
|
||||
|
||||
|
||||
no tests ran in 0.12s
|
||||
|
||||
@@ -264,7 +264,7 @@ the cache and nothing will be printed:
|
||||
FAILED test_caching.py::test_function - assert 42 == 23
|
||||
1 failed in 0.12s
|
||||
|
||||
See the :fixture:`config.cache fixture <config.cache>` for more details.
|
||||
See the :fixture:`config.cache fixture <cache>` for more details.
|
||||
|
||||
|
||||
Inspecting Cache content
|
||||
|
||||
@@ -28,6 +28,205 @@ with advance notice in the **Deprecations** section of releases.
|
||||
|
||||
.. towncrier release notes start
|
||||
|
||||
pytest 6.1.0 (2020-09-26)
|
||||
=========================
|
||||
|
||||
Breaking Changes
|
||||
----------------
|
||||
|
||||
- `#5585 <https://github.com/pytest-dev/pytest/issues/5585>`_: As per our policy, the following features which have been deprecated in the 5.X series are now
|
||||
removed:
|
||||
|
||||
* The ``funcargnames`` read-only property of ``FixtureRequest``, ``Metafunc``, and ``Function`` classes. Use ``fixturenames`` attribute.
|
||||
|
||||
* ``@pytest.fixture`` no longer supports positional arguments, pass all arguments by keyword instead.
|
||||
|
||||
* Direct construction of ``Node`` subclasses now raise an error, use ``from_parent`` instead.
|
||||
|
||||
* The default value for ``junit_family`` has changed to ``xunit2``. If you require the old format, add ``junit_family=xunit1`` to your configuration file.
|
||||
|
||||
* The ``TerminalReporter`` no longer has a ``writer`` attribute. Plugin authors may use the public functions of the ``TerminalReporter`` instead of accessing the ``TerminalWriter`` object directly.
|
||||
|
||||
* The ``--result-log`` option has been removed. Users are recommended to use the `pytest-reportlog <https://github.com/pytest-dev/pytest-reportlog>`__ plugin instead.
|
||||
|
||||
|
||||
For more information consult
|
||||
`Deprecations and Removals <https://docs.pytest.org/en/stable/deprecations.html>`__ in the docs.
|
||||
|
||||
|
||||
|
||||
Deprecations
|
||||
------------
|
||||
|
||||
- `#6981 <https://github.com/pytest-dev/pytest/issues/6981>`_: The ``pytest.collect`` module is deprecated: all its names can be imported from ``pytest`` directly.
|
||||
|
||||
|
||||
- `#7097 <https://github.com/pytest-dev/pytest/issues/7097>`_: The ``pytest._fillfuncargs`` function is deprecated. This function was kept
|
||||
for backward compatibility with an older plugin.
|
||||
|
||||
It's functionality is not meant to be used directly, but if you must replace
|
||||
it, use `function._request._fillfixtures()` instead, though note this is not
|
||||
a public API and may break in the future.
|
||||
|
||||
|
||||
- `#7210 <https://github.com/pytest-dev/pytest/issues/7210>`_: The special ``-k '-expr'`` syntax to ``-k`` is deprecated. Use ``-k 'not expr'``
|
||||
instead.
|
||||
|
||||
The special ``-k 'expr:'`` syntax to ``-k`` is deprecated. Please open an issue
|
||||
if you use this and want a replacement.
|
||||
|
||||
|
||||
- `#7255 <https://github.com/pytest-dev/pytest/issues/7255>`_: The :func:`pytest_warning_captured <_pytest.hookspec.pytest_warning_captured>` hook is deprecated in favor
|
||||
of :func:`pytest_warning_recorded <_pytest.hookspec.pytest_warning_recorded>`, and will be removed in a future version.
|
||||
|
||||
|
||||
- `#7648 <https://github.com/pytest-dev/pytest/issues/7648>`_: The ``gethookproxy()`` and ``isinitpath()`` methods of ``FSCollector`` and ``Package`` are deprecated;
|
||||
use ``self.session.gethookproxy()`` and ``self.session.isinitpath()`` instead.
|
||||
This should work on all pytest versions.
|
||||
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- `#7667 <https://github.com/pytest-dev/pytest/issues/7667>`_: New ``--durations-min`` command-line flag controls the minimal duration for inclusion in the slowest list of tests shown by ``--durations``. Previously this was hard-coded to ``0.005s``.
|
||||
|
||||
|
||||
|
||||
Improvements
|
||||
------------
|
||||
|
||||
- `#6681 <https://github.com/pytest-dev/pytest/issues/6681>`_: Internal pytest warnings issued during the early stages of initialization are now properly handled and can filtered through :confval:`filterwarnings` or ``--pythonwarnings/-W``.
|
||||
|
||||
This also fixes a number of long standing issues: `#2891 <https://github.com/pytest-dev/pytest/issues/2891>`__, `#7620 <https://github.com/pytest-dev/pytest/issues/7620>`__, `#7426 <https://github.com/pytest-dev/pytest/issues/7426>`__.
|
||||
|
||||
|
||||
- `#7572 <https://github.com/pytest-dev/pytest/issues/7572>`_: When a plugin listed in ``required_plugins`` is missing or an unknown config key is used with ``--strict-config``, a simple error message is now shown instead of a stacktrace.
|
||||
|
||||
|
||||
- `#7685 <https://github.com/pytest-dev/pytest/issues/7685>`_: Added two new attributes :attr:`rootpath <_pytest.config.Config.rootpath>` and :attr:`inipath <_pytest.config.Config.inipath>` to :class:`Config <_pytest.config.Config>`.
|
||||
These attributes are :class:`pathlib.Path` versions of the existing :attr:`rootdir <_pytest.config.Config.rootdir>` and :attr:`inifile <_pytest.config.Config.inifile>` attributes,
|
||||
and should be preferred over them when possible.
|
||||
|
||||
|
||||
- `#7780 <https://github.com/pytest-dev/pytest/issues/7780>`_: Public classes which are not designed to be inherited from are now marked `@final <https://docs.python.org/3/library/typing.html#typing.final>`_.
|
||||
Code which inherits from these classes will trigger a type-checking (e.g. mypy) error, but will still work in runtime.
|
||||
Currently the ``final`` designation does not appear in the API Reference but hopefully will in the future.
|
||||
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#1953 <https://github.com/pytest-dev/pytest/issues/1953>`_: Fixed error when overwriting a parametrized fixture, while also reusing the super fixture value.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# conftest.py
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(params=[1, 2])
|
||||
def foo(request):
|
||||
return request.param
|
||||
|
||||
|
||||
# test_foo.py
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def foo(foo):
|
||||
return foo * 2
|
||||
|
||||
|
||||
- `#4984 <https://github.com/pytest-dev/pytest/issues/4984>`_: Fixed an internal error crash with ``IndexError: list index out of range`` when
|
||||
collecting a module which starts with a decorated function, the decorator
|
||||
raises, and assertion rewriting is enabled.
|
||||
|
||||
|
||||
- `#7591 <https://github.com/pytest-dev/pytest/issues/7591>`_: pylint shouldn't complain anymore about unimplemented abstract methods when inheriting from :ref:`File <non-python tests>`.
|
||||
|
||||
|
||||
- `#7628 <https://github.com/pytest-dev/pytest/issues/7628>`_: Fixed test collection when a full path without a drive letter was passed to pytest on Windows (for example ``\projects\tests\test.py`` instead of ``c:\projects\tests\pytest.py``).
|
||||
|
||||
|
||||
- `#7638 <https://github.com/pytest-dev/pytest/issues/7638>`_: Fix handling of command-line options that appear as paths but trigger an OS-level syntax error on Windows, such as the options used internally by ``pytest-xdist``.
|
||||
|
||||
|
||||
- `#7742 <https://github.com/pytest-dev/pytest/issues/7742>`_: Fixed INTERNALERROR when accessing locals / globals with faulty ``exec``.
|
||||
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- `#1477 <https://github.com/pytest-dev/pytest/issues/1477>`_: Removed faq.rst and its reference in contents.rst.
|
||||
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- `#7536 <https://github.com/pytest-dev/pytest/issues/7536>`_: The internal ``junitxml`` plugin has rewritten to use ``xml.etree.ElementTree``.
|
||||
The order of attributes in XML elements might differ. Some unneeded escaping is
|
||||
no longer performed.
|
||||
|
||||
|
||||
- `#7587 <https://github.com/pytest-dev/pytest/issues/7587>`_: The dependency on the ``more-itertools`` package has been removed.
|
||||
|
||||
|
||||
- `#7631 <https://github.com/pytest-dev/pytest/issues/7631>`_: The result type of :meth:`capfd.readouterr() <_pytest.capture.CaptureFixture.readouterr>` (and similar) is no longer a namedtuple,
|
||||
but should behave like one in all respects. This was done for technical reasons.
|
||||
|
||||
|
||||
- `#7671 <https://github.com/pytest-dev/pytest/issues/7671>`_: When collecting tests, pytest finds test classes and functions by examining the
|
||||
attributes of python objects (modules, classes and instances). To speed up this
|
||||
process, pytest now ignores builtin attributes (like ``__class__``,
|
||||
``__delattr__`` and ``__new__``) without consulting the :confval:`python_classes` and
|
||||
:confval:`python_functions` configuration options and without passing them to plugins
|
||||
using the :func:`pytest_pycollect_makeitem <_pytest.hookspec.pytest_pycollect_makeitem>` hook.
|
||||
|
||||
|
||||
pytest 6.0.2 (2020-09-04)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#7148 <https://github.com/pytest-dev/pytest/issues/7148>`_: Fixed ``--log-cli`` potentially causing unrelated ``print`` output to be swallowed.
|
||||
|
||||
|
||||
- `#7672 <https://github.com/pytest-dev/pytest/issues/7672>`_: Fixed log-capturing level restored incorrectly if ``caplog.set_level`` is called more than once.
|
||||
|
||||
|
||||
- `#7686 <https://github.com/pytest-dev/pytest/issues/7686>`_: Fixed `NotSetType.token` being used as the parameter ID when the parametrization list is empty.
|
||||
Regressed in pytest 6.0.0.
|
||||
|
||||
|
||||
- `#7707 <https://github.com/pytest-dev/pytest/issues/7707>`_: Fix internal error when handling some exceptions that contain multiple lines or the style uses multiple lines (``--tb=line`` for example).
|
||||
|
||||
|
||||
pytest 6.0.1 (2020-07-30)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#7394 <https://github.com/pytest-dev/pytest/issues/7394>`_: Passing an empty ``help`` value to ``Parser.add_option`` is now accepted instead of crashing when running ``pytest --help``.
|
||||
Passing ``None`` raises a more informative ``TypeError``.
|
||||
|
||||
|
||||
- `#7558 <https://github.com/pytest-dev/pytest/issues/7558>`_: Fix pylint ``not-callable`` lint on ``pytest.mark.parametrize()`` and the other builtin marks:
|
||||
``skip``, ``skipif``, ``xfail``, ``usefixtures``, ``filterwarnings``.
|
||||
|
||||
|
||||
- `#7559 <https://github.com/pytest-dev/pytest/issues/7559>`_: Fix regression in plugins using ``TestReport.longreprtext`` (such as ``pytest-html``) when ``TestReport.longrepr`` is not a string.
|
||||
|
||||
|
||||
- `#7569 <https://github.com/pytest-dev/pytest/issues/7569>`_: Fix logging capture handler's level not reset on teardown after a call to ``caplog.set_level()``.
|
||||
|
||||
|
||||
pytest 6.0.0 (2020-07-28)
|
||||
=========================
|
||||
|
||||
@@ -192,9 +391,9 @@ Breaking Changes
|
||||
|
||||
|
||||
- `#7224 <https://github.com/pytest-dev/pytest/issues/7224>`_: The `item.catch_log_handler` and `item.catch_log_handlers` attributes, set by the
|
||||
logging plugin and never meant to be public , are no longer available.
|
||||
logging plugin and never meant to be public, are no longer available.
|
||||
|
||||
The deprecated ``--no-print-logs`` option is removed. Use ``--show-capture`` instead.
|
||||
The deprecated ``--no-print-logs`` option and ``log_print`` ini option are removed. Use ``--show-capture`` instead.
|
||||
|
||||
|
||||
- `#7226 <https://github.com/pytest-dev/pytest/issues/7226>`_: Removed the unused ``args`` parameter from ``pytest.Function.__init__``.
|
||||
@@ -7383,7 +7582,7 @@ Bug fixes:
|
||||
- pluginmanager.register(...) now raises ValueError if the
|
||||
plugin has been already registered or the name is taken
|
||||
|
||||
- fix issue159: improve http://pytest.org/en/stable/faq.html
|
||||
- fix issue159: improve https://docs.pytest.org/en/6.0.1/faq.html
|
||||
especially with respect to the "magic" history, also mention
|
||||
pytest-django, trial and unittest integration.
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ Full pytest documentation
|
||||
customize
|
||||
example/index
|
||||
bash-completion
|
||||
faq
|
||||
|
||||
backwards-compatibility
|
||||
deprecations
|
||||
|
||||
@@ -180,10 +180,15 @@ are never merged - the first match wins.
|
||||
The internal :class:`Config <_pytest.config.Config>` object (accessible via hooks or through the :fixture:`pytestconfig` fixture)
|
||||
will subsequently carry these attributes:
|
||||
|
||||
- ``config.rootdir``: the determined root directory, guaranteed to exist.
|
||||
- :attr:`config.rootpath <_pytest.config.Config.rootpath>`: the determined root directory, guaranteed to exist.
|
||||
|
||||
- ``config.inifile``: the determined ``configfile``, may be ``None`` (it is named ``inifile``
|
||||
for historical reasons).
|
||||
- :attr:`config.inipath <_pytest.config.Config.inipath>`: the determined ``configfile``, may be ``None``
|
||||
(it is named ``inipath`` for historical reasons).
|
||||
|
||||
.. versionadded:: 6.1
|
||||
The ``config.rootpath`` and ``config.inipath`` properties. They are :class:`pathlib.Path`
|
||||
versions of the older ``config.rootdir`` and ``config.inifile``, which have type
|
||||
``py.path.local``, and still exist for backward compatibility.
|
||||
|
||||
The ``rootdir`` is used as a reference directory for constructing test
|
||||
addresses ("nodeids") and can be used also by plugins for storing
|
||||
|
||||
@@ -16,8 +16,7 @@ Deprecated Features
|
||||
-------------------
|
||||
|
||||
Below is a complete list of all pytest features which are considered deprecated. Using those features will issue
|
||||
:class:`_pytest.warning_types.PytestWarning` or subclasses, which can be filtered using
|
||||
:ref:`standard warning filters <warnings>`.
|
||||
:class:`PytestWarning` or subclasses, which can be filtered using :ref:`standard warning filters <warnings>`.
|
||||
|
||||
|
||||
The ``pytest_warning_captured`` hook
|
||||
@@ -30,11 +29,19 @@ This hook has an `item` parameter which cannot be serialized by ``pytest-xdist``
|
||||
Use the ``pytest_warning_recored`` hook instead, which replaces the ``item`` parameter
|
||||
by a ``nodeid`` parameter.
|
||||
|
||||
The ``pytest.collect`` module
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 6.0
|
||||
|
||||
The ``pytest.collect`` module is no longer part of the public API, all its names
|
||||
should now be imported from ``pytest`` directly instead.
|
||||
|
||||
|
||||
The ``pytest._fillfuncargs`` function
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 5.5
|
||||
.. deprecated:: 6.0
|
||||
|
||||
This function was kept for backward compatibility with an older plugin.
|
||||
|
||||
@@ -43,6 +50,11 @@ it, use `function._request._fillfixtures()` instead, though note this is not
|
||||
a public API and may break in the future.
|
||||
|
||||
|
||||
Removed Features
|
||||
----------------
|
||||
|
||||
As stated in our :ref:`backwards-compatibility` policy, deprecated features are removed only in major releases after
|
||||
an appropriate period of deprecation has passed.
|
||||
|
||||
``--no-print-logs`` command-line option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -51,45 +63,54 @@ a public API and may break in the future.
|
||||
.. versionremoved:: 6.0
|
||||
|
||||
|
||||
Option ``--no-print-logs`` is removed. If you used ``--no-print-logs``, please use ``--show-capture`` instead.
|
||||
The ``--no-print-logs`` option and ``log_print`` ini setting are removed. If
|
||||
you used them, please use ``--show-capture`` instead.
|
||||
|
||||
``--show-capture`` command-line option was added in ``pytest 3.5.0`` and allows to specify how to
|
||||
A ``--show-capture`` command-line option was added in ``pytest 3.5.0`` which allows to specify how to
|
||||
display captured output when tests fail: ``no``, ``stdout``, ``stderr``, ``log`` or ``all`` (the default).
|
||||
|
||||
|
||||
|
||||
Node Construction changed to ``Node.from_parent``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Result log (``--result-log``)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 5.4
|
||||
.. deprecated:: 4.0
|
||||
.. versionremoved:: 6.0
|
||||
|
||||
The construction of nodes now should use the named constructor ``from_parent``.
|
||||
This limitation in api surface intends to enable better/simpler refactoring of the collection tree.
|
||||
The ``--result-log`` option produces a stream of test reports which can be
|
||||
analysed at runtime, but it uses a custom format which requires users to implement their own
|
||||
parser.
|
||||
|
||||
This means that instead of :code:`MyItem(name="foo", parent=collector, obj=42)`
|
||||
one now has to invoke :code:`MyItem.from_parent(collector, name="foo")`.
|
||||
The `pytest-reportlog <https://github.com/pytest-dev/pytest-reportlog>`__ plugin provides a ``--report-log`` option, a more standard and extensible alternative, producing
|
||||
one JSON object per-line, and should cover the same use cases. Please try it out and provide feedback.
|
||||
|
||||
Plugins that wish to support older versions of pytest and suppress the warning can use
|
||||
`hasattr` to check if `from_parent` exists in that version:
|
||||
The ``pytest-reportlog`` plugin might even be merged into the core
|
||||
at some point, depending on the plans for the plugins and number of users using it.
|
||||
|
||||
.. code-block:: python
|
||||
``pytest_collect_directory`` hook
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
def pytest_pycollect_makeitem(collector, name, obj):
|
||||
if hasattr(MyItem, "from_parent"):
|
||||
item = MyItem.from_parent(collector, name="foo")
|
||||
item.obj = 42
|
||||
return item
|
||||
else:
|
||||
return MyItem(name="foo", parent=collector, obj=42)
|
||||
.. versionremoved:: 6.0
|
||||
|
||||
Note that ``from_parent`` should only be called with keyword arguments for the parameters.
|
||||
The ``pytest_collect_directory`` has not worked properly for years (it was called
|
||||
but the results were ignored). Users may consider using :func:`pytest_collection_modifyitems <_pytest.hookspec.pytest_collection_modifyitems>` instead.
|
||||
|
||||
TerminalReporter.writer
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionremoved:: 6.0
|
||||
|
||||
The ``TerminalReporter.writer`` attribute has been deprecated and should no longer be used. This
|
||||
was inadvertently exposed as part of the public API of that plugin and ties it too much
|
||||
with ``py.io.TerminalWriter``.
|
||||
|
||||
Plugins that used ``TerminalReporter.writer`` directly should instead use ``TerminalReporter``
|
||||
methods that provide the same functionality.
|
||||
|
||||
``junit_family`` default value change to "xunit2"
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 5.2
|
||||
.. versionchanged:: 6.0
|
||||
|
||||
The default value of ``junit_family`` option will change to ``xunit2`` in pytest 6.0, which
|
||||
is an update of the old ``xunit1`` format and is supported by default in modern tools
|
||||
@@ -125,11 +146,44 @@ Services known to support the ``xunit2`` format:
|
||||
* `Jenkins <https://www.jenkins.io/>`__ with the `JUnit <https://plugins.jenkins.io/junit>`__ plugin.
|
||||
* `Azure Pipelines <https://azure.microsoft.com/en-us/services/devops/pipelines>`__.
|
||||
|
||||
Node Construction changed to ``Node.from_parent``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionchanged:: 6.0
|
||||
|
||||
The construction of nodes now should use the named constructor ``from_parent``.
|
||||
This limitation in api surface intends to enable better/simpler refactoring of the collection tree.
|
||||
|
||||
This means that instead of :code:`MyItem(name="foo", parent=collector, obj=42)`
|
||||
one now has to invoke :code:`MyItem.from_parent(collector, name="foo")`.
|
||||
|
||||
Plugins that wish to support older versions of pytest and suppress the warning can use
|
||||
`hasattr` to check if `from_parent` exists in that version:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_pycollect_makeitem(collector, name, obj):
|
||||
if hasattr(MyItem, "from_parent"):
|
||||
item = MyItem.from_parent(collector, name="foo")
|
||||
item.obj = 42
|
||||
return item
|
||||
else:
|
||||
return MyItem(name="foo", parent=collector, obj=42)
|
||||
|
||||
Note that ``from_parent`` should only be called with keyword arguments for the parameters.
|
||||
|
||||
|
||||
``pytest.fixture`` arguments are keyword only
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionremoved:: 6.0
|
||||
|
||||
Passing arguments to pytest.fixture() as positional arguments has been removed - pass them by keyword instead.
|
||||
|
||||
``funcargnames`` alias for ``fixturenames``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 5.0
|
||||
.. versionremoved:: 6.0
|
||||
|
||||
The ``FixtureRequest``, ``Metafunc``, and ``Function`` classes track the names of
|
||||
their associated fixtures, with the aptly-named ``fixturenames`` attribute.
|
||||
@@ -140,42 +194,6 @@ in places where we or plugin authors must distinguish between fixture names and
|
||||
names supplied by non-fixture things such as ``pytest.mark.parametrize``.
|
||||
|
||||
|
||||
Result log (``--result-log``)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 4.0
|
||||
|
||||
The ``--result-log`` option produces a stream of test reports which can be
|
||||
analysed at runtime, but it uses a custom format which requires users to implement their own
|
||||
parser.
|
||||
|
||||
The `pytest-reportlog <https://github.com/pytest-dev/pytest-reportlog>`__ plugin provides a ``--report-log`` option, a more standard and extensible alternative, producing
|
||||
one JSON object per-line, and should cover the same use cases. Please try it out and provide feedback.
|
||||
|
||||
The plan is remove the ``--result-log`` option in pytest 6.0 if ``pytest-reportlog`` proves satisfactory
|
||||
to all users and is deemed stable. The ``pytest-reportlog`` plugin might even be merged into the core
|
||||
at some point, depending on the plans for the plugins and number of users using it.
|
||||
|
||||
TerminalReporter.writer
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 5.4
|
||||
|
||||
The ``TerminalReporter.writer`` attribute has been deprecated and should no longer be used. This
|
||||
was inadvertently exposed as part of the public API of that plugin and ties it too much
|
||||
with ``py.io.TerminalWriter``.
|
||||
|
||||
Plugins that used ``TerminalReporter.writer`` directly should instead use ``TerminalReporter``
|
||||
methods that provide the same functionality.
|
||||
|
||||
|
||||
Removed Features
|
||||
----------------
|
||||
|
||||
As stated in our :ref:`backwards-compatibility` policy, deprecated features are removed only in major releases after
|
||||
an appropriate period of deprecation has passed.
|
||||
|
||||
|
||||
``pytest.config`` global
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -357,7 +375,7 @@ Metafunc.addcall
|
||||
|
||||
.. versionremoved:: 4.0
|
||||
|
||||
:meth:`_pytest.python.Metafunc.addcall` was a precursor to the current parametrized mechanism. Users should use
|
||||
``_pytest.python.Metafunc.addcall`` was a precursor to the current parametrized mechanism. Users should use
|
||||
:meth:`_pytest.python.Metafunc.parametrize` instead.
|
||||
|
||||
Example:
|
||||
@@ -592,7 +610,7 @@ This has been documented as deprecated for years, but only now we are actually e
|
||||
|
||||
.. versionremoved:: 4.0
|
||||
|
||||
As part of a large :ref:`marker-revamp`, :meth:`_pytest.nodes.Node.get_marker` is deprecated. See
|
||||
As part of a large :ref:`marker-revamp`, ``_pytest.nodes.Node.get_marker`` is removed. See
|
||||
:ref:`the documentation <update marker code>` on tips on how to update your code.
|
||||
|
||||
|
||||
|
||||
@@ -201,6 +201,11 @@ Or to select "http" and "quick" tests:
|
||||
You can use ``and``, ``or``, ``not`` and parentheses.
|
||||
|
||||
|
||||
In addition to the test's name, ``-k`` also matches the names of the test's parents (usually, the name of the file and class it's in),
|
||||
attributes set on the test function, markers applied to it or its parents and any :attr:`extra keywords <_pytest.nodes.Node.extra_keyword_matches>`
|
||||
explicitly added to it or its parents.
|
||||
|
||||
|
||||
Registering markers
|
||||
-------------------------------------
|
||||
|
||||
@@ -280,7 +285,7 @@ its test methods:
|
||||
This is equivalent to directly applying the decorator to the
|
||||
two test functions.
|
||||
|
||||
To apply marks at the module level, use the :globalvar:`pytestmark` global variable:
|
||||
To apply marks at the module level, use the :globalvar:`pytestmark` global variable::
|
||||
|
||||
import pytest
|
||||
pytestmark = pytest.mark.webtest
|
||||
|
||||
@@ -12,7 +12,7 @@ A basic example for specifying tests in Yaml files
|
||||
.. _`pytest-yamlwsgi`: http://bitbucket.org/aafshar/pytest-yamlwsgi/src/tip/pytest_yamlwsgi.py
|
||||
.. _`PyYAML`: https://pypi.org/project/PyYAML/
|
||||
|
||||
Here is an example ``conftest.py`` (extracted from Ali Afshnars special purpose `pytest-yamlwsgi`_ plugin). This ``conftest.py`` will collect ``test*.yaml`` files and will execute the yaml-formatted content as custom tests:
|
||||
Here is an example ``conftest.py`` (extracted from Ali Afshar's special purpose `pytest-yamlwsgi`_ plugin). This ``conftest.py`` will collect ``test*.yaml`` files and will execute the yaml-formatted content as custom tests:
|
||||
|
||||
.. include:: nonpython/conftest.py
|
||||
:literal:
|
||||
|
||||
@@ -9,7 +9,8 @@ def pytest_collect_file(parent, path):
|
||||
|
||||
class YamlFile(pytest.File):
|
||||
def collect(self):
|
||||
import yaml # we need a yaml parser, e.g. PyYAML
|
||||
# We need a yaml parser, e.g. PyYAML.
|
||||
import yaml
|
||||
|
||||
raw = yaml.safe_load(self.fspath.open())
|
||||
for name, spec in sorted(raw.items()):
|
||||
@@ -23,12 +24,12 @@ class YamlItem(pytest.Item):
|
||||
|
||||
def runtest(self):
|
||||
for name, value in sorted(self.spec.items()):
|
||||
# some custom test execution (dumb example follows)
|
||||
# Some custom test execution (dumb example follows).
|
||||
if name != value:
|
||||
raise YamlException(self, name, value)
|
||||
|
||||
def repr_failure(self, excinfo):
|
||||
""" called when self.runtest() raises an exception. """
|
||||
"""Called when self.runtest() raises an exception."""
|
||||
if isinstance(excinfo.value, YamlException):
|
||||
return "\n".join(
|
||||
[
|
||||
@@ -43,4 +44,4 @@ class YamlItem(pytest.Item):
|
||||
|
||||
|
||||
class YamlException(Exception):
|
||||
""" custom exception for error reporting. """
|
||||
"""Custom exception for error reporting."""
|
||||
|
||||
@@ -313,3 +313,12 @@ interpreter:
|
||||
collect_ignore = ["setup.py"]
|
||||
if sys.version_info[0] > 2:
|
||||
collect_ignore_glob = ["*_py2.py"]
|
||||
|
||||
Since Pytest 2.6, users can prevent pytest from discovering classes that start
|
||||
with ``Test`` by setting a boolean ``__test__`` attribute to ``False``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Will not be discovered as a test
|
||||
class TestClass:
|
||||
__test__ = False
|
||||
|
||||
158
doc/en/faq.rst
158
doc/en/faq.rst
@@ -1,158 +0,0 @@
|
||||
Some Issues and Questions
|
||||
==================================
|
||||
|
||||
.. note::
|
||||
|
||||
This FAQ is here only mostly for historic reasons. Checkout
|
||||
`pytest Q&A at Stackoverflow <http://stackoverflow.com/search?q=pytest>`_
|
||||
for many questions and answers related to pytest and/or use
|
||||
:ref:`contact channels` to get help.
|
||||
|
||||
On naming, nosetests, licensing and magic
|
||||
------------------------------------------------
|
||||
|
||||
How does pytest relate to nose and unittest?
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
``pytest`` and nose_ share basic philosophy when it comes
|
||||
to running and writing Python tests. In fact, you can run many tests
|
||||
written for nose with ``pytest``. nose_ was originally created
|
||||
as a clone of ``pytest`` when ``pytest`` was in the ``0.8`` release
|
||||
cycle. Note that starting with pytest-2.0 support for running unittest
|
||||
test suites is majorly improved.
|
||||
|
||||
how does pytest relate to twisted's trial?
|
||||
++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
Since some time ``pytest`` has builtin support for supporting tests
|
||||
written using trial. It does not itself start a reactor, however,
|
||||
and does not handle Deferreds returned from a test in pytest style.
|
||||
If you are using trial's unittest.TestCase chances are that you can
|
||||
just run your tests even if you return Deferreds. In addition,
|
||||
there also is a dedicated `pytest-twisted
|
||||
<https://pypi.org/project/pytest-twisted/>`_ plugin which allows you to
|
||||
return deferreds from pytest-style tests, allowing the use of
|
||||
:ref:`fixtures <fixtures>` and other features.
|
||||
|
||||
how does pytest work with Django?
|
||||
++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
In 2012, some work is going into the `pytest-django plugin <https://pypi.org/project/pytest-django/>`_. It substitutes the usage of Django's
|
||||
``manage.py test`` and allows the use of all pytest features_ most of which
|
||||
are not available from Django directly.
|
||||
|
||||
.. _features: features.html
|
||||
|
||||
|
||||
What's this "magic" with pytest? (historic notes)
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
Around 2007 (version ``0.8``) some people thought that ``pytest``
|
||||
was using too much "magic". It had been part of the `pylib`_ which
|
||||
contains a lot of unrelated python library code. Around 2010 there
|
||||
was a major cleanup refactoring, which removed unused or deprecated code
|
||||
and resulted in the new ``pytest`` PyPI package which strictly contains
|
||||
only test-related code. This release also brought a complete pluginification
|
||||
such that the core is around 300 lines of code and everything else is
|
||||
implemented in plugins. Thus ``pytest`` today is a small, universally runnable
|
||||
and customizable testing framework for Python. Note, however, that
|
||||
``pytest`` uses metaprogramming techniques and reading its source is
|
||||
thus likely not something for Python beginners.
|
||||
|
||||
A second "magic" issue was the assert statement debugging feature.
|
||||
Nowadays, ``pytest`` explicitly rewrites assert statements in test modules
|
||||
in order to provide more useful :ref:`assert feedback <assertfeedback>`.
|
||||
This completely avoids previous issues of confusing assertion-reporting.
|
||||
It also means, that you can use Python's ``-O`` optimization without losing
|
||||
assertions in test modules.
|
||||
|
||||
You can also turn off all assertion interaction using the
|
||||
``--assert=plain`` option.
|
||||
|
||||
.. _`py namespaces`: index.html
|
||||
.. _`py/__init__.py`: http://bitbucket.org/hpk42/py-trunk/src/trunk/py/__init__.py
|
||||
|
||||
|
||||
Why can I use both ``pytest`` and ``py.test`` commands?
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
pytest used to be part of the py package, which provided several developer
|
||||
utilities, all starting with ``py.<TAB>``, thus providing nice TAB-completion.
|
||||
If you install ``pip install pycmd`` you get these tools from a separate
|
||||
package. Once ``pytest`` became a separate package, the ``py.test`` name was
|
||||
retained due to avoid a naming conflict with another tool. This conflict was
|
||||
eventually resolved, and the ``pytest`` command was therefore introduced. In
|
||||
future versions of pytest, we may deprecate and later remove the ``py.test``
|
||||
command to avoid perpetuating the confusion.
|
||||
|
||||
pytest fixtures, parametrized tests
|
||||
-------------------------------------------------------
|
||||
|
||||
.. _funcargs: funcargs.html
|
||||
|
||||
Is using pytest fixtures versus xUnit setup a style question?
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
For simple applications and for people experienced with nose_ or
|
||||
unittest-style test setup using `xUnit style setup`_ probably
|
||||
feels natural. For larger test suites, parametrized testing
|
||||
or setup of complex test resources using fixtures_ may feel more natural.
|
||||
Moreover, fixtures are ideal for writing advanced test support
|
||||
code (like e.g. the monkeypatch_, the tmpdir_ or capture_ fixtures)
|
||||
because the support code can register setup/teardown functions
|
||||
in a managed class/module/function scope.
|
||||
|
||||
.. _monkeypatch: monkeypatch.html
|
||||
.. _tmpdir: tmpdir.html
|
||||
.. _capture: capture.html
|
||||
.. _fixtures: fixture.html
|
||||
|
||||
.. _`why pytest_pyfuncarg__ methods?`:
|
||||
|
||||
.. _`Convention over Configuration`: http://en.wikipedia.org/wiki/Convention_over_Configuration
|
||||
|
||||
Can I yield multiple values from a fixture function?
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
There are two conceptual reasons why yielding from a factory function
|
||||
is not possible:
|
||||
|
||||
* If multiple factories yielded values there would
|
||||
be no natural place to determine the combination
|
||||
policy - in real-world examples some combinations
|
||||
often should not run.
|
||||
|
||||
* Calling factories for obtaining test function arguments
|
||||
is part of setting up and running a test. At that
|
||||
point it is not possible to add new test calls to
|
||||
the test collection anymore.
|
||||
|
||||
However, with pytest-2.3 you can use the :ref:`@pytest.fixture` decorator
|
||||
and specify ``params`` so that all tests depending on the factory-created
|
||||
resource will run multiple times with different parameters.
|
||||
|
||||
You can also use the ``pytest_generate_tests`` hook to
|
||||
implement the `parametrization scheme of your choice`_. See also
|
||||
:ref:`paramexamples` for more examples.
|
||||
|
||||
.. _`parametrization scheme of your choice`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/
|
||||
|
||||
pytest interaction with other packages
|
||||
---------------------------------------------------
|
||||
|
||||
Issues with pytest, multiprocess and setuptools?
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
On Windows the multiprocess package will instantiate sub processes
|
||||
by pickling and thus implicitly re-import a lot of local modules.
|
||||
Unfortunately, setuptools-0.6.11 does not ``if __name__=='__main__'``
|
||||
protect its generated command line script. This leads to infinite
|
||||
recursion when running a test that instantiates Processes.
|
||||
|
||||
As of mid-2013, there shouldn't be a problem anymore when you
|
||||
use the standard setuptools (note that distribute has been merged
|
||||
back into setuptools which is now shipped directly with virtualenv).
|
||||
|
||||
.. _nose: https://nose.readthedocs.io/en/latest/
|
||||
.. _pylib: https://py.readthedocs.io/en/latest/
|
||||
.. _`xUnit style setup`: xunit_setup.html
|
||||
@@ -121,7 +121,7 @@ Fixtures as Function arguments
|
||||
Test functions can receive fixture objects by naming them as an input
|
||||
argument. For each argument name, a fixture function with that name provides
|
||||
the fixture object. Fixture functions are registered by marking them with
|
||||
:py:func:`@pytest.fixture <_pytest.python.fixture>`. Let's look at a simple
|
||||
:py:func:`@pytest.fixture <pytest.fixture>`. Let's look at a simple
|
||||
self-contained test module containing a fixture and a test function
|
||||
using it:
|
||||
|
||||
@@ -144,7 +144,7 @@ using it:
|
||||
assert 0 # for demo purposes
|
||||
|
||||
Here, the ``test_ehlo`` needs the ``smtp_connection`` fixture value. pytest
|
||||
will discover and call the :py:func:`@pytest.fixture <_pytest.python.fixture>`
|
||||
will discover and call the :py:func:`@pytest.fixture <pytest.fixture>`
|
||||
marked ``smtp_connection`` fixture function. Running the test looks like this:
|
||||
|
||||
.. code-block:: pytest
|
||||
@@ -252,7 +252,7 @@ Scope: sharing fixtures across classes, modules, packages or session
|
||||
Fixtures requiring network access depend on connectivity and are
|
||||
usually time-expensive to create. Extending the previous example, we
|
||||
can add a ``scope="module"`` parameter to the
|
||||
:py:func:`@pytest.fixture <_pytest.python.fixture>` invocation
|
||||
:py:func:`@pytest.fixture <pytest.fixture>` invocation
|
||||
to cause the decorated ``smtp_connection`` fixture function to only be invoked
|
||||
once per test *module* (the default is to invoke once per test *function*).
|
||||
Multiple test functions in a test module will thus
|
||||
@@ -592,7 +592,7 @@ will not be executed.
|
||||
Fixtures can introspect the requesting test context
|
||||
-------------------------------------------------------------
|
||||
|
||||
Fixture functions can accept the :py:class:`request <FixtureRequest>` object
|
||||
Fixture functions can accept the :py:class:`request <_pytest.fixtures.FixtureRequest>` object
|
||||
to introspect the "requesting" test function, class or module context.
|
||||
Further extending the previous ``smtp_connection`` fixture example, let's
|
||||
read an optional server URL from the test module which uses our fixture:
|
||||
@@ -664,7 +664,7 @@ from the module namespace.
|
||||
Using markers to pass data to fixtures
|
||||
-------------------------------------------------------------
|
||||
|
||||
Using the :py:class:`request <FixtureRequest>` object, a fixture can also access
|
||||
Using the :py:class:`request <_pytest.fixtures.FixtureRequest>` object, a fixture can also access
|
||||
markers which are applied to a test function. This can be useful to pass data
|
||||
into a fixture from a test:
|
||||
|
||||
@@ -775,7 +775,7 @@ through the special :py:class:`request <FixtureRequest>` object:
|
||||
smtp_connection.close()
|
||||
|
||||
The main change is the declaration of ``params`` with
|
||||
:py:func:`@pytest.fixture <_pytest.python.fixture>`, a list of values
|
||||
:py:func:`@pytest.fixture <pytest.fixture>`, a list of values
|
||||
for each of which the fixture function will execute and can access
|
||||
a value via ``request.param``. No test function code needs to change.
|
||||
So let's just do another run:
|
||||
@@ -1136,8 +1136,8 @@ and teared down after every test that used it.
|
||||
|
||||
.. _`usefixtures`:
|
||||
|
||||
Using fixtures from classes, modules or projects
|
||||
----------------------------------------------------------------------
|
||||
Use fixtures in classes and modules with ``usefixtures``
|
||||
--------------------------------------------------------
|
||||
|
||||
.. regendoc:wipe
|
||||
|
||||
@@ -1531,3 +1531,37 @@ Given the tests file structure is:
|
||||
In the example above, a parametrized fixture is overridden with a non-parametrized version, and
|
||||
a non-parametrized fixture is overridden with a parametrized version for certain test module.
|
||||
The same applies for the test folder level obviously.
|
||||
|
||||
|
||||
Using fixtures from other projects
|
||||
----------------------------------
|
||||
|
||||
Usually projects that provide pytest support will use :ref:`entry points <setuptools entry points>`,
|
||||
so just installing those projects into an environment will make those fixtures available for use.
|
||||
|
||||
In case you want to use fixtures from a project that does not use entry points, you can
|
||||
define :globalvar:`pytest_plugins` in your top ``conftest.py`` file to register that module
|
||||
as a plugin.
|
||||
|
||||
Suppose you have some fixtures in ``mylibrary.fixtures`` and you want to reuse them into your
|
||||
``app/tests`` directory.
|
||||
|
||||
All you need to do is to define :globalvar:`pytest_plugins` in ``app/tests/conftest.py``
|
||||
pointing to that module.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
pytest_plugins = "mylibrary.fixtures"
|
||||
|
||||
This effectively registers ``mylibrary.fixtures`` as a plugin, making all its fixtures and
|
||||
hooks available to tests in ``app/tests``.
|
||||
|
||||
.. note::
|
||||
|
||||
Sometimes users will *import* fixtures from other projects for use, however this is not
|
||||
recommended: importing fixtures into a module will register them in pytest
|
||||
as *defined* in that module.
|
||||
|
||||
This has minor consequences, such as appearing multiple times in ``pytest --help``,
|
||||
but it is not **recommended** because this behavior might change/stop working
|
||||
in future versions.
|
||||
|
||||
@@ -51,7 +51,7 @@ There are several limitations and difficulties with this approach:
|
||||
performs parametrization at the places where the resource
|
||||
is used. Moreover, you need to modify the factory to use an
|
||||
``extrakey`` parameter containing ``request.param`` to the
|
||||
:py:func:`~python.Request.cached_setup` call.
|
||||
``Request.cached_setup`` call.
|
||||
|
||||
3. Multiple parametrized session-scoped resources will be active
|
||||
at the same time, making it hard for them to affect global state
|
||||
@@ -113,7 +113,7 @@ This new way of parametrizing funcarg factories should in many cases
|
||||
allow to re-use already written factories because effectively
|
||||
``request.param`` was already used when test functions/classes were
|
||||
parametrized via
|
||||
:py:func:`~_pytest.python.Metafunc.parametrize(indirect=True)` calls.
|
||||
:py:func:`metafunc.parametrize(indirect=True) <_pytest.python.Metafunc.parametrize>` calls.
|
||||
|
||||
Of course it's perfectly fine to combine parametrization and scoping:
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Install ``pytest``
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest --version
|
||||
pytest 6.0.0
|
||||
pytest 6.1.0
|
||||
|
||||
.. _`simpletest`:
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ More details can be found in the `original PR <https://github.com/pytest-dev/pyt
|
||||
.. note::
|
||||
|
||||
in a future major release of pytest we will introduce class based markers,
|
||||
at which point markers will no longer be limited to instances of :py:class:`Mark`.
|
||||
at which point markers will no longer be limited to instances of :py:class:`~_pytest.mark.Mark`.
|
||||
|
||||
|
||||
cache plugin integrated into the core
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
:orphan:
|
||||
|
||||
.. sidebar:: Next Open Trainings
|
||||
|
||||
- `Professional testing with Python <https://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_, via Python Academy, February 1-3 2021, Leipzig (Germany) and remote.
|
||||
|
||||
Also see `previous talks and blogposts <talks.html>`_.
|
||||
|
||||
.. _features:
|
||||
|
||||
pytest: helps you write better programs
|
||||
@@ -55,17 +61,17 @@ See :ref:`Getting Started <getstarted>` for more examples.
|
||||
Features
|
||||
--------
|
||||
|
||||
- Detailed info on failing :ref:`assert statements <assert>` (no need to remember ``self.assert*`` names);
|
||||
- Detailed info on failing :ref:`assert statements <assert>` (no need to remember ``self.assert*`` names)
|
||||
|
||||
- :ref:`Auto-discovery <test discovery>` of test modules and functions;
|
||||
- :ref:`Auto-discovery <test discovery>` of test modules and functions
|
||||
|
||||
- :ref:`Modular fixtures <fixture>` for managing small or parametrized long-lived test resources;
|
||||
- :ref:`Modular fixtures <fixture>` for managing small or parametrized long-lived test resources
|
||||
|
||||
- Can run :ref:`unittest <unittest>` (including trial) and :ref:`nose <noseintegration>` test suites out of the box;
|
||||
- Can run :ref:`unittest <unittest>` (including trial) and :ref:`nose <noseintegration>` test suites out of the box
|
||||
|
||||
- Python 3.5+ and PyPy 3;
|
||||
- Python 3.5+ and PyPy 3
|
||||
|
||||
- Rich plugin architecture, with over 315+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community;
|
||||
- Rich plugin architecture, with over 315+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community
|
||||
|
||||
|
||||
Documentation
|
||||
|
||||
@@ -43,7 +43,17 @@ You can register custom marks in your ``pytest.ini`` file like this:
|
||||
slow: marks tests as slow (deselect with '-m "not slow"')
|
||||
serial
|
||||
|
||||
Note that everything after the ``:`` is an optional description.
|
||||
or in your ``pyproject.toml`` file like this:
|
||||
|
||||
.. code-block:: toml
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
markers = [
|
||||
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
|
||||
"serial",
|
||||
]
|
||||
|
||||
Note that everything past the ``:`` after the mark name is an optional description.
|
||||
|
||||
Alternatively, you can register new markers programmatically in a
|
||||
:ref:`pytest_configure <initialization-hooks>` hook:
|
||||
@@ -66,7 +76,7 @@ Raising errors on unknown marks
|
||||
|
||||
Unregistered marks applied with the ``@pytest.mark.name_of_the_mark`` decorator
|
||||
will always emit a warning in order to avoid silently doing something
|
||||
surprising due to mis-typed names. As described in the previous section, you can disable
|
||||
surprising due to mistyped names. As described in the previous section, you can disable
|
||||
the warning for custom marks by registering them in your ``pytest.ini`` file or
|
||||
using a custom ``pytest_configure`` hook.
|
||||
|
||||
|
||||
@@ -33,25 +33,25 @@ Consider the following scenarios:
|
||||
|
||||
1. Modifying the behavior of a function or the property of a class for a test e.g.
|
||||
there is an API call or database connection you will not make for a test but you know
|
||||
what the expected output should be. Use :py:meth:`monkeypatch.setattr` to patch the
|
||||
what the expected output should be. Use :py:meth:`monkeypatch.setattr <MonkeyPatch.setattr>` to patch the
|
||||
function or property with your desired testing behavior. This can include your own functions.
|
||||
Use :py:meth:`monkeypatch.delattr` to remove the function or property for the test.
|
||||
Use :py:meth:`monkeypatch.delattr <MonkeyPatch.delattr>` to remove the function or property for the test.
|
||||
|
||||
2. Modifying the values of dictionaries e.g. you have a global configuration that
|
||||
you want to modify for certain test cases. Use :py:meth:`monkeypatch.setitem` to patch the
|
||||
dictionary for the test. :py:meth:`monkeypatch.delitem` can be used to remove items.
|
||||
you want to modify for certain test cases. Use :py:meth:`monkeypatch.setitem <MonkeyPatch.setitem>` to patch the
|
||||
dictionary for the test. :py:meth:`monkeypatch.delitem <MonkeyPatch.delitem>` can be used to remove items.
|
||||
|
||||
3. Modifying environment variables for a test e.g. to test program behavior if an
|
||||
environment variable is missing, or to set multiple values to a known variable.
|
||||
:py:meth:`monkeypatch.setenv` and :py:meth:`monkeypatch.delenv` can be used for
|
||||
:py:meth:`monkeypatch.setenv <MonkeyPatch.setenv>` and :py:meth:`monkeypatch.delenv <MonkeyPatch.delenv>` can be used for
|
||||
these patches.
|
||||
|
||||
4. Use ``monkeypatch.setenv("PATH", value, prepend=os.pathsep)`` to modify ``$PATH``, and
|
||||
:py:meth:`monkeypatch.chdir` to change the context of the current working directory
|
||||
:py:meth:`monkeypatch.chdir <MonkeyPatch.chdir>` to change the context of the current working directory
|
||||
during a test.
|
||||
|
||||
5. Use :py:meth:`monkeypatch.syspath_prepend` to modify ``sys.path`` which will also
|
||||
call :py:meth:`pkg_resources.fixup_namespace_packages` and :py:meth:`importlib.invalidate_caches`.
|
||||
5. Use :py:meth:`monkeypatch.syspath_prepend <MonkeyPatch.syspath_prepend>` to modify ``sys.path`` which will also
|
||||
call ``pkg_resources.fixup_namespace_packages`` and :py:func:`importlib.invalidate_caches`.
|
||||
|
||||
See the `monkeypatch blog post`_ for some introduction material
|
||||
and a discussion of its motivation.
|
||||
@@ -66,10 +66,10 @@ testing, you do not want your test to depend on the running user. ``monkeypatch`
|
||||
can be used to patch functions dependent on the user to always return a
|
||||
specific value.
|
||||
|
||||
In this example, :py:meth:`monkeypatch.setattr` is used to patch ``Path.home``
|
||||
In this example, :py:meth:`monkeypatch.setattr <MonkeyPatch.setattr>` is used to patch ``Path.home``
|
||||
so that the known testing path ``Path("/abc")`` is always used when the test is run.
|
||||
This removes any dependency on the running user for testing purposes.
|
||||
:py:meth:`monkeypatch.setattr` must be called before the function which will use
|
||||
:py:meth:`monkeypatch.setattr <MonkeyPatch.setattr>` must be called before the function which will use
|
||||
the patched function is called.
|
||||
After the test function finishes the ``Path.home`` modification will be undone.
|
||||
|
||||
@@ -102,7 +102,7 @@ After the test function finishes the ``Path.home`` modification will be undone.
|
||||
Monkeypatching returned objects: building mock classes
|
||||
------------------------------------------------------
|
||||
|
||||
:py:meth:`monkeypatch.setattr` can be used in conjunction with classes to mock returned
|
||||
:py:meth:`monkeypatch.setattr <MonkeyPatch.setattr>` can be used in conjunction with classes to mock returned
|
||||
objects from functions instead of values.
|
||||
Imagine a simple function to take an API url and return the json response.
|
||||
|
||||
@@ -330,7 +330,7 @@ This behavior can be moved into ``fixture`` structures and shared across tests:
|
||||
Monkeypatching dictionaries
|
||||
---------------------------
|
||||
|
||||
:py:meth:`monkeypatch.setitem` can be used to safely set the values of dictionaries
|
||||
:py:meth:`monkeypatch.setitem <MonkeyPatch.setitem>` can be used to safely set the values of dictionaries
|
||||
to specific values during tests. Take this simplified connection string example:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -367,7 +367,7 @@ For testing purposes we can patch the ``DEFAULT_CONFIG`` dictionary to specific
|
||||
result = app.create_connection_string()
|
||||
assert result == expected
|
||||
|
||||
You can use the :py:meth:`monkeypatch.delitem` to remove values.
|
||||
You can use the :py:meth:`monkeypatch.delitem <MonkeyPatch.delitem>` to remove values.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ Mark a test function as using the given fixture names.
|
||||
|
||||
.. py:function:: pytest.mark.usefixtures(*names)
|
||||
|
||||
:param args: the names of the fixture to use, as strings
|
||||
:param args: The names of the fixture to use, as strings.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -209,8 +209,10 @@ Marks a test function as *expected to fail*.
|
||||
Condition for marking the test function as xfail (``True/False`` or a
|
||||
:ref:`condition string <string conditions>`). If a bool, you also have
|
||||
to specify ``reason`` (see :ref:`condition string <string conditions>`).
|
||||
:keyword str reason: Reason why the test function is marked as xfail.
|
||||
:keyword Exception raises: Exception subclass expected to be raised by the test function; other exceptions will fail the test.
|
||||
:keyword str reason:
|
||||
Reason why the test function is marked as xfail.
|
||||
:keyword Type[Exception] raises:
|
||||
Exception subclass expected to be raised by the test function; other exceptions will fail the test.
|
||||
:keyword bool run:
|
||||
If the test function should actually be executed. If ``False``, the function will always xfail and will
|
||||
not be executed (useful if a function is segfaulting).
|
||||
@@ -224,7 +226,7 @@ Marks a test function as *expected to fail*.
|
||||
a new release of a library fixes a known bug).
|
||||
|
||||
|
||||
custom marks
|
||||
Custom marks
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Marks are created dynamically using the factory object ``pytest.mark`` and applied as a decorator.
|
||||
@@ -238,7 +240,7 @@ For example:
|
||||
...
|
||||
|
||||
Will create and attach a :class:`Mark <_pytest.mark.structures.Mark>` object to the collected
|
||||
:class:`Item <_pytest.nodes.Item>`, which can then be accessed by fixtures or hooks with
|
||||
:class:`Item <pytest.Item>`, which can then be accessed by fixtures or hooks with
|
||||
:meth:`Node.iter_markers <_pytest.nodes.Node.iter_markers>`. The ``mark`` object will have the following attributes:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -473,7 +475,7 @@ caplog
|
||||
.. autofunction:: _pytest.logging.caplog()
|
||||
:no-auto-options:
|
||||
|
||||
This returns a :class:`_pytest.logging.LogCaptureFixture` instance.
|
||||
Returns a :class:`_pytest.logging.LogCaptureFixture` instance.
|
||||
|
||||
.. autoclass:: _pytest.logging.LogCaptureFixture
|
||||
:members:
|
||||
@@ -491,7 +493,7 @@ monkeypatch
|
||||
.. autofunction:: _pytest.monkeypatch.monkeypatch()
|
||||
:no-auto-options:
|
||||
|
||||
This returns a :class:`MonkeyPatch` instance.
|
||||
Returns a :class:`MonkeyPatch` instance.
|
||||
|
||||
.. autoclass:: _pytest.monkeypatch.MonkeyPatch
|
||||
:members:
|
||||
@@ -537,14 +539,11 @@ recwarn
|
||||
.. autofunction:: recwarn()
|
||||
:no-auto-options:
|
||||
|
||||
.. autoclass:: _pytest.recwarn.WarningsRecorder()
|
||||
.. autoclass:: WarningsRecorder()
|
||||
:members:
|
||||
|
||||
Each recorded warning is an instance of :class:`warnings.WarningMessage`.
|
||||
|
||||
.. note::
|
||||
:class:`RecordedWarning` was changed from a plain class to a namedtuple in pytest 3.1
|
||||
|
||||
.. note::
|
||||
``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated
|
||||
differently; see :ref:`ensuring_function_triggers`.
|
||||
@@ -654,7 +653,6 @@ Collection hooks
|
||||
|
||||
.. autofunction:: pytest_collection
|
||||
.. autofunction:: pytest_ignore_collect
|
||||
.. autofunction:: pytest_collect_directory
|
||||
.. autofunction:: pytest_collect_file
|
||||
.. autofunction:: pytest_pycollect_makemodule
|
||||
|
||||
@@ -675,7 +673,7 @@ items, delete or otherwise amend the test items:
|
||||
Test running (runtest) hooks
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
All runtest related hooks receive a :py:class:`pytest.Item <_pytest.main.Item>` object.
|
||||
All runtest related hooks receive a :py:class:`pytest.Item <pytest.Item>` object.
|
||||
|
||||
.. autofunction:: pytest_runtestloop
|
||||
.. autofunction:: pytest_runtest_protocol
|
||||
@@ -687,8 +685,8 @@ All runtest related hooks receive a :py:class:`pytest.Item <_pytest.main.Item>`
|
||||
.. autofunction:: pytest_runtest_makereport
|
||||
|
||||
For deeper understanding you may look at the default implementation of
|
||||
these hooks in :py:mod:`_pytest.runner` and maybe also
|
||||
in :py:mod:`_pytest.pdb` which interacts with :py:mod:`_pytest.capture`
|
||||
these hooks in ``_pytest.runner`` and maybe also
|
||||
in ``_pytest.pdb`` which interacts with ``_pytest.capture``
|
||||
and its input/output capturing in order to immediately drop
|
||||
into interactive debugging when a test failure occurs.
|
||||
|
||||
@@ -751,14 +749,14 @@ CallInfo
|
||||
Class
|
||||
~~~~~
|
||||
|
||||
.. autoclass:: _pytest.python.Class()
|
||||
.. autoclass:: pytest.Class()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Collector
|
||||
~~~~~~~~~
|
||||
|
||||
.. autoclass:: _pytest.nodes.Collector()
|
||||
.. autoclass:: pytest.Collector()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
@@ -783,12 +781,19 @@ ExceptionInfo
|
||||
:members:
|
||||
|
||||
|
||||
pytest.ExitCode
|
||||
~~~~~~~~~~~~~~~
|
||||
ExitCode
|
||||
~~~~~~~~
|
||||
|
||||
.. autoclass:: _pytest.config.ExitCode
|
||||
.. autoclass:: pytest.ExitCode
|
||||
:members:
|
||||
|
||||
File
|
||||
~~~~
|
||||
|
||||
.. autoclass:: pytest.File()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
FixtureDef
|
||||
~~~~~~~~~~
|
||||
@@ -807,14 +812,14 @@ FSCollector
|
||||
Function
|
||||
~~~~~~~~
|
||||
|
||||
.. autoclass:: _pytest.python.Function()
|
||||
.. autoclass:: pytest.Function()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Item
|
||||
~~~~
|
||||
|
||||
.. autoclass:: _pytest.nodes.Item()
|
||||
.. autoclass:: pytest.Item()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
@@ -848,7 +853,7 @@ Metafunc
|
||||
Module
|
||||
~~~~~~
|
||||
|
||||
.. autoclass:: _pytest.python.Module()
|
||||
.. autoclass:: pytest.Module()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
@@ -864,12 +869,6 @@ Parser
|
||||
.. autoclass:: _pytest.config.argparsing.Parser()
|
||||
:members:
|
||||
|
||||
PluginManager
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: pluggy.PluginManager()
|
||||
:members:
|
||||
|
||||
|
||||
PytestPluginManager
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
@@ -877,12 +876,13 @@ PytestPluginManager
|
||||
.. autoclass:: _pytest.config.PytestPluginManager()
|
||||
:members:
|
||||
:undoc-members:
|
||||
:inherited-members:
|
||||
:show-inheritance:
|
||||
|
||||
Session
|
||||
~~~~~~~
|
||||
|
||||
.. autoclass:: _pytest.main.Session()
|
||||
.. autoclass:: pytest.Session()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
@@ -1024,7 +1024,7 @@ When set (regardless of value), pytest will use color in terminal output.
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
.. autoclass:: _pytest.config.UsageError()
|
||||
.. autoclass:: pytest.UsageError()
|
||||
:show-inheritance:
|
||||
|
||||
.. _`warnings ref`:
|
||||
@@ -1466,20 +1466,6 @@ passed multiple times. The expected format is ``name=value``. For example::
|
||||
For more information, see :ref:`logging`.
|
||||
|
||||
|
||||
.. confval:: log_print
|
||||
|
||||
|
||||
|
||||
If set to ``False``, will disable displaying captured logging messages for failed tests.
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[pytest]
|
||||
log_print = False
|
||||
|
||||
For more information, see :ref:`logging`.
|
||||
|
||||
|
||||
.. confval:: markers
|
||||
|
||||
When the ``--strict-markers`` or ``--strict`` command-line arguments are used,
|
||||
@@ -1666,3 +1652,296 @@ passed multiple times. The expected format is ``name=value``. For example::
|
||||
|
||||
[pytest]
|
||||
xfail_strict = True
|
||||
|
||||
|
||||
.. _`command-line-flags`:
|
||||
|
||||
Command-line Flags
|
||||
------------------
|
||||
|
||||
All the command-line flags can be obtained by running ``pytest --help``::
|
||||
|
||||
$ pytest --help
|
||||
usage: pytest [options] [file_or_dir] [file_or_dir] [...]
|
||||
|
||||
positional arguments:
|
||||
file_or_dir
|
||||
|
||||
general:
|
||||
-k EXPRESSION only run tests which match the given substring
|
||||
expression. An expression is a python evaluatable
|
||||
expression where all names are substring-matched
|
||||
against test names and their parent classes.
|
||||
Example: -k 'test_method or test_other' matches all
|
||||
test functions and classes whose name contains
|
||||
'test_method' or 'test_other', while -k 'not
|
||||
test_method' matches those that don't contain
|
||||
'test_method' in their names. -k 'not test_method
|
||||
and not test_other' will eliminate the matches.
|
||||
Additionally keywords are matched to classes and
|
||||
functions containing extra names in their
|
||||
'extra_keyword_matches' set, as well as functions
|
||||
which have names assigned directly to them. The
|
||||
matching is case-insensitive.
|
||||
-m MARKEXPR only run tests matching given mark expression.
|
||||
For example: -m 'mark1 and not mark2'.
|
||||
--markers show markers (builtin, plugin and per-project ones).
|
||||
-x, --exitfirst exit instantly on first error or failed test.
|
||||
--fixtures, --funcargs
|
||||
show available fixtures, sorted by plugin appearance
|
||||
(fixtures with leading '_' are only shown with '-v')
|
||||
--fixtures-per-test show fixtures per test
|
||||
--pdb start the interactive Python debugger on errors or
|
||||
KeyboardInterrupt.
|
||||
--pdbcls=modulename:classname
|
||||
start a custom interactive Python debugger on
|
||||
errors. For example:
|
||||
--pdbcls=IPython.terminal.debugger:TerminalPdb
|
||||
--trace Immediately break when running each test.
|
||||
--capture=method per-test capturing method: one of fd|sys|no|tee-sys.
|
||||
-s shortcut for --capture=no.
|
||||
--runxfail report the results of xfail tests as if they were
|
||||
not marked
|
||||
--lf, --last-failed rerun only the tests that failed at the last run (or
|
||||
all if none failed)
|
||||
--ff, --failed-first run all tests, but run the last failures first.
|
||||
This may re-order tests and thus lead to repeated
|
||||
fixture setup/teardown.
|
||||
--nf, --new-first run tests from new files first, then the rest of the
|
||||
tests sorted by file mtime
|
||||
--cache-show=[CACHESHOW]
|
||||
show cache contents, don't perform collection or
|
||||
tests. Optional argument: glob (default: '*').
|
||||
--cache-clear remove all cache contents at start of test run.
|
||||
--lfnf={all,none}, --last-failed-no-failures={all,none}
|
||||
which tests to run with no previously (known)
|
||||
failures.
|
||||
--sw, --stepwise exit on test failure and continue from last failing
|
||||
test next time
|
||||
--stepwise-skip ignore the first failing test but stop on the next
|
||||
failing test
|
||||
|
||||
reporting:
|
||||
--durations=N show N slowest setup/test durations (N=0 for all).
|
||||
--durations-min=N Minimal duration in seconds for inclusion in slowest
|
||||
list. Default 0.005
|
||||
-v, --verbose increase verbosity.
|
||||
--no-header disable header
|
||||
--no-summary disable summary
|
||||
-q, --quiet decrease verbosity.
|
||||
--verbosity=VERBOSE set verbosity. Default is 0.
|
||||
-r chars show extra test summary info as specified by chars:
|
||||
(f)ailed, (E)rror, (s)kipped, (x)failed, (X)passed,
|
||||
(p)assed, (P)assed with output, (a)ll except passed
|
||||
(p/P), or (A)ll. (w)arnings are enabled by default
|
||||
(see --disable-warnings), 'N' can be used to reset
|
||||
the list. (default: 'fE').
|
||||
--disable-warnings, --disable-pytest-warnings
|
||||
disable warnings summary
|
||||
-l, --showlocals show locals in tracebacks (disabled by default).
|
||||
--tb=style traceback print mode
|
||||
(auto/long/short/line/native/no).
|
||||
--show-capture={no,stdout,stderr,log,all}
|
||||
Controls how captured stdout/stderr/log is shown on
|
||||
failed tests. Default is 'all'.
|
||||
--full-trace don't cut any tracebacks (default is to cut).
|
||||
--color=color color terminal output (yes/no/auto).
|
||||
--code-highlight={yes,no}
|
||||
Whether code should be highlighted (only if --color
|
||||
is also enabled)
|
||||
--pastebin=mode send failed|all info to bpaste.net pastebin service.
|
||||
--junit-xml=path create junit-xml style report file at given path.
|
||||
--junit-prefix=str prepend prefix to classnames in junit-xml output
|
||||
|
||||
pytest-warnings:
|
||||
-W PYTHONWARNINGS, --pythonwarnings=PYTHONWARNINGS
|
||||
set which warnings to report, see -W option of
|
||||
python itself.
|
||||
--maxfail=num exit after first num failures or errors.
|
||||
--strict-config any warnings encountered while parsing the `pytest`
|
||||
section of the configuration file raise errors.
|
||||
--strict-markers, --strict
|
||||
markers not registered in the `markers` section of
|
||||
the configuration file raise errors.
|
||||
-c file load configuration from `file` instead of trying to
|
||||
locate one of the implicit configuration files.
|
||||
--continue-on-collection-errors
|
||||
Force test execution even if collection errors
|
||||
occur.
|
||||
--rootdir=ROOTDIR Define root directory for tests. Can be relative
|
||||
path: 'root_dir', './root_dir',
|
||||
'root_dir/another_dir/'; absolute path:
|
||||
'/home/user/root_dir'; path with variables:
|
||||
'$HOME/root_dir'.
|
||||
|
||||
collection:
|
||||
--collect-only, --co only collect tests, don't execute them.
|
||||
--pyargs try to interpret all arguments as python packages.
|
||||
--ignore=path ignore path during collection (multi-allowed).
|
||||
--ignore-glob=path ignore path pattern during collection (multi-
|
||||
allowed).
|
||||
--deselect=nodeid_prefix
|
||||
deselect item (via node id prefix) during collection
|
||||
(multi-allowed).
|
||||
--confcutdir=dir only load conftest.py's relative to specified dir.
|
||||
--noconftest Don't load any conftest.py files.
|
||||
--keep-duplicates Keep duplicate tests.
|
||||
--collect-in-virtualenv
|
||||
Don't ignore tests in a local virtualenv directory
|
||||
--import-mode={prepend,append,importlib}
|
||||
prepend/append to sys.path when importing test
|
||||
modules and conftest files, default is to prepend.
|
||||
--doctest-modules run doctests in all .py modules
|
||||
--doctest-report={none,cdiff,ndiff,udiff,only_first_failure}
|
||||
choose another output format for diffs on doctest
|
||||
failure
|
||||
--doctest-glob=pat doctests file matching pattern, default: test*.txt
|
||||
--doctest-ignore-import-errors
|
||||
ignore doctest ImportErrors
|
||||
--doctest-continue-on-failure
|
||||
for a given doctest, continue to run after the first
|
||||
failure
|
||||
|
||||
test session debugging and configuration:
|
||||
--basetemp=dir base temporary directory for this test run.(warning:
|
||||
this directory is removed if it exists)
|
||||
-V, --version display pytest version and information about
|
||||
plugins.When given twice, also display information
|
||||
about plugins.
|
||||
-h, --help show help message and configuration info
|
||||
-p name early-load given plugin module name or entry point
|
||||
(multi-allowed).
|
||||
To avoid loading of plugins, use the `no:` prefix,
|
||||
e.g. `no:doctest`.
|
||||
--trace-config trace considerations of conftest.py files.
|
||||
--debug store internal tracing debug information in
|
||||
'pytestdebug.log'.
|
||||
-o OVERRIDE_INI, --override-ini=OVERRIDE_INI
|
||||
override ini option with "option=value" style, e.g.
|
||||
`-o xfail_strict=True -o cache_dir=cache`.
|
||||
--assert=MODE Control assertion debugging tools.
|
||||
'plain' performs no assertion debugging.
|
||||
'rewrite' (the default) rewrites assert statements
|
||||
in test modules on import to provide assert
|
||||
expression information.
|
||||
--setup-only only setup fixtures, do not execute tests.
|
||||
--setup-show show setup of fixtures while executing tests.
|
||||
--setup-plan show what fixtures and tests would be executed but
|
||||
don't execute anything.
|
||||
|
||||
logging:
|
||||
--log-level=LEVEL level of messages to catch/display.
|
||||
Not set by default, so it depends on the root/parent
|
||||
log handler's effective level, where it is "WARNING"
|
||||
by default.
|
||||
--log-format=LOG_FORMAT
|
||||
log format as used by the logging module.
|
||||
--log-date-format=LOG_DATE_FORMAT
|
||||
log date format as used by the logging module.
|
||||
--log-cli-level=LOG_CLI_LEVEL
|
||||
cli logging level.
|
||||
--log-cli-format=LOG_CLI_FORMAT
|
||||
log format as used by the logging module.
|
||||
--log-cli-date-format=LOG_CLI_DATE_FORMAT
|
||||
log date format as used by the logging module.
|
||||
--log-file=LOG_FILE path to a file when logging will be written to.
|
||||
--log-file-level=LOG_FILE_LEVEL
|
||||
log file logging level.
|
||||
--log-file-format=LOG_FILE_FORMAT
|
||||
log format as used by the logging module.
|
||||
--log-file-date-format=LOG_FILE_DATE_FORMAT
|
||||
log date format as used by the logging module.
|
||||
--log-auto-indent=LOG_AUTO_INDENT
|
||||
Auto-indent multiline messages passed to the logging
|
||||
module. Accepts true|on, false|off or an integer.
|
||||
|
||||
[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found:
|
||||
|
||||
markers (linelist): markers for test functions
|
||||
empty_parameter_set_mark (string):
|
||||
default marker for empty parametersets
|
||||
norecursedirs (args): directory patterns to avoid for recursion
|
||||
testpaths (args): directories to search for tests when no files or
|
||||
directories are given in the command line.
|
||||
filterwarnings (linelist):
|
||||
Each line specifies a pattern for
|
||||
warnings.filterwarnings. Processed after
|
||||
-W/--pythonwarnings.
|
||||
usefixtures (args): list of default fixtures to be used with this
|
||||
project
|
||||
python_files (args): glob-style file patterns for Python test module
|
||||
discovery
|
||||
python_classes (args):
|
||||
prefixes or glob names for Python test class
|
||||
discovery
|
||||
python_functions (args):
|
||||
prefixes or glob names for Python test function and
|
||||
method discovery
|
||||
disable_test_id_escaping_and_forfeit_all_rights_to_community_support (bool):
|
||||
disable string escape non-ascii characters, might
|
||||
cause unwanted side effects(use at your own risk)
|
||||
console_output_style (string):
|
||||
console output: "classic", or with additional
|
||||
progress information ("progress" (percentage) |
|
||||
"count").
|
||||
xfail_strict (bool): default for the strict parameter of xfail markers
|
||||
when not given explicitly (default: False)
|
||||
enable_assertion_pass_hook (bool):
|
||||
Enables the pytest_assertion_pass hook.Make sure to
|
||||
delete any previously generated pyc cache files.
|
||||
junit_suite_name (string):
|
||||
Test suite name for JUnit report
|
||||
junit_logging (string):
|
||||
Write captured log messages to JUnit report: one of
|
||||
no|log|system-out|system-err|out-err|all
|
||||
junit_log_passing_tests (bool):
|
||||
Capture log information for passing tests to JUnit
|
||||
report:
|
||||
junit_duration_report (string):
|
||||
Duration time to report: one of total|call
|
||||
junit_family (string):
|
||||
Emit XML for schema: one of legacy|xunit1|xunit2
|
||||
doctest_optionflags (args):
|
||||
option flags for doctests
|
||||
doctest_encoding (string):
|
||||
encoding used for doctest files
|
||||
cache_dir (string): cache directory path.
|
||||
log_level (string): default value for --log-level
|
||||
log_format (string): default value for --log-format
|
||||
log_date_format (string):
|
||||
default value for --log-date-format
|
||||
log_cli (bool): enable log display during test run (also known as
|
||||
"live logging").
|
||||
log_cli_level (string):
|
||||
default value for --log-cli-level
|
||||
log_cli_format (string):
|
||||
default value for --log-cli-format
|
||||
log_cli_date_format (string):
|
||||
default value for --log-cli-date-format
|
||||
log_file (string): default value for --log-file
|
||||
log_file_level (string):
|
||||
default value for --log-file-level
|
||||
log_file_format (string):
|
||||
default value for --log-file-format
|
||||
log_file_date_format (string):
|
||||
default value for --log-file-date-format
|
||||
log_auto_indent (string):
|
||||
default value for --log-auto-indent
|
||||
faulthandler_timeout (string):
|
||||
Dump the traceback of all threads if a test takes
|
||||
more than TIMEOUT seconds to finish.
|
||||
addopts (args): extra command line options
|
||||
minversion (string): minimally required pytest version
|
||||
required_plugins (args):
|
||||
plugins that must be present for pytest to run
|
||||
|
||||
environment variables:
|
||||
PYTEST_ADDOPTS extra command line options
|
||||
PYTEST_PLUGINS comma-separated plugins to load during startup
|
||||
PYTEST_DISABLE_PLUGIN_AUTOLOAD set to disable plugin auto-loading
|
||||
PYTEST_DEBUG set to enable debug tracing of pytest's internals
|
||||
|
||||
|
||||
to see available markers type: pytest --markers
|
||||
to see available fixtures type: pytest --fixtures
|
||||
(shown according to specified file_or_dir or current dir if not specified; fixtures with leading '_' are only shown with the '-v' option
|
||||
|
||||
@@ -2,13 +2,6 @@
|
||||
Talks and Tutorials
|
||||
==========================
|
||||
|
||||
.. sidebar:: Next Open Trainings
|
||||
|
||||
- `Free 1h webinar: "pytest: Test Driven Development für Python" <https://mylearning.ch/kurse/online-kurse/tech-webinar/>`_ (German), online, August 18 2020.
|
||||
- `"pytest: Test Driven Development (nicht nur) für Python" <https://workshoptage.ch/workshops/2020/pytest-test-driven-development-nicht-nur-fuer-python/>`_ (German) at the `CH Open Workshoptage <https://workshoptage.ch/>`_, September 8 2020, HSLU Campus Rotkreuz (ZG), Switzerland.
|
||||
|
||||
.. _`funcargs`: funcargs.html
|
||||
|
||||
Books
|
||||
---------------------------------------------
|
||||
|
||||
@@ -21,6 +14,16 @@ Books
|
||||
Talks and blog postings
|
||||
---------------------------------------------
|
||||
|
||||
- Webinar: `pytest: Test Driven Development für Python (German) <https://bruhin.software/ins-pytest/>`_, Florian Bruhin, via mylearning.ch, 2020
|
||||
|
||||
- Webinar: `Simplify Your Tests with Fixtures <https://blog.jetbrains.com/pycharm/2020/08/webinar-recording-simplify-your-tests-with-fixtures-with-oliver-bestwalter/>`_, Oliver Bestwalter, via JetBrains, 2020
|
||||
|
||||
- Training: `Introduction to pytest - simple, rapid and fun testing with Python <https://www.youtube.com/watch?v=CMuSn9cofbI>`_, Florian Bruhin, PyConDE 2019
|
||||
|
||||
- Abridged metaprogramming classics - this episode: pytest, Oliver Bestwalter, PyConDE 2019 (`repository <https://github.com/obestwalter/abridged-meta-programming-classics>`__, `recording <https://www.youtube.com/watch?v=zHpeMTJsBRk&feature=youtu.be>`__)
|
||||
|
||||
- Testing PySide/PyQt code easily using the pytest framework, Florian Bruhin, Qt World Summit 2019 (`slides <https://bruhin.software/talks/qtws19.pdf>`__, `recording <https://www.youtube.com/watch?v=zdsBS5BXGqQ>`__)
|
||||
|
||||
- `pytest: recommendations, basic packages for testing in Python and Django, Andreu Vallbona, PyBCN June 2019 <https://www.slideshare.net/AndreuVallbonaPlazas/pybcn-pytest-recomendaciones-paquetes-bsicos-para-testing-en-python-y-django>`_.
|
||||
|
||||
- pytest: recommendations, basic packages for testing in Python and Django, Andreu Vallbona, PyconES 2017 (`slides in english <http://talks.apsl.io/testing-pycones-2017/>`_, `video in spanish <https://www.youtube.com/watch?v=K20GeR-lXDk>`_)
|
||||
@@ -52,8 +55,6 @@ Talks and blog postings
|
||||
- `pytest: helps you write better Django apps, Andreas Pelme, DjangoCon
|
||||
Europe 2014 <https://www.youtube.com/watch?v=aaArYVh6XSM>`_.
|
||||
|
||||
- :ref:`fixtures`
|
||||
|
||||
- `Testing Django Applications with pytest, Andreas Pelme, EuroPython
|
||||
2013 <https://www.youtube.com/watch?v=aUf8Fkb7TaY>`_.
|
||||
|
||||
|
||||
@@ -192,8 +192,13 @@ You can override the default temporary directory setting like this:
|
||||
|
||||
pytest --basetemp=mydir
|
||||
|
||||
When distributing tests on the local machine, ``pytest`` takes care to
|
||||
configure a basetemp directory for the sub processes such that all temporary
|
||||
.. warning::
|
||||
|
||||
The contents of ``mydir`` will be completely removed, so make sure to use a directory
|
||||
for that purpose only.
|
||||
|
||||
When distributing tests on the local machine using ``pytest-xdist``, care is taken to
|
||||
automatically configure a basetemp directory for the sub processes such that all temporary
|
||||
data lands below a single per-test run basetemp directory.
|
||||
|
||||
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
|
||||
|
||||
@@ -33,7 +33,7 @@ Running ``pytest`` can result in six different exit codes:
|
||||
:Exit code 4: pytest command line usage error
|
||||
:Exit code 5: No tests were collected
|
||||
|
||||
They are represented by the :class:`_pytest.config.ExitCode` enum. The exit codes being a part of the public API can be imported and accessed directly using:
|
||||
They are represented by the :class:`pytest.ExitCode` enum. The exit codes being a part of the public API can be imported and accessed directly using:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -57,6 +57,8 @@ Getting help on version, option names, environment variables
|
||||
pytest -h | --help # show help on command line and config file options
|
||||
|
||||
|
||||
The full command-line flags can be found in the :ref:`reference <command-line-flags>`.
|
||||
|
||||
.. _maxfail:
|
||||
|
||||
Stopping after the first (or N) failures
|
||||
@@ -426,14 +428,15 @@ Pytest supports the use of ``breakpoint()`` with the following behaviours:
|
||||
Profiling test execution duration
|
||||
-------------------------------------
|
||||
|
||||
.. versionchanged:: 6.0
|
||||
|
||||
To get a list of the slowest 10 test durations:
|
||||
To get a list of the slowest 10 test durations over 1.0s long:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest --durations=10
|
||||
pytest --durations=10 --durations-min=1.0
|
||||
|
||||
By default, pytest will not show test durations that are too small (<0.01s) unless ``-vv`` is passed on the command-line.
|
||||
By default, pytest will not show test durations that are too small (<0.005s) unless ``-vv`` is passed on the command-line.
|
||||
|
||||
|
||||
.. _faulthandler:
|
||||
|
||||
@@ -68,16 +68,30 @@ them into errors:
|
||||
FAILED test_show_warnings.py::test_one - UserWarning: api v1, should use ...
|
||||
1 failed in 0.12s
|
||||
|
||||
The same option can be set in the ``pytest.ini`` file using the ``filterwarnings`` ini option.
|
||||
For example, the configuration below will ignore all user warnings, but will transform
|
||||
The same option can be set in the ``pytest.ini`` or ``pyproject.toml`` file using the
|
||||
``filterwarnings`` ini option. For example, the configuration below will ignore all
|
||||
user warnings and specific deprecation warnings matching a regex, but will transform
|
||||
all other warnings into errors.
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
# pytest.ini
|
||||
[pytest]
|
||||
filterwarnings =
|
||||
error
|
||||
ignore::UserWarning
|
||||
ignore:function ham\(\) is deprecated:DeprecationWarning
|
||||
|
||||
.. code-block:: toml
|
||||
|
||||
# pyproject.toml
|
||||
[tool.pytest.ini_options]
|
||||
filterwarnings = [
|
||||
"error",
|
||||
"ignore::UserWarning",
|
||||
# note the use of single quote below to denote "raw" strings in TOML
|
||||
'ignore:function ham\(\) is deprecated:DeprecationWarning',
|
||||
]
|
||||
|
||||
|
||||
When a warning matches more than one option in the list, the action for the last matching option
|
||||
@@ -353,7 +367,7 @@ warnings, or index into it to get a particular recorded warning.
|
||||
|
||||
.. currentmodule:: _pytest.warnings
|
||||
|
||||
Full API: :class:`WarningsRecorder`.
|
||||
Full API: :class:`~_pytest.recwarn.WarningsRecorder`.
|
||||
|
||||
.. _custom_failure_messages:
|
||||
|
||||
|
||||
@@ -404,7 +404,7 @@ return a result object, with which we can assert the tests' outcomes.
|
||||
result.assert_outcomes(passed=4)
|
||||
|
||||
|
||||
additionally it is possible to copy examples for an example folder before running pytest on it
|
||||
Additionally it is possible to copy examples for an example folder before running pytest on it.
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
@@ -614,6 +614,11 @@ among each other.
|
||||
Declaring new hooks
|
||||
------------------------
|
||||
|
||||
.. note::
|
||||
|
||||
This is a quick overview on how to add new hooks and how they work in general, but a more complete
|
||||
overview can be found in `the pluggy documentation <https://pluggy.readthedocs.io/en/latest/>`__.
|
||||
|
||||
.. currentmodule:: _pytest.hookspec
|
||||
|
||||
Plugins and ``conftest.py`` files may declare new hooks that can then be
|
||||
@@ -627,7 +632,7 @@ Hooks are usually declared as do-nothing functions that contain only
|
||||
documentation describing when the hook will be called and what return values
|
||||
are expected. The names of the functions must start with `pytest_` otherwise pytest won't recognize them.
|
||||
|
||||
Here's an example. Let's assume this code is in the ``hooks.py`` module.
|
||||
Here's an example. Let's assume this code is in the ``sample_hook.py`` module.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -643,10 +648,10 @@ class or module can then be passed to the ``pluginmanager`` using the ``pytest_a
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_addhooks(pluginmanager):
|
||||
""" This example assumes the hooks are grouped in the 'hooks' module. """
|
||||
from my_app.tests import hooks
|
||||
""" This example assumes the hooks are grouped in the 'sample_hook' module. """
|
||||
from my_app.tests import sample_hook
|
||||
|
||||
pluginmanager.add_hookspecs(hooks)
|
||||
pluginmanager.add_hookspecs(sample_hook)
|
||||
|
||||
For a real world example, see `newhooks.py`_ from `xdist <https://github.com/pytest-dev/pytest-xdist>`_.
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ fixtures (setup and teardown test state) on a per-module/class/function basis.
|
||||
.. note::
|
||||
|
||||
While these setup/teardown methods are simple and familiar to those
|
||||
coming from a ``unittest`` or nose ``background``, you may also consider
|
||||
coming from a ``unittest`` or ``nose`` background, you may also consider
|
||||
using pytest's more powerful :ref:`fixture mechanism
|
||||
<fixture>` which leverages the concept of dependency injection, allowing
|
||||
for a more modular and more scalable approach for managing test state,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import py
|
||||
import requests
|
||||
|
||||
issues_url = "https://api.github.com/repos/pytest-dev/pytest/issues"
|
||||
@@ -31,12 +31,12 @@ def get_issues():
|
||||
|
||||
|
||||
def main(args):
|
||||
cachefile = py.path.local(args.cache)
|
||||
cachefile = Path(args.cache)
|
||||
if not cachefile.exists() or args.refresh:
|
||||
issues = get_issues()
|
||||
cachefile.write(json.dumps(issues))
|
||||
cachefile.write_text(json.dumps(issues), "utf-8")
|
||||
else:
|
||||
issues = json.loads(cachefile.read())
|
||||
issues = json.loads(cachefile.read_text("utf-8"))
|
||||
|
||||
open_issues = [x for x in issues if x["state"] == "open"]
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
[build-system]
|
||||
requires = [
|
||||
# sync with setup.py until we discard non-pep-517/518
|
||||
"setuptools>=40.0",
|
||||
"setuptools-scm",
|
||||
"setuptools>=42.0",
|
||||
"setuptools-scm[toml]>=3.4",
|
||||
"wheel",
|
||||
]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.setuptools_scm]
|
||||
write_to = "src/_pytest/_version.py"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
minversion = "2.0"
|
||||
addopts = "-rfEX -p pytester --strict-markers"
|
||||
python_files = ["test_*.py", "*_test.py", "testing/*/*.py"]
|
||||
python_files = ["test_*.py", "*_test.py", "testing/python/*.py"]
|
||||
python_classes = ["Test", "Acceptance"]
|
||||
python_functions = ["test"]
|
||||
# NOTE: "doc" is not included here, but gets tested explicitly via "doctesting".
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
This script is part of the pytest release process which is triggered by comments
|
||||
in issues.
|
||||
|
||||
This script is started by the `release-on-comment.yml` workflow, which is triggered by two comment
|
||||
related events:
|
||||
This script is started by the `release-on-comment.yml` workflow, which always executes on
|
||||
`master` and is triggered by two comment related events:
|
||||
|
||||
* https://help.github.com/en/actions/reference/events-that-trigger-workflows#issue-comment-event-issue_comment
|
||||
* https://help.github.com/en/actions/reference/events-that-trigger-workflows#issues-event-issues
|
||||
@@ -30,7 +30,7 @@ import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
from subprocess import CalledProcessError
|
||||
from subprocess import check_call
|
||||
@@ -94,7 +94,6 @@ def print_and_exit(msg) -> None:
|
||||
|
||||
|
||||
def trigger_release(payload_path: Path, token: str) -> None:
|
||||
error_contents = "" # to be used to store error output in case any command fails
|
||||
payload, base_branch, is_major = validate_and_get_issue_comment_payload(
|
||||
payload_path
|
||||
)
|
||||
@@ -119,6 +118,7 @@ def trigger_release(payload_path: Path, token: str) -> None:
|
||||
issue.create_comment(str(e))
|
||||
print_and_exit(f"{Fore.RED}{e}")
|
||||
|
||||
error_contents = ""
|
||||
try:
|
||||
print(f"Version: {Fore.CYAN}{version}")
|
||||
|
||||
@@ -146,11 +146,12 @@ def trigger_release(payload_path: Path, token: str) -> None:
|
||||
|
||||
print(f"Branch {Fore.CYAN}{release_branch}{Fore.RESET} created.")
|
||||
|
||||
# important to use tox here because we have changed branches, so dependencies
|
||||
# might have changed as well
|
||||
cmdline = ["tox", "-e", "release", "--", version, "--skip-check-links"]
|
||||
print("Running", " ".join(cmdline))
|
||||
run(
|
||||
[sys.executable, "scripts/release.py", version, "--skip-check-links"],
|
||||
text=True,
|
||||
check=True,
|
||||
capture_output=True,
|
||||
cmdline, text=True, check=True, capture_output=True,
|
||||
)
|
||||
|
||||
oauth_url = f"https://{token}:x-oauth-basic@github.com/{SLUG}.git"
|
||||
@@ -178,43 +179,31 @@ def trigger_release(payload_path: Path, token: str) -> None:
|
||||
)
|
||||
print(f"Notified in original comment {Fore.CYAN}{comment.url}{Fore.RESET}.")
|
||||
|
||||
print(f"{Fore.GREEN}Success.")
|
||||
except CalledProcessError as e:
|
||||
error_contents = e.output
|
||||
except Exception as e:
|
||||
error_contents = str(e)
|
||||
link = f"https://github.com/{SLUG}/actions/runs/{os.environ['GITHUB_RUN_ID']}"
|
||||
issue.create_comment(
|
||||
dedent(
|
||||
f"""
|
||||
Sorry, the request to prepare release `{version}` from {base_branch} failed with:
|
||||
|
||||
```
|
||||
{e}
|
||||
```
|
||||
|
||||
See: {link}.
|
||||
"""
|
||||
)
|
||||
)
|
||||
print_and_exit(f"{Fore.RED}{e}")
|
||||
error_contents = f"CalledProcessError\noutput:\n{e.output}\nstderr:\n{e.stderr}"
|
||||
except Exception:
|
||||
error_contents = f"Exception:\n{traceback.format_exc()}"
|
||||
|
||||
if error_contents:
|
||||
link = f"https://github.com/{SLUG}/actions/runs/{os.environ['GITHUB_RUN_ID']}"
|
||||
issue.create_comment(
|
||||
dedent(
|
||||
f"""
|
||||
Sorry, the request to prepare release `{version}` from {base_branch} failed with:
|
||||
|
||||
```
|
||||
{error_contents}
|
||||
```
|
||||
|
||||
See: {link}.
|
||||
"""
|
||||
)
|
||||
msg = ERROR_COMMENT.format(
|
||||
version=version, base_branch=base_branch, contents=error_contents, link=link
|
||||
)
|
||||
issue.create_comment(msg)
|
||||
print_and_exit(f"{Fore.RED}{error_contents}")
|
||||
else:
|
||||
print(f"{Fore.GREEN}Success.")
|
||||
|
||||
|
||||
ERROR_COMMENT = """\
|
||||
The request to prepare release `{version}` from {base_branch} failed with:
|
||||
|
||||
```
|
||||
{contents}
|
||||
```
|
||||
|
||||
See: {link}.
|
||||
"""
|
||||
|
||||
|
||||
def find_next_version(base_branch: str, is_major: bool) -> str:
|
||||
|
||||
@@ -3,23 +3,20 @@ pytest-{version}
|
||||
|
||||
The pytest team is proud to announce the {version} release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
This release contains new features, improvements, bug fixes, and breaking changes, so users
|
||||
are encouraged to take a look at the CHANGELOG carefully:
|
||||
|
||||
This release contains a number of bug fixes and improvements, so users are encouraged
|
||||
to take a look at the CHANGELOG:
|
||||
|
||||
https://docs.pytest.org/en/latest/changelog.html
|
||||
https://docs.pytest.org/en/stable/changelog.html
|
||||
|
||||
For complete documentation, please visit:
|
||||
|
||||
https://docs.pytest.org/en/latest/
|
||||
https://docs.pytest.org/en/stable/
|
||||
|
||||
As usual, you can upgrade from PyPI via:
|
||||
|
||||
pip install -U pytest
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
{contributors}
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
|
||||
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
{contributors}
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
"""
|
||||
Invoke development tasks.
|
||||
"""
|
||||
"""Invoke development tasks."""
|
||||
import argparse
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
@@ -42,7 +42,6 @@ packages =
|
||||
install_requires =
|
||||
attrs>=17.4.0
|
||||
iniconfig
|
||||
more-itertools>=4.0.0
|
||||
packaging
|
||||
pluggy>=0.12,<1.0
|
||||
py>=1.8.2
|
||||
@@ -97,10 +96,13 @@ formats = sdist.tgz,bdist_wheel
|
||||
[mypy]
|
||||
mypy_path = src
|
||||
check_untyped_defs = True
|
||||
disallow_any_generics = True
|
||||
ignore_missing_imports = True
|
||||
no_implicit_optional = True
|
||||
show_error_codes = True
|
||||
strict_equality = True
|
||||
warn_redundant_casts = True
|
||||
warn_return_any = True
|
||||
warn_unreachable = True
|
||||
warn_unused_configs = True
|
||||
no_implicit_reexport = True
|
||||
|
||||
7
setup.py
7
setup.py
@@ -1,9 +1,4 @@
|
||||
from setuptools import setup
|
||||
|
||||
|
||||
def main():
|
||||
setup(use_scm_version={"write_to": "src/_pytest/_version.py"})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
setup()
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"""allow bash-completion for argparse with argcomplete if installed
|
||||
needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
|
||||
"""Allow bash-completion for argparse with argcomplete if installed.
|
||||
|
||||
Needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
|
||||
to find the magic string, so _ARGCOMPLETE env. var is never set, and
|
||||
this does not need special code.
|
||||
this does not need special code).
|
||||
|
||||
Function try_argcomplete(parser) should be called directly before
|
||||
the call to ArgumentParser.parse_args().
|
||||
@@ -10,8 +11,7 @@ The filescompleter is what you normally would use on the positional
|
||||
arguments specification, in order to get "dirname/" after "dirn<TAB>"
|
||||
instead of the default "dirname ":
|
||||
|
||||
optparser.add_argument(Config._file_or_dir, nargs='*'
|
||||
).completer=filescompleter
|
||||
optparser.add_argument(Config._file_or_dir, nargs='*').completer=filescompleter
|
||||
|
||||
Other, application specific, completers should go in the file
|
||||
doing the add_argument calls as they need to be specified as .completer
|
||||
@@ -20,35 +20,43 @@ attribute points to will not be used).
|
||||
|
||||
SPEEDUP
|
||||
=======
|
||||
|
||||
The generic argcomplete script for bash-completion
|
||||
(/etc/bash_completion.d/python-argcomplete.sh )
|
||||
(/etc/bash_completion.d/python-argcomplete.sh)
|
||||
uses a python program to determine startup script generated by pip.
|
||||
You can speed up completion somewhat by changing this script to include
|
||||
# PYTHON_ARGCOMPLETE_OK
|
||||
so the the python-argcomplete-check-easy-install-script does not
|
||||
need to be called to find the entry point of the code and see if that is
|
||||
marked with PYTHON_ARGCOMPLETE_OK
|
||||
marked with PYTHON_ARGCOMPLETE_OK.
|
||||
|
||||
INSTALL/DEBUGGING
|
||||
=================
|
||||
|
||||
To include this support in another application that has setup.py generated
|
||||
scripts:
|
||||
- add the line:
|
||||
|
||||
- Add the line:
|
||||
# PYTHON_ARGCOMPLETE_OK
|
||||
near the top of the main python entry point
|
||||
- include in the file calling parse_args():
|
||||
near the top of the main python entry point.
|
||||
|
||||
- Include in the file calling parse_args():
|
||||
from _argcomplete import try_argcomplete, filescompleter
|
||||
, call try_argcomplete just before parse_args(), and optionally add
|
||||
filescompleter to the positional arguments' add_argument()
|
||||
Call try_argcomplete just before parse_args(), and optionally add
|
||||
filescompleter to the positional arguments' add_argument().
|
||||
|
||||
If things do not work right away:
|
||||
- switch on argcomplete debugging with (also helpful when doing custom
|
||||
|
||||
- Switch on argcomplete debugging with (also helpful when doing custom
|
||||
completers):
|
||||
export _ARC_DEBUG=1
|
||||
- run:
|
||||
|
||||
- Run:
|
||||
python-argcomplete-check-easy-install-script $(which appname)
|
||||
echo $?
|
||||
will echo 0 if the magic line has been found, 1 if not
|
||||
- sometimes it helps to find early on errors using:
|
||||
will echo 0 if the magic line has been found, 1 if not.
|
||||
|
||||
- Sometimes it helps to find early on errors using:
|
||||
_ARGCOMPLETE=1 _ARC_DEBUG=1 appname
|
||||
which should throw a KeyError: 'COMPLINE' (which is properly set by the
|
||||
global argcomplete script).
|
||||
@@ -63,13 +71,13 @@ from typing import Optional
|
||||
|
||||
|
||||
class FastFilesCompleter:
|
||||
"Fast file completer class"
|
||||
"""Fast file completer class."""
|
||||
|
||||
def __init__(self, directories: bool = True) -> None:
|
||||
self.directories = directories
|
||||
|
||||
def __call__(self, prefix: str, **kwargs: Any) -> List[str]:
|
||||
"""only called on non option completions"""
|
||||
# Only called on non option completions.
|
||||
if os.path.sep in prefix[1:]:
|
||||
prefix_dir = len(os.path.dirname(prefix) + os.path.sep)
|
||||
else:
|
||||
@@ -77,7 +85,7 @@ class FastFilesCompleter:
|
||||
completion = []
|
||||
globbed = []
|
||||
if "*" not in prefix and "?" not in prefix:
|
||||
# we are on unix, otherwise no bash
|
||||
# We are on unix, otherwise no bash.
|
||||
if not prefix or prefix[-1] == os.path.sep:
|
||||
globbed.extend(glob(prefix + ".*"))
|
||||
prefix += "*"
|
||||
@@ -85,7 +93,7 @@ class FastFilesCompleter:
|
||||
for x in sorted(globbed):
|
||||
if os.path.isdir(x):
|
||||
x += "/"
|
||||
# append stripping the prefix (like bash, not like compgen)
|
||||
# Append stripping the prefix (like bash, not like compgen).
|
||||
completion.append(x[prefix_dir:])
|
||||
return completion
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ from .code import ExceptionInfo
|
||||
from .code import filter_traceback
|
||||
from .code import Frame
|
||||
from .code import getfslineno
|
||||
from .code import getrawcode
|
||||
from .code import Traceback
|
||||
from .code import TracebackEntry
|
||||
from .source import getrawcode
|
||||
from .source import Source
|
||||
|
||||
__all__ = [
|
||||
|
||||
@@ -38,9 +38,11 @@ from _pytest._io import TerminalWriter
|
||||
from _pytest._io.saferepr import safeformat
|
||||
from _pytest._io.saferepr import saferepr
|
||||
from _pytest.compat import ATTRS_EQ_FIELD
|
||||
from _pytest.compat import final
|
||||
from _pytest.compat import get_real_func
|
||||
from _pytest.compat import overload
|
||||
from _pytest.compat import TYPE_CHECKING
|
||||
from _pytest.pathlib import Path
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Type
|
||||
@@ -71,9 +73,8 @@ class Code:
|
||||
|
||||
@property
|
||||
def path(self) -> Union[py.path.local, str]:
|
||||
"""Return a path object pointing to source code (or a str in case
|
||||
of OSError / non-existing file).
|
||||
"""
|
||||
"""Return a path object pointing to source code, or an ``str`` in
|
||||
case of ``OSError`` / non-existing file."""
|
||||
if not self.raw.co_filename:
|
||||
return ""
|
||||
try:
|
||||
@@ -246,10 +247,20 @@ class TracebackEntry:
|
||||
|
||||
Mostly for internal use.
|
||||
"""
|
||||
f = self.frame
|
||||
tbh = f.f_locals.get(
|
||||
"__tracebackhide__", f.f_globals.get("__tracebackhide__", False)
|
||||
tbh = (
|
||||
False
|
||||
) # type: Union[bool, Callable[[Optional[ExceptionInfo[BaseException]]], bool]]
|
||||
for maybe_ns_dct in (self.frame.f_locals, self.frame.f_globals):
|
||||
# in normal cases, f_locals and f_globals are dictionaries
|
||||
# however via `exec(...)` / `eval(...)` they can be other types
|
||||
# (even incorrect types!).
|
||||
# as such, we suppress all exceptions while accessing __tracebackhide__
|
||||
try:
|
||||
tbh = maybe_ns_dct["__tracebackhide__"]
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
break
|
||||
if tbh and callable(tbh):
|
||||
return tbh(None if self._excinfo is None else self._excinfo())
|
||||
return tbh
|
||||
@@ -334,11 +345,11 @@ class Traceback(List[TracebackEntry]):
|
||||
|
||||
@overload
|
||||
def __getitem__(self, key: int) -> TracebackEntry:
|
||||
raise NotImplementedError()
|
||||
...
|
||||
|
||||
@overload # noqa: F811
|
||||
def __getitem__(self, key: slice) -> "Traceback": # noqa: F811
|
||||
raise NotImplementedError()
|
||||
...
|
||||
|
||||
def __getitem__( # noqa: F811
|
||||
self, key: Union[int, slice]
|
||||
@@ -404,6 +415,7 @@ co_equal = compile(
|
||||
_E = TypeVar("_E", bound=BaseException, covariant=True)
|
||||
|
||||
|
||||
@final
|
||||
@attr.s(repr=False)
|
||||
class ExceptionInfo(Generic[_E]):
|
||||
"""Wraps sys.exc_info() objects and offers help for navigating the traceback."""
|
||||
@@ -420,15 +432,16 @@ class ExceptionInfo(Generic[_E]):
|
||||
exc_info: Tuple["Type[_E]", "_E", TracebackType],
|
||||
exprinfo: Optional[str] = None,
|
||||
) -> "ExceptionInfo[_E]":
|
||||
"""Returns an ExceptionInfo for an existing exc_info tuple.
|
||||
"""Return an ExceptionInfo for an existing exc_info tuple.
|
||||
|
||||
.. warning::
|
||||
|
||||
Experimental API
|
||||
|
||||
:param exprinfo: a text string helping to determine if we should
|
||||
strip ``AssertionError`` from the output, defaults
|
||||
to the exception message/``__str__()``
|
||||
:param exprinfo:
|
||||
A text string helping to determine if we should strip
|
||||
``AssertionError`` from the output. Defaults to the exception
|
||||
message/``__str__()``.
|
||||
"""
|
||||
_striptext = ""
|
||||
if exprinfo is None and isinstance(exc_info[1], AssertionError):
|
||||
@@ -444,15 +457,16 @@ class ExceptionInfo(Generic[_E]):
|
||||
def from_current(
|
||||
cls, exprinfo: Optional[str] = None
|
||||
) -> "ExceptionInfo[BaseException]":
|
||||
"""Returns an ExceptionInfo matching the current traceback.
|
||||
"""Return an ExceptionInfo matching the current traceback.
|
||||
|
||||
.. warning::
|
||||
|
||||
Experimental API
|
||||
|
||||
:param exprinfo: a text string helping to determine if we should
|
||||
strip ``AssertionError`` from the output, defaults
|
||||
to the exception message/``__str__()``
|
||||
:param exprinfo:
|
||||
A text string helping to determine if we should strip
|
||||
``AssertionError`` from the output. Defaults to the exception
|
||||
message/``__str__()``.
|
||||
"""
|
||||
tup = sys.exc_info()
|
||||
assert tup[0] is not None, "no current exception"
|
||||
@@ -467,7 +481,7 @@ class ExceptionInfo(Generic[_E]):
|
||||
return cls(None)
|
||||
|
||||
def fill_unfilled(self, exc_info: Tuple["Type[_E]", _E, TracebackType]) -> None:
|
||||
"""fill an unfilled ExceptionInfo created with for_later()"""
|
||||
"""Fill an unfilled ExceptionInfo created with ``for_later()``."""
|
||||
assert self._excinfo is None, "ExceptionInfo was already filled"
|
||||
self._excinfo = exc_info
|
||||
|
||||
@@ -568,7 +582,8 @@ class ExceptionInfo(Generic[_E]):
|
||||
Show locals per traceback entry.
|
||||
Ignored if ``style=="native"``.
|
||||
|
||||
:param str style: long|short|no|native|value traceback style
|
||||
:param str style:
|
||||
long|short|no|native|value traceback style.
|
||||
|
||||
:param bool abspath:
|
||||
If paths should be changed to absolute or left unchanged.
|
||||
@@ -583,7 +598,8 @@ class ExceptionInfo(Generic[_E]):
|
||||
:param bool truncate_locals:
|
||||
With ``showlocals==True``, make sure locals can be safely represented as strings.
|
||||
|
||||
:param bool chain: if chained exceptions in Python 3 should be shown.
|
||||
:param bool chain:
|
||||
If chained exceptions in Python 3 should be shown.
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
|
||||
@@ -610,7 +626,7 @@ class ExceptionInfo(Generic[_E]):
|
||||
)
|
||||
return fmt.repr_excinfo(self)
|
||||
|
||||
def match(self, regexp: "Union[str, Pattern]") -> "Literal[True]":
|
||||
def match(self, regexp: "Union[str, Pattern[str]]") -> "Literal[True]":
|
||||
"""Check whether the regular expression `regexp` matches the string
|
||||
representation of the exception using :func:`python:re.search`.
|
||||
|
||||
@@ -643,7 +659,7 @@ class FormattedExcinfo:
|
||||
astcache = attr.ib(default=attr.Factory(dict), init=False, repr=False)
|
||||
|
||||
def _getindent(self, source: "Source") -> int:
|
||||
# figure out indent for given source
|
||||
# Figure out indent for the given source.
|
||||
try:
|
||||
s = str(source.getstatement(len(source) - 1))
|
||||
except KeyboardInterrupt:
|
||||
@@ -673,9 +689,9 @@ class FormattedExcinfo:
|
||||
|
||||
def get_source(
|
||||
self,
|
||||
source: "Source",
|
||||
source: Optional["Source"],
|
||||
line_index: int = -1,
|
||||
excinfo: Optional[ExceptionInfo] = None,
|
||||
excinfo: Optional[ExceptionInfo[BaseException]] = None,
|
||||
short: bool = False,
|
||||
) -> List[str]:
|
||||
"""Return formatted and marked up source lines."""
|
||||
@@ -700,11 +716,14 @@ class FormattedExcinfo:
|
||||
return lines
|
||||
|
||||
def get_exconly(
|
||||
self, excinfo: ExceptionInfo, indent: int = 4, markall: bool = False
|
||||
self,
|
||||
excinfo: ExceptionInfo[BaseException],
|
||||
indent: int = 4,
|
||||
markall: bool = False,
|
||||
) -> List[str]:
|
||||
lines = []
|
||||
indentstr = " " * indent
|
||||
# get the real exception information out
|
||||
# Get the real exception information out.
|
||||
exlines = excinfo.exconly(tryshort=True).split("\n")
|
||||
failindent = self.fail_marker + indentstr[1:]
|
||||
for line in exlines:
|
||||
@@ -730,8 +749,7 @@ class FormattedExcinfo:
|
||||
str_repr = saferepr(value)
|
||||
else:
|
||||
str_repr = safeformat(value)
|
||||
# if len(str_repr) < 70 or not isinstance(value,
|
||||
# (list, tuple, dict)):
|
||||
# if len(str_repr) < 70 or not isinstance(value, (list, tuple, dict)):
|
||||
lines.append("{:<10} = {}".format(name, str_repr))
|
||||
# else:
|
||||
# self._line("%-10s =\\" % (name,))
|
||||
@@ -741,7 +759,9 @@ class FormattedExcinfo:
|
||||
return None
|
||||
|
||||
def repr_traceback_entry(
|
||||
self, entry: TracebackEntry, excinfo: Optional[ExceptionInfo] = None
|
||||
self,
|
||||
entry: TracebackEntry,
|
||||
excinfo: Optional[ExceptionInfo[BaseException]] = None,
|
||||
) -> "ReprEntry":
|
||||
lines = [] # type: List[str]
|
||||
style = entry._repr_style if entry._repr_style is not None else self.style
|
||||
@@ -783,7 +803,7 @@ class FormattedExcinfo:
|
||||
path = np
|
||||
return path
|
||||
|
||||
def repr_traceback(self, excinfo: ExceptionInfo) -> "ReprTraceback":
|
||||
def repr_traceback(self, excinfo: ExceptionInfo[BaseException]) -> "ReprTraceback":
|
||||
traceback = excinfo.traceback
|
||||
if self.tbfilter:
|
||||
traceback = traceback.filter()
|
||||
@@ -809,16 +829,17 @@ class FormattedExcinfo:
|
||||
def _truncate_recursive_traceback(
|
||||
self, traceback: Traceback
|
||||
) -> Tuple[Traceback, Optional[str]]:
|
||||
"""
|
||||
Truncate the given recursive traceback trying to find the starting point
|
||||
of the recursion.
|
||||
"""Truncate the given recursive traceback trying to find the starting
|
||||
point of the recursion.
|
||||
|
||||
The detection is done by going through each traceback entry and finding the
|
||||
point in which the locals of the frame are equal to the locals of a previous frame (see ``recursionindex()``.
|
||||
The detection is done by going through each traceback entry and
|
||||
finding the point in which the locals of the frame are equal to the
|
||||
locals of a previous frame (see ``recursionindex()``).
|
||||
|
||||
Handle the situation where the recursion process might raise an exception (for example
|
||||
comparing numpy arrays using equality raises a TypeError), in which case we do our best to
|
||||
warn the user of the error and show a limited traceback.
|
||||
Handle the situation where the recursion process might raise an
|
||||
exception (for example comparing numpy arrays using equality raises a
|
||||
TypeError), in which case we do our best to warn the user of the
|
||||
error and show a limited traceback.
|
||||
"""
|
||||
try:
|
||||
recursionindex = traceback.recursionindex()
|
||||
@@ -847,12 +868,14 @@ class FormattedExcinfo:
|
||||
|
||||
return traceback, extraline
|
||||
|
||||
def repr_excinfo(self, excinfo: ExceptionInfo) -> "ExceptionChainRepr":
|
||||
def repr_excinfo(
|
||||
self, excinfo: ExceptionInfo[BaseException]
|
||||
) -> "ExceptionChainRepr":
|
||||
repr_chain = (
|
||||
[]
|
||||
) # type: List[Tuple[ReprTraceback, Optional[ReprFileLocation], Optional[str]]]
|
||||
e = excinfo.value
|
||||
excinfo_ = excinfo # type: Optional[ExceptionInfo]
|
||||
e = excinfo.value # type: Optional[BaseException]
|
||||
excinfo_ = excinfo # type: Optional[ExceptionInfo[BaseException]]
|
||||
descr = None
|
||||
seen = set() # type: Set[int]
|
||||
while e is not None and id(e) not in seen:
|
||||
@@ -863,8 +886,8 @@ class FormattedExcinfo:
|
||||
excinfo_._getreprcrash() if self.style != "value" else None
|
||||
) # type: Optional[ReprFileLocation]
|
||||
else:
|
||||
# fallback to native repr if the exception doesn't have a traceback:
|
||||
# ExceptionInfo objects require a full traceback to work
|
||||
# Fallback to native repr if the exception doesn't have a traceback:
|
||||
# ExceptionInfo objects require a full traceback to work.
|
||||
reprtraceback = ReprTracebackNative(
|
||||
traceback.format_exception(type(e), e, None)
|
||||
)
|
||||
@@ -915,7 +938,7 @@ class TerminalRepr:
|
||||
# This class is abstract -- only subclasses are instantiated.
|
||||
@attr.s(**{ATTRS_EQ_FIELD: False}) # type: ignore
|
||||
class ExceptionRepr(TerminalRepr):
|
||||
# Provided by in subclasses.
|
||||
# Provided by subclasses.
|
||||
reprcrash = None # type: Optional[ReprFileLocation]
|
||||
reprtraceback = None # type: ReprTraceback
|
||||
|
||||
@@ -942,7 +965,7 @@ class ExceptionChainRepr(ExceptionRepr):
|
||||
def __attrs_post_init__(self) -> None:
|
||||
super().__attrs_post_init__()
|
||||
# reprcrash and reprtraceback of the outermost (the newest) exception
|
||||
# in the chain
|
||||
# in the chain.
|
||||
self.reprtraceback = self.chain[-1][0]
|
||||
self.reprcrash = self.chain[-1][1]
|
||||
|
||||
@@ -974,7 +997,7 @@ class ReprTraceback(TerminalRepr):
|
||||
entrysep = "_ "
|
||||
|
||||
def toterminal(self, tw: TerminalWriter) -> None:
|
||||
# the entries might have different styles
|
||||
# The entries might have different styles.
|
||||
for i, entry in enumerate(self.reprentries):
|
||||
if entry.style == "long":
|
||||
tw.line("")
|
||||
@@ -1017,7 +1040,7 @@ class ReprEntry(TerminalRepr):
|
||||
style = attr.ib(type="_TracebackStyle")
|
||||
|
||||
def _write_entry_lines(self, tw: TerminalWriter) -> None:
|
||||
"""Writes the source code portions of a list of traceback entries with syntax highlighting.
|
||||
"""Write the source code portions of a list of traceback entries with syntax highlighting.
|
||||
|
||||
Usually entries are lines like these:
|
||||
|
||||
@@ -1038,25 +1061,21 @@ class ReprEntry(TerminalRepr):
|
||||
# such as "> assert 0"
|
||||
fail_marker = "{} ".format(FormattedExcinfo.fail_marker)
|
||||
indent_size = len(fail_marker)
|
||||
indents = []
|
||||
source_lines = []
|
||||
failure_lines = []
|
||||
seeing_failures = False
|
||||
for line in self.lines:
|
||||
is_source_line = not line.startswith(fail_marker)
|
||||
if is_source_line:
|
||||
assert not seeing_failures, (
|
||||
"Unexpected failure lines between source lines:\n"
|
||||
+ "\n".join(self.lines)
|
||||
)
|
||||
indents = [] # type: List[str]
|
||||
source_lines = [] # type: List[str]
|
||||
failure_lines = [] # type: List[str]
|
||||
for index, line in enumerate(self.lines):
|
||||
is_failure_line = line.startswith(fail_marker)
|
||||
if is_failure_line:
|
||||
# from this point on all lines are considered part of the failure
|
||||
failure_lines.extend(self.lines[index:])
|
||||
break
|
||||
else:
|
||||
if self.style == "value":
|
||||
source_lines.append(line)
|
||||
else:
|
||||
indents.append(line[:indent_size])
|
||||
source_lines.append(line[indent_size:])
|
||||
else:
|
||||
seeing_failures = True
|
||||
failure_lines.append(line)
|
||||
|
||||
tw._write_source(source_lines, indents)
|
||||
|
||||
@@ -1099,8 +1118,8 @@ class ReprFileLocation(TerminalRepr):
|
||||
message = attr.ib(type=str)
|
||||
|
||||
def toterminal(self, tw: TerminalWriter) -> None:
|
||||
# filename and lineno output for each entry,
|
||||
# using an output format that most editors understand
|
||||
# Filename and lineno output for each entry, using an output format
|
||||
# that most editors understand.
|
||||
msg = self.message
|
||||
i = msg.find("\n")
|
||||
if i != -1:
|
||||
@@ -1175,17 +1194,17 @@ def getfslineno(obj: object) -> Tuple[Union[str, py.path.local], int]:
|
||||
return code.path, code.firstlineno
|
||||
|
||||
|
||||
# relative paths that we use to filter traceback entries from appearing to the user;
|
||||
# see filter_traceback
|
||||
# Relative paths that we use to filter traceback entries from appearing to the user;
|
||||
# see filter_traceback.
|
||||
# note: if we need to add more paths than what we have now we should probably use a list
|
||||
# for better maintenance
|
||||
# for better maintenance.
|
||||
|
||||
_PLUGGY_DIR = py.path.local(pluggy.__file__.rstrip("oc"))
|
||||
_PLUGGY_DIR = Path(pluggy.__file__.rstrip("oc"))
|
||||
# pluggy is either a package or a single module depending on the version
|
||||
if _PLUGGY_DIR.basename == "__init__.py":
|
||||
_PLUGGY_DIR = _PLUGGY_DIR.dirpath()
|
||||
_PYTEST_DIR = py.path.local(_pytest.__file__).dirpath()
|
||||
_PY_DIR = py.path.local(py.__file__).dirpath()
|
||||
if _PLUGGY_DIR.name == "__init__.py":
|
||||
_PLUGGY_DIR = _PLUGGY_DIR.parent
|
||||
_PYTEST_DIR = Path(_pytest.__file__).parent
|
||||
_PY_DIR = Path(py.__file__).parent
|
||||
|
||||
|
||||
def filter_traceback(entry: TracebackEntry) -> bool:
|
||||
@@ -1197,15 +1216,23 @@ def filter_traceback(entry: TracebackEntry) -> bool:
|
||||
* internal traceback from pytest or its internal libraries, py and pluggy.
|
||||
"""
|
||||
# entry.path might sometimes return a str object when the entry
|
||||
# points to dynamically generated code
|
||||
# see https://bitbucket.org/pytest-dev/py/issues/71
|
||||
# points to dynamically generated code.
|
||||
# See https://bitbucket.org/pytest-dev/py/issues/71.
|
||||
raw_filename = entry.frame.code.raw.co_filename
|
||||
is_generated = "<" in raw_filename and ">" in raw_filename
|
||||
if is_generated:
|
||||
return False
|
||||
|
||||
# entry.path might point to a non-existing file, in which case it will
|
||||
# also return a str object. see #1133
|
||||
p = py.path.local(entry.path)
|
||||
return (
|
||||
not p.relto(_PLUGGY_DIR) and not p.relto(_PYTEST_DIR) and not p.relto(_PY_DIR)
|
||||
)
|
||||
# also return a str object. See #1133.
|
||||
p = Path(entry.path)
|
||||
|
||||
parents = p.parents
|
||||
if _PLUGGY_DIR in parents:
|
||||
return False
|
||||
if _PYTEST_DIR in parents:
|
||||
return False
|
||||
if _PY_DIR in parents:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@@ -44,11 +44,11 @@ class Source:
|
||||
|
||||
@overload
|
||||
def __getitem__(self, key: int) -> str:
|
||||
raise NotImplementedError()
|
||||
...
|
||||
|
||||
@overload # noqa: F811
|
||||
def __getitem__(self, key: slice) -> "Source": # noqa: F811
|
||||
raise NotImplementedError()
|
||||
...
|
||||
|
||||
def __getitem__(self, key: Union[int, slice]) -> Union[str, "Source"]: # noqa: F811
|
||||
if isinstance(key, int):
|
||||
@@ -67,9 +67,7 @@ class Source:
|
||||
return len(self.lines)
|
||||
|
||||
def strip(self) -> "Source":
|
||||
""" return new source object with trailing
|
||||
and leading blank lines removed.
|
||||
"""
|
||||
"""Return new Source object with trailing and leading blank lines removed."""
|
||||
start, end = 0, len(self)
|
||||
while start < end and not self.lines[start].strip():
|
||||
start += 1
|
||||
@@ -80,31 +78,28 @@ class Source:
|
||||
return source
|
||||
|
||||
def indent(self, indent: str = " " * 4) -> "Source":
|
||||
""" return a copy of the source object with
|
||||
all lines indented by the given indent-string.
|
||||
"""
|
||||
"""Return a copy of the source object with all lines indented by the
|
||||
given indent-string."""
|
||||
newsource = Source()
|
||||
newsource.lines = [(indent + line) for line in self.lines]
|
||||
return newsource
|
||||
|
||||
def getstatement(self, lineno: int) -> "Source":
|
||||
""" return Source statement which contains the
|
||||
given linenumber (counted from 0).
|
||||
"""
|
||||
"""Return Source statement which contains the given linenumber
|
||||
(counted from 0)."""
|
||||
start, end = self.getstatementrange(lineno)
|
||||
return self[start:end]
|
||||
|
||||
def getstatementrange(self, lineno: int) -> Tuple[int, int]:
|
||||
""" return (start, end) tuple which spans the minimal
|
||||
statement region which containing the given lineno.
|
||||
"""
|
||||
"""Return (start, end) tuple which spans the minimal statement region
|
||||
which containing the given lineno."""
|
||||
if not (0 <= lineno < len(self)):
|
||||
raise IndexError("lineno out of range")
|
||||
ast, start, end = getstatementrange_ast(lineno, self)
|
||||
return start, end
|
||||
|
||||
def deindent(self) -> "Source":
|
||||
"""return a new source object deindented."""
|
||||
"""Return a new Source object deindented."""
|
||||
newsource = Source()
|
||||
newsource.lines[:] = deindent(self.lines)
|
||||
return newsource
|
||||
@@ -129,7 +124,7 @@ def findsource(obj) -> Tuple[Optional[Source], int]:
|
||||
|
||||
|
||||
def getrawcode(obj, trycall: bool = True):
|
||||
""" return code object for given function. """
|
||||
"""Return code object for given function."""
|
||||
try:
|
||||
return obj.__code__
|
||||
except AttributeError:
|
||||
@@ -148,8 +143,8 @@ def deindent(lines: Iterable[str]) -> List[str]:
|
||||
|
||||
|
||||
def get_statement_startend2(lineno: int, node: ast.AST) -> Tuple[int, Optional[int]]:
|
||||
# flatten all statements and except handlers into one lineno-list
|
||||
# AST's line numbers start indexing at 1
|
||||
# Flatten all statements and except handlers into one lineno-list.
|
||||
# AST's line numbers start indexing at 1.
|
||||
values = [] # type: List[int]
|
||||
for x in ast.walk(node):
|
||||
if isinstance(x, (ast.stmt, ast.ExceptHandler)):
|
||||
@@ -157,7 +152,7 @@ def get_statement_startend2(lineno: int, node: ast.AST) -> Tuple[int, Optional[i
|
||||
for name in ("finalbody", "orelse"):
|
||||
val = getattr(x, name, None) # type: Optional[List[ast.stmt]]
|
||||
if val:
|
||||
# treat the finally/orelse part as its own statement
|
||||
# Treat the finally/orelse part as its own statement.
|
||||
values.append(val[0].lineno - 1 - 1)
|
||||
values.sort()
|
||||
insert_index = bisect_right(values, lineno)
|
||||
@@ -178,13 +173,13 @@ def getstatementrange_ast(
|
||||
if astnode is None:
|
||||
content = str(source)
|
||||
# See #4260:
|
||||
# don't produce duplicate warnings when compiling source to find ast
|
||||
# Don't produce duplicate warnings when compiling source to find AST.
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
astnode = ast.parse(content, "source", "exec")
|
||||
|
||||
start, end = get_statement_startend2(lineno, astnode)
|
||||
# we need to correct the end:
|
||||
# We need to correct the end:
|
||||
# - ast-parsing strips comments
|
||||
# - there might be empty lines
|
||||
# - we might have lesser indented code blocks at the end
|
||||
@@ -192,10 +187,10 @@ def getstatementrange_ast(
|
||||
end = len(source.lines)
|
||||
|
||||
if end > start + 1:
|
||||
# make sure we don't span differently indented code blocks
|
||||
# by using the BlockFinder helper used which inspect.getsource() uses itself
|
||||
# Make sure we don't span differently indented code blocks
|
||||
# by using the BlockFinder helper used which inspect.getsource() uses itself.
|
||||
block_finder = inspect.BlockFinder()
|
||||
# if we start with an indented line, put blockfinder to "started" mode
|
||||
# If we start with an indented line, put blockfinder to "started" mode.
|
||||
block_finder.started = source.lines[start][0].isspace()
|
||||
it = ((x + "\n") for x in source.lines[start:end])
|
||||
try:
|
||||
@@ -206,7 +201,7 @@ def getstatementrange_ast(
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# the end might still point to a comment or empty line, correct it
|
||||
# The end might still point to a comment or empty line, correct it.
|
||||
while end:
|
||||
line = source.lines[end - 1].lstrip()
|
||||
if line.startswith("#") or not line:
|
||||
|
||||
@@ -36,9 +36,8 @@ def _ellipsize(s: str, maxsize: int) -> str:
|
||||
|
||||
|
||||
class SafeRepr(reprlib.Repr):
|
||||
"""subclass of repr.Repr that limits the resulting size of repr()
|
||||
and includes information on exceptions raised during the call.
|
||||
"""
|
||||
"""repr.Repr that limits the resulting size of repr() and includes
|
||||
information on exceptions raised during the call."""
|
||||
|
||||
def __init__(self, maxsize: int) -> None:
|
||||
super().__init__()
|
||||
@@ -65,7 +64,8 @@ class SafeRepr(reprlib.Repr):
|
||||
|
||||
|
||||
def safeformat(obj: object) -> str:
|
||||
"""return a pretty printed string for the given object.
|
||||
"""Return a pretty printed string for the given object.
|
||||
|
||||
Failing __repr__ functions of user instances will be represented
|
||||
with a short exception info.
|
||||
"""
|
||||
@@ -76,11 +76,14 @@ def safeformat(obj: object) -> str:
|
||||
|
||||
|
||||
def saferepr(obj: object, maxsize: int = 240) -> str:
|
||||
"""return a size-limited safe repr-string for the given object.
|
||||
"""Return a size-limited safe repr-string for the given object.
|
||||
|
||||
Failing __repr__ functions of user instances will be represented
|
||||
with a short exception info and 'saferepr' generally takes
|
||||
care to never raise exceptions itself. This function is a wrapper
|
||||
around the Repr/reprlib functionality of the standard 2.6 lib.
|
||||
care to never raise exceptions itself.
|
||||
|
||||
This function is a wrapper around the Repr/reprlib functionality of the
|
||||
standard 2.6 lib.
|
||||
"""
|
||||
return SafeRepr(maxsize).repr(obj)
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ from typing import Sequence
|
||||
from typing import TextIO
|
||||
|
||||
from .wcwidth import wcswidth
|
||||
from _pytest.compat import final
|
||||
|
||||
|
||||
# This code was initially copied from py 1.8.1, file _io/terminalwriter.py.
|
||||
@@ -36,6 +37,7 @@ def should_do_markup(file: TextIO) -> bool:
|
||||
)
|
||||
|
||||
|
||||
@final
|
||||
class TerminalWriter:
|
||||
_esctable = dict(
|
||||
black=30,
|
||||
@@ -111,13 +113,13 @@ class TerminalWriter:
|
||||
) -> None:
|
||||
if fullwidth is None:
|
||||
fullwidth = self.fullwidth
|
||||
# the goal is to have the line be as long as possible
|
||||
# under the condition that len(line) <= fullwidth
|
||||
# The goal is to have the line be as long as possible
|
||||
# under the condition that len(line) <= fullwidth.
|
||||
if sys.platform == "win32":
|
||||
# if we print in the last column on windows we are on a
|
||||
# If we print in the last column on windows we are on a
|
||||
# new line but there is no way to verify/neutralize this
|
||||
# (we may not know the exact line width)
|
||||
# so let's be defensive to avoid empty lines in the output
|
||||
# (we may not know the exact line width).
|
||||
# So let's be defensive to avoid empty lines in the output.
|
||||
fullwidth -= 1
|
||||
if title is not None:
|
||||
# we want 2 + 2*len(fill) + len(title) <= fullwidth
|
||||
@@ -131,9 +133,9 @@ class TerminalWriter:
|
||||
# we want len(sepchar)*N <= fullwidth
|
||||
# i.e. N <= fullwidth // len(sepchar)
|
||||
line = sepchar * (fullwidth // len(sepchar))
|
||||
# in some situations there is room for an extra sepchar at the right,
|
||||
# In some situations there is room for an extra sepchar at the right,
|
||||
# in particular if we consider that with a sepchar like "_ " the
|
||||
# trailing space is not important at the end of the line
|
||||
# trailing space is not important at the end of the line.
|
||||
if len(line) + len(sepchar.rstrip()) <= fullwidth:
|
||||
line += sepchar.rstrip()
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
"""
|
||||
support for presenting detailed information in failing assertions.
|
||||
"""
|
||||
"""Support for presenting detailed information in failing assertions."""
|
||||
import sys
|
||||
from typing import Any
|
||||
from typing import Generator
|
||||
@@ -55,11 +53,11 @@ def register_assert_rewrite(*names: str) -> None:
|
||||
actually imported, usually in your __init__.py if you are a plugin
|
||||
using a package.
|
||||
|
||||
:raise TypeError: if the given module names are not strings.
|
||||
:raises TypeError: If the given module names are not strings.
|
||||
"""
|
||||
for name in names:
|
||||
if not isinstance(name, str):
|
||||
msg = "expected module names as *args, got {0} instead"
|
||||
msg = "expected module names as *args, got {0} instead" # type: ignore[unreachable]
|
||||
raise TypeError(msg.format(repr(names)))
|
||||
for hook in sys.meta_path:
|
||||
if isinstance(hook, rewrite.AssertionRewritingHook):
|
||||
@@ -105,9 +103,9 @@ def install_importhook(config: Config) -> rewrite.AssertionRewritingHook:
|
||||
|
||||
|
||||
def pytest_collection(session: "Session") -> None:
|
||||
# this hook is only called when test modules are collected
|
||||
# This hook is only called when test modules are collected
|
||||
# so for example not in the master process of pytest-xdist
|
||||
# (which does not collect test modules)
|
||||
# (which does not collect test modules).
|
||||
assertstate = session.config._store.get(assertstate_key, None)
|
||||
if assertstate:
|
||||
if assertstate.hook is not None:
|
||||
@@ -116,18 +114,17 @@ def pytest_collection(session: "Session") -> None:
|
||||
|
||||
@hookimpl(tryfirst=True, hookwrapper=True)
|
||||
def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
||||
"""Setup the pytest_assertrepr_compare and pytest_assertion_pass hooks
|
||||
"""Setup the pytest_assertrepr_compare and pytest_assertion_pass hooks.
|
||||
|
||||
The rewrite module will use util._reprcompare if
|
||||
it exists to use custom reporting via the
|
||||
pytest_assertrepr_compare hook. This sets up this custom
|
||||
The rewrite module will use util._reprcompare if it exists to use custom
|
||||
reporting via the pytest_assertrepr_compare hook. This sets up this custom
|
||||
comparison for the test.
|
||||
"""
|
||||
|
||||
ihook = item.ihook
|
||||
|
||||
def callbinrepr(op, left: object, right: object) -> Optional[str]:
|
||||
"""Call the pytest_assertrepr_compare hook and prepare the result
|
||||
"""Call the pytest_assertrepr_compare hook and prepare the result.
|
||||
|
||||
This uses the first result from the hook and then ensures the
|
||||
following:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user