Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa6f97d6cd | ||
|
|
20f1c95be2 | ||
|
|
c8ae63db7f | ||
|
|
195c1fcda4 | ||
|
|
6956a00056 | ||
|
|
4e7a69d45a | ||
|
|
ea35fd299a | ||
|
|
c30ffc5b46 | ||
|
|
741c8482d8 | ||
|
|
a6726abbe2 | ||
|
|
8c1016884f | ||
|
|
981ca24d40 | ||
|
|
2a22b81240 | ||
|
|
cca9b90905 | ||
|
|
2476da4445 | ||
|
|
c642e6d550 | ||
|
|
2cf78187a8 | ||
|
|
8f9779d43c | ||
|
|
16664a1b72 | ||
|
|
1569fac603 | ||
|
|
a3599cacb5 | ||
|
|
27613b8d70 | ||
|
|
cef74be094 | ||
|
|
83dc953669 | ||
|
|
fb38e8d097 | ||
|
|
d74baf4a52 | ||
|
|
d9b8f7cf0a | ||
|
|
69212d15fa | ||
|
|
44d3282bb7 | ||
|
|
fafe00aaee | ||
|
|
477225c18a | ||
|
|
4e51b9200f | ||
|
|
b0fb02297e | ||
|
|
e47a352c49 | ||
|
|
767b3b2cc0 | ||
|
|
4eae23a633 | ||
|
|
6989435490 | ||
|
|
b178175e95 | ||
|
|
de7c19a373 | ||
|
|
82611bdc1e | ||
|
|
f0e12d4d61 | ||
|
|
3293758545 | ||
|
|
4c41b7e88b | ||
|
|
74495a2b7f | ||
|
|
a5e67a26b0 | ||
|
|
8e0b08d5da | ||
|
|
5ad0d1acb9 | ||
|
|
89b6b2ee2b | ||
|
|
ddf7d88a51 | ||
|
|
733f8027d2 | ||
|
|
8317542c9e | ||
|
|
48f78f9ba0 | ||
|
|
1e1955dbb7 | ||
|
|
ca68875eab | ||
|
|
15a45388fa | ||
|
|
017dd1ccd6 | ||
|
|
18569f44c1 | ||
|
|
d8d6812bdf | ||
|
|
a5061484d4 | ||
|
|
69ea076d55 | ||
|
|
40cb2f5b54 | ||
|
|
724e22cb00 | ||
|
|
3a2fd96305 | ||
|
|
138b19a930 | ||
|
|
822686e880 | ||
|
|
9dc54f79b0 | ||
|
|
93dbae24e1 | ||
|
|
02fdbe2e76 | ||
|
|
12e7db85af | ||
|
|
56e4392444 | ||
|
|
8220eca963 | ||
|
|
b9c98762f5 | ||
|
|
8003fd23b9 | ||
|
|
8d605b9b26 | ||
|
|
14e0c3e105 | ||
|
|
45facc16c8 | ||
|
|
99fe887d7c | ||
|
|
8dbf9dc1aa | ||
|
|
baaee2148d | ||
|
|
f7d1ab870f | ||
|
|
b8201c280e | ||
|
|
1f0c50b475 | ||
|
|
da82e1853c | ||
|
|
a566eb9c70 | ||
|
|
d3971c30f4 | ||
|
|
780044b64a | ||
|
|
8354995abc | ||
|
|
8b8b1214f4 | ||
|
|
f854cf66f4 | ||
|
|
c475106f12 |
58
.github/workflows/main.yml
vendored
@@ -3,7 +3,7 @@ name: main
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
- "[0-9]+.[0-9]+.x"
|
||||
tags:
|
||||
- "[0-9]+.[0-9]+.[0-9]+"
|
||||
@@ -11,13 +11,18 @@ on:
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
- "[0-9]+.[0-9]+.x"
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -27,6 +32,8 @@ jobs:
|
||||
"windows-py37",
|
||||
"windows-py37-pluggy",
|
||||
"windows-py38",
|
||||
"windows-py39",
|
||||
"windows-py310",
|
||||
|
||||
"ubuntu-py36",
|
||||
"ubuntu-py37",
|
||||
@@ -34,6 +41,7 @@ jobs:
|
||||
"ubuntu-py37-freeze",
|
||||
"ubuntu-py38",
|
||||
"ubuntu-py39",
|
||||
"ubuntu-py310",
|
||||
"ubuntu-pypy3",
|
||||
|
||||
"macos-py37",
|
||||
@@ -56,12 +64,20 @@ jobs:
|
||||
- name: "windows-py37-pluggy"
|
||||
python: "3.7"
|
||||
os: windows-latest
|
||||
tox_env: "py37-pluggymaster-xdist"
|
||||
tox_env: "py37-pluggymain-xdist"
|
||||
- name: "windows-py38"
|
||||
python: "3.8"
|
||||
os: windows-latest
|
||||
tox_env: "py38-unittestextras"
|
||||
use_coverage: true
|
||||
- name: "windows-py39"
|
||||
python: "3.9"
|
||||
os: windows-latest
|
||||
tox_env: "py39-xdist"
|
||||
- name: "windows-py310"
|
||||
python: "3.10.1"
|
||||
os: windows-latest
|
||||
tox_env: "py310-xdist"
|
||||
|
||||
- name: "ubuntu-py36"
|
||||
python: "3.6"
|
||||
@@ -75,7 +91,7 @@ jobs:
|
||||
- name: "ubuntu-py37-pluggy"
|
||||
python: "3.7"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py37-pluggymaster-xdist"
|
||||
tox_env: "py37-pluggymain-xdist"
|
||||
- name: "ubuntu-py37-freeze"
|
||||
python: "3.7"
|
||||
os: ubuntu-latest
|
||||
@@ -88,6 +104,10 @@ jobs:
|
||||
python: "3.9"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py39-xdist"
|
||||
- name: "ubuntu-py310"
|
||||
python: "3.10.1"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py310-xdist"
|
||||
- name: "ubuntu-pypy3"
|
||||
python: "pypy3"
|
||||
os: ubuntu-latest
|
||||
@@ -122,10 +142,13 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python ${{ matrix.python }}
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
@@ -154,28 +177,13 @@ jobs:
|
||||
CODECOV_NAME: ${{ matrix.name }}
|
||||
run: bash scripts/report-coverage.sh -F GHA,${{ runner.os }}
|
||||
|
||||
linting:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- name: set PY
|
||||
run: echo "name=PY::$(python -c 'import hashlib, sys;print(hashlib.sha256(sys.version.encode()+sys.executable.encode()).hexdigest())')" >> $GITHUB_ENV
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pre-commit
|
||||
key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install tox
|
||||
- run: tox -e linting
|
||||
|
||||
deploy:
|
||||
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') && github.repository == 'pytest-dev/pytest'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
needs: [build]
|
||||
|
||||
@@ -183,25 +191,31 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.7"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade wheel setuptools tox
|
||||
|
||||
- name: Build package
|
||||
run: |
|
||||
python setup.py sdist bdist_wheel
|
||||
|
||||
- name: Publish package to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@master
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.pypi_token }}
|
||||
|
||||
- name: Publish GitHub release notes
|
||||
env:
|
||||
GH_RELEASE_NOTES_TOKEN: ${{ secrets.release_notes }}
|
||||
GH_RELEASE_NOTES_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
sudo apt-get install pandoc
|
||||
tox -e publish-gh-release-notes
|
||||
|
||||
11
.github/workflows/release-on-comment.yml
vendored
@@ -7,9 +7,15 @@ on:
|
||||
issue_comment:
|
||||
types: [created, edited]
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
|
||||
if: (github.event.comment && startsWith(github.event.comment.body, '@pytestbot please')) || (github.event.issue && !github.event.comment && startsWith(github.event.issue.body, '@pytestbot please'))
|
||||
|
||||
@@ -17,15 +23,18 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.8"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade setuptools tox
|
||||
|
||||
- name: Prepare release
|
||||
run: |
|
||||
tox -e release-on-comment -- $GITHUB_EVENT_PATH ${{ secrets.chatops }}
|
||||
tox -e release-on-comment -- $GITHUB_EVENT_PATH ${{ github.token }}
|
||||
|
||||
@@ -39,11 +39,10 @@ repos:
|
||||
- id: pyupgrade
|
||||
args: [--py36-plus]
|
||||
- repo: https://github.com/asottile/setup-cfg-fmt
|
||||
rev: v1.11.0
|
||||
rev: v1.17.0
|
||||
hooks:
|
||||
- id: setup-cfg-fmt
|
||||
# TODO: when upgrading setup-cfg-fmt this can be removed
|
||||
args: [--max-py-version=3.9]
|
||||
args: [--max-py-version=3.10]
|
||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||
rev: v1.6.0
|
||||
hooks:
|
||||
|
||||
6
AUTHORS
@@ -21,6 +21,7 @@ Anders Hovmöller
|
||||
Andras Mitzki
|
||||
Andras Tim
|
||||
Andrea Cimatoribus
|
||||
Andreas Motl
|
||||
Andreas Zeidler
|
||||
Andrey Paramonov
|
||||
Andrzej Klajnert
|
||||
@@ -56,6 +57,7 @@ Charles Cloud
|
||||
Charles Machalow
|
||||
Charnjit SiNGH (CCSJ)
|
||||
Chris Lamb
|
||||
Chris NeJame
|
||||
Christian Boelsen
|
||||
Christian Fetzer
|
||||
Christian Neumüller
|
||||
@@ -135,6 +137,7 @@ Iwan Briquemont
|
||||
Jaap Broekhuizen
|
||||
Jakob van Santen
|
||||
Jakub Mitoraj
|
||||
James Frost
|
||||
Jan Balster
|
||||
Janne Vanhala
|
||||
Jason R. Coombs
|
||||
@@ -238,6 +241,7 @@ Petter Strandmark
|
||||
Philipp Loose
|
||||
Pieter Mulder
|
||||
Piotr Banaszkiewicz
|
||||
Piotr Dybowski
|
||||
Piotr Helm
|
||||
Prakhar Gurunani
|
||||
Prashant Anand
|
||||
@@ -271,6 +275,7 @@ Sankt Petersbug
|
||||
Segev Finer
|
||||
Serhii Mozghovyi
|
||||
Seth Junot
|
||||
Shantanu Jain
|
||||
Shubham Adep
|
||||
Simon Gomizelj
|
||||
Simon Kerr
|
||||
@@ -298,6 +303,7 @@ Tom Dalton
|
||||
Tom Viner
|
||||
Tomáš Gavenčiak
|
||||
Tomer Keren
|
||||
Tony Narlock
|
||||
Tor Colvin
|
||||
Trevor Bekolay
|
||||
Tyler Goodlet
|
||||
|
||||
@@ -236,7 +236,7 @@ Here is a simple overview, with pytest-specific bits:
|
||||
$ cd pytest
|
||||
# now, create your own branch off "master":
|
||||
|
||||
$ git checkout -b your-bugfix-branch-name master
|
||||
$ git checkout -b your-bugfix-branch-name main
|
||||
|
||||
Given we have "major.minor.micro" version numbers, bug fixes will usually
|
||||
be released in micro releases whereas features will be released in
|
||||
@@ -318,7 +318,7 @@ Here is a simple overview, with pytest-specific bits:
|
||||
compare: your-branch-name
|
||||
|
||||
base-fork: pytest-dev/pytest
|
||||
base: master
|
||||
base: main
|
||||
|
||||
|
||||
Writing Tests
|
||||
|
||||
12
README.rst
@@ -1,4 +1,4 @@
|
||||
.. image:: https://docs.pytest.org/en/stable/_static/pytest1.png
|
||||
.. image:: https://github.com/pytest-dev/pytest/raw/main/doc/en/img/pytest_logo_curves.svg
|
||||
:target: https://docs.pytest.org/en/stable/
|
||||
:align: center
|
||||
:alt: pytest
|
||||
@@ -15,7 +15,7 @@
|
||||
.. image:: https://img.shields.io/pypi/pyversions/pytest.svg
|
||||
:target: https://pypi.org/project/pytest/
|
||||
|
||||
.. image:: https://codecov.io/gh/pytest-dev/pytest/branch/master/graph/badge.svg
|
||||
.. image:: https://codecov.io/gh/pytest-dev/pytest/branch/main/graph/badge.svg
|
||||
:target: https://codecov.io/gh/pytest-dev/pytest
|
||||
:alt: Code coverage Status
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
.. image:: https://github.com/pytest-dev/pytest/workflows/main/badge.svg
|
||||
:target: https://github.com/pytest-dev/pytest/actions?query=workflow%3Amain
|
||||
|
||||
.. image:: https://results.pre-commit.ci/badge/github/pytest-dev/pytest/main.svg
|
||||
:target: https://results.pre-commit.ci/latest/github/pytest-dev/pytest/master
|
||||
:alt: pre-commit.ci status
|
||||
|
||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/psf/black
|
||||
|
||||
@@ -149,8 +153,8 @@ Tidelift will coordinate the fix and disclosure.
|
||||
License
|
||||
-------
|
||||
|
||||
Copyright Holger Krekel and others, 2004-2020.
|
||||
Copyright Holger Krekel and others, 2004-2021.
|
||||
|
||||
Distributed under the terms of the `MIT`_ license, pytest is free and open source software.
|
||||
|
||||
.. _`MIT`: https://github.com/pytest-dev/pytest/blob/master/LICENSE
|
||||
.. _`MIT`: https://github.com/pytest-dev/pytest/blob/main/LICENSE
|
||||
|
||||
1
changelog/12363.doc.rst
Normal file
@@ -0,0 +1 @@
|
||||
The documentation webpages now links to a canonical version to reduce outdated documentation in search engine results.
|
||||
@@ -6,6 +6,11 @@ Release announcements
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
release-6.2.5
|
||||
release-6.2.4
|
||||
release-6.2.3
|
||||
release-6.2.2
|
||||
release-6.2.1
|
||||
release-6.2.0
|
||||
release-6.1.2
|
||||
release-6.1.1
|
||||
|
||||
20
doc/en/announce/release-6.2.1.rst
Normal file
@@ -0,0 +1,20 @@
|
||||
pytest-6.2.1
|
||||
=======================================
|
||||
|
||||
pytest 6.2.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/stable/changelog.html.
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Bruno Oliveira
|
||||
* Jakob van Santen
|
||||
* Ran Benita
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
21
doc/en/announce/release-6.2.2.rst
Normal file
@@ -0,0 +1,21 @@
|
||||
pytest-6.2.2
|
||||
=======================================
|
||||
|
||||
pytest 6.2.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:
|
||||
|
||||
* Adam Johnson
|
||||
* Bruno Oliveira
|
||||
* Chris NeJame
|
||||
* Ran Benita
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
19
doc/en/announce/release-6.2.3.rst
Normal file
@@ -0,0 +1,19 @@
|
||||
pytest-6.2.3
|
||||
=======================================
|
||||
|
||||
pytest 6.2.3 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
|
||||
22
doc/en/announce/release-6.2.4.rst
Normal file
@@ -0,0 +1,22 @@
|
||||
pytest-6.2.4
|
||||
=======================================
|
||||
|
||||
pytest 6.2.4 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:
|
||||
|
||||
* Anthony Sottile
|
||||
* Bruno Oliveira
|
||||
* Christian Maurer
|
||||
* Florian Bruhin
|
||||
* Ran Benita
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
30
doc/en/announce/release-6.2.5.rst
Normal file
@@ -0,0 +1,30 @@
|
||||
pytest-6.2.5
|
||||
=======================================
|
||||
|
||||
pytest 6.2.5 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:
|
||||
|
||||
* Anthony Sottile
|
||||
* Bruno Oliveira
|
||||
* Brylie Christopher Oxley
|
||||
* Daniel Asztalos
|
||||
* Florian Bruhin
|
||||
* Jason Haugen
|
||||
* MapleCCC
|
||||
* Michał Górny
|
||||
* Miro Hrončok
|
||||
* Ran Benita
|
||||
* Ronny Pfannschmidt
|
||||
* Sylvain Bellemare
|
||||
* Thomas Güttler
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -31,7 +31,7 @@ you will see the return value of the function call:
|
||||
|
||||
$ pytest test_assert1.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
@@ -188,7 +188,7 @@ if you run this module:
|
||||
|
||||
$ pytest test_assert2.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
|
||||
@@ -86,7 +86,7 @@ If you then run it with ``--lf``:
|
||||
|
||||
$ pytest --lf
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
@@ -133,7 +133,7 @@ of ``FF`` and dots):
|
||||
|
||||
$ pytest --ff
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 50 items
|
||||
@@ -277,7 +277,7 @@ You can always peek at the content of the cache using the
|
||||
|
||||
$ pytest --cache-show
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
@@ -358,7 +358,7 @@ filtering:
|
||||
|
||||
$ pytest --cache-show example/*
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
|
||||
@@ -83,7 +83,7 @@ of the failing function and hide the other one:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
|
||||
@@ -28,6 +28,80 @@ with advance notice in the **Deprecations** section of releases.
|
||||
|
||||
.. towncrier release notes start
|
||||
|
||||
pytest 6.2.5 (2021-08-29)
|
||||
=========================
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- `#8494 <https://github.com/pytest-dev/pytest/issues/8494>`_: Python 3.10 is now supported.
|
||||
|
||||
|
||||
- `#9040 <https://github.com/pytest-dev/pytest/issues/9040>`_: Enable compatibility with ``pluggy 1.0`` or later.
|
||||
|
||||
|
||||
pytest 6.2.4 (2021-05-04)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#8539 <https://github.com/pytest-dev/pytest/issues/8539>`_: Fixed assertion rewriting on Python 3.10.
|
||||
|
||||
|
||||
pytest 6.2.3 (2021-04-03)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#8414 <https://github.com/pytest-dev/pytest/issues/8414>`_: pytest used to create directories under ``/tmp`` with world-readable
|
||||
permissions. This means that any user in the system was able to read
|
||||
information written by tests in temporary directories (such as those created by
|
||||
the ``tmp_path``/``tmpdir`` fixture). Now the directories are created with
|
||||
private permissions.
|
||||
|
||||
pytest used silenty use a pre-existing ``/tmp/pytest-of-<username>`` directory,
|
||||
even if owned by another user. This means another user could pre-create such a
|
||||
directory and gain control of another user's temporary directory. Now such a
|
||||
condition results in an error.
|
||||
|
||||
|
||||
pytest 6.2.2 (2021-01-25)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#8152 <https://github.com/pytest-dev/pytest/issues/8152>`_: Fixed "(<Skipped instance>)" being shown as a skip reason in the verbose test summary line when the reason is empty.
|
||||
|
||||
|
||||
- `#8249 <https://github.com/pytest-dev/pytest/issues/8249>`_: Fix the ``faulthandler`` plugin for occasions when running with ``twisted.logger`` and using ``pytest --capture=no``.
|
||||
|
||||
|
||||
pytest 6.2.1 (2020-12-15)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#7678 <https://github.com/pytest-dev/pytest/issues/7678>`_: Fixed bug where ``ImportPathMismatchError`` would be raised for files compiled in
|
||||
the host and loaded later from an UNC mounted path (Windows).
|
||||
|
||||
|
||||
- `#8132 <https://github.com/pytest-dev/pytest/issues/8132>`_: Fixed regression in ``approx``: in 6.2.0 ``approx`` no longer raises
|
||||
``TypeError`` when dealing with non-numeric types, falling back to normal comparison.
|
||||
Before 6.2.0, array types like tf.DeviceArray fell through to the scalar case,
|
||||
and happened to compare correctly to a scalar if they had only one element.
|
||||
After 6.2.0, these types began failing, because they inherited neither from
|
||||
standard Python number hierarchy nor from ``numpy.ndarray``.
|
||||
|
||||
``approx`` now converts arguments to ``numpy.ndarray`` if they expose the array
|
||||
protocol and are not scalars. This treats array-like objects like numpy arrays,
|
||||
regardless of size.
|
||||
|
||||
|
||||
pytest 6.2.0 (2020-12-12)
|
||||
=========================
|
||||
|
||||
|
||||
@@ -235,6 +235,9 @@ html_show_sourcelink = False
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = "pytestdoc"
|
||||
|
||||
# The base URL which points to the root of the HTML documentation. It is used
|
||||
# to indicate the location of document using the canonical link relation (#12363).
|
||||
html_baseurl = "https://docs.pytest.org/en/stable/"
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
|
||||
@@ -7,21 +7,22 @@ Contact channels
|
||||
|
||||
- `pytest issue tracker`_ to report bugs or suggest features (for version
|
||||
2.0 and above).
|
||||
|
||||
- `pytest discussions`_ at github for general questions.
|
||||
- `pytest on stackoverflow.com <http://stackoverflow.com/search?q=pytest>`_
|
||||
to post questions with the tag ``pytest``. New Questions will usually
|
||||
to post precise questions with the tag ``pytest``. New Questions will usually
|
||||
be seen by pytest users or developers and answered quickly.
|
||||
|
||||
- `Testing In Python`_: a mailing list for Python testing tools and discussion.
|
||||
|
||||
- `pytest-dev at python.org (mailing list)`_ pytest specific announcements and discussions.
|
||||
|
||||
- `pytest-commit at python.org (mailing list)`_: for commits and new issues
|
||||
|
||||
- :doc:`contribution guide <contributing>` for help on submitting pull
|
||||
requests to GitHub.
|
||||
|
||||
- ``#pylib`` on irc.freenode.net IRC channel for random questions.
|
||||
- ``#pytest`` `on irc.libera.chat <ircs://irc.libera.chat:6697/#pytest>`_ IRC
|
||||
channel for random questions (using an IRC client, `via webchat
|
||||
<https://web.libera.chat/#pytest>`_, or `via Matrix
|
||||
<https://matrix.to/#/%23pytest:libera.chat>`_).
|
||||
|
||||
- private mail to Holger.Krekel at gmail com if you want to communicate sensitive issues
|
||||
|
||||
@@ -32,6 +33,8 @@ Contact channels
|
||||
.. _`pytest issue tracker`: https://github.com/pytest-dev/pytest/issues
|
||||
.. _`old issue tracker`: http://bitbucket.org/hpk42/py-trunk/issues/
|
||||
|
||||
.. _`pytest discussions`: https://github.com/pytest-dev/pytest/discussions
|
||||
|
||||
.. _`merlinux.eu`: http://merlinux.eu
|
||||
|
||||
.. _`get an account`:
|
||||
|
||||
@@ -4,4 +4,4 @@ Development Guide
|
||||
|
||||
The contributing guidelines are to be found :ref:`here <contributing>`.
|
||||
The release procedure for pytest is documented on
|
||||
`GitHub <https://github.com/pytest-dev/pytest/blob/master/RELEASING.rst>`_.
|
||||
`GitHub <https://github.com/pytest-dev/pytest/blob/main/RELEASING.rst>`_.
|
||||
|
||||
@@ -29,7 +29,7 @@ then you can just invoke ``pytest`` directly:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
@@ -58,7 +58,7 @@ and functions, including from test modules:
|
||||
|
||||
$ pytest --doctest-modules
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
|
||||
132
doc/en/example/fixtures/fixture_availability.svg
Normal file
@@ -0,0 +1,132 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="572" height="542">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class, circle.module, circle.package {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class, text.module, text.package {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
line, path {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- main scope -->
|
||||
<circle class="package" r="270" cx="286" cy="271" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 26,271 A 260 260 0 0 1 546 271" id="testp"/>
|
||||
</defs>
|
||||
<text class="package">
|
||||
<textPath href="#testp" startOffset="50%">tests</textPath>
|
||||
</text>
|
||||
|
||||
<!-- subpackage -->
|
||||
<circle class="package" r="140" cx="186" cy="271" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 56,271 A 130 130 0 0 1 316 271" id="subpackage"/>
|
||||
</defs>
|
||||
<text class="package">
|
||||
<textPath href="#subpackage" startOffset="50%">subpackage</textPath>
|
||||
</text>
|
||||
|
||||
<!-- test_subpackage.py -->
|
||||
<circle class="module" r="90" cx="186" cy="311" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 106,311 A 80 80 0 0 1 266 311" id="testSubpackage"/>
|
||||
</defs>
|
||||
<text class="module">
|
||||
<textPath href="#testSubpackage" startOffset="50%">test_subpackage.py</textPath>
|
||||
</text>
|
||||
<!-- innermost -->
|
||||
<line x1="186" x2="186" y1="271" y2="351"/>
|
||||
<!-- mid -->
|
||||
<path d="M 186 351 L 136 351 L 106 331 L 106 196" />
|
||||
<!-- order -->
|
||||
<path d="M 186 351 L 256 351 L 316 291 L 316 136" />
|
||||
<!-- top -->
|
||||
<path d="M 186 351 L 186 391 L 231 436 L 331 436" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="186" cy="271" />
|
||||
<text x="186" y="271">innermost</text>
|
||||
<rect class="test" width="110" height="50" x="131" y="326" />
|
||||
<text x="186" y="351">test_order</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="126" cy="196" />
|
||||
<text x="126" y="196">mid</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testSubpackageOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="90" cx="186" cy="311" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="96" cy="311" mask="url(#testSubpackageOrderMask)"/>
|
||||
<text class="module" x="96" y="311">1</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="subpackageOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="140" cx="186" cy="271" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="46" cy="271" mask="url(#subpackageOrderMask)"/>
|
||||
<text class="module" x="46" y="271">2</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testsOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="270" cx="286" cy="271" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="16" cy="271" mask="url(#testsOrderMask)"/>
|
||||
<text class="module" x="16" y="271">3</text>
|
||||
|
||||
<!-- test_top.py -->
|
||||
<circle class="module" r="85" cx="441" cy="271" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 366,271 A 75 75 0 0 1 516 271" id="testTop"/>
|
||||
</defs>
|
||||
<text class="module">
|
||||
<textPath href="#testTop" startOffset="50%">test_top.py</textPath>
|
||||
</text>
|
||||
<!-- innermost -->
|
||||
<line x1="441" x2="441" y1="306" y2="236"/>
|
||||
<!-- order -->
|
||||
<path d="M 441 306 L 376 306 L 346 276 L 346 136" />
|
||||
<!-- top -->
|
||||
<path d="M 441 306 L 441 411 L 411 436 L 331 436" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="441" cy="236" />
|
||||
<text x="441" y="236">innermost</text>
|
||||
<rect class="test" width="110" height="50" x="386" y="281" />
|
||||
<text x="441" y="306">test_order</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testTopOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="85" cx="441" cy="271" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="526" cy="271" mask="url(#testTopOrderMask)"/>
|
||||
<text class="module" x="526" y="271">1</text>
|
||||
<!-- scope order number -->
|
||||
<circle class="module" r="15" cx="556" cy="271" mask="url(#testsOrderMask)"/>
|
||||
<text class="module" x="556" y="271">2</text>
|
||||
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="331" cy="436" />
|
||||
<text x="331" y="436">top</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="331" cy="136" />
|
||||
<text x="331" y="136">order</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
142
doc/en/example/fixtures/fixture_availability_plugins.svg
Normal file
@@ -0,0 +1,142 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="587" height="382">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
alignment-baseline: center;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class, circle.module, circle.package, circle.plugin {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class, text.module, text.package, text.plugin {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
line, path {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- plugin_a.py scope -->
|
||||
<circle class="plugin" r="85" cx="486" cy="86" />
|
||||
<!-- plugin name -->
|
||||
<defs>
|
||||
<path d="M 411,86 A 75 75 0 0 1 561 86" id="pluginA"/>
|
||||
</defs>
|
||||
<text class="plugin">
|
||||
<textPath href="#pluginA" startOffset="50%">plugin_a</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="pluginAOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="85" cx="486" cy="86" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="571" cy="86" mask="url(#pluginAOrderMask)"/>
|
||||
<text class="module" x="571" y="86">4</text>
|
||||
|
||||
<!-- plugin_b.py scope -->
|
||||
<circle class="plugin" r="85" cx="486" cy="296" />
|
||||
<!-- plugin name -->
|
||||
<defs>
|
||||
<path d="M 411,296 A 75 75 0 0 1 561 296" id="pluginB"/>
|
||||
</defs>
|
||||
<text class="plugin">
|
||||
<textPath href="#pluginB" startOffset="50%">plugin_b</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="pluginBOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="85" cx="486" cy="296" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="571" cy="296" mask="url(#pluginBOrderMask)"/>
|
||||
<text class="module" x="571" y="296">4</text>
|
||||
|
||||
<!-- main scope -->
|
||||
<circle class="package" r="190" cx="191" cy="191" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 11,191 A 180 180 0 0 1 371 191" id="testp"/>
|
||||
</defs>
|
||||
<text class="package">
|
||||
<textPath href="#testp" startOffset="50%">tests</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="mainOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="190" cx="191" cy="191" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="381" cy="191" mask="url(#mainOrderMask)"/>
|
||||
<text class="module" x="381" y="191">3</text>
|
||||
|
||||
<!-- subpackage -->
|
||||
<circle class="package" r="140" cx="191" cy="231" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 61,231 A 130 130 0 0 1 321 231" id="subpackage"/>
|
||||
</defs>
|
||||
<text class="package">
|
||||
<textPath href="#subpackage" startOffset="50%">subpackage</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="subpackageOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="140" cx="191" cy="231" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="331" cy="231" mask="url(#subpackageOrderMask)"/>
|
||||
<text class="module" x="331" y="231">2</text>
|
||||
|
||||
<!-- test_subpackage.py -->
|
||||
<circle class="module" r="90" cx="191" cy="271" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 111,271 A 80 80 0 0 1 271 271" id="testSubpackage"/>
|
||||
</defs>
|
||||
<text class="module">
|
||||
<textPath href="#testSubpackage" startOffset="50%">test_subpackage.py</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testSubpackageOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="90" cx="191" cy="271" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="281" cy="271" mask="url(#testSubpackageOrderMask)"/>
|
||||
<text class="module" x="281" y="271">1</text>
|
||||
|
||||
<!-- innermost -->
|
||||
<line x1="191" x2="191" y1="231" y2="311"/>
|
||||
<!-- mid -->
|
||||
<path d="M 191 306 L 101 306 L 91 296 L 91 156 L 101 146 L 191 146" />
|
||||
<!-- order -->
|
||||
<path d="M 191 316 L 91 316 L 81 306 L 81 61 L 91 51 L 191 51" />
|
||||
<!-- a_fix -->
|
||||
<path d="M 191 306 L 291 306 L 301 296 L 301 96 L 311 86 L 486 86" />
|
||||
<!-- b_fix -->
|
||||
<path d="M 191 316 L 316 316 L 336 296 L 486 296" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="191" cy="231" />
|
||||
<text x="191" y="231">inner</text>
|
||||
<rect class="test" width="110" height="50" x="136" y="286" />
|
||||
<text x="191" y="311">test_order</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="191" cy="146" />
|
||||
<text x="191" y="146">mid</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="191" cy="51" />
|
||||
<text x="191" y="51">order</text>
|
||||
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="486" cy="86" />
|
||||
<text x="486" y="86">a_fix</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="486" cy="296" />
|
||||
<text x="486" y="296">b_fix</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
@@ -1,38 +0,0 @@
|
||||
import pytest
|
||||
|
||||
# fixtures documentation order example
|
||||
order = []
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def s1():
|
||||
order.append("s1")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def m1():
|
||||
order.append("m1")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def f1(f3):
|
||||
order.append("f1")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def f3():
|
||||
order.append("f3")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def a1():
|
||||
order.append("a1")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def f2():
|
||||
order.append("f2")
|
||||
|
||||
|
||||
def test_order(f1, m1, f2, s1):
|
||||
assert order == ["s1", "m1", "a1", "f3", "f1", "f2"]
|
||||
45
doc/en/example/fixtures/test_fixtures_order_autouse.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def order():
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def a(order):
|
||||
order.append("a")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def b(a, order):
|
||||
order.append("b")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def c(b, order):
|
||||
order.append("c")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def d(b, order):
|
||||
order.append("d")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def e(d, order):
|
||||
order.append("e")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def f(e, order):
|
||||
order.append("f")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def g(f, c, order):
|
||||
order.append("g")
|
||||
|
||||
|
||||
def test_order_and_g(g, order):
|
||||
assert order == ["a", "b", "c", "d", "e", "f", "g"]
|
||||
64
doc/en/example/fixtures/test_fixtures_order_autouse.svg
Normal file
@@ -0,0 +1,64 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="252" height="682">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
path, line {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
rect.autouse {
|
||||
fill: #ca7f3d;
|
||||
}
|
||||
</style>
|
||||
<path d="M126,586 L26,506 L26,236" />
|
||||
<path d="M226,446 L226,236 L126,166" />
|
||||
<line x1="126" x2="126" y1="656" y2="516" />
|
||||
<line x1="126" x2="226" y1="516" y2="446" />
|
||||
<line x1="226" x2="126" y1="446" y2="376" />
|
||||
<line x1="126" x2="126" y1="376" y2="166" />
|
||||
<line x1="26" x2="126" y1="236" y2="166" />
|
||||
<line x1="126" x2="126" y1="166" y2="26" />
|
||||
<line x1="126" x2="126" y1="96" y2="26" />
|
||||
<rect class="autouse" width="251" height="40" x="0" y="286" />
|
||||
<text x="126" y="306">autouse</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="126" cy="26" />
|
||||
<text x="126" y="26">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="96" />
|
||||
<text x="126" y="96">a</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="166" />
|
||||
<text x="126" y="166">b</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="26" cy="236" />
|
||||
<text x="26" y="236">c</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="376" />
|
||||
<text x="126" y="376">d</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="446" />
|
||||
<text x="226" y="446">e</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="516" />
|
||||
<text x="126" y="516">f</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="586" />
|
||||
<text x="126" y="586">g</text>
|
||||
<rect class="test" width="110" height="50" x="71" y="631" />
|
||||
<text x="126" y="656">test_order</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,31 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def order():
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture(scope="class", autouse=True)
|
||||
def c1(order):
|
||||
order.append("c1")
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def c2(order):
|
||||
order.append("c2")
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def c3(order, c1):
|
||||
order.append("c3")
|
||||
|
||||
|
||||
class TestClassWithC1Request:
|
||||
def test_order(self, order, c1, c3):
|
||||
assert order == ["c1", "c3"]
|
||||
|
||||
|
||||
class TestClassWithoutC1Request:
|
||||
def test_order(self, order, c2):
|
||||
assert order == ["c1", "c2"]
|
||||
@@ -0,0 +1,76 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="862" height="402">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
line {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
}
|
||||
rect.autouse {
|
||||
fill: #ca7f3d;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- TestWithC1Request -->
|
||||
<circle class="class" r="200" cx="221" cy="201" />
|
||||
<line x1="221" x2="221" y1="61" y2="316"/>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="221" cy="61" />
|
||||
<text x="221" y="61">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="221" cy="131" />
|
||||
<text x="221" y="131">c1</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="221" cy="271" />
|
||||
<text x="221" y="271">c3</text>
|
||||
<rect class="test" width="110" height="50" x="166" y="316" />
|
||||
<text x="221" y="341">test_order</text>
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M31,201 A 190 190 0 0 1 411 201" id="testClassWith"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath href="#testClassWith" startOffset="50%">TestWithC1Request</textPath>
|
||||
</text>
|
||||
|
||||
<!-- TestWithoutC1Request -->
|
||||
<circle class="class" r="200" cx="641" cy="201" />
|
||||
<line x1="641" x2="641" y1="61" y2="316"/>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="641" cy="61" />
|
||||
<text x="641" y="61">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="641" cy="131" />
|
||||
<text x="641" y="131">c1</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="641" cy="271" />
|
||||
<text x="641" y="271">c2</text>
|
||||
<rect class="test" width="110" height="50" x="586" y="316" />
|
||||
<text x="641" y="341">test_order</text>
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M451,201 A 190 190 0 0 1 831 201" id="testClassWithout"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath href="#testClassWithout" startOffset="50%">TestWithoutC1Request</textPath>
|
||||
</text>
|
||||
|
||||
<rect class="autouse" width="862" height="40" x="1" y="181" />
|
||||
<rect width="10" height="100" class="autouse" x="426" y="151" />
|
||||
<text x="431" y="201">autouse</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,36 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def order():
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def c1(order):
|
||||
order.append("c1")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def c2(order):
|
||||
order.append("c2")
|
||||
|
||||
|
||||
class TestClassWithAutouse:
|
||||
@pytest.fixture(autouse=True)
|
||||
def c3(self, order, c2):
|
||||
order.append("c3")
|
||||
|
||||
def test_req(self, order, c1):
|
||||
assert order == ["c2", "c3", "c1"]
|
||||
|
||||
def test_no_req(self, order):
|
||||
assert order == ["c2", "c3"]
|
||||
|
||||
|
||||
class TestClassWithoutAutouse:
|
||||
def test_req(self, order, c1):
|
||||
assert order == ["c1"]
|
||||
|
||||
def test_no_req(self, order):
|
||||
assert order == []
|
||||
@@ -0,0 +1,100 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="862" height="502">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
line {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
}
|
||||
rect.autouse {
|
||||
fill: #ca7f3d;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- TestWithAutouse -->
|
||||
<circle class="class" r="250" cx="251" cy="251" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M11,251 A 240 240 0 0 1 491 251" id="testClassWith"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath href="#testClassWith" startOffset="50%">TestWithAutouse</textPath>
|
||||
</text>
|
||||
<mask id="autouseScope">
|
||||
<circle fill="white" r="249" cx="251" cy="251" />
|
||||
</mask>
|
||||
|
||||
<!-- TestWithAutouse.test_req -->
|
||||
<line x1="176" x2="176" y1="76" y2="426"/>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="176" cy="76" />
|
||||
<text x="176" y="76">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="176" cy="146" />
|
||||
<text x="176" y="146">c2</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="176" cy="216" />
|
||||
<text x="176" y="216">c3</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="176" cy="356" />
|
||||
<text x="176" y="356">c1</text>
|
||||
<rect class="test" width="100" height="50" x="126" y="401" />
|
||||
<text x="176" y="426">test_req</text>
|
||||
|
||||
<!-- TestWithAutouse.test_no_req -->
|
||||
<line x1="326" x2="326" y1="76" y2="346"/>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="326" cy="76" />
|
||||
<text x="326" y="76">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="326" cy="146" />
|
||||
<text x="326" y="146">c2</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="326" cy="216" />
|
||||
<text x="326" y="216">c3</text>
|
||||
<rect class="test" width="120" height="50" x="266" y="331" />
|
||||
<text x="326" y="356">test_no_req</text>
|
||||
|
||||
<rect class="autouse" width="500" height="40" x="1" y="266" mask="url(#autouseScope)"/>
|
||||
<text x="261" y="286">autouse</text>
|
||||
|
||||
<!-- TestWithoutAutouse -->
|
||||
<circle class="class" r="170" cx="691" cy="251" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 531,251 A 160 160 0 0 1 851 251" id="testClassWithout"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath href="#testClassWithout" startOffset="50%">TestWithoutAutouse</textPath>
|
||||
</text>
|
||||
|
||||
<!-- TestWithoutAutouse.test_req -->
|
||||
<line x1="616" x2="616" y1="181" y2="321"/>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="616" cy="181" />
|
||||
<text x="616" y="181">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="616" cy="251" />
|
||||
<text x="616" y="251">c1</text>
|
||||
<rect class="test" width="100" height="50" x="566" y="296" />
|
||||
<text x="616" y="321">test_req</text>
|
||||
|
||||
<!-- TestWithoutAutouse.test_no_req -->
|
||||
<line x1="766" x2="766" y1="181" y2="251"/>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="766" cy="181" />
|
||||
<text x="766" y="181">order</text>
|
||||
<rect class="test" width="120" height="50" x="706" y="226" />
|
||||
<text x="766" y="251">test_no_req</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
45
doc/en/example/fixtures/test_fixtures_order_dependencies.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def order():
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def a(order):
|
||||
order.append("a")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def b(a, order):
|
||||
order.append("b")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def c(a, b, order):
|
||||
order.append("c")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def d(c, b, order):
|
||||
order.append("d")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def e(d, b, order):
|
||||
order.append("e")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def f(e, order):
|
||||
order.append("f")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def g(f, c, order):
|
||||
order.append("g")
|
||||
|
||||
|
||||
def test_order(g, order):
|
||||
assert order == ["a", "b", "c", "d", "e", "f", "g"]
|
||||
60
doc/en/example/fixtures/test_fixtures_order_dependencies.svg
Normal file
@@ -0,0 +1,60 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="252" height="612">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
path, line {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
</style>
|
||||
<path d="M126,516 L26,436 L26,236" />
|
||||
<path d="M226,376 L226,236 L126,166" />
|
||||
<line x1="126" x2="126" y1="586" y2="446" />
|
||||
<line x1="126" x2="226" y1="446" y2="376" />
|
||||
<line x1="226" x2="126" y1="376" y2="306" />
|
||||
<line x1="126" x2="26" y1="306" y2="236" />
|
||||
<line x1="126" x2="126" y1="306" y2="166" />
|
||||
<line x1="26" x2="126" y1="236" y2="166" />
|
||||
<line x1="126" x2="126" y1="166" y2="26" />
|
||||
<line x1="126" x2="126" y1="96" y2="26" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="126" cy="26" />
|
||||
<text x="126" y="26">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="96" />
|
||||
<text x="126" y="96">a</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="166" />
|
||||
<text x="126" y="166">b</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="26" cy="236" />
|
||||
<text x="26" y="236">c</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="306" />
|
||||
<text x="126" y="306">d</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="376" />
|
||||
<text x="226" y="376">e</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="446" />
|
||||
<text x="126" y="446">f</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="516" />
|
||||
<text x="126" y="516">g</text>
|
||||
<rect class="test" width="110" height="50" x="71" y="561" />
|
||||
<text x="126" y="586">test_order</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,51 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="112" height="612">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
path, line {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
</style>
|
||||
<line x1="56" x2="56" y1="611" y2="26" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="56" cy="26" />
|
||||
<text x="56" y="26">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="96" />
|
||||
<text x="56" y="96">a</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="166" />
|
||||
<text x="56" y="166">b</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="236" />
|
||||
<text x="56" y="236">c</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="306" />
|
||||
<text x="56" y="306">d</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="376" />
|
||||
<text x="56" y="376">e</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="446" />
|
||||
<text x="56" y="446">f</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="516" />
|
||||
<text x="56" y="516">g</text>
|
||||
<rect class="test" width="110" height="50" x="1" y="561" />
|
||||
<text x="56" y="586">test_order</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,60 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="252" height="542">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
path, line {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
</style>
|
||||
<path d="M126,446 L26,376 L26,236" />
|
||||
<path d="M226,306 L126,236 L126,166" />
|
||||
<line x1="126" x2="126" y1="516" y2="446" />
|
||||
<line x1="226" x2="226" y1="376" y2="306" />
|
||||
<line x1="226" x2="226" y1="306" y2="236" />
|
||||
<line x1="226" x2="126" y1="236" y2="166" />
|
||||
<line x1="126" x2="226" y1="446" y2="376" />
|
||||
<line x1="26" x2="126" y1="236" y2="166" />
|
||||
<line x1="126" x2="126" y1="166" y2="96" />
|
||||
<line x1="126" x2="126" y1="96" y2="26" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="126" cy="26" />
|
||||
<text x="126" y="26">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="96" />
|
||||
<text x="126" y="96">a</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="166" />
|
||||
<text x="126" y="166">b</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="26" cy="236" />
|
||||
<text x="26" y="236">c</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="236" />
|
||||
<text x="226" y="236">d</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="306" />
|
||||
<text x="226" y="306">e</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="376" />
|
||||
<text x="226" y="376">f</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="446" />
|
||||
<text x="126" y="446">g</text>
|
||||
<rect class="test" width="110" height="50" x="71" y="491" />
|
||||
<text x="126" y="516">test_order</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
36
doc/en/example/fixtures/test_fixtures_order_scope.py
Normal file
@@ -0,0 +1,36 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def order():
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def func(order):
|
||||
order.append("function")
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def cls(order):
|
||||
order.append("class")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def mod(order):
|
||||
order.append("module")
|
||||
|
||||
|
||||
@pytest.fixture(scope="package")
|
||||
def pack(order):
|
||||
order.append("package")
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def sess(order):
|
||||
order.append("session")
|
||||
|
||||
|
||||
class TestClass:
|
||||
def test_order(self, func, cls, mod, pack, sess, order):
|
||||
assert order == ["session", "package", "module", "class", "function"]
|
||||
55
doc/en/example/fixtures/test_fixtures_order_scope.svg
Normal file
@@ -0,0 +1,55 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="262" height="537">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
line {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
}
|
||||
</style>
|
||||
<!-- TestClass -->
|
||||
<circle class="class" r="130" cx="131" cy="406" />
|
||||
<line x1="131" x2="131" y1="21" y2="446"/>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="26" />
|
||||
<text x="131" y="26">order</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="96" />
|
||||
<text x="131" y="96">sess</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="166" />
|
||||
<text x="131" y="166">pack</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="236" />
|
||||
<text x="131" y="236">mod</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="306" />
|
||||
<text x="131" y="306">cls</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="376" />
|
||||
<text x="131" y="376">func</text>
|
||||
<rect class="test" width="110" height="50" x="76" y="421" />
|
||||
<text x="131" y="446">test_order</text>
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M131,526 A 120 120 0 0 1 136 286" id="testClass"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath href="#testClass" startOffset="50%">TestClass</textPath>
|
||||
</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,29 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def order():
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def outer(order, inner):
|
||||
order.append("outer")
|
||||
|
||||
|
||||
class TestOne:
|
||||
@pytest.fixture
|
||||
def inner(self, order):
|
||||
order.append("one")
|
||||
|
||||
def test_order(self, order, outer):
|
||||
assert order == ["one", "outer"]
|
||||
|
||||
|
||||
class TestTwo:
|
||||
@pytest.fixture
|
||||
def inner(self, order):
|
||||
order.append("two")
|
||||
|
||||
def test_order(self, order, outer):
|
||||
assert order == ["two", "outer"]
|
||||
@@ -0,0 +1,115 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="562" height="532">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
circle.module {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class, text.module {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
line, path {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
</style>
|
||||
<!-- main scope -->
|
||||
<circle class="module" r="265" cx="281" cy="266" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 26,266 A 255 255 0 0 1 536 266" id="testModule"/>
|
||||
</defs>
|
||||
<text class="module">
|
||||
<textPath href="#testModule" startOffset="50%">test_fixtures_request_different_scope.py</textPath>
|
||||
</text>
|
||||
|
||||
<!-- TestOne -->
|
||||
<circle class="class" r="100" cx="141" cy="266" />
|
||||
<!-- inner -->
|
||||
<line x1="141" x2="141" y1="231" y2="301"/>
|
||||
<!-- order -->
|
||||
<path d="M 141 296 L 201 296 L 211 286 L 211 146 L 221 136 L 281 136" />
|
||||
<!-- outer -->
|
||||
<path d="M 141 306 L 201 306 L 211 316 L 211 386 L 221 396 L 281 396" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="141" cy="231" />
|
||||
<text x="141" y="231">inner</text>
|
||||
<rect class="test" width="110" height="50" x="86" y="276" />
|
||||
<text x="141" y="301">test_order</text>
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 51,266 A 90 90 0 0 1 231 266" id="testOne"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath href="#testOne" startOffset="50%">TestOne</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testOneOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="100" cx="141" cy="266" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="41" cy="266" mask="url(#testOneOrderMask)"/>
|
||||
<text class="module" x="41" y="266">1</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testMainOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="265" cx="281" cy="266" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="16" cy="266" mask="url(#testMainOrderMask)"/>
|
||||
<text class="module" x="16" y="266">2</text>
|
||||
|
||||
<!-- TestTwo -->
|
||||
<circle class="class" r="100" cx="421" cy="266" />
|
||||
<!-- inner -->
|
||||
<line x1="421" x2="421" y1="231" y2="301"/>
|
||||
<!-- order -->
|
||||
<path d="M 421 296 L 361 296 L 351 286 L 351 146 L 341 136 L 281 136" />
|
||||
<!-- outer -->
|
||||
<path d="M 421 306 L 361 306 L 351 316 L 351 386 L 341 396 L 281 396" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="421" cy="231" />
|
||||
<text x="421" y="231">inner</text>
|
||||
<rect class="test" width="110" height="50" x="366" y="276" />
|
||||
<text x="421" y="301">test_order</text>
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 331,266 A 90 90 0 0 1 511 266" id="testTwo"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath href="#testTwo" startOffset="50%">TestTwo</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testTwoOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="100" cx="421" cy="266" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="521" cy="266" mask="url(#testTwoOrderMask)"/>
|
||||
<text class="module" x="521" y="266">1</text>
|
||||
<!-- scope order number -->
|
||||
<circle class="module" r="15" cx="546" cy="266" mask="url(#testMainOrderMask)"/>
|
||||
<text class="module" x="546" y="266">2</text>
|
||||
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="281" cy="396" />
|
||||
<text x="281" y="396">outer</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="281" cy="136" />
|
||||
<text x="281" y="136">order</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@@ -45,7 +45,7 @@ You can then restrict a test run to only run tests marked with ``webtest``:
|
||||
|
||||
$ pytest -v -m webtest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 3 deselected / 1 selected
|
||||
@@ -60,7 +60,7 @@ Or the inverse, running all tests except the webtest ones:
|
||||
|
||||
$ pytest -v -m "not webtest"
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 1 deselected / 3 selected
|
||||
@@ -82,7 +82,7 @@ tests based on their module, class, method, or function name:
|
||||
|
||||
$ pytest -v test_server.py::TestClass::test_method
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 1 item
|
||||
@@ -97,7 +97,7 @@ You can also select on the class:
|
||||
|
||||
$ pytest -v test_server.py::TestClass
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 1 item
|
||||
@@ -112,7 +112,7 @@ Or select multiple nodes:
|
||||
|
||||
$ pytest -v test_server.py::TestClass test_server.py::test_send_http
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 2 items
|
||||
@@ -156,7 +156,7 @@ The expression matching is now case-insensitive.
|
||||
|
||||
$ pytest -v -k http # running with the above defined example module
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 3 deselected / 1 selected
|
||||
@@ -171,7 +171,7 @@ And you can also run all tests except the ones that match the keyword:
|
||||
|
||||
$ pytest -k "not send_http" -v
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 1 deselected / 3 selected
|
||||
@@ -188,7 +188,7 @@ Or to select "http" and "quick" tests:
|
||||
|
||||
$ pytest -k "http or quick" -v
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 2 deselected / 2 selected
|
||||
@@ -397,7 +397,7 @@ the test needs:
|
||||
|
||||
$ pytest -E stage2
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
@@ -412,7 +412,7 @@ and here is one that specifies exactly the environment needed:
|
||||
|
||||
$ pytest -E stage1
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
@@ -605,7 +605,7 @@ then you will see two tests skipped and two executed tests as expected:
|
||||
|
||||
$ pytest -rs # this option reports skip reasons
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items
|
||||
@@ -622,7 +622,7 @@ Note that if you specify a platform via the marker-command line option like this
|
||||
|
||||
$ pytest -m linux
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items / 3 deselected / 1 selected
|
||||
@@ -686,7 +686,7 @@ We can now use the ``-m option`` to select one set:
|
||||
|
||||
$ pytest -m interface --tb=short
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items / 2 deselected / 2 selected
|
||||
@@ -713,7 +713,7 @@ or to select both "event" and "interface" tests:
|
||||
|
||||
$ pytest -m "interface or event" --tb=short
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items / 1 deselected / 3 selected
|
||||
|
||||
@@ -29,7 +29,7 @@ now execute the test specification:
|
||||
|
||||
nonpython $ pytest test_simple.yaml
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR/nonpython
|
||||
collected 2 items
|
||||
@@ -66,7 +66,7 @@ consulted when reporting in ``verbose`` mode:
|
||||
|
||||
nonpython $ pytest -v
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR/nonpython
|
||||
collecting ... collected 2 items
|
||||
@@ -92,7 +92,7 @@ interesting to just look at the collection tree:
|
||||
|
||||
nonpython $ pytest --collect-only
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR/nonpython
|
||||
collected 2 items
|
||||
|
||||
@@ -160,7 +160,7 @@ objects, they are still using the default pytest representation:
|
||||
|
||||
$ pytest test_time.py --collect-only
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 8 items
|
||||
@@ -225,7 +225,7 @@ this is a fully self-contained example which you can run with:
|
||||
|
||||
$ pytest test_scenarios.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items
|
||||
@@ -240,7 +240,7 @@ If you just collect tests you'll also nicely see 'advanced' and 'basic' as varia
|
||||
|
||||
$ pytest --collect-only test_scenarios.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items
|
||||
@@ -319,7 +319,7 @@ Let's first see how it looks like at collection time:
|
||||
|
||||
$ pytest test_backends.py --collect-only
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
@@ -418,7 +418,7 @@ The result of this test will be successful:
|
||||
|
||||
$ pytest -v test_indirect_list.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 1 item
|
||||
@@ -508,11 +508,12 @@ Running it results in some skips if we don't have all the python interpreters in
|
||||
.. code-block:: pytest
|
||||
|
||||
. $ pytest -rs -q multipython.py
|
||||
ssssssssssss...ssssssssssss [100%]
|
||||
sssssssssssssssssssssssssss [100%]
|
||||
========================= short test summary info ==========================
|
||||
SKIPPED [12] multipython.py:29: 'python3.5' not found
|
||||
SKIPPED [12] multipython.py:29: 'python3.7' not found
|
||||
3 passed, 24 skipped in 0.12s
|
||||
SKIPPED [9] multipython.py:29: 'python3.5' not found
|
||||
SKIPPED [9] multipython.py:29: 'python3.6' not found
|
||||
SKIPPED [9] multipython.py:29: 'python3.7' not found
|
||||
27 skipped in 0.12s
|
||||
|
||||
Indirect parametrization of optional implementations/imports
|
||||
--------------------------------------------------------------------
|
||||
@@ -572,7 +573,7 @@ If you run this with reporting for skips enabled:
|
||||
|
||||
$ pytest -rs test_module.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
@@ -634,16 +635,16 @@ Then run ``pytest`` with verbose mode and with only the ``basic`` marker:
|
||||
|
||||
$ pytest -v -m basic
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 14 items / 11 deselected / 3 selected
|
||||
collecting ... collected 24 items / 21 deselected / 3 selected
|
||||
|
||||
test_pytest_param_example.py::test_eval[1+7-8] PASSED [ 33%]
|
||||
test_pytest_param_example.py::test_eval[basic_2+4] PASSED [ 66%]
|
||||
test_pytest_param_example.py::test_eval[basic_6*9] XFAIL [100%]
|
||||
|
||||
=============== 2 passed, 11 deselected, 1 xfailed in 0.12s ================
|
||||
=============== 2 passed, 21 deselected, 1 xfailed in 0.12s ================
|
||||
|
||||
As the result:
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ The test collection would look like this:
|
||||
|
||||
$ pytest --collect-only
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR, configfile: pytest.ini
|
||||
collected 2 items
|
||||
@@ -209,7 +209,7 @@ You can always peek at the collection tree without running tests like this:
|
||||
|
||||
. $ pytest --collect-only pythoncollection.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR, configfile: pytest.ini
|
||||
collected 3 items
|
||||
@@ -291,7 +291,7 @@ file will be left out:
|
||||
|
||||
$ pytest --collect-only
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR, configfile: pytest.ini
|
||||
collected 0 items
|
||||
|
||||
@@ -9,7 +9,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
|
||||
assertion $ pytest failure_demo.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR/assertion
|
||||
collected 44 items
|
||||
|
||||
@@ -175,7 +175,7 @@ directory with the above conftest.py:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 0 items
|
||||
@@ -240,7 +240,7 @@ and when running it will see a skipped "slow" test:
|
||||
|
||||
$ pytest -rs # "-rs" means report details on the little 's'
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
@@ -257,7 +257,7 @@ Or run it including the ``slow`` marked test:
|
||||
|
||||
$ pytest --runslow
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
@@ -401,7 +401,7 @@ which will add the string to the test header accordingly:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
project deps: mylib-1.1
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
@@ -430,7 +430,7 @@ which will add info only when run with "--v":
|
||||
|
||||
$ pytest -v
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
info1: did you know that ...
|
||||
did you?
|
||||
@@ -445,7 +445,7 @@ and nothing when run plainly:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 0 items
|
||||
@@ -485,7 +485,7 @@ Now we can profile which test functions execute the slowest:
|
||||
|
||||
$ pytest --durations=3
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 3 items
|
||||
@@ -591,7 +591,7 @@ If we run this:
|
||||
|
||||
$ pytest -rx
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items
|
||||
@@ -675,7 +675,7 @@ We can run this:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 7 items
|
||||
@@ -794,7 +794,7 @@ and run them:
|
||||
|
||||
$ pytest test_module.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
@@ -901,7 +901,7 @@ and run it:
|
||||
|
||||
$ pytest -s test_module.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 3 items
|
||||
|
||||
1698
doc/en/fixture.rst
@@ -168,7 +168,7 @@ pytest for a long time offered a pytest_configure and a pytest_sessionstart
|
||||
hook which are often used to setup global resources. This suffers from
|
||||
several problems:
|
||||
|
||||
1. in distributed testing the master process would setup test resources
|
||||
1. in distributed testing the managing process would setup test resources
|
||||
that are never needed because it only co-ordinates the test run
|
||||
activities of the worker processes.
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Install ``pytest``
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest --version
|
||||
pytest 6.2.0
|
||||
pytest 6.2.5
|
||||
|
||||
.. _`simpletest`:
|
||||
|
||||
@@ -53,7 +53,7 @@ That’s it. You can now execute the test function:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
.. 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.
|
||||
- `Professional Testing with Python <https://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_, via `Python Academy <https://www.python-academy.com/>`_, February 1st to 3rd, 2022, Leipzig (Germany) and remote.
|
||||
|
||||
Also see `previous talks and blogposts <talks.html>`_.
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
pytest: helps you write better programs
|
||||
=======================================
|
||||
|
||||
.. module:: pytest
|
||||
|
||||
The ``pytest`` framework makes it easy to write small tests, yet
|
||||
scales to support complex functional testing for applications and libraries.
|
||||
@@ -34,7 +35,7 @@ To execute it:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
@@ -71,7 +72,7 @@ Features
|
||||
|
||||
- Python 3.6+ 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 <https://docs.pytest.org/en/latest/reference/plugin_list.html>`_ and thriving community
|
||||
|
||||
|
||||
Documentation
|
||||
@@ -128,8 +129,8 @@ Tidelift will coordinate the fix and disclosure.
|
||||
License
|
||||
-------
|
||||
|
||||
Copyright Holger Krekel and others, 2004-2020.
|
||||
Copyright Holger Krekel and others, 2004-2021.
|
||||
|
||||
Distributed under the terms of the `MIT`_ license, pytest is free and open source software.
|
||||
|
||||
.. _`MIT`: https://github.com/pytest-dev/pytest/blob/master/LICENSE
|
||||
.. _`MIT`: https://github.com/pytest-dev/pytest/blob/main/LICENSE
|
||||
|
||||
@@ -29,4 +29,4 @@ Distributed under the terms of the `MIT`_ license, pytest is free and open sourc
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
.. _`MIT`: https://github.com/pytest-dev/pytest/blob/master/LICENSE
|
||||
.. _`MIT`: https://github.com/pytest-dev/pytest/blob/main/LICENSE
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Monkeypatching/mocking modules and environments
|
||||
================================================================
|
||||
|
||||
.. currentmodule:: _pytest.monkeypatch
|
||||
.. currentmodule:: pytest
|
||||
|
||||
Sometimes tests need to invoke functionality which depends
|
||||
on global settings or which invokes code which cannot be easily
|
||||
@@ -434,7 +434,7 @@ separate fixtures for each potential mock and reference them in the needed tests
|
||||
_ = app.create_connection_string()
|
||||
|
||||
|
||||
.. currentmodule:: _pytest.monkeypatch
|
||||
.. currentmodule:: pytest
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
@@ -56,7 +56,7 @@ them in turn:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 3 items
|
||||
@@ -134,7 +134,7 @@ Let's run this:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 3 items
|
||||
|
||||
@@ -920,11 +920,8 @@ TestReport
|
||||
_Result
|
||||
~~~~~~~
|
||||
|
||||
Result used within :ref:`hook wrappers <hookwrapper>`.
|
||||
Result object used within :ref:`hook wrappers <hookwrapper>`, see :py:class:`_Result in the pluggy documentation <pluggy._callers._Result>` for more information.
|
||||
|
||||
.. autoclass:: pluggy.callers._Result
|
||||
.. automethod:: pluggy.callers._Result.get_result
|
||||
.. automethod:: pluggy.callers._Result.force_result
|
||||
|
||||
Global Variables
|
||||
----------------
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pallets-sphinx-themes
|
||||
pluggy>=1.0
|
||||
pygments-pytest>=1.1.0
|
||||
sphinx-removed-in>=0.2.0
|
||||
sphinx>=3.1,<4
|
||||
|
||||
@@ -373,7 +373,7 @@ Running it with the report-on-xfail option gives this output:
|
||||
|
||||
example $ pytest -rx xfail_demo.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR/example
|
||||
collected 7 items
|
||||
|
||||
@@ -39,7 +39,7 @@ Running this would result in a passed test except for the last
|
||||
|
||||
$ pytest test_tmp_path.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
@@ -109,7 +109,7 @@ Running this would result in a passed test except for the last
|
||||
|
||||
$ pytest test_tmpdir.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
|
||||
@@ -137,7 +137,7 @@ the ``self.db`` values in the traceback:
|
||||
|
||||
$ pytest test_unittest_db.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
|
||||
@@ -218,7 +218,7 @@ Example:
|
||||
|
||||
$ pytest -ra
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 6 items
|
||||
@@ -276,7 +276,7 @@ More than one character can be used, so for example to only see failed and skipp
|
||||
|
||||
$ pytest -rfs
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 6 items
|
||||
@@ -312,7 +312,7 @@ captured output:
|
||||
|
||||
$ pytest -rpP
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 6 items
|
||||
|
||||
@@ -28,7 +28,7 @@ Running pytest now produces this output:
|
||||
|
||||
$ pytest test_show_warnings.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
@@ -173,8 +173,6 @@ DeprecationWarning and PendingDeprecationWarning
|
||||
------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
By default pytest will display ``DeprecationWarning`` and ``PendingDeprecationWarning`` warnings from
|
||||
user code and third-party libraries, as recommended by `PEP-0565 <https://www.python.org/dev/peps/pep-0565>`_.
|
||||
This helps users keep their code modern and avoid breakages when deprecated warnings are effectively removed.
|
||||
@@ -230,27 +228,8 @@ that a certain function call triggers a ``DeprecationWarning`` or
|
||||
This test will fail if ``myfunction`` does not issue a deprecation warning
|
||||
when called with a ``17`` argument.
|
||||
|
||||
By default, ``DeprecationWarning`` and ``PendingDeprecationWarning`` will not be
|
||||
caught when using :func:`pytest.warns` or :ref:`recwarn <recwarn>` because
|
||||
the default Python warnings filters hide
|
||||
them. If you wish to record them in your own code, use
|
||||
``warnings.simplefilter('always')``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import warnings
|
||||
import pytest
|
||||
|
||||
|
||||
def test_deprecation(recwarn):
|
||||
warnings.simplefilter("always")
|
||||
myfunction(17)
|
||||
assert len(recwarn) == 1
|
||||
assert recwarn.pop(DeprecationWarning)
|
||||
|
||||
|
||||
The :ref:`recwarn <recwarn>` fixture automatically ensures to reset the warnings
|
||||
filter at the end of the test, so no global state is leaked.
|
||||
|
||||
.. _`asserting warnings`:
|
||||
|
||||
@@ -317,9 +296,9 @@ additional information:
|
||||
Alternatively, you can examine raised warnings in detail using the
|
||||
:ref:`recwarn <recwarn>` fixture (see below).
|
||||
|
||||
.. note::
|
||||
``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated
|
||||
differently; see :ref:`ensuring_function_triggers`.
|
||||
|
||||
The :ref:`recwarn <recwarn>` fixture automatically ensures to reset the warnings
|
||||
filter at the end of the test, so no global state is leaked.
|
||||
|
||||
.. _`recording warnings`:
|
||||
|
||||
|
||||
@@ -442,7 +442,7 @@ Additionally it is possible to copy examples for an example folder before runnin
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR, configfile: pytest.ini
|
||||
collected 2 items
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import sys
|
||||
|
||||
from distutils.core import setup
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -26,6 +26,8 @@ filterwarnings = [
|
||||
# produced by older pyparsing<=2.2.0.
|
||||
"default:Using or importing the ABCs:DeprecationWarning:pyparsing.*",
|
||||
"default:the imp module is deprecated in favour of importlib:DeprecationWarning:nose.*",
|
||||
# distutils is deprecated in 3.10, scheduled for removal in 3.12
|
||||
"ignore:The distutils package is deprecated:DeprecationWarning",
|
||||
# produced by python3.6/site.py itself (3.6.7 on Travis, could not trigger it with 3.6.8)."
|
||||
"ignore:.*U.*mode is deprecated:DeprecationWarning:(?!(pytest|_pytest))",
|
||||
# produced by pytest-xdist
|
||||
@@ -40,6 +42,14 @@ filterwarnings = [
|
||||
"default:invalid escape sequence:DeprecationWarning",
|
||||
# ignore use of unregistered marks, because we use many to test the implementation
|
||||
"ignore::_pytest.warning_types.PytestUnknownMarkWarning",
|
||||
# https://github.com/benjaminp/six/issues/341
|
||||
"ignore:_SixMetaPathImporter\\.exec_module\\(\\) not found; falling back to load_module\\(\\):ImportWarning",
|
||||
# https://github.com/benjaminp/six/pull/352
|
||||
"ignore:_SixMetaPathImporter\\.find_spec\\(\\) not found; falling back to find_module\\(\\):ImportWarning",
|
||||
# https://github.com/pypa/setuptools/pull/2517
|
||||
"ignore:VendorImporter\\.find_spec\\(\\) not found; falling back to find_module\\(\\):ImportWarning",
|
||||
# https://github.com/pytest-dev/execnet/pull/127
|
||||
"ignore:isSet\\(\\) is deprecated, use is_set\\(\\) instead:DeprecationWarning",
|
||||
]
|
||||
pytester_example_dir = "testing/example_scripts"
|
||||
markers = [
|
||||
|
||||
@@ -23,8 +23,8 @@ Then the appropriate version will be obtained based on the given branch name:
|
||||
|
||||
After that, it will create a release using the `release` tox environment, and push a new PR.
|
||||
|
||||
**Secret**: currently the secret is defined in the @pytestbot account, which the core maintainers
|
||||
have access to. There we created a new secret named `chatops` with write access to the repository.
|
||||
**Token**: currently the token from the GitHub Actions is used, pushed with
|
||||
`pytest bot <pytestbot@gmail.com>` commit author.
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
|
||||
@@ -1,18 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -euo pipefail
|
||||
set -x
|
||||
|
||||
if [ -z "$TOXENV" ]; then
|
||||
# Install coverage.
|
||||
if [[ -z ${TOXENV+x} || -z $TOXENV ]]; then
|
||||
python -m pip install coverage
|
||||
else
|
||||
# Add last TOXENV to $PATH.
|
||||
PATH="$PWD/.tox/${TOXENV##*,}/bin:$PATH"
|
||||
fi
|
||||
|
||||
# Run coverage.
|
||||
python -m coverage combine
|
||||
python -m coverage xml
|
||||
python -m coverage report -m
|
||||
|
||||
# Download and verify latest Codecov bash uploader.
|
||||
# Set --connect-timeout to work around https://github.com/curl/curl/issues/4461
|
||||
curl -S -L --connect-timeout 5 --retry 6 -s https://codecov.io/bash -o codecov-upload.sh
|
||||
bash codecov-upload.sh -Z -X fix -f coverage.xml "$@"
|
||||
curl --silent --show-error --location --connect-timeout 5 --retry 6 -o codecov https://codecov.io/bash
|
||||
VERSION=$(grep --only-matching 'VERSION=\"[0-9\.]*\"' codecov | cut -d'"' -f2)
|
||||
if command -v sha256sum; then
|
||||
sha256sum --check --strict --ignore-missing --quiet <(curl --silent "https://raw.githubusercontent.com/codecov/codecov-bash/${VERSION}/SHA256SUM")
|
||||
else
|
||||
shasum --algorithm 256 --check --strict --ignore-missing --quiet <(curl --silent "https://raw.githubusercontent.com/codecov/codecov-bash/${VERSION}/SHA256SUM")
|
||||
fi
|
||||
|
||||
# Upload coverage.
|
||||
bash codecov -Z -X fix -f coverage.xml "$@"
|
||||
|
||||
@@ -21,11 +21,14 @@ classifiers =
|
||||
Programming Language :: Python :: 3.7
|
||||
Programming Language :: Python :: 3.8
|
||||
Programming Language :: Python :: 3.9
|
||||
Programming Language :: Python :: 3.10
|
||||
Topic :: Software Development :: Libraries
|
||||
Topic :: Software Development :: Testing
|
||||
Topic :: Utilities
|
||||
keywords = test, unittest
|
||||
project_urls =
|
||||
Changelog=https://docs.pytest.org/en/stable/changelog.html
|
||||
Twitter=https://twitter.com/pytestdotorg
|
||||
Source=https://github.com/pytest-dev/pytest
|
||||
Tracker=https://github.com/pytest-dev/pytest/issues
|
||||
|
||||
@@ -42,7 +45,7 @@ install_requires =
|
||||
attrs>=19.2.0
|
||||
iniconfig
|
||||
packaging
|
||||
pluggy>=0.12,<1.0.0a1
|
||||
pluggy>=0.12,<2.0
|
||||
py>=1.8.2
|
||||
toml
|
||||
atomicwrites>=1.0;sys_platform=="win32"
|
||||
@@ -52,7 +55,7 @@ python_requires = >=3.6
|
||||
package_dir =
|
||||
=src
|
||||
setup_requires =
|
||||
setuptools>=>=42.0
|
||||
setuptools>=42.0
|
||||
setuptools-scm>=3.4
|
||||
zip_safe = no
|
||||
|
||||
|
||||
@@ -673,12 +673,9 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||
if not mod.body:
|
||||
# Nothing to do.
|
||||
return
|
||||
# Insert some special imports at the top of the module but after any
|
||||
# docstrings and __future__ imports.
|
||||
aliases = [
|
||||
ast.alias("builtins", "@py_builtins"),
|
||||
ast.alias("_pytest.assertion.rewrite", "@pytest_ar"),
|
||||
]
|
||||
|
||||
# We'll insert some special imports at the top of the module, but after any
|
||||
# docstrings and __future__ imports, so first figure out where that is.
|
||||
doc = getattr(mod, "docstring", None)
|
||||
expect_docstring = doc is None
|
||||
if doc is not None and self.is_rewrite_disabled(doc):
|
||||
@@ -710,10 +707,27 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||
lineno = item.decorator_list[0].lineno
|
||||
else:
|
||||
lineno = item.lineno
|
||||
# Now actually insert the special imports.
|
||||
if sys.version_info >= (3, 10):
|
||||
aliases = [
|
||||
ast.alias("builtins", "@py_builtins", lineno=lineno, col_offset=0),
|
||||
ast.alias(
|
||||
"_pytest.assertion.rewrite",
|
||||
"@pytest_ar",
|
||||
lineno=lineno,
|
||||
col_offset=0,
|
||||
),
|
||||
]
|
||||
else:
|
||||
aliases = [
|
||||
ast.alias("builtins", "@py_builtins"),
|
||||
ast.alias("_pytest.assertion.rewrite", "@pytest_ar"),
|
||||
]
|
||||
imports = [
|
||||
ast.Import([alias], lineno=lineno, col_offset=0) for alias in aliases
|
||||
]
|
||||
mod.body[pos:pos] = imports
|
||||
|
||||
# Collect asserts.
|
||||
nodes: List[ast.AST] = [mod]
|
||||
while nodes:
|
||||
|
||||
@@ -69,7 +69,12 @@ class FaultHandlerHooks:
|
||||
@staticmethod
|
||||
def _get_stderr_fileno():
|
||||
try:
|
||||
return sys.stderr.fileno()
|
||||
fileno = sys.stderr.fileno()
|
||||
# The Twisted Logger will return an invalid file descriptor since it is not backed
|
||||
# by an FD. So, let's also forward this to the same code path as with pytest-xdist.
|
||||
if fileno == -1:
|
||||
raise AttributeError()
|
||||
return fileno
|
||||
except (AttributeError, io.UnsupportedOperation):
|
||||
# pytest-xdist monkeypatches sys.stderr with an object that is not an actual file.
|
||||
# https://docs.python.org/3/library/faulthandler.html#issue-with-file-descriptors
|
||||
|
||||
@@ -38,7 +38,7 @@ class OutcomeException(BaseException):
|
||||
self.pytrace = pytrace
|
||||
|
||||
def __repr__(self) -> str:
|
||||
if self.msg:
|
||||
if self.msg is not None:
|
||||
return self.msg
|
||||
return f"<{self.__class__.__name__} instance>"
|
||||
|
||||
|
||||
@@ -64,13 +64,6 @@ def get_lock_path(path: _AnyPurePath) -> _AnyPurePath:
|
||||
return path.joinpath(".lock")
|
||||
|
||||
|
||||
def ensure_reset_dir(path: Path) -> None:
|
||||
"""Ensure the given path is an empty directory."""
|
||||
if path.exists():
|
||||
rm_rf(path)
|
||||
path.mkdir()
|
||||
|
||||
|
||||
def on_rm_rf_error(func, path: str, exc, *, start_path: Path) -> bool:
|
||||
"""Handle known read-only errors during rmtree.
|
||||
|
||||
@@ -214,7 +207,7 @@ def _force_symlink(
|
||||
pass
|
||||
|
||||
|
||||
def make_numbered_dir(root: Path, prefix: str) -> Path:
|
||||
def make_numbered_dir(root: Path, prefix: str, mode: int = 0o700) -> Path:
|
||||
"""Create a directory with an increased number as suffix for the given prefix."""
|
||||
for i in range(10):
|
||||
# try up to 10 times to create the folder
|
||||
@@ -222,7 +215,7 @@ def make_numbered_dir(root: Path, prefix: str) -> Path:
|
||||
new_number = max_existing + 1
|
||||
new_path = root.joinpath(f"{prefix}{new_number}")
|
||||
try:
|
||||
new_path.mkdir()
|
||||
new_path.mkdir(mode=mode)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
@@ -354,13 +347,13 @@ def cleanup_numbered_dir(
|
||||
|
||||
|
||||
def make_numbered_dir_with_cleanup(
|
||||
root: Path, prefix: str, keep: int, lock_timeout: float
|
||||
root: Path, prefix: str, keep: int, lock_timeout: float, mode: int,
|
||||
) -> Path:
|
||||
"""Create a numbered dir with a cleanup lock and remove old ones."""
|
||||
e = None
|
||||
for i in range(10):
|
||||
try:
|
||||
p = make_numbered_dir(root, prefix)
|
||||
p = make_numbered_dir(root, prefix, mode)
|
||||
lock_path = create_cleanup_lock(p)
|
||||
register_cleanup_lock_removal(lock_path)
|
||||
except Exception as exc:
|
||||
@@ -543,7 +536,7 @@ def import_path(
|
||||
module_file = module_file[: -(len(os.path.sep + "__init__.py"))]
|
||||
|
||||
try:
|
||||
is_same = os.path.samefile(str(path), module_file)
|
||||
is_same = _is_same(str(path), module_file)
|
||||
except FileNotFoundError:
|
||||
is_same = False
|
||||
|
||||
@@ -553,6 +546,20 @@ def import_path(
|
||||
return mod
|
||||
|
||||
|
||||
# Implement a special _is_same function on Windows which returns True if the two filenames
|
||||
# compare equal, to circumvent os.path.samefile returning False for mounts in UNC (#7678).
|
||||
if sys.platform.startswith("win"):
|
||||
|
||||
def _is_same(f1: str, f2: str) -> bool:
|
||||
return Path(f1) == Path(f2) or os.path.samefile(f1, f2)
|
||||
|
||||
|
||||
else:
|
||||
|
||||
def _is_same(f1: str, f2: str) -> bool:
|
||||
return os.path.samefile(f1, f2)
|
||||
|
||||
|
||||
def resolve_package_path(path: Path) -> Optional[Path]:
|
||||
"""Return the Python package path by looking for the last
|
||||
directory upwards which still contains an __init__.py.
|
||||
|
||||
@@ -1426,7 +1426,7 @@ class Pytester:
|
||||
:rtype: RunResult
|
||||
"""
|
||||
__tracebackhide__ = True
|
||||
p = make_numbered_dir(root=self.path, prefix="runpytest-")
|
||||
p = make_numbered_dir(root=self.path, prefix="runpytest-", mode=0o700)
|
||||
args = ("--basetemp=%s" % p,) + args
|
||||
plugins = [x for x in self.plugins if isinstance(x, str)]
|
||||
if plugins:
|
||||
@@ -1445,7 +1445,7 @@ class Pytester:
|
||||
The pexpect child is returned.
|
||||
"""
|
||||
basetemp = self.path / "temp-pexpect"
|
||||
basetemp.mkdir()
|
||||
basetemp.mkdir(mode=0o700)
|
||||
invoke = " ".join(map(str, self._getpytestargs()))
|
||||
cmd = f"{invoke} --basetemp={basetemp} {string}"
|
||||
return self.spawn(cmd, expect_timeout=expect_timeout)
|
||||
|
||||
@@ -15,9 +15,14 @@ from typing import overload
|
||||
from typing import Pattern
|
||||
from typing import Tuple
|
||||
from typing import Type
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TypeVar
|
||||
from typing import Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from numpy import ndarray
|
||||
|
||||
|
||||
import _pytest._code
|
||||
from _pytest.compat import final
|
||||
from _pytest.compat import STRING_TYPES
|
||||
@@ -232,10 +237,11 @@ class ApproxScalar(ApproxBase):
|
||||
def __eq__(self, actual) -> bool:
|
||||
"""Return whether the given value is equal to the expected value
|
||||
within the pre-specified tolerance."""
|
||||
if _is_numpy_array(actual):
|
||||
asarray = _as_numpy_array(actual)
|
||||
if asarray is not None:
|
||||
# Call ``__eq__()`` manually to prevent infinite-recursion with
|
||||
# numpy<1.13. See #3748.
|
||||
return all(self.__eq__(a) for a in actual.flat)
|
||||
return all(self.__eq__(a) for a in asarray.flat)
|
||||
|
||||
# Short-circuit exact equality.
|
||||
if actual == self.expected:
|
||||
@@ -521,6 +527,7 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
|
||||
elif isinstance(expected, Mapping):
|
||||
cls = ApproxMapping
|
||||
elif _is_numpy_array(expected):
|
||||
expected = _as_numpy_array(expected)
|
||||
cls = ApproxNumpy
|
||||
elif (
|
||||
isinstance(expected, Iterable)
|
||||
@@ -536,16 +543,30 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
|
||||
|
||||
|
||||
def _is_numpy_array(obj: object) -> bool:
|
||||
"""Return true if the given object is a numpy array.
|
||||
"""
|
||||
Return true if the given object is implicitly convertible to ndarray,
|
||||
and numpy is already imported.
|
||||
"""
|
||||
return _as_numpy_array(obj) is not None
|
||||
|
||||
A special effort is made to avoid importing numpy unless it's really necessary.
|
||||
|
||||
def _as_numpy_array(obj: object) -> Optional["ndarray"]:
|
||||
"""
|
||||
Return an ndarray if the given object is implicitly convertible to ndarray,
|
||||
and numpy is already imported, otherwise None.
|
||||
"""
|
||||
import sys
|
||||
|
||||
np: Any = sys.modules.get("numpy")
|
||||
if np is not None:
|
||||
return isinstance(obj, np.ndarray)
|
||||
return False
|
||||
# avoid infinite recursion on numpy scalars, which have __array__
|
||||
if np.isscalar(obj):
|
||||
return None
|
||||
elif isinstance(obj, np.ndarray):
|
||||
return obj
|
||||
elif hasattr(obj, "__array__") or hasattr("obj", "__array_interface__"):
|
||||
return np.asarray(obj)
|
||||
return None
|
||||
|
||||
|
||||
# builtin pytest.raises helper
|
||||
|
||||
@@ -1400,4 +1400,6 @@ def _get_raw_skip_reason(report: TestReport) -> str:
|
||||
_, _, reason = report.longrepr
|
||||
if reason.startswith("Skipped: "):
|
||||
reason = reason[len("Skipped: ") :]
|
||||
elif reason == "Skipped":
|
||||
reason = ""
|
||||
return reason
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Support for providing temporary directories to test functions."""
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
@@ -8,10 +9,10 @@ from typing import Optional
|
||||
import attr
|
||||
import py
|
||||
|
||||
from .pathlib import ensure_reset_dir
|
||||
from .pathlib import LOCK_TIMEOUT
|
||||
from .pathlib import make_numbered_dir
|
||||
from .pathlib import make_numbered_dir_with_cleanup
|
||||
from .pathlib import rm_rf
|
||||
from _pytest.compat import final
|
||||
from _pytest.config import Config
|
||||
from _pytest.deprecated import check_ispytest
|
||||
@@ -90,20 +91,22 @@ class TempPathFactory:
|
||||
basename = self._ensure_relative_to_basetemp(basename)
|
||||
if not numbered:
|
||||
p = self.getbasetemp().joinpath(basename)
|
||||
p.mkdir()
|
||||
p.mkdir(mode=0o700)
|
||||
else:
|
||||
p = make_numbered_dir(root=self.getbasetemp(), prefix=basename)
|
||||
p = make_numbered_dir(root=self.getbasetemp(), prefix=basename, mode=0o700)
|
||||
self._trace("mktemp", p)
|
||||
return p
|
||||
|
||||
def getbasetemp(self) -> Path:
|
||||
"""Return base temporary directory."""
|
||||
"""Return the base temporary directory, creating it if needed."""
|
||||
if self._basetemp is not None:
|
||||
return self._basetemp
|
||||
|
||||
if self._given_basetemp is not None:
|
||||
basetemp = self._given_basetemp
|
||||
ensure_reset_dir(basetemp)
|
||||
if basetemp.exists():
|
||||
rm_rf(basetemp)
|
||||
basetemp.mkdir(mode=0o700)
|
||||
basetemp = basetemp.resolve()
|
||||
else:
|
||||
from_env = os.environ.get("PYTEST_DEBUG_TEMPROOT")
|
||||
@@ -112,14 +115,37 @@ class TempPathFactory:
|
||||
# use a sub-directory in the temproot to speed-up
|
||||
# make_numbered_dir() call
|
||||
rootdir = temproot.joinpath(f"pytest-of-{user}")
|
||||
rootdir.mkdir(exist_ok=True)
|
||||
rootdir.mkdir(mode=0o700, exist_ok=True)
|
||||
# Because we use exist_ok=True with a predictable name, make sure
|
||||
# we are the owners, to prevent any funny business (on unix, where
|
||||
# temproot is usually shared).
|
||||
# Also, to keep things private, fixup any world-readable temp
|
||||
# rootdir's permissions. Historically 0o755 was used, so we can't
|
||||
# just error out on this, at least for a while.
|
||||
if sys.platform != "win32":
|
||||
uid = os.getuid()
|
||||
rootdir_stat = rootdir.stat()
|
||||
# getuid shouldn't fail, but cpython defines such a case.
|
||||
# Let's hope for the best.
|
||||
if uid != -1:
|
||||
if rootdir_stat.st_uid != uid:
|
||||
raise OSError(
|
||||
f"The temporary directory {rootdir} is not owned by the current user. "
|
||||
"Fix this and try again."
|
||||
)
|
||||
if (rootdir_stat.st_mode & 0o077) != 0:
|
||||
os.chmod(rootdir, rootdir_stat.st_mode & ~0o077)
|
||||
basetemp = make_numbered_dir_with_cleanup(
|
||||
prefix="pytest-", root=rootdir, keep=3, lock_timeout=LOCK_TIMEOUT
|
||||
prefix="pytest-",
|
||||
root=rootdir,
|
||||
keep=3,
|
||||
lock_timeout=LOCK_TIMEOUT,
|
||||
mode=0o700,
|
||||
)
|
||||
assert basetemp is not None, basetemp
|
||||
self._basetemp = t = basetemp
|
||||
self._trace("new basetemp", t)
|
||||
return t
|
||||
self._basetemp = basetemp
|
||||
self._trace("new basetemp", basetemp)
|
||||
return basetemp
|
||||
|
||||
|
||||
@final
|
||||
|
||||
@@ -1173,7 +1173,7 @@ def test_usage_error_code(pytester: Pytester) -> None:
|
||||
assert result.ret == ExitCode.USAGE_ERROR
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.filterwarnings("default::pytest.PytestUnhandledCoroutineWarning")
|
||||
def test_warn_on_async_function(pytester: Pytester) -> None:
|
||||
# In the below we .close() the coroutine only to avoid
|
||||
# "RuntimeWarning: coroutine 'test_2' was never awaited"
|
||||
@@ -1206,7 +1206,7 @@ def test_warn_on_async_function(pytester: Pytester) -> None:
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.filterwarnings("default::pytest.PytestUnhandledCoroutineWarning")
|
||||
def test_warn_on_async_gen_function(pytester: Pytester) -> None:
|
||||
pytester.makepyfile(
|
||||
test_async="""
|
||||
|
||||
@@ -447,6 +447,36 @@ class TestApprox:
|
||||
assert a12 != approx(a21)
|
||||
assert a21 != approx(a12)
|
||||
|
||||
def test_numpy_array_protocol(self):
|
||||
"""
|
||||
array-like objects such as tensorflow's DeviceArray are handled like ndarray.
|
||||
See issue #8132
|
||||
"""
|
||||
np = pytest.importorskip("numpy")
|
||||
|
||||
class DeviceArray:
|
||||
def __init__(self, value, size):
|
||||
self.value = value
|
||||
self.size = size
|
||||
|
||||
def __array__(self):
|
||||
return self.value * np.ones(self.size)
|
||||
|
||||
class DeviceScalar:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __array__(self):
|
||||
return np.array(self.value)
|
||||
|
||||
expected = 1
|
||||
actual = 1 + 1e-6
|
||||
assert approx(expected) == DeviceArray(actual, size=1)
|
||||
assert approx(expected) == DeviceArray(actual, size=2)
|
||||
assert approx(expected) == DeviceScalar(actual)
|
||||
assert approx(DeviceScalar(expected)) == actual
|
||||
assert approx(DeviceScalar(expected)) == DeviceScalar(actual)
|
||||
|
||||
def test_doctests(self, mocked_doctest_runner) -> None:
|
||||
import doctest
|
||||
|
||||
|
||||
@@ -1210,7 +1210,7 @@ def test_unorderable_types(testdir):
|
||||
assert result.ret == ExitCode.NO_TESTS_COLLECTED
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.filterwarnings("default::pytest.PytestCollectionWarning")
|
||||
def test_dont_collect_non_function_callable(testdir):
|
||||
"""Test for issue https://github.com/pytest-dev/pytest/issues/331
|
||||
|
||||
|
||||
@@ -1212,7 +1212,7 @@ def test_collect_symlink_dir(pytester: Pytester) -> None:
|
||||
"""A symlinked directory is collected."""
|
||||
dir = pytester.mkdir("dir")
|
||||
dir.joinpath("test_it.py").write_text("def test_it(): pass", "utf-8")
|
||||
pytester.path.joinpath("symlink_dir").symlink_to(dir)
|
||||
symlink_or_skip(pytester.path.joinpath("symlink_dir"), dir)
|
||||
result = pytester.runpytest()
|
||||
result.assert_outcomes(passed=2)
|
||||
|
||||
|
||||
@@ -290,7 +290,7 @@ class TestParseIni:
|
||||
result = pytester.runpytest()
|
||||
result.stdout.no_fnmatch_line("*PytestConfigWarning*")
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.filterwarnings("default::pytest.PytestConfigWarning")
|
||||
def test_disable_warnings_plugin_disables_config_warnings(
|
||||
self, pytester: Pytester
|
||||
) -> None:
|
||||
@@ -1247,9 +1247,19 @@ def test_load_initial_conftest_last_ordering(_config_for_test):
|
||||
m = My()
|
||||
pm.register(m)
|
||||
hc = pm.hook.pytest_load_initial_conftests
|
||||
values = hc._nonwrappers + hc._wrappers
|
||||
expected = ["_pytest.config", m.__module__, "_pytest.capture", "_pytest.warnings"]
|
||||
assert [x.function.__module__ for x in values] == expected
|
||||
hookimpls = [
|
||||
(
|
||||
hookimpl.function.__module__,
|
||||
"wrapper" if hookimpl.hookwrapper else "nonwrapper",
|
||||
)
|
||||
for hookimpl in hc.get_hookimpls()
|
||||
]
|
||||
assert hookimpls == [
|
||||
("_pytest.config", "nonwrapper"),
|
||||
(m.__module__, "nonwrapper"),
|
||||
("_pytest.capture", "wrapper"),
|
||||
("_pytest.warnings", "wrapper"),
|
||||
]
|
||||
|
||||
|
||||
def test_get_plugin_specs_as_list() -> None:
|
||||
@@ -1780,7 +1790,7 @@ def test_invocation_args(pytester: Pytester) -> None:
|
||||
)
|
||||
def test_config_blocked_default_plugins(pytester: Pytester, plugin: str) -> None:
|
||||
if plugin == "debugging":
|
||||
# Fixed in xdist master (after 1.27.0).
|
||||
# Fixed in xdist (after 1.27.0).
|
||||
# https://github.com/pytest-dev/pytest-xdist/pull/422
|
||||
try:
|
||||
import xdist # noqa: F401
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import io
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
@@ -135,3 +136,27 @@ def test_already_initialized(faulthandler_timeout: int, pytester: Pytester) -> N
|
||||
result.stdout.no_fnmatch_line(warning_line)
|
||||
result.stdout.fnmatch_lines("*1 passed*")
|
||||
assert result.ret == 0
|
||||
|
||||
|
||||
def test_get_stderr_fileno_invalid_fd() -> None:
|
||||
"""Test for faulthandler being able to handle invalid file descriptors for stderr (#8249)."""
|
||||
from _pytest.faulthandler import FaultHandlerHooks
|
||||
|
||||
class StdErrWrapper(io.StringIO):
|
||||
"""
|
||||
Mimic ``twisted.logger.LoggingFile`` to simulate returning an invalid file descriptor.
|
||||
|
||||
https://github.com/twisted/twisted/blob/twisted-20.3.0/src/twisted/logger/_io.py#L132-L139
|
||||
"""
|
||||
|
||||
def fileno(self):
|
||||
return -1
|
||||
|
||||
wrapper = StdErrWrapper()
|
||||
|
||||
with pytest.MonkeyPatch.context() as mp:
|
||||
mp.setattr("sys.stderr", wrapper)
|
||||
|
||||
# Even when the stderr wrapper signals an invalid file descriptor,
|
||||
# ``_get_stderr_fileno()`` should return the real one.
|
||||
assert FaultHandlerHooks._get_stderr_fileno() == 2
|
||||
|
||||
@@ -7,6 +7,7 @@ from textwrap import dedent
|
||||
import py
|
||||
|
||||
import pytest
|
||||
from _pytest.monkeypatch import MonkeyPatch
|
||||
from _pytest.pathlib import bestrelpath
|
||||
from _pytest.pathlib import commonpath
|
||||
from _pytest.pathlib import ensure_deletable
|
||||
@@ -414,3 +415,23 @@ def test_visit_ignores_errors(tmpdir) -> None:
|
||||
"bar",
|
||||
"foo",
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only")
|
||||
def test_samefile_false_negatives(tmp_path: Path, monkeypatch: MonkeyPatch) -> None:
|
||||
"""
|
||||
import_file() should not raise ImportPathMismatchError if the paths are exactly
|
||||
equal on Windows. It seems directories mounted as UNC paths make os.path.samefile
|
||||
return False, even when they are clearly equal.
|
||||
"""
|
||||
module_path = tmp_path.joinpath("my_module.py")
|
||||
module_path.write_text("def foo(): return 42")
|
||||
monkeypatch.syspath_prepend(tmp_path)
|
||||
|
||||
with monkeypatch.context() as mp:
|
||||
# Forcibly make os.path.samefile() return False here to ensure we are comparing
|
||||
# the paths too. Using a context to narrow the patch as much as possible given
|
||||
# this is an important system function.
|
||||
mp.setattr(os.path, "samefile", lambda x, y: False)
|
||||
module = import_path(module_path)
|
||||
assert getattr(module, "foo")() == 42
|
||||
|
||||
@@ -27,6 +27,17 @@ def test_recwarn_functional(pytester: Pytester) -> None:
|
||||
reprec.assertoutcome(passed=1)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("")
|
||||
def test_recwarn_captures_deprecation_warning(recwarn: WarningsRecorder) -> None:
|
||||
"""
|
||||
Check that recwarn can capture DeprecationWarning by default
|
||||
without custom filterwarnings (see #8666).
|
||||
"""
|
||||
warnings.warn(DeprecationWarning("some deprecation"))
|
||||
assert len(recwarn) == 1
|
||||
assert recwarn.pop(DeprecationWarning)
|
||||
|
||||
|
||||
class TestWarningsRecorderChecker:
|
||||
def test_recording(self) -> None:
|
||||
rec = WarningsRecorder(_ispytest=True)
|
||||
|
||||
@@ -1128,19 +1128,30 @@ def test_errors_in_xfail_skip_expressions(pytester: Pytester) -> None:
|
||||
markline = markline[5:]
|
||||
elif sys.version_info >= (3, 8) or hasattr(sys, "pypy_version_info"):
|
||||
markline = markline[4:]
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
|
||||
if sys.version_info[:2] >= (3, 10):
|
||||
expected = [
|
||||
"*ERROR*test_nameerror*",
|
||||
"*evaluating*skipif*condition*",
|
||||
"*asd*",
|
||||
"*ERROR*test_syntax*",
|
||||
"*evaluating*xfail*condition*",
|
||||
" syntax error",
|
||||
markline,
|
||||
"SyntaxError: invalid syntax",
|
||||
"*1 pass*2 errors*",
|
||||
"",
|
||||
"During handling of the above exception, another exception occurred:",
|
||||
]
|
||||
)
|
||||
else:
|
||||
expected = [
|
||||
"*ERROR*test_nameerror*",
|
||||
]
|
||||
|
||||
expected += [
|
||||
"*evaluating*skipif*condition*",
|
||||
"*asd*",
|
||||
"*ERROR*test_syntax*",
|
||||
"*evaluating*xfail*condition*",
|
||||
" syntax error",
|
||||
markline,
|
||||
"SyntaxError: invalid syntax",
|
||||
"*1 pass*2 errors*",
|
||||
]
|
||||
result.stdout.fnmatch_lines(expected)
|
||||
|
||||
|
||||
def test_xfail_skipif_with_globals(pytester: Pytester) -> None:
|
||||
|
||||
@@ -366,6 +366,26 @@ class TestTerminal:
|
||||
@pytest.mark.xfail(reason="")
|
||||
def test_4():
|
||||
assert False
|
||||
|
||||
@pytest.mark.skip
|
||||
def test_5():
|
||||
pass
|
||||
|
||||
@pytest.mark.xfail
|
||||
def test_6():
|
||||
pass
|
||||
|
||||
def test_7():
|
||||
pytest.skip()
|
||||
|
||||
def test_8():
|
||||
pytest.skip("888 is great")
|
||||
|
||||
def test_9():
|
||||
pytest.xfail()
|
||||
|
||||
def test_10():
|
||||
pytest.xfail("It's 🕙 o'clock")
|
||||
"""
|
||||
)
|
||||
result = pytester.runpytest("-v")
|
||||
@@ -375,6 +395,12 @@ class TestTerminal:
|
||||
"test_verbose_skip_reason.py::test_2 XPASS (456) *",
|
||||
"test_verbose_skip_reason.py::test_3 XFAIL (789) *",
|
||||
"test_verbose_skip_reason.py::test_4 XFAIL *",
|
||||
"test_verbose_skip_reason.py::test_5 SKIPPED (unconditional skip) *",
|
||||
"test_verbose_skip_reason.py::test_6 XPASS *",
|
||||
"test_verbose_skip_reason.py::test_7 SKIPPED *",
|
||||
"test_verbose_skip_reason.py::test_8 SKIPPED (888 is great) *",
|
||||
"test_verbose_skip_reason.py::test_9 XFAIL *",
|
||||
"test_verbose_skip_reason.py::test_10 XFAIL (It's 🕙 o'clock) *",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -1592,7 +1618,7 @@ def test_terminal_summary(pytester: Pytester) -> None:
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.filterwarnings("default::UserWarning")
|
||||
def test_terminal_summary_warnings_are_displayed(pytester: Pytester) -> None:
|
||||
"""Test that warnings emitted during pytest_terminal_summary are displayed.
|
||||
(#1305).
|
||||
@@ -1629,7 +1655,7 @@ def test_terminal_summary_warnings_are_displayed(pytester: Pytester) -> None:
|
||||
assert stdout.count("=== warnings summary ") == 2
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.filterwarnings("default::UserWarning")
|
||||
def test_terminal_summary_warnings_header_once(pytester: Pytester) -> None:
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
|
||||
@@ -8,7 +8,7 @@ if sys.version_info < (3, 8):
|
||||
pytest.skip("threadexception plugin needs Python>=3.8", allow_module_level=True)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.filterwarnings("default::pytest.PytestUnhandledThreadExceptionWarning")
|
||||
def test_unhandled_thread_exception(pytester: Pytester) -> None:
|
||||
pytester.makepyfile(
|
||||
test_it="""
|
||||
@@ -42,7 +42,7 @@ def test_unhandled_thread_exception(pytester: Pytester) -> None:
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.filterwarnings("default::pytest.PytestUnhandledThreadExceptionWarning")
|
||||
def test_unhandled_thread_exception_in_setup(pytester: Pytester) -> None:
|
||||
pytester.makepyfile(
|
||||
test_it="""
|
||||
@@ -78,7 +78,7 @@ def test_unhandled_thread_exception_in_setup(pytester: Pytester) -> None:
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.filterwarnings("default::pytest.PytestUnhandledThreadExceptionWarning")
|
||||
def test_unhandled_thread_exception_in_teardown(pytester: Pytester) -> None:
|
||||
pytester.makepyfile(
|
||||
test_it="""
|
||||
|
||||
@@ -445,3 +445,44 @@ def test_basetemp_with_read_only_files(pytester: Pytester) -> None:
|
||||
# running a second time and ensure we don't crash
|
||||
result = pytester.runpytest("--basetemp=tmp")
|
||||
assert result.ret == 0
|
||||
|
||||
|
||||
@pytest.mark.skipif(not hasattr(os, "getuid"), reason="checks unix permissions")
|
||||
def test_tmp_path_factory_create_directory_with_safe_permissions(
|
||||
tmp_path: Path, monkeypatch,
|
||||
) -> None:
|
||||
"""Verify that pytest creates directories under /tmp with private permissions."""
|
||||
# Use the test's tmp_path as the system temproot (/tmp).
|
||||
monkeypatch.setenv("PYTEST_DEBUG_TEMPROOT", str(tmp_path))
|
||||
tmp_factory = TempPathFactory(None, lambda *args: None, _ispytest=True)
|
||||
basetemp = tmp_factory.getbasetemp()
|
||||
|
||||
# No world-readable permissions.
|
||||
assert (basetemp.stat().st_mode & 0o077) == 0
|
||||
# Parent too (pytest-of-foo).
|
||||
assert (basetemp.parent.stat().st_mode & 0o077) == 0
|
||||
|
||||
|
||||
@pytest.mark.skipif(not hasattr(os, "getuid"), reason="checks unix permissions")
|
||||
def test_tmp_path_factory_fixes_up_world_readable_permissions(
|
||||
tmp_path: Path, monkeypatch,
|
||||
) -> None:
|
||||
"""Verify that if a /tmp/pytest-of-foo directory already exists with
|
||||
world-readable permissions, it is fixed.
|
||||
|
||||
pytest used to mkdir with such permissions, that's why we fix it up.
|
||||
"""
|
||||
# Use the test's tmp_path as the system temproot (/tmp).
|
||||
monkeypatch.setenv("PYTEST_DEBUG_TEMPROOT", str(tmp_path))
|
||||
tmp_factory = TempPathFactory(None, lambda *args: None, _ispytest=True)
|
||||
basetemp = tmp_factory.getbasetemp()
|
||||
|
||||
# Before - simulate bad perms.
|
||||
os.chmod(basetemp.parent, 0o777)
|
||||
assert (basetemp.parent.stat().st_mode & 0o077) != 0
|
||||
|
||||
tmp_factory = TempPathFactory(None, lambda *args: None, _ispytest=True)
|
||||
basetemp = tmp_factory.getbasetemp()
|
||||
|
||||
# After - fixed.
|
||||
assert (basetemp.parent.stat().st_mode & 0o077) == 0
|
||||
|
||||
@@ -533,7 +533,9 @@ class TestTrialUnittest:
|
||||
# will crash both at test time and at teardown
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest("-vv", "-oconsole_output_style=classic")
|
||||
result = testdir.runpytest(
|
||||
"-vv", "-oconsole_output_style=classic", "-W", "ignore::DeprecationWarning"
|
||||
)
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"test_trial_error.py::TC::test_four FAILED",
|
||||
|
||||
@@ -8,7 +8,7 @@ if sys.version_info < (3, 8):
|
||||
pytest.skip("unraisableexception plugin needs Python>=3.8", allow_module_level=True)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.filterwarnings("default::pytest.PytestUnraisableExceptionWarning")
|
||||
def test_unraisable(pytester: Pytester) -> None:
|
||||
pytester.makepyfile(
|
||||
test_it="""
|
||||
@@ -40,7 +40,7 @@ def test_unraisable(pytester: Pytester) -> None:
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.filterwarnings("default::pytest.PytestUnraisableExceptionWarning")
|
||||
def test_unraisable_in_setup(pytester: Pytester) -> None:
|
||||
pytester.makepyfile(
|
||||
test_it="""
|
||||
@@ -76,7 +76,7 @@ def test_unraisable_in_setup(pytester: Pytester) -> None:
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.filterwarnings("default::pytest.PytestUnraisableExceptionWarning")
|
||||
def test_unraisable_in_teardown(pytester: Pytester) -> None:
|
||||
pytester.makepyfile(
|
||||
test_it="""
|
||||
|
||||
@@ -38,7 +38,7 @@ def pyfile_with_warnings(testdir: Testdir, request: FixtureRequest) -> str:
|
||||
return str(test_file)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.filterwarnings("default::UserWarning", "default::RuntimeWarning")
|
||||
def test_normal_flow(testdir, pyfile_with_warnings):
|
||||
"""Check that the warnings section is displayed."""
|
||||
result = testdir.runpytest(pyfile_with_warnings)
|
||||
@@ -55,7 +55,7 @@ def test_normal_flow(testdir, pyfile_with_warnings):
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("always")
|
||||
@pytest.mark.filterwarnings("always::UserWarning")
|
||||
def test_setup_teardown_warnings(testdir):
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
@@ -123,7 +123,7 @@ def test_ignore(testdir, pyfile_with_warnings, method):
|
||||
assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("always")
|
||||
@pytest.mark.filterwarnings("always::UserWarning")
|
||||
def test_unicode(testdir):
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
@@ -182,7 +182,7 @@ def test_filterwarnings_mark(testdir, default_config):
|
||||
testdir.makeini(
|
||||
"""
|
||||
[pytest]
|
||||
filterwarnings = always
|
||||
filterwarnings = always::RuntimeWarning
|
||||
"""
|
||||
)
|
||||
testdir.makepyfile(
|
||||
@@ -202,7 +202,9 @@ def test_filterwarnings_mark(testdir, default_config):
|
||||
warnings.warn(RuntimeWarning())
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest("-W always" if default_config == "cmdline" else "")
|
||||
result = testdir.runpytest(
|
||||
"-W always::RuntimeWarning" if default_config == "cmdline" else ""
|
||||
)
|
||||
result.stdout.fnmatch_lines(["*= 1 failed, 2 passed, 1 warning in *"])
|
||||
|
||||
|
||||
@@ -217,7 +219,7 @@ def test_non_string_warning_argument(testdir):
|
||||
warnings.warn(UserWarning(1, 'foo'))
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest("-W", "always")
|
||||
result = testdir.runpytest("-W", "always::UserWarning")
|
||||
result.stdout.fnmatch_lines(["*= 1 passed, 1 warning in *"])
|
||||
|
||||
|
||||
@@ -236,7 +238,7 @@ def test_filterwarnings_mark_registration(testdir):
|
||||
assert result.ret == 0
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("always")
|
||||
@pytest.mark.filterwarnings("always::UserWarning")
|
||||
def test_warning_captured_hook(testdir):
|
||||
testdir.makeconftest(
|
||||
"""
|
||||
@@ -297,7 +299,7 @@ def test_warning_captured_hook(testdir):
|
||||
assert collected_result[3] is None, str(collected)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("always")
|
||||
@pytest.mark.filterwarnings("always::UserWarning")
|
||||
def test_collection_warnings(testdir):
|
||||
"""Check that we also capture warnings issued during test collection (#3251)."""
|
||||
testdir.makepyfile(
|
||||
@@ -321,7 +323,7 @@ def test_collection_warnings(testdir):
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("always")
|
||||
@pytest.mark.filterwarnings("always::UserWarning")
|
||||
def test_mark_regex_escape(testdir):
|
||||
"""@pytest.mark.filterwarnings should not try to escape regex characters (#3936)"""
|
||||
testdir.makepyfile(
|
||||
@@ -337,7 +339,7 @@ def test_mark_regex_escape(testdir):
|
||||
assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("default")
|
||||
@pytest.mark.filterwarnings("default::pytest.PytestWarning")
|
||||
@pytest.mark.parametrize("ignore_pytest_warnings", ["no", "ini", "cmdline"])
|
||||
def test_hide_pytest_internal_warnings(testdir, ignore_pytest_warnings):
|
||||
"""Make sure we can ignore internal pytest warnings using a warnings filter."""
|
||||
@@ -383,7 +385,7 @@ def test_option_precedence_cmdline_over_ini(testdir, ignore_on_cmdline):
|
||||
testdir.makeini(
|
||||
"""
|
||||
[pytest]
|
||||
filterwarnings = error
|
||||
filterwarnings = error::UserWarning
|
||||
"""
|
||||
)
|
||||
testdir.makepyfile(
|
||||
@@ -578,7 +580,7 @@ def test_warnings_checker_twice():
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore::pytest.PytestExperimentalApiWarning")
|
||||
@pytest.mark.filterwarnings("always")
|
||||
@pytest.mark.filterwarnings("always::UserWarning")
|
||||
def test_group_warnings_by_message(testdir):
|
||||
testdir.copy_example("warnings/test_group_warnings_by_message.py")
|
||||
result = testdir.runpytest()
|
||||
@@ -610,7 +612,7 @@ def test_group_warnings_by_message(testdir):
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore::pytest.PytestExperimentalApiWarning")
|
||||
@pytest.mark.filterwarnings("always")
|
||||
@pytest.mark.filterwarnings("always::UserWarning")
|
||||
def test_group_warnings_by_message_summary(testdir):
|
||||
testdir.copy_example("warnings/test_group_warnings_by_message_summary")
|
||||
testdir.syspathinsert()
|
||||
|
||||
5
tox.ini
@@ -9,8 +9,9 @@ envlist =
|
||||
py37
|
||||
py38
|
||||
py39
|
||||
py310
|
||||
pypy3
|
||||
py37-{pexpect,xdist,unittestextras,numpy,pluggymaster}
|
||||
py37-{pexpect,xdist,unittestextras,numpy,pluggymain}
|
||||
doctesting
|
||||
plugins
|
||||
py37-freeze
|
||||
@@ -46,7 +47,7 @@ deps =
|
||||
doctesting: PyYAML
|
||||
numpy: numpy>=1.19.4
|
||||
pexpect: pexpect>=4.8.0
|
||||
pluggymaster: git+https://github.com/pytest-dev/pluggy.git@master
|
||||
pluggymain: pluggy @ git+https://github.com/pytest-dev/pluggy.git
|
||||
pygments>=2.7.2
|
||||
unittestextras: twisted
|
||||
unittestextras: asynctest
|
||||
|
||||