Compare commits
29 Commits
7.1.0.dev0
...
6.2.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
e7073afe6e |
@@ -25,7 +25,6 @@ exclude_lines =
|
||||
^\s*raise NotImplementedError\b
|
||||
^\s*return NotImplemented\b
|
||||
^\s*assert False(,|$)
|
||||
^\s*assert_never\(
|
||||
|
||||
^\s*if TYPE_CHECKING:
|
||||
^\s*@overload( |$)
|
||||
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -13,7 +13,7 @@ If this change fixes an issue, please:
|
||||
|
||||
Unless your change is trivial or a small documentation fix (e.g., a typo or reword of a small section) please:
|
||||
|
||||
- [ ] Create a new changelog file in the `changelog` folder, with a name like `<ISSUE NUMBER>.<TYPE>.rst`. See [changelog/README.rst](https://github.com/pytest-dev/pytest/blob/main/changelog/README.rst) for details.
|
||||
- [ ] Create a new changelog file in the `changelog` folder, with a name like `<ISSUE NUMBER>.<TYPE>.rst`. See [changelog/README.rst](https://github.com/pytest-dev/pytest/blob/master/changelog/README.rst) for details.
|
||||
|
||||
Write sentences in the **past or present tense**, examples:
|
||||
|
||||
|
||||
90
.github/workflows/main.yml
vendored
@@ -3,7 +3,7 @@ name: main
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
- "[0-9]+.[0-9]+.x"
|
||||
tags:
|
||||
- "[0-9]+.[0-9]+.[0-9]+"
|
||||
@@ -11,21 +11,13 @@ on:
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
- "[0-9]+.[0-9]+.x"
|
||||
|
||||
env:
|
||||
PYTEST_ADDOPTS: "--color=yes"
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -35,8 +27,6 @@ jobs:
|
||||
"windows-py37",
|
||||
"windows-py37-pluggy",
|
||||
"windows-py38",
|
||||
"windows-py39",
|
||||
"windows-py310",
|
||||
|
||||
"ubuntu-py36",
|
||||
"ubuntu-py37",
|
||||
@@ -44,7 +34,6 @@ jobs:
|
||||
"ubuntu-py37-freeze",
|
||||
"ubuntu-py38",
|
||||
"ubuntu-py39",
|
||||
"ubuntu-py310",
|
||||
"ubuntu-pypy3",
|
||||
|
||||
"macos-py37",
|
||||
@@ -67,20 +56,12 @@ jobs:
|
||||
- name: "windows-py37-pluggy"
|
||||
python: "3.7"
|
||||
os: windows-latest
|
||||
tox_env: "py37-pluggymain-xdist"
|
||||
tox_env: "py37-pluggymaster-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-dev"
|
||||
os: windows-latest
|
||||
tox_env: "py310-xdist"
|
||||
|
||||
- name: "ubuntu-py36"
|
||||
python: "3.6"
|
||||
@@ -94,7 +75,7 @@ jobs:
|
||||
- name: "ubuntu-py37-pluggy"
|
||||
python: "3.7"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py37-pluggymain-xdist"
|
||||
tox_env: "py37-pluggymaster-xdist"
|
||||
- name: "ubuntu-py37-freeze"
|
||||
python: "3.7"
|
||||
os: ubuntu-latest
|
||||
@@ -107,12 +88,8 @@ jobs:
|
||||
python: "3.9"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py39-xdist"
|
||||
- name: "ubuntu-py310"
|
||||
python: "3.10-dev"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py310-xdist"
|
||||
- name: "ubuntu-pypy3"
|
||||
python: "pypy-3.7"
|
||||
python: "pypy3"
|
||||
os: ubuntu-latest
|
||||
tox_env: "pypy3-xdist"
|
||||
|
||||
@@ -145,13 +122,10 @@ 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
|
||||
@@ -163,27 +137,45 @@ jobs:
|
||||
|
||||
- name: Test with coverage
|
||||
if: "matrix.use_coverage"
|
||||
run: "tox -e ${{ matrix.tox_env }}-coverage"
|
||||
env:
|
||||
_PYTEST_TOX_COVERAGE_RUN: "coverage run -m"
|
||||
COVERAGE_PROCESS_START: ".coveragerc"
|
||||
_PYTEST_TOX_EXTRA_DEP: "coverage-enable-subprocess"
|
||||
run: "tox -e ${{ matrix.tox_env }}"
|
||||
|
||||
- name: Generate coverage report
|
||||
if: "matrix.use_coverage"
|
||||
run: python -m coverage xml
|
||||
- name: Prepare coverage token
|
||||
if: (matrix.use_coverage && ( github.repository == 'pytest-dev/pytest' || github.event_name == 'pull_request' ))
|
||||
run: |
|
||||
python scripts/append_codecov_token.py
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
if: "matrix.use_coverage"
|
||||
uses: codecov/codecov-action@v2
|
||||
- name: Report coverage
|
||||
if: (matrix.use_coverage)
|
||||
env:
|
||||
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:
|
||||
fail_ci_if_error: true
|
||||
files: ./coverage.xml
|
||||
verbose: true
|
||||
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]
|
||||
|
||||
@@ -191,31 +183,25 @@ 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 build tox
|
||||
|
||||
pip install --upgrade wheel setuptools tox
|
||||
- name: Build package
|
||||
run: |
|
||||
python -m build
|
||||
|
||||
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: ${{ github.token }}
|
||||
GH_RELEASE_NOTES_TOKEN: ${{ secrets.release_notes }}
|
||||
run: |
|
||||
sudo apt-get install pandoc
|
||||
tox -e publish-gh-release-notes
|
||||
|
||||
52
.github/workflows/prepare-release-pr.yml
vendored
@@ -1,52 +0,0 @@
|
||||
name: prepare release pr
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch:
|
||||
description: 'Branch to base the release from'
|
||||
required: true
|
||||
default: ''
|
||||
major:
|
||||
description: 'Major release? (yes/no)'
|
||||
required: true
|
||||
default: 'no'
|
||||
prerelease:
|
||||
description: 'Prerelease (ex: rc1). Leave empty if not a pre-release.'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- 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 PR (minor/patch release)
|
||||
if: github.event.inputs.major == 'no'
|
||||
run: |
|
||||
tox -e prepare-release-pr -- ${{ github.event.inputs.branch }} ${{ github.token }} --prerelease='${{ github.event.inputs.prerelease }}'
|
||||
|
||||
- name: Prepare release PR (major release)
|
||||
if: github.event.inputs.major == 'yes'
|
||||
run: |
|
||||
tox -e prepare-release-pr -- ${{ github.event.inputs.branch }} ${{ github.token }} --major --prerelease='${{ github.event.inputs.prerelease }}'
|
||||
31
.github/workflows/release-on-comment.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# part of our release process, see `release-on-comment.py`
|
||||
name: release on comment
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened, edited]
|
||||
issue_comment:
|
||||
types: [created, edited]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
if: (github.event.comment && startsWith(github.event.comment.body, '@pytestbot please')) || (github.event.issue && !github.event.comment && startsWith(github.event.issue.body, '@pytestbot please'))
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- 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 }}
|
||||
48
.github/workflows/update-plugin-list.yml
vendored
@@ -1,48 +0,0 @@
|
||||
name: Update Plugin List
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# At 00:00 on Sunday.
|
||||
# https://crontab.guru
|
||||
- cron: '0 0 * * 0'
|
||||
workflow_dispatch:
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
createPullRequest:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install packaging requests tabulate[widechars] tqdm
|
||||
|
||||
- name: Update Plugin List
|
||||
run: python scripts/update-plugin-list.py
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@2455e1596942c2902952003bbb574afbbe2ab2e6
|
||||
with:
|
||||
commit-message: '[automated] Update plugin list'
|
||||
author: 'pytest bot <pytestbot@users.noreply.github.com>'
|
||||
branch: update-plugin-list/patch
|
||||
delete-branch: true
|
||||
branch-suffix: short-commit-hash
|
||||
title: '[automated] Update plugin list'
|
||||
body: '[automated] Update plugin list'
|
||||
3
.gitignore
vendored
@@ -53,6 +53,3 @@ coverage.xml
|
||||
|
||||
# generated by pip
|
||||
pip-wheel-metadata/
|
||||
|
||||
# pytest debug logs generated via --debug
|
||||
pytestdebug.log
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 21.11b1
|
||||
rev: 19.10b0
|
||||
hooks:
|
||||
- id: black
|
||||
args: [--safe, --quiet]
|
||||
- repo: https://github.com/asottile/blacken-docs
|
||||
rev: v1.12.0
|
||||
rev: v1.8.0
|
||||
hooks:
|
||||
- id: blacken-docs
|
||||
additional_dependencies: [black==20.8b1]
|
||||
additional_dependencies: [black==19.10b0]
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.0.1
|
||||
rev: v3.2.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
@@ -20,8 +20,8 @@ repos:
|
||||
- id: debug-statements
|
||||
exclude: _pytest/(debugging|hookspec).py
|
||||
language_version: python3
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 4.0.1
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.8.3
|
||||
hooks:
|
||||
- id: flake8
|
||||
language_version: python3
|
||||
@@ -29,26 +29,27 @@ repos:
|
||||
- flake8-typing-imports==1.9.0
|
||||
- flake8-docstrings==1.5.0
|
||||
- repo: https://github.com/asottile/reorder_python_imports
|
||||
rev: v2.6.0
|
||||
rev: v2.3.5
|
||||
hooks:
|
||||
- id: reorder-python-imports
|
||||
args: ['--application-directories=.:src', --py36-plus]
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.29.1
|
||||
rev: v2.7.2
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py36-plus]
|
||||
- repo: https://github.com/asottile/setup-cfg-fmt
|
||||
rev: v1.20.0
|
||||
rev: v1.11.0
|
||||
hooks:
|
||||
- id: setup-cfg-fmt
|
||||
args: [--max-py-version=3.10]
|
||||
# TODO: when upgrading setup-cfg-fmt this can be removed
|
||||
args: [--max-py-version=3.9]
|
||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||
rev: v1.9.0
|
||||
rev: v1.6.0
|
||||
hooks:
|
||||
- id: python-use-type-annotations
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v0.910-1
|
||||
rev: v0.790
|
||||
hooks:
|
||||
- id: mypy
|
||||
files: ^(src/|testing/)
|
||||
@@ -58,9 +59,6 @@ repos:
|
||||
- py>=1.8.2
|
||||
- attrs>=19.2.0
|
||||
- packaging
|
||||
- tomli
|
||||
- types-atomicwrites
|
||||
- types-pkg_resources
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: rst
|
||||
@@ -91,9 +89,3 @@ repos:
|
||||
xml\.
|
||||
)
|
||||
types: [python]
|
||||
- id: py-path-deprecated
|
||||
name: py.path usage is deprecated
|
||||
exclude: docs|src/_pytest/deprecated.py|testing/deprecated_test.py
|
||||
language: pygrep
|
||||
entry: \bpy\.path\.local
|
||||
types: [python]
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
version: 2
|
||||
|
||||
python:
|
||||
version: 3.7
|
||||
install:
|
||||
- requirements: doc/en/requirements.txt
|
||||
- method: pip
|
||||
path: .
|
||||
|
||||
build:
|
||||
os: ubuntu-20.04
|
||||
tools:
|
||||
python: "3.9"
|
||||
apt_packages:
|
||||
- inkscape
|
||||
|
||||
formats:
|
||||
- epub
|
||||
- pdf
|
||||
- htmlzip
|
||||
|
||||
26
AUTHORS
@@ -5,7 +5,6 @@ Contributors include::
|
||||
|
||||
Aaron Coleman
|
||||
Abdeali JK
|
||||
Abdelrahman Elbehery
|
||||
Abhijeet Kasurde
|
||||
Adam Johnson
|
||||
Adam Uhlir
|
||||
@@ -13,7 +12,6 @@ Ahn Ki-Wook
|
||||
Akiomi Kamakura
|
||||
Alan Velasco
|
||||
Alexander Johnson
|
||||
Alexander King
|
||||
Alexei Kozlenok
|
||||
Allan Feldman
|
||||
Aly Sivji
|
||||
@@ -25,7 +23,6 @@ Andras Tim
|
||||
Andrea Cimatoribus
|
||||
Andreas Motl
|
||||
Andreas Zeidler
|
||||
Andrew Shapton
|
||||
Andrey Paramonov
|
||||
Andrzej Klajnert
|
||||
Andrzej Ostrowski
|
||||
@@ -33,11 +30,9 @@ Andy Freeland
|
||||
Anthon van der Neut
|
||||
Anthony Shaw
|
||||
Anthony Sottile
|
||||
Anton Grinevich
|
||||
Anton Lodder
|
||||
Antony Lee
|
||||
Arel Cordero
|
||||
Arias Emmanuel
|
||||
Ariel Pillemer
|
||||
Armin Rigo
|
||||
Aron Coyle
|
||||
@@ -45,7 +40,6 @@ Aron Curzon
|
||||
Aviral Verma
|
||||
Aviv Palivoda
|
||||
Barney Gale
|
||||
Ben Gartner
|
||||
Ben Webb
|
||||
Benjamin Peterson
|
||||
Bernard Pratz
|
||||
@@ -64,7 +58,6 @@ Charles Machalow
|
||||
Charnjit SiNGH (CCSJ)
|
||||
Chris Lamb
|
||||
Chris NeJame
|
||||
Chris Rose
|
||||
Christian Boelsen
|
||||
Christian Fetzer
|
||||
Christian Neumüller
|
||||
@@ -77,14 +70,12 @@ Christopher Gilling
|
||||
Claire Cecil
|
||||
Claudio Madotto
|
||||
CrazyMerlyn
|
||||
Cristian Vera
|
||||
Cyrus Maden
|
||||
Damian Skrzypczak
|
||||
Daniel Grana
|
||||
Daniel Hahler
|
||||
Daniel Nuri
|
||||
Daniel Wandschneider
|
||||
Daniele Procida
|
||||
Danielle Jenkins
|
||||
Daniil Galiev
|
||||
Dave Hunt
|
||||
@@ -96,7 +87,6 @@ David Vierra
|
||||
Daw-Ran Liou
|
||||
Debi Mishra
|
||||
Denis Kirisov
|
||||
Denivy Braiam Rück
|
||||
Dhiren Serai
|
||||
Diego Russo
|
||||
Dmitry Dygalo
|
||||
@@ -105,14 +95,11 @@ Dominic Mortlock
|
||||
Duncan Betts
|
||||
Edison Gustavo Muenz
|
||||
Edoardo Batini
|
||||
Edson Tadeu M. Manoel
|
||||
Eduardo Schettino
|
||||
Eli Boyarski
|
||||
Elizaveta Shashkova
|
||||
Éloi Rivard
|
||||
Endre Galaczi
|
||||
Eric Hunsberger
|
||||
Eric Liu
|
||||
Eric Siegerman
|
||||
Erik Aronesty
|
||||
Erik M. Bray
|
||||
@@ -129,9 +116,7 @@ Garvit Shubham
|
||||
Gene Wood
|
||||
George Kussumoto
|
||||
Georgy Dyuldin
|
||||
Gergely Kalmár
|
||||
Gleb Nikonorov
|
||||
Graeme Smecher
|
||||
Graham Horler
|
||||
Greg Price
|
||||
Gregory Lee
|
||||
@@ -140,7 +125,6 @@ Grigorii Eremeev (budulianin)
|
||||
Guido Wesdorp
|
||||
Guoqiang Zhang
|
||||
Harald Armin Massa
|
||||
Harshna
|
||||
Henk-Jaap Wagenaar
|
||||
Holger Kohr
|
||||
Hugo van Kemenade
|
||||
@@ -153,7 +137,6 @@ Iwan Briquemont
|
||||
Jaap Broekhuizen
|
||||
Jakob van Santen
|
||||
Jakub Mitoraj
|
||||
James Bourbeau
|
||||
Jan Balster
|
||||
Janne Vanhala
|
||||
Jason R. Coombs
|
||||
@@ -174,7 +157,6 @@ Josh Karpel
|
||||
Joshua Bronson
|
||||
Jurko Gospodnetić
|
||||
Justyna Janczyszyn
|
||||
Justice Ndou
|
||||
Kale Kundert
|
||||
Kamran Ahmad
|
||||
Karl O. Pinc
|
||||
@@ -229,7 +211,6 @@ Michael Goerz
|
||||
Michael Krebs
|
||||
Michael Seifert
|
||||
Michal Wajszczuk
|
||||
Michał Zięba
|
||||
Mihai Capotă
|
||||
Mike Hoyle (hoylemd)
|
||||
Mike Lundy
|
||||
@@ -243,7 +224,6 @@ Nicholas Murphy
|
||||
Niclas Olofsson
|
||||
Nicolas Delaby
|
||||
Nikolay Kondratyev
|
||||
Olga Matoula
|
||||
Oleg Pidsadnyi
|
||||
Oleg Sushchenko
|
||||
Oliver Bestwalter
|
||||
@@ -251,7 +231,6 @@ Omar Kohl
|
||||
Omer Hadari
|
||||
Ondřej Súkup
|
||||
Oscar Benjamin
|
||||
Parth Patel
|
||||
Patrick Hayes
|
||||
Pauli Virtanen
|
||||
Pavel Karateev
|
||||
@@ -286,7 +265,6 @@ Ross Lawley
|
||||
Ruaridh Williamson
|
||||
Russel Winder
|
||||
Ryan Wooden
|
||||
Saiprasad Kale
|
||||
Samuel Dion-Girardeau
|
||||
Samuel Searles-Bryant
|
||||
Samuele Pedroni
|
||||
@@ -295,7 +273,6 @@ Sankt Petersbug
|
||||
Segev Finer
|
||||
Serhii Mozghovyi
|
||||
Seth Junot
|
||||
Shantanu Jain
|
||||
Shubham Adep
|
||||
Simon Gomizelj
|
||||
Simon Kerr
|
||||
@@ -311,12 +288,10 @@ Sven-Hendrik Haase
|
||||
Sylvain Marié
|
||||
Tadek Teleżyński
|
||||
Takafumi Arakaki
|
||||
Taneli Hukkinen
|
||||
Tanvi Mehta
|
||||
Tarcisio Fischer
|
||||
Tareq Alayan
|
||||
Ted Xiao
|
||||
Terje Runde
|
||||
Thomas Grainger
|
||||
Thomas Hisch
|
||||
Tim Hoffmann
|
||||
@@ -349,6 +324,5 @@ Xuan Luong
|
||||
Xuecong Liao
|
||||
Yoav Caspi
|
||||
Zac Hatfield-Dodds
|
||||
Zachary Kneupper
|
||||
Zoltán Máté
|
||||
Zsolt Cserna
|
||||
|
||||
@@ -4,4 +4,4 @@ Changelog
|
||||
|
||||
The pytest CHANGELOG is located `here <https://docs.pytest.org/en/stable/changelog.html>`__.
|
||||
|
||||
The source document can be found at: https://github.com/pytest-dev/pytest/blob/main/doc/en/changelog.rst
|
||||
The source document can be found at: https://github.com/pytest-dev/pytest/blob/master/doc/en/changelog.rst
|
||||
|
||||
@@ -160,7 +160,7 @@ the following:
|
||||
|
||||
- an issue tracker for bug reports and enhancement requests.
|
||||
|
||||
- a `changelog <https://keepachangelog.com/>`_.
|
||||
- a `changelog <http://keepachangelog.com/>`_.
|
||||
|
||||
If no contributor strongly objects and two agree, the repository can then be
|
||||
transferred to the ``pytest-dev`` organisation.
|
||||
@@ -234,9 +234,9 @@ Here is a simple overview, with pytest-specific bits:
|
||||
|
||||
$ git clone git@github.com:YOUR_GITHUB_USERNAME/pytest.git
|
||||
$ cd pytest
|
||||
# now, create your own branch off "main":
|
||||
# now, create your own branch off "master":
|
||||
|
||||
$ git checkout -b your-bugfix-branch-name main
|
||||
$ git checkout -b your-bugfix-branch-name master
|
||||
|
||||
Given we have "major.minor.micro" version numbers, bug fixes will usually
|
||||
be released in micro releases whereas features will be released in
|
||||
@@ -259,7 +259,7 @@ Here is a simple overview, with pytest-specific bits:
|
||||
|
||||
Tox is used to run all the tests and will automatically setup virtualenvs
|
||||
to run the tests in.
|
||||
(will implicitly use https://virtualenv.pypa.io/en/latest/)::
|
||||
(will implicitly use http://www.virtualenv.org/en/latest/)::
|
||||
|
||||
$ pip install tox
|
||||
|
||||
@@ -318,26 +318,26 @@ Here is a simple overview, with pytest-specific bits:
|
||||
compare: your-branch-name
|
||||
|
||||
base-fork: pytest-dev/pytest
|
||||
base: main
|
||||
base: master
|
||||
|
||||
|
||||
Writing Tests
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Writing tests for plugins or for pytest itself is often done using the `pytester fixture <https://docs.pytest.org/en/stable/reference/reference.html#pytester>`_, as a "black-box" test.
|
||||
Writing tests for plugins or for pytest itself is often done using the `testdir fixture <https://docs.pytest.org/en/stable/reference.html#testdir>`_, as a "black-box" test.
|
||||
|
||||
For example, to ensure a simple test passes you can write:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def test_true_assertion(pytester):
|
||||
pytester.makepyfile(
|
||||
def test_true_assertion(testdir):
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
def test_foo():
|
||||
assert True
|
||||
"""
|
||||
)
|
||||
result = pytester.runpytest()
|
||||
result = testdir.runpytest()
|
||||
result.assert_outcomes(failed=0, passed=1)
|
||||
|
||||
|
||||
@@ -346,14 +346,14 @@ Alternatively, it is possible to make checks based on the actual output of the t
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def test_true_assertion(pytester):
|
||||
pytester.makepyfile(
|
||||
def test_true_assertion(testdir):
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
def test_foo():
|
||||
assert False
|
||||
"""
|
||||
)
|
||||
result = pytester.runpytest()
|
||||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines(["*assert False*", "*1 failed*"])
|
||||
|
||||
When choosing a file where to write a new test, take a look at the existing files and see if there's
|
||||
@@ -387,15 +387,15 @@ Suppose for example that the latest release was 1.2.3, and you want to include
|
||||
a bug fix in 1.2.4 (check https://github.com/pytest-dev/pytest/releases for the
|
||||
actual latest release). The procedure for this is:
|
||||
|
||||
#. First, make sure the bug is fixed the ``main`` branch, with a regular pull
|
||||
#. First, make sure the bug is fixed the ``master`` branch, with a regular pull
|
||||
request, as described above. An exception to this is if the bug fix is not
|
||||
applicable to ``main`` anymore.
|
||||
applicable to ``master`` anymore.
|
||||
|
||||
#. ``git checkout origin/1.2.x -b backport-XXXX`` # use the main PR number here
|
||||
#. ``git checkout origin/1.2.x -b backport-XXXX`` # use the master PR number here
|
||||
|
||||
#. Locate the merge commit on the PR, in the *merged* message, for example:
|
||||
|
||||
nicoddemus merged commit 0f8b462 into pytest-dev:main
|
||||
nicoddemus merged commit 0f8b462 into pytest-dev:master
|
||||
|
||||
#. ``git cherry-pick -x -m1 REVISION`` # use the revision you found above (``0f8b462``).
|
||||
|
||||
@@ -408,8 +408,8 @@ actual latest release). The procedure for this is:
|
||||
Who does the backporting
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
As mentioned above, bugs should first be fixed on ``main`` (except in rare occasions
|
||||
that a bug only happens in a previous release). So, who should do the backport procedure described
|
||||
As mentioned above, bugs should first be fixed on ``master`` (except in rare occasions
|
||||
that a bug only happens in a previous release). So who should do the backport procedure described
|
||||
above?
|
||||
|
||||
1. If the bug was fixed by a core developer, it is the main responsibility of that core developer
|
||||
@@ -417,8 +417,8 @@ above?
|
||||
2. However, often the merge is done by another maintainer, in which case it is nice of them to
|
||||
do the backport procedure if they have the time.
|
||||
3. For bugs submitted by non-maintainers, it is expected that a core developer will to do
|
||||
the backport, normally the one that merged the PR on ``main``.
|
||||
4. If a non-maintainers notices a bug which is fixed on ``main`` but has not been backported
|
||||
the backport, normally the one that merged the PR on ``master``.
|
||||
4. If a non-maintainers notices a bug which is fixed on ``master`` but has not been backported
|
||||
(due to maintainers forgetting to apply the *needs backport* label, or just plain missing it),
|
||||
they are also welcome to open a PR with the backport. The procedure is simple and really
|
||||
helps with the maintenance of the project.
|
||||
@@ -447,7 +447,7 @@ can always reopen the issue/pull request in their own time later if it makes sen
|
||||
When to close
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Here are a few general rules the maintainers use deciding when to close issues/PRs because
|
||||
Here are a few general rules the maintainers use to decide when to close issues/PRs because
|
||||
of lack of inactivity:
|
||||
|
||||
* Issues labeled ``question`` or ``needs information``: closed after 14 days inactive.
|
||||
@@ -459,15 +459,15 @@ The above are **not hard rules**, but merely **guidelines**, and can be (and oft
|
||||
Closing pull requests
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When closing a Pull Request, it needs to be acknowledging the time, effort, and interest demonstrated by the person which submitted it. As mentioned previously, it is not the intent of the team to dismiss a stalled pull request entirely but to merely to clear up our queue, so a message like the one below is warranted when closing a pull request that went stale:
|
||||
When closing a Pull Request, it needs to be acknowledge the time, effort, and interest demonstrated by the person which submitted it. As mentioned previously, it is not the intent of the team to dismiss stalled pull request entirely but to merely to clear up our queue, so a message like the one below is warranted when closing a pull request that went stale:
|
||||
|
||||
Hi <contributor>,
|
||||
|
||||
First of all, we would like to thank you for your time and effort on working on this, the pytest team deeply appreciates it.
|
||||
First of all we would like to thank you for your time and effort on working on this, the pytest team deeply appreciates it.
|
||||
|
||||
We noticed it has been awhile since you have updated this PR, however. pytest is a high activity project, with many issues/PRs being opened daily, so it is hard for us maintainers to track which PRs are ready for merging, for review, or need more attention.
|
||||
|
||||
So for those reasons we, think it is best to close the PR for now, but with the only intention to clean up our queue, it is by no means a rejection of your changes. We still encourage you to re-open this PR (it is just a click of a button away) when you are ready to get back to it.
|
||||
So for those reasons we think it is best to close the PR for now, but with the only intention to cleanup our queue, it is by no means a rejection of your changes. We still encourage you to re-open this PR (it is just a click of a button away) when you are ready to get back to it.
|
||||
|
||||
Again we appreciate your time for working on this, and hope you might get back to this at a later time!
|
||||
|
||||
|
||||
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2004 Holger Krekel and others
|
||||
Copyright (c) 2004-2020 Holger Krekel and others
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
||||
37
README.rst
@@ -1,7 +1,6 @@
|
||||
.. image:: https://github.com/pytest-dev/pytest/raw/main/doc/en/img/pytest_logo_curves.svg
|
||||
.. image:: https://docs.pytest.org/en/stable/_static/pytest1.png
|
||||
:target: https://docs.pytest.org/en/stable/
|
||||
:align: center
|
||||
:height: 200
|
||||
:alt: pytest
|
||||
|
||||
|
||||
@@ -16,17 +15,16 @@
|
||||
.. image:: https://img.shields.io/pypi/pyversions/pytest.svg
|
||||
:target: https://pypi.org/project/pytest/
|
||||
|
||||
.. image:: https://codecov.io/gh/pytest-dev/pytest/branch/main/graph/badge.svg
|
||||
.. image:: https://codecov.io/gh/pytest-dev/pytest/branch/master/graph/badge.svg
|
||||
:target: https://codecov.io/gh/pytest-dev/pytest
|
||||
:alt: Code coverage Status
|
||||
|
||||
.. image:: https://travis-ci.org/pytest-dev/pytest.svg?branch=master
|
||||
:target: https://travis-ci.org/pytest-dev/pytest
|
||||
|
||||
.. image:: https://github.com/pytest-dev/pytest/workflows/main/badge.svg
|
||||
:target: https://github.com/pytest-dev/pytest/actions?query=workflow%3Amain
|
||||
|
||||
.. image:: https://results.pre-commit.ci/badge/github/pytest-dev/pytest/main.svg
|
||||
:target: https://results.pre-commit.ci/latest/github/pytest-dev/pytest/main
|
||||
:alt: pre-commit.ci status
|
||||
|
||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/psf/black
|
||||
|
||||
@@ -37,15 +35,6 @@
|
||||
:target: https://pytest.readthedocs.io/en/latest/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
.. image:: https://img.shields.io/badge/Discord-pytest--dev-blue
|
||||
:target: https://discord.com/invite/pytest-dev
|
||||
:alt: Discord
|
||||
|
||||
.. image:: https://img.shields.io/badge/Libera%20chat-%23pytest-orange
|
||||
:target: https://web.libera.chat/#pytest
|
||||
:alt: Libera chat
|
||||
|
||||
|
||||
The ``pytest`` framework makes it easy to write small tests, yet
|
||||
scales to support complex functional testing for applications and libraries.
|
||||
|
||||
@@ -88,21 +77,21 @@ Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` stat
|
||||
Features
|
||||
--------
|
||||
|
||||
- Detailed info on failing `assert statements <https://docs.pytest.org/en/stable/how-to/assert.html>`_ (no need to remember ``self.assert*`` names)
|
||||
- Detailed info on failing `assert statements <https://docs.pytest.org/en/stable/assert.html>`_ (no need to remember ``self.assert*`` names)
|
||||
|
||||
- `Auto-discovery
|
||||
<https://docs.pytest.org/en/stable/explanation/goodpractices.html#python-test-discovery>`_
|
||||
<https://docs.pytest.org/en/stable/goodpractices.html#python-test-discovery>`_
|
||||
of test modules and functions
|
||||
|
||||
- `Modular fixtures <https://docs.pytest.org/en/stable/explanation/fixtures.html>`_ for
|
||||
- `Modular fixtures <https://docs.pytest.org/en/stable/fixture.html>`_ for
|
||||
managing small or parametrized long-lived test resources
|
||||
|
||||
- Can run `unittest <https://docs.pytest.org/en/stable/how-to/unittest.html>`_ (or trial),
|
||||
`nose <https://docs.pytest.org/en/stable/how-to/nose.html>`_ test suites out of the box
|
||||
- Can run `unittest <https://docs.pytest.org/en/stable/unittest.html>`_ (or trial),
|
||||
`nose <https://docs.pytest.org/en/stable/nose.html>`_ test suites out of the box
|
||||
|
||||
- Python 3.6+ and PyPy3
|
||||
|
||||
- Rich plugin architecture, with over 850+ `external plugins <https://docs.pytest.org/en/latest/reference/plugin_list.html>`_ and thriving community
|
||||
- Rich plugin architecture, with over 850+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community
|
||||
|
||||
|
||||
Documentation
|
||||
@@ -160,8 +149,8 @@ Tidelift will coordinate the fix and disclosure.
|
||||
License
|
||||
-------
|
||||
|
||||
Copyright Holger Krekel and others, 2004.
|
||||
Copyright Holger Krekel and others, 2004-2020.
|
||||
|
||||
Distributed under the terms of the `MIT`_ license, pytest is free and open source software.
|
||||
|
||||
.. _`MIT`: https://github.com/pytest-dev/pytest/blob/main/LICENSE
|
||||
.. _`MIT`: https://github.com/pytest-dev/pytest/blob/master/LICENSE
|
||||
|
||||
112
RELEASING.rst
@@ -14,89 +14,59 @@ Preparing: Automatic Method
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
We have developed an automated workflow for releases, that uses GitHub workflows and is triggered
|
||||
by `manually running <https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow>`__
|
||||
the `prepare-release-pr workflow <https://github.com/pytest-dev/pytest/actions/workflows/prepare-release-pr.yml>`__
|
||||
on GitHub Actions.
|
||||
by opening an issue.
|
||||
|
||||
The automation will decide the new version number based on the following criteria:
|
||||
Bug-fix releases
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
- If the "major release" input is set to "yes", release a new major release
|
||||
(e.g. 7.0.0 -> 8.0.0)
|
||||
- If there are any ``.feature.rst`` or ``.breaking.rst`` files in the
|
||||
``changelog`` directory, release a new minor release (e.g. 7.0.0 -> 7.1.0)
|
||||
- Otherwise, release a bugfix release (e.g. 7.0.0 -> 7.0.1)
|
||||
- If the "prerelease" input is set, append the string to the version number
|
||||
(e.g. 7.0.0 -> 8.0.0rc1), if "major" is set, and "prerelease" is set to `rc1`)
|
||||
A bug-fix release is always done from a maintenance branch, so for example to release bug-fix
|
||||
``5.1.2``, open a new issue and add this comment to the body::
|
||||
|
||||
Bug-fix and minor releases
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@pytestbot please prepare release from 5.1.x
|
||||
|
||||
Bug-fix and minor releases are always done from a maintenance branch. First,
|
||||
consider double-checking the ``changelog`` directory to see if there are any
|
||||
breaking changes or new features.
|
||||
Where ``5.1.x`` is the maintenance branch for the ``5.1`` series.
|
||||
|
||||
For a new minor release, first create a new maintenance branch from ``main``::
|
||||
The automated workflow will publish a PR for a branch ``release-5.1.2``
|
||||
and notify it as a comment in the issue.
|
||||
|
||||
git fetch --all
|
||||
git branch 7.1.x upstream/main
|
||||
git push upstream 7.1.x
|
||||
|
||||
Then, trigger the workflow with the following inputs:
|
||||
|
||||
- branch: **7.1.x**
|
||||
- major release: **no**
|
||||
- prerelease: empty
|
||||
|
||||
Or via the commandline using `GitHub's cli <https://github.com/cli/cli>`__::
|
||||
|
||||
gh workflow run prepare-release-pr.yml -f branch=7.1.x -f major=no -f prerelease=
|
||||
|
||||
Where ``7.1.x`` is the maintenance branch for the ``7.1`` series. The automated
|
||||
workflow will publish a PR for a branch ``release-7.1.0``.
|
||||
|
||||
Similarly, for a bug-fix release, use the existing maintenance branch and
|
||||
trigger the workflow with e.g. ``branch: 7.0.x`` to get a new ``release-7.0.1``
|
||||
PR.
|
||||
|
||||
Major releases
|
||||
Minor releases
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
1. Create a new maintenance branch from ``main``::
|
||||
1. Create a new maintenance branch from ``master``::
|
||||
|
||||
git fetch --all
|
||||
git branch 8.0.x upstream/main
|
||||
git push upstream 8.0.x
|
||||
git branch 5.2.x upstream/master
|
||||
git push upstream 5.2.x
|
||||
|
||||
2. Trigger the workflow with the following inputs:
|
||||
2. Open a new issue and add this comment to the body::
|
||||
|
||||
- branch: **8.0.x**
|
||||
- major release: **yes**
|
||||
- prerelease: empty
|
||||
@pytestbot please prepare release from 5.2.x
|
||||
|
||||
Or via the commandline::
|
||||
The automated workflow will publish a PR for a branch ``release-5.2.0`` and
|
||||
notify it as a comment in the issue.
|
||||
|
||||
gh workflow run prepare-release-pr.yml -f branch=8.0.x -f major=yes -f prerelease=
|
||||
Major and release candidates
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The automated workflow will publish a PR for a branch ``release-8.0.0``.
|
||||
1. Create a new maintenance branch from ``master``::
|
||||
|
||||
git fetch --all
|
||||
git branch 6.0.x upstream/master
|
||||
git push upstream 6.0.x
|
||||
|
||||
2. For a **major release**, open a new issue and add this comment in the body::
|
||||
|
||||
@pytestbot please prepare major release from 6.0.x
|
||||
|
||||
For a **release candidate**, the comment must be (TODO: `#7551 <https://github.com/pytest-dev/pytest/issues/7551>`__)::
|
||||
|
||||
@pytestbot please prepare release candidate from 6.0.x
|
||||
|
||||
The automated workflow will publish a PR for a branch ``release-6.0.0`` and
|
||||
notify it as a comment in the issue.
|
||||
|
||||
At this point on, this follows the same workflow as other maintenance branches: bug-fixes are merged
|
||||
into ``main`` and ported back to the maintenance branch, even for release candidates.
|
||||
|
||||
Release candidates
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To release a release candidate, set the "prerelease" input to the version number
|
||||
suffix to use. To release a ``8.0.0rc1``, proceed like under "major releases", but set:
|
||||
|
||||
- branch: 8.0.x
|
||||
- major release: yes
|
||||
- prerelease: **rc1**
|
||||
|
||||
Or via the commandline::
|
||||
|
||||
gh workflow run prepare-release-pr.yml -f branch=8.0.x -f major=yes -f prerelease=rc1
|
||||
|
||||
The automated workflow will publish a PR for a branch ``release-8.0.0rc1``.
|
||||
into ``master`` and ported back to the maintenance branch, even for release candidates.
|
||||
|
||||
**A note about release candidates**
|
||||
|
||||
@@ -113,7 +83,7 @@ to be executed on that platform.
|
||||
To release a version ``MAJOR.MINOR.PATCH``, follow these steps:
|
||||
|
||||
#. For major and minor releases, create a new branch ``MAJOR.MINOR.x`` from
|
||||
``upstream/main`` and push it to ``upstream``.
|
||||
``upstream/master`` and push it to ``upstream``.
|
||||
|
||||
#. Create a branch ``release-MAJOR.MINOR.PATCH`` from the ``MAJOR.MINOR.x`` branch.
|
||||
|
||||
@@ -144,18 +114,18 @@ Both automatic and manual processes described above follow the same steps from t
|
||||
|
||||
#. Merge the PR.
|
||||
|
||||
#. Cherry-pick the CHANGELOG / announce files to the ``main`` branch::
|
||||
#. Cherry-pick the CHANGELOG / announce files to the ``master`` branch::
|
||||
|
||||
git fetch --all --prune
|
||||
git checkout upstream/main -b cherry-pick-release
|
||||
git checkout origin/master -b cherry-pick-release
|
||||
git cherry-pick -x -m1 upstream/MAJOR.MINOR.x
|
||||
|
||||
#. Open a PR for ``cherry-pick-release`` and merge it once CI passes. No need to wait for approvals if there were no conflicts on the previous step.
|
||||
|
||||
#. For major and minor releases, tag the release cherry-pick merge commit in main with
|
||||
#. For major and minor releases, tag the release cherry-pick merge commit in master with
|
||||
a dev tag for the next feature release::
|
||||
|
||||
git checkout main
|
||||
git checkout master
|
||||
git pull
|
||||
git tag MAJOR.{MINOR+1}.0.dev0
|
||||
git push git@github.com:pytest-dev/pytest.git MAJOR.{MINOR+1}.0.dev0
|
||||
|
||||
@@ -25,7 +25,6 @@ The current list of contributors receiving funding are:
|
||||
|
||||
* `@asottile`_
|
||||
* `@nicoddemus`_
|
||||
* `@The-Compiler`_
|
||||
|
||||
Contributors interested in receiving a part of the funds just need to submit a PR adding their
|
||||
name to the list. Contributors that want to stop receiving the funds should also submit a PR
|
||||
@@ -57,4 +56,3 @@ funds. Just drop a line to one of the `@pytest-dev/tidelift-admins`_ or use the
|
||||
|
||||
.. _`@asottile`: https://github.com/asottile
|
||||
.. _`@nicoddemus`: https://github.com/nicoddemus
|
||||
.. _`@The-Compiler`: https://github.com/The-Compiler
|
||||
|
||||
@@ -34,10 +34,6 @@ REGENDOC_ARGS := \
|
||||
|
||||
regen: REGENDOC_FILES:=*.rst */*.rst
|
||||
regen:
|
||||
# need to reset cachedir to the non-tox default
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTEST_ADDOPTS="-pno:hypothesis -p no:hypothesispytest -Wignore::pytest.PytestUnknownMarkWarning -o cache_dir=.pytest_cache" \
|
||||
COLUMNS=76 \
|
||||
regendoc --update ${REGENDOC_FILES} ${REGENDOC_ARGS}
|
||||
PYTHONDONTWRITEBYTECODE=1 PYTEST_ADDOPTS="-pno:hypothesis -Wignore::pytest.PytestUnknownMarkWarning" COLUMNS=76 regendoc --update ${REGENDOC_FILES} ${REGENDOC_ARGS}
|
||||
|
||||
.PHONY: regen
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
<h3>Contents</h3>
|
||||
<h3><a href="{{ pathto(master_doc) }}">{{ _('Table Of Contents') }}</a></h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="{{ pathto('index') }}">Home</a></li>
|
||||
|
||||
<li><a href="{{ pathto('getting-started') }}">Get started</a></li>
|
||||
<li><a href="{{ pathto('how-to/index') }}">How-to guides</a></li>
|
||||
<li><a href="{{ pathto('reference/index') }}">Reference guides</a></li>
|
||||
<li><a href="{{ pathto('explanation/index') }}">Explanation</a></li>
|
||||
<li><a href="{{ pathto('contents') }}">Complete table of contents</a></li>
|
||||
<li><a href="{{ pathto('example/index') }}">Library of examples</a></li>
|
||||
</ul>
|
||||
|
||||
<h3>About the project</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="{{ pathto('getting-started') }}">Install</a></li>
|
||||
<li><a href="{{ pathto('contents') }}">Contents</a></li>
|
||||
<li><a href="{{ pathto('reference') }}">API Reference</a></li>
|
||||
<li><a href="{{ pathto('example/index') }}">Examples</a></li>
|
||||
<li><a href="{{ pathto('customize') }}">Customize</a></li>
|
||||
<li><a href="{{ pathto('changelog') }}">Changelog</a></li>
|
||||
<li><a href="{{ pathto('contributing') }}">Contributing</a></li>
|
||||
<li><a href="{{ pathto('backwards-compatibility') }}">Backwards Compatibility</a></li>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<ul>
|
||||
<li><a href="https://pypi.org/project/pytest/">pytest @ PyPI</a></li>
|
||||
<li><a href="https://github.com/pytest-dev/pytest/">pytest @ GitHub</a></li>
|
||||
<li><a href="http://plugincompat.herokuapp.com/">3rd party plugins</a></li>
|
||||
<li><a href="https://github.com/pytest-dev/pytest/issues">Issue Tracker</a></li>
|
||||
<li><a href="https://media.readthedocs.org/pdf/pytest/latest/pytest.pdf">PDF Documentation</a>
|
||||
</ul>
|
||||
|
||||
@@ -10,9 +10,10 @@ Are you an enthusiastic pytest user, the local testing guru in your workplace? O
|
||||
|
||||
We will pair experienced pytest users with open source projects, for a month's effort of getting new development teams started with pytest.
|
||||
|
||||
In 2015 we are trying this for the first time. In February and March 2015 we will gather volunteers on both sides, in April we will do the work, and in May we will evaluate how it went. This effort is being coordinated by Brianna Laugher. If you have any questions or comments, you can raise them on the `@pytestdotorg twitter account <https://twitter.com/pytestdotorg>`_\, the :issue:`issue tracker <676>` or the `pytest-dev mailing list`_.
|
||||
In 2015 we are trying this for the first time. In February and March 2015 we will gather volunteers on both sides, in April we will do the work, and in May we will evaluate how it went. This effort is being coordinated by Brianna Laugher. If you have any questions or comments, you can raise them on the `@pytestdotorg twitter account <https://twitter.com/pytestdotorg>`_ the `issue tracker`_ or the `pytest-dev mailing list`_.
|
||||
|
||||
|
||||
.. _`issue tracker`: https://github.com/pytest-dev/pytest/issues/676
|
||||
.. _`pytest-dev mailing list`: https://mail.python.org/mailman/listinfo/pytest-dev
|
||||
|
||||
|
||||
|
||||
@@ -6,9 +6,6 @@ Release announcements
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
release-7.0.0rc1
|
||||
release-6.2.5
|
||||
release-6.2.4
|
||||
release-6.2.3
|
||||
release-6.2.2
|
||||
release-6.2.1
|
||||
|
||||
@@ -36,12 +36,12 @@ New Features
|
||||
|
||||
import pytest ; pytest.main(arglist, pluginlist)
|
||||
|
||||
see http://pytest.org/en/stable/how-to/usage.html for details.
|
||||
see http://pytest.org/en/stable/usage.html for details.
|
||||
|
||||
- new and better reporting information in assert expressions
|
||||
if comparing lists, sequences or strings.
|
||||
|
||||
see http://pytest.org/en/stable/how-to/assert.html#newreport
|
||||
see http://pytest.org/en/stable/assert.html#newreport
|
||||
|
||||
- new configuration through ini-files (setup.cfg or tox.ini recognized),
|
||||
for example::
|
||||
@@ -50,7 +50,7 @@ New Features
|
||||
norecursedirs = .hg data* # don't ever recurse in such dirs
|
||||
addopts = -x --pyargs # add these command line options by default
|
||||
|
||||
see http://pytest.org/en/stable/reference/customize.html
|
||||
see http://pytest.org/en/stable/customize.html
|
||||
|
||||
- improved standard unittest support. In general py.test should now
|
||||
better be able to run custom unittest.TestCases like twisted trial
|
||||
|
||||
@@ -57,7 +57,7 @@ Changes between 2.0.0 and 2.0.1
|
||||
- refinements to "collecting" output on non-ttys
|
||||
- refine internal plugin registration and --traceconfig output
|
||||
- introduce a mechanism to prevent/unregister plugins from the
|
||||
command line, see http://pytest.org/en/stable/how-to/plugins.html#cmdunregister
|
||||
command line, see http://pytest.org/en/stable/plugins.html#cmdunregister
|
||||
- activate resultlog plugin by default
|
||||
- fix regression wrt yielded tests which due to the
|
||||
collection-before-running semantics were not
|
||||
|
||||
@@ -12,7 +12,7 @@ courtesy of Benjamin Peterson. You can now safely use ``assert``
|
||||
statements in test modules without having to worry about side effects
|
||||
or python optimization ("-OO") options. This is achieved by rewriting
|
||||
assert statements in test modules upon import, using a PEP302 hook.
|
||||
See https://docs.pytest.org/en/stable/how-to/assert.html for
|
||||
See https://docs.pytest.org/en/stable/assert.html for
|
||||
detailed information. The work has been partly sponsored by my company,
|
||||
merlinux GmbH.
|
||||
|
||||
@@ -24,7 +24,7 @@ If you want to install or upgrade pytest, just type one of::
|
||||
easy_install -U pytest
|
||||
|
||||
best,
|
||||
holger krekel / https://merlinux.eu/
|
||||
holger krekel / http://merlinux.eu
|
||||
|
||||
Changes between 2.0.3 and 2.1.0
|
||||
----------------------------------------------
|
||||
|
||||
@@ -20,7 +20,7 @@ If you want to install or upgrade pytest, just type one of::
|
||||
easy_install -U pytest
|
||||
|
||||
best,
|
||||
holger krekel / https://merlinux.eu/
|
||||
holger krekel / http://merlinux.eu
|
||||
|
||||
Changes between 2.1.0 and 2.1.1
|
||||
----------------------------------------------
|
||||
|
||||
@@ -19,7 +19,7 @@ If you want to install or upgrade pytest, just type one of::
|
||||
easy_install -U pytest
|
||||
|
||||
best,
|
||||
holger krekel / https://merlinux.eu/
|
||||
holger krekel / http://merlinux.eu
|
||||
|
||||
Changes between 2.1.1 and 2.1.2
|
||||
----------------------------------------
|
||||
|
||||
@@ -9,7 +9,7 @@ with these improvements:
|
||||
|
||||
- new @pytest.mark.parametrize decorator to run tests with different arguments
|
||||
- new metafunc.parametrize() API for parametrizing arguments independently
|
||||
- see examples at http://pytest.org/en/stable/example/how-to/parametrize.html
|
||||
- see examples at http://pytest.org/en/stable/example/parametrize.html
|
||||
- NOTE that parametrize() related APIs are still a bit experimental
|
||||
and might change in future releases.
|
||||
|
||||
@@ -78,7 +78,7 @@ Changes between 2.1.3 and 2.2.0
|
||||
or through plugin hooks. Also introduce a "--strict" option which
|
||||
will treat unregistered markers as errors
|
||||
allowing to avoid typos and maintain a well described set of markers
|
||||
for your test suite. See examples at http://pytest.org/en/stable/how-to/mark.html
|
||||
for your test suite. See examples at http://pytest.org/en/stable/mark.html
|
||||
and its links.
|
||||
- issue50: introduce "-m marker" option to select tests based on markers
|
||||
(this is a stricter and more predictable version of "-k" in that "-m"
|
||||
|
||||
@@ -13,12 +13,12 @@ re-usable fixture design.
|
||||
|
||||
For detailed info and tutorial-style examples, see:
|
||||
|
||||
http://pytest.org/en/stable/explanation/fixtures.html
|
||||
http://pytest.org/en/stable/fixture.html
|
||||
|
||||
Moreover, there is now support for using pytest fixtures/funcargs with
|
||||
unittest-style suites, see here for examples:
|
||||
|
||||
http://pytest.org/en/stable/how-to/unittest.html
|
||||
http://pytest.org/en/stable/unittest.html
|
||||
|
||||
Besides, more unittest-test suites are now expected to "simply work"
|
||||
with pytest.
|
||||
|
||||
@@ -16,7 +16,7 @@ comes with the following fixes and features:
|
||||
- yielded test functions will now have autouse-fixtures active but
|
||||
cannot accept fixtures as funcargs - it's anyway recommended to
|
||||
rather use the post-2.0 parametrize features instead of yield, see:
|
||||
http://pytest.org/en/stable/example/how-to/parametrize.html
|
||||
http://pytest.org/en/stable/example/parametrize.html
|
||||
- fix autouse-issue where autouse-fixtures would not be discovered
|
||||
if defined in an a/conftest.py file and tests in a/tests/test_some.py
|
||||
- fix issue226 - LIFO ordering for fixture teardowns
|
||||
|
||||
@@ -23,13 +23,14 @@ a full list of details. A few feature highlights:
|
||||
called if the corresponding setup method succeeded.
|
||||
|
||||
- integrate tab-completion on command line options if you
|
||||
have :pypi:`argcomplete` configured.
|
||||
have `argcomplete <https://pypi.org/project/argcomplete/>`_
|
||||
configured.
|
||||
|
||||
- allow boolean expression directly with skipif/xfail
|
||||
if a "reason" is also specified.
|
||||
|
||||
- a new hook ``pytest_load_initial_conftests`` allows plugins like
|
||||
:pypi:`pytest-django` to
|
||||
`pytest-django <https://pypi.org/project/pytest-django/>`_ to
|
||||
influence the environment before conftest files import ``django``.
|
||||
|
||||
- reporting: color the last line red or green depending if
|
||||
|
||||
@@ -45,29 +45,29 @@ The py.test Development Team
|
||||
**New Features**
|
||||
|
||||
* New ``pytest.mark.skip`` mark, which unconditionally skips marked tests.
|
||||
Thanks :user:`MichaelAquilina` for the complete PR (:pull:`1040`).
|
||||
Thanks `@MichaelAquilina`_ for the complete PR (`#1040`_).
|
||||
|
||||
* ``--doctest-glob`` may now be passed multiple times in the command-line.
|
||||
Thanks :user:`jab` and :user:`nicoddemus` for the PR.
|
||||
Thanks `@jab`_ and `@nicoddemus`_ for the PR.
|
||||
|
||||
* New ``-rp`` and ``-rP`` reporting options give the summary and full output
|
||||
of passing tests, respectively. Thanks to :user:`codewarrior0` for the PR.
|
||||
of passing tests, respectively. Thanks to `@codewarrior0`_ for the PR.
|
||||
|
||||
* ``pytest.mark.xfail`` now has a ``strict`` option which makes ``XPASS``
|
||||
tests to fail the test suite, defaulting to ``False``. There's also a
|
||||
``xfail_strict`` ini option that can be used to configure it project-wise.
|
||||
Thanks :user:`rabbbit` for the request and :user:`nicoddemus` for the PR (:issue:`1355`).
|
||||
Thanks `@rabbbit`_ for the request and `@nicoddemus`_ for the PR (`#1355`_).
|
||||
|
||||
* ``Parser.addini`` now supports options of type ``bool``. Thanks
|
||||
:user:`nicoddemus` for the PR.
|
||||
`@nicoddemus`_ for the PR.
|
||||
|
||||
* New ``ALLOW_BYTES`` doctest option strips ``b`` prefixes from byte strings
|
||||
in doctest output (similar to ``ALLOW_UNICODE``).
|
||||
Thanks :user:`jaraco` for the request and :user:`nicoddemus` for the PR (:issue:`1287`).
|
||||
Thanks `@jaraco`_ for the request and `@nicoddemus`_ for the PR (`#1287`_).
|
||||
|
||||
* give a hint on KeyboardInterrupt to use the --fulltrace option to show the errors,
|
||||
this fixes :issue:`1366`.
|
||||
Thanks to :user:`hpk42` for the report and :user:`RonnyPfannschmidt` for the PR.
|
||||
this fixes `#1366`_.
|
||||
Thanks to `@hpk42`_ for the report and `@RonnyPfannschmidt`_ for the PR.
|
||||
|
||||
* catch IndexError exceptions when getting exception source location. This fixes
|
||||
pytest internal error for dynamically generated code (fixtures and tests)
|
||||
@@ -91,44 +91,69 @@ The py.test Development Team
|
||||
`pylib <https://pylib.readthedocs.io/en/stable/>`_.
|
||||
|
||||
* ``pytest_enter_pdb`` now optionally receives the pytest config object.
|
||||
Thanks :user:`nicoddemus` for the PR.
|
||||
Thanks `@nicoddemus`_ for the PR.
|
||||
|
||||
* Removed code and documentation for Python 2.5 or lower versions,
|
||||
including removal of the obsolete ``_pytest.assertion.oldinterpret`` module.
|
||||
Thanks :user:`nicoddemus` for the PR (:issue:`1226`).
|
||||
Thanks `@nicoddemus`_ for the PR (`#1226`_).
|
||||
|
||||
* Comparisons now always show up in full when ``CI`` or ``BUILD_NUMBER`` is
|
||||
found in the environment, even when -vv isn't used.
|
||||
Thanks :user:`The-Compiler` for the PR.
|
||||
Thanks `@The-Compiler`_ for the PR.
|
||||
|
||||
* ``--lf`` and ``--ff`` now support long names: ``--last-failed`` and
|
||||
``--failed-first`` respectively.
|
||||
Thanks :user:`MichaelAquilina` for the PR.
|
||||
Thanks `@MichaelAquilina`_ for the PR.
|
||||
|
||||
* Added expected exceptions to pytest.raises fail message
|
||||
|
||||
* Collection only displays progress ("collecting X items") when in a terminal.
|
||||
This avoids cluttering the output when using ``--color=yes`` to obtain
|
||||
colors in CI integrations systems (:issue:`1397`).
|
||||
colors in CI integrations systems (`#1397`_).
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
* The ``-s`` and ``-c`` options should now work under ``xdist``;
|
||||
``Config.fromdictargs`` now represents its input much more faithfully.
|
||||
Thanks to :user:`bukzor` for the complete PR (:issue:`680`).
|
||||
Thanks to `@bukzor`_ for the complete PR (`#680`_).
|
||||
|
||||
* Fix (:issue:`1290`): support Python 3.5's ``@`` operator in assertion rewriting.
|
||||
Thanks :user:`Shinkenjoe` for report with test case and :user:`tomviner` for the PR.
|
||||
* Fix (`#1290`_): support Python 3.5's ``@`` operator in assertion rewriting.
|
||||
Thanks `@Shinkenjoe`_ for report with test case and `@tomviner`_ for the PR.
|
||||
|
||||
* Fix formatting utf-8 explanation messages (:issue:`1379`).
|
||||
Thanks :user:`biern` for the PR.
|
||||
* Fix formatting utf-8 explanation messages (`#1379`_).
|
||||
Thanks `@biern`_ for the PR.
|
||||
|
||||
* Fix `traceback style docs`_ to describe all of the available options
|
||||
(auto/long/short/line/native/no), with ``auto`` being the default since v2.6.
|
||||
Thanks :user:`hackebrot` for the PR.
|
||||
Thanks `@hackebrot`_ for the PR.
|
||||
|
||||
* Fix (:issue:`1422`): junit record_xml_property doesn't allow multiple records
|
||||
* Fix (`#1422`_): junit record_xml_property doesn't allow multiple records
|
||||
with same name.
|
||||
|
||||
|
||||
.. _`traceback style docs`: https://pytest.org/en/stable/how-to/output.html#modifying-python-traceback-printing
|
||||
.. _`traceback style docs`: https://pytest.org/en/stable/usage.html#modifying-python-traceback-printing
|
||||
|
||||
.. _#1422: https://github.com/pytest-dev/pytest/issues/1422
|
||||
.. _#1379: https://github.com/pytest-dev/pytest/issues/1379
|
||||
.. _#1366: https://github.com/pytest-dev/pytest/issues/1366
|
||||
.. _#1040: https://github.com/pytest-dev/pytest/pull/1040
|
||||
.. _#680: https://github.com/pytest-dev/pytest/issues/680
|
||||
.. _#1287: https://github.com/pytest-dev/pytest/pull/1287
|
||||
.. _#1226: https://github.com/pytest-dev/pytest/pull/1226
|
||||
.. _#1290: https://github.com/pytest-dev/pytest/pull/1290
|
||||
.. _#1355: https://github.com/pytest-dev/pytest/pull/1355
|
||||
.. _#1397: https://github.com/pytest-dev/pytest/issues/1397
|
||||
.. _@biern: https://github.com/biern
|
||||
.. _@MichaelAquilina: https://github.com/MichaelAquilina
|
||||
.. _@bukzor: https://github.com/bukzor
|
||||
.. _@hpk42: https://github.com/hpk42
|
||||
.. _@nicoddemus: https://github.com/nicoddemus
|
||||
.. _@jab: https://github.com/jab
|
||||
.. _@codewarrior0: https://github.com/codewarrior0
|
||||
.. _@jaraco: https://github.com/jaraco
|
||||
.. _@The-Compiler: https://github.com/The-Compiler
|
||||
.. _@Shinkenjoe: https://github.com/Shinkenjoe
|
||||
.. _@tomviner: https://github.com/tomviner
|
||||
.. _@RonnyPfannschmidt: https://github.com/RonnyPfannschmidt
|
||||
.. _@rabbbit: https://github.com/rabbbit
|
||||
.. _@hackebrot: https://github.com/hackebrot
|
||||
|
||||
@@ -37,21 +37,31 @@ The py.test Development Team
|
||||
**Bug Fixes**
|
||||
|
||||
* Improve error message when a plugin fails to load.
|
||||
Thanks :user:`nicoddemus` for the PR.
|
||||
Thanks `@nicoddemus`_ for the PR.
|
||||
|
||||
* Fix (:issue:`1178`):
|
||||
* Fix (`#1178 <https://github.com/pytest-dev/pytest/issues/1178>`_):
|
||||
``pytest.fail`` with non-ascii characters raises an internal pytest error.
|
||||
Thanks :user:`nicoddemus` for the PR.
|
||||
Thanks `@nicoddemus`_ for the PR.
|
||||
|
||||
* Fix (:issue:`469`): junit parses report.nodeid incorrectly, when params IDs
|
||||
contain ``::``. Thanks :user:`tomviner` for the PR (:pull:`1431`).
|
||||
* Fix (`#469`_): junit parses report.nodeid incorrectly, when params IDs
|
||||
contain ``::``. Thanks `@tomviner`_ for the PR (`#1431`_).
|
||||
|
||||
* Fix (:issue:`578`): SyntaxErrors
|
||||
* Fix (`#578 <https://github.com/pytest-dev/pytest/issues/578>`_): SyntaxErrors
|
||||
containing non-ascii lines at the point of failure generated an internal
|
||||
py.test error.
|
||||
Thanks :user:`asottile` for the report and :user:`nicoddemus` for the PR.
|
||||
Thanks `@asottile`_ for the report and `@nicoddemus`_ for the PR.
|
||||
|
||||
* Fix (:issue:`1437`): When passing in a bytestring regex pattern to parameterize
|
||||
* Fix (`#1437`_): When passing in a bytestring regex pattern to parameterize
|
||||
attempt to decode it as utf-8 ignoring errors.
|
||||
|
||||
* Fix (:issue:`649`): parametrized test nodes cannot be specified to run on the command line.
|
||||
* Fix (`#649`_): parametrized test nodes cannot be specified to run on the command line.
|
||||
|
||||
|
||||
.. _#1437: https://github.com/pytest-dev/pytest/issues/1437
|
||||
.. _#469: https://github.com/pytest-dev/pytest/issues/469
|
||||
.. _#1431: https://github.com/pytest-dev/pytest/pull/1431
|
||||
.. _#649: https://github.com/pytest-dev/pytest/issues/649
|
||||
|
||||
.. _@asottile: https://github.com/asottile
|
||||
.. _@nicoddemus: https://github.com/nicoddemus
|
||||
.. _@tomviner: https://github.com/tomviner
|
||||
|
||||
@@ -39,27 +39,40 @@ The py.test Development Team
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
* fix :issue:`510`: skip tests where one parameterize dimension was empty
|
||||
thanks Alex Stapleton for the Report and :user:`RonnyPfannschmidt` for the PR
|
||||
* fix `#510`_: skip tests where one parameterize dimension was empty
|
||||
thanks Alex Stapleton for the Report and `@RonnyPfannschmidt`_ for the PR
|
||||
|
||||
* Fix Xfail does not work with condition keyword argument.
|
||||
Thanks :user:`astraw38` for reporting the issue (:issue:`1496`) and :user:`tomviner`
|
||||
for PR the (:pull:`1524`).
|
||||
Thanks `@astraw38`_ for reporting the issue (`#1496`_) and `@tomviner`_
|
||||
for PR the (`#1524`_).
|
||||
|
||||
* Fix win32 path issue when putting custom config file with absolute path
|
||||
in ``pytest.main("-c your_absolute_path")``.
|
||||
|
||||
* Fix maximum recursion depth detection when raised error class is not aware
|
||||
of unicode/encoded bytes.
|
||||
Thanks :user:`prusse-martin` for the PR (:pull:`1506`).
|
||||
Thanks `@prusse-martin`_ for the PR (`#1506`_).
|
||||
|
||||
* Fix ``pytest.mark.skip`` mark when used in strict mode.
|
||||
Thanks :user:`pquentin` for the PR and :user:`RonnyPfannschmidt` for
|
||||
Thanks `@pquentin`_ for the PR and `@RonnyPfannschmidt`_ for
|
||||
showing how to fix the bug.
|
||||
|
||||
* Minor improvements and fixes to the documentation.
|
||||
Thanks :user:`omarkohl` for the PR.
|
||||
Thanks `@omarkohl`_ for the PR.
|
||||
|
||||
* Fix ``--fixtures`` to show all fixture definitions as opposed to just
|
||||
one per fixture name.
|
||||
Thanks to :user:`hackebrot` for the PR.
|
||||
Thanks to `@hackebrot`_ for the PR.
|
||||
|
||||
.. _#510: https://github.com/pytest-dev/pytest/issues/510
|
||||
.. _#1506: https://github.com/pytest-dev/pytest/pull/1506
|
||||
.. _#1496: https://github.com/pytest-dev/pytest/issues/1496
|
||||
.. _#1524: https://github.com/pytest-dev/pytest/pull/1524
|
||||
|
||||
.. _@astraw38: https://github.com/astraw38
|
||||
.. _@hackebrot: https://github.com/hackebrot
|
||||
.. _@omarkohl: https://github.com/omarkohl
|
||||
.. _@pquentin: https://github.com/pquentin
|
||||
.. _@prusse-martin: https://github.com/prusse-martin
|
||||
.. _@RonnyPfannschmidt: https://github.com/RonnyPfannschmidt
|
||||
.. _@tomviner: https://github.com/tomviner
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
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
|
||||
@@ -1,30 +0,0 @@
|
||||
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
|
||||
@@ -1,74 +0,0 @@
|
||||
pytest-7.0.0rc1
|
||||
=======================================
|
||||
|
||||
The pytest team is proud to announce the 7.0.0rc1 prerelease!
|
||||
|
||||
This is a prerelease, not intended for production use, but to test the upcoming features and improvements
|
||||
in order to catch any major problems before the final version is released to the major public.
|
||||
|
||||
We appreciate your help testing this out before the final release, making sure to report any
|
||||
regressions to our issue tracker:
|
||||
|
||||
https://github.com/pytest-dev/pytest/issues
|
||||
|
||||
When doing so, please include the string ``[prerelease]`` in the title.
|
||||
|
||||
You can upgrade from PyPI via:
|
||||
|
||||
pip install pytest==7.0.0rc1
|
||||
|
||||
Users are encouraged to take a look at the CHANGELOG carefully:
|
||||
|
||||
https://docs.pytest.org/en/stable/changelog.html
|
||||
|
||||
Thanks to all the contributors to this release:
|
||||
|
||||
* Adam J. Stewart
|
||||
* Alexander King
|
||||
* Amin Alaee
|
||||
* Andrew Neitsch
|
||||
* Anthony Sottile
|
||||
* Ben Davies
|
||||
* Bernát Gábor
|
||||
* Brian Okken
|
||||
* Bruno Oliveira
|
||||
* Cristian Vera
|
||||
* David Szotten
|
||||
* Eddie
|
||||
* Emmanuel Arias
|
||||
* Emmanuel Meric de Bellefon
|
||||
* Eric Liu
|
||||
* Florian Bruhin
|
||||
* GergelyKalmar
|
||||
* Graeme Smecher
|
||||
* Harshna
|
||||
* Hugo van Kemenade
|
||||
* Jakub Kulík
|
||||
* James Myatt
|
||||
* Jeff Rasley
|
||||
* Kale Kundert
|
||||
* Miro Hrončok
|
||||
* Naveen-Pratap
|
||||
* Oleg Höfling
|
||||
* Ran Benita
|
||||
* Ronny Pfannschmidt
|
||||
* Simon K
|
||||
* Srip
|
||||
* Sören Wegener
|
||||
* Taneli Hukkinen
|
||||
* Terje Runde
|
||||
* Thomas Grainger
|
||||
* Thomas Hisch
|
||||
* William Jamir Silva
|
||||
* Zac Hatfield-Dodds
|
||||
* andrewdotn
|
||||
* denivyruck
|
||||
* ericluoliu
|
||||
* oleg.hoefling
|
||||
* symonk
|
||||
* ziebam
|
||||
* Éloi Rivard
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -1,14 +1,16 @@
|
||||
.. _`assert`:
|
||||
|
||||
How to write and report assertions in tests
|
||||
The writing and reporting of assertions in tests
|
||||
==================================================
|
||||
|
||||
.. _`assertfeedback`:
|
||||
.. _`assert with the assert statement`:
|
||||
.. _`assert`:
|
||||
|
||||
|
||||
Asserting with the ``assert`` statement
|
||||
---------------------------------------------------------
|
||||
|
||||
``pytest`` allows you to use the standard Python ``assert`` for verifying
|
||||
``pytest`` allows you to use the standard python ``assert`` for verifying
|
||||
expectations and values in Python tests. For example, you can write the
|
||||
following:
|
||||
|
||||
@@ -29,8 +31,9 @@ you will see the return value of the function call:
|
||||
|
||||
$ pytest test_assert1.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
|
||||
test_assert1.py F [100%]
|
||||
@@ -95,13 +98,13 @@ and if you need to have access to the actual exception info you may use:
|
||||
f()
|
||||
assert "maximum recursion" in str(excinfo.value)
|
||||
|
||||
``excinfo`` is an :class:`~pytest.ExceptionInfo` instance, which is a wrapper around
|
||||
``excinfo`` is an ``ExceptionInfo`` instance, which is a wrapper around
|
||||
the actual exception raised. The main attributes of interest are
|
||||
``.type``, ``.value`` and ``.traceback``.
|
||||
|
||||
You can pass a ``match`` keyword parameter to the context-manager to test
|
||||
that a regular expression matches on the string representation of an exception
|
||||
(similar to the ``TestCase.assertRaisesRegex`` method from ``unittest``):
|
||||
(similar to the ``TestCase.assertRaisesRegexp`` method from ``unittest``):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -172,6 +175,8 @@ when it encounters comparisons. For example:
|
||||
.. code-block:: python
|
||||
|
||||
# content of test_assert2.py
|
||||
|
||||
|
||||
def test_set_comparison():
|
||||
set1 = set("1308")
|
||||
set2 = set("8035")
|
||||
@@ -183,8 +188,9 @@ if you run this module:
|
||||
|
||||
$ pytest test_assert2.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
|
||||
test_assert2.py F [100%]
|
||||
@@ -203,7 +209,7 @@ if you run this module:
|
||||
E '5'
|
||||
E Use -v to get the full diff
|
||||
|
||||
test_assert2.py:4: AssertionError
|
||||
test_assert2.py:6: AssertionError
|
||||
========================= short test summary info ==========================
|
||||
FAILED test_assert2.py::test_set_comparison - AssertionError: assert {'0'...
|
||||
============================ 1 failed in 0.12s =============================
|
||||
@@ -295,7 +301,7 @@ modules directly discovered by its test collection process, so **asserts in
|
||||
supporting modules which are not themselves test modules will not be rewritten**.
|
||||
|
||||
You can manually enable assertion rewriting for an imported module by calling
|
||||
:ref:`register_assert_rewrite <assertion-rewriting>`
|
||||
`register_assert_rewrite <https://docs.pytest.org/en/stable/writing_plugins.html#assertion-rewriting>`_
|
||||
before you import it (a good place to do that is in your root ``conftest.py``).
|
||||
|
||||
For further information, Benjamin Peterson wrote up `Behind the scenes of pytest's new assertion rewriting <http://pybites.blogspot.com/2011/07/behind-scenes-of-pytests-new-assertion.html>`_.
|
||||
@@ -22,9 +22,7 @@ b) transitional: the old and new API don't conflict
|
||||
|
||||
We will only start the removal of deprecated functionality in major releases (e.g. if we deprecate something in 3.0 we will start to remove it in 4.0), and keep it around for at least two minor releases (e.g. if we deprecate something in 3.9 and 4.0 is the next release, we start to remove it in 5.0, not in 4.0).
|
||||
|
||||
A deprecated feature scheduled to be removed in major version X will use the warning class `PytestRemovedInXWarning` (a subclass of :class:`~pytest.PytestDeprecationwarning`).
|
||||
|
||||
When the deprecation expires (e.g. 4.0 is released), we won't remove the deprecated functionality immediately, but will use the standard warning filters to turn `PytestRemovedInXWarning` (e.g. `PytestRemovedIn4Warning`) into **errors** by default. This approach makes it explicit that removal is imminent, and still gives you time to turn the deprecated feature into a warning instead of an error so it can be dealt with in your own time. In the next minor release (e.g. 4.1), the feature will be effectively removed.
|
||||
When the deprecation expires (e.g. 4.0 is released), we won't remove the deprecated functionality immediately, but will use the standard warning filters to turn them into **errors** by default. This approach makes it explicit that removal is imminent, and still gives you time to turn the deprecated feature into a warning instead of an error so it can be dealt with in your own time. In the next minor release (e.g. 4.1), the feature will be effectively removed.
|
||||
|
||||
|
||||
c) true breakage: should only be considered when normal transition is unreasonably unsustainable and would offset important development/features by years.
|
||||
@@ -32,15 +30,15 @@ c) true breakage: should only be considered when normal transition is unreasonab
|
||||
|
||||
Examples for such upcoming changes:
|
||||
|
||||
* removal of ``pytest_runtest_protocol/nextitem`` - :issue:`895`
|
||||
* removal of ``pytest_runtest_protocol/nextitem`` - `#895`_
|
||||
* rearranging of the node tree to include ``FunctionDefinition``
|
||||
* rearranging of ``SetupState`` :issue:`895`
|
||||
* rearranging of ``SetupState`` `#895`_
|
||||
|
||||
True breakages must be announced first in an issue containing:
|
||||
|
||||
* Detailed description of the change
|
||||
* Rationale
|
||||
* Expected impact on users and plugin authors (example in :issue:`895`)
|
||||
* Expected impact on users and plugin authors (example in `#895`_)
|
||||
|
||||
After there's no hard *-1* on the issue it should be followed up by an initial proof-of-concept Pull Request.
|
||||
|
||||
@@ -77,3 +75,6 @@ Deprecation Roadmap
|
||||
Features currently deprecated and removed in previous releases can be found in :ref:`deprecations`.
|
||||
|
||||
We track future deprecation and removal of features using milestones and the `deprecation <https://github.com/pytest-dev/pytest/issues?q=label%3A%22type%3A+deprecation%22>`_ and `removal <https://github.com/pytest-dev/pytest/labels/type%3A%20removal>`_ labels on GitHub.
|
||||
|
||||
|
||||
.. _`#895`: https://github.com/pytest-dev/pytest/issues/895
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
.. _bash_completion:
|
||||
|
||||
How to set up bash completion
|
||||
=============================
|
||||
Setting up bash completion
|
||||
==========================
|
||||
|
||||
When using bash as your shell, ``pytest`` can use argcomplete
|
||||
(https://argcomplete.readthedocs.io/) for auto-completion.
|
||||
@@ -6,7 +6,7 @@ Pytest API and builtin fixtures
|
||||
================================================
|
||||
|
||||
|
||||
Most of the information of this page has been moved over to :ref:`api-reference`.
|
||||
Most of the information of this page has been moved over to :ref:`reference`.
|
||||
|
||||
For information on plugin hooks and objects, see :ref:`plugins`.
|
||||
|
||||
@@ -16,13 +16,8 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
|
||||
.. code-block:: pytest
|
||||
|
||||
$ pytest --fixtures -v
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /home/sweet/project
|
||||
collected 0 items
|
||||
cache -- .../_pytest/cacheprovider.py:510
|
||||
$ pytest -q --fixtures
|
||||
cache
|
||||
Return a cache object that can persist state between testing sessions.
|
||||
|
||||
cache.get(key, default)
|
||||
@@ -33,41 +28,40 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
|
||||
Values can be any object handled by the json stdlib module.
|
||||
|
||||
capsys -- .../_pytest/capture.py:878
|
||||
capsys
|
||||
Enable text capturing of writes to ``sys.stdout`` and ``sys.stderr``.
|
||||
|
||||
The captured output is made available via ``capsys.readouterr()`` method
|
||||
calls, which return a ``(out, err)`` namedtuple.
|
||||
``out`` and ``err`` will be ``text`` objects.
|
||||
|
||||
capsysbinary -- .../_pytest/capture.py:895
|
||||
capsysbinary
|
||||
Enable bytes capturing of writes to ``sys.stdout`` and ``sys.stderr``.
|
||||
|
||||
The captured output is made available via ``capsysbinary.readouterr()``
|
||||
method calls, which return a ``(out, err)`` namedtuple.
|
||||
``out`` and ``err`` will be ``bytes`` objects.
|
||||
|
||||
capfd -- .../_pytest/capture.py:912
|
||||
capfd
|
||||
Enable text capturing of writes to file descriptors ``1`` and ``2``.
|
||||
|
||||
The captured output is made available via ``capfd.readouterr()`` method
|
||||
calls, which return a ``(out, err)`` namedtuple.
|
||||
``out`` and ``err`` will be ``text`` objects.
|
||||
|
||||
capfdbinary -- .../_pytest/capture.py:929
|
||||
capfdbinary
|
||||
Enable bytes capturing of writes to file descriptors ``1`` and ``2``.
|
||||
|
||||
The captured output is made available via ``capfd.readouterr()`` method
|
||||
calls, which return a ``(out, err)`` namedtuple.
|
||||
``out`` and ``err`` will be ``byte`` objects.
|
||||
|
||||
doctest_namespace [session scope] -- .../_pytest/doctest.py:731
|
||||
doctest_namespace [session scope]
|
||||
Fixture that returns a :py:class:`dict` that will be injected into the
|
||||
namespace of doctests.
|
||||
|
||||
pytestconfig [session scope] -- .../_pytest/fixtures.py:1365
|
||||
Session-scoped fixture that returns the session's :class:`pytest.Config`
|
||||
object.
|
||||
pytestconfig [session scope]
|
||||
Session-scoped fixture that returns the :class:`_pytest.config.Config` object.
|
||||
|
||||
Example::
|
||||
|
||||
@@ -75,7 +69,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
if pytestconfig.getoption("verbose") > 0:
|
||||
...
|
||||
|
||||
record_property -- .../_pytest/junitxml.py:282
|
||||
record_property
|
||||
Add extra properties to the calling test.
|
||||
|
||||
User properties become part of the test report and are available to the
|
||||
@@ -89,13 +83,13 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
def test_function(record_property):
|
||||
record_property("example_key", 1)
|
||||
|
||||
record_xml_attribute -- .../_pytest/junitxml.py:305
|
||||
record_xml_attribute
|
||||
Add extra xml attributes to the tag for the calling test.
|
||||
|
||||
The fixture is callable with ``name, value``. The value is
|
||||
automatically XML-encoded.
|
||||
|
||||
record_testsuite_property [session scope] -- .../_pytest/junitxml.py:343
|
||||
record_testsuite_property [session scope]
|
||||
Record a new ``<property>`` tag as child of the root ``<testsuite>``.
|
||||
|
||||
This is suitable to writing global information regarding the entire test
|
||||
@@ -114,27 +108,10 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
.. warning::
|
||||
|
||||
Currently this fixture **does not work** with the
|
||||
`pytest-xdist <https://github.com/pytest-dev/pytest-xdist>`__ plugin. See
|
||||
:issue:`7767` for details.
|
||||
`pytest-xdist <https://github.com/pytest-dev/pytest-xdist>`__ plugin. See issue
|
||||
`#7767 <https://github.com/pytest-dev/pytest/issues/7767>`__ for details.
|
||||
|
||||
tmpdir_factory [session scope] -- .../_pytest/legacypath.py:292
|
||||
Return a :class:`pytest.TempdirFactory` instance for the test session.
|
||||
|
||||
tmpdir -- .../_pytest/legacypath.py:299
|
||||
Return a temporary directory path object which is unique to each test
|
||||
function invocation, created as a sub directory of the base temporary
|
||||
directory.
|
||||
|
||||
By default, a new base temporary directory is created each test session,
|
||||
and old bases are removed after 3 sessions, to aid in debugging. If
|
||||
``--basetemp`` is used then it is cleared each session. See :ref:`base
|
||||
temporary directory`.
|
||||
|
||||
The returned object is a `legacy_path`_ object.
|
||||
|
||||
.. _legacy_path: https://py.readthedocs.io/en/latest/path.html
|
||||
|
||||
caplog -- .../_pytest/logging.py:483
|
||||
caplog
|
||||
Access and control log capturing.
|
||||
|
||||
Captured logs are available through the following properties/methods::
|
||||
@@ -145,7 +122,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
* caplog.record_tuples -> list of (logger_name, level, message) tuples
|
||||
* caplog.clear() -> clear captured records and formatted log output string
|
||||
|
||||
monkeypatch -- .../_pytest/monkeypatch.py:29
|
||||
monkeypatch
|
||||
A convenient fixture for monkey-patching.
|
||||
|
||||
The fixture provides these methods to modify objects, dictionaries or
|
||||
@@ -155,7 +132,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
monkeypatch.delattr(obj, name, raising=True)
|
||||
monkeypatch.setitem(mapping, name, value)
|
||||
monkeypatch.delitem(obj, name, raising=True)
|
||||
monkeypatch.setenv(name, value, prepend=None)
|
||||
monkeypatch.setenv(name, value, prepend=False)
|
||||
monkeypatch.delenv(name, raising=True)
|
||||
monkeypatch.syspath_prepend(path)
|
||||
monkeypatch.chdir(path)
|
||||
@@ -164,16 +141,33 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
fixture has finished. The ``raising`` parameter determines if a KeyError
|
||||
or AttributeError will be raised if the set/deletion operation has no target.
|
||||
|
||||
recwarn -- .../_pytest/recwarn.py:29
|
||||
recwarn
|
||||
Return a :class:`WarningsRecorder` instance that records all warnings emitted by test functions.
|
||||
|
||||
See https://docs.python.org/library/how-to/capture-warnings.html for information
|
||||
See http://docs.python.org/library/warnings.html for information
|
||||
on warning categories.
|
||||
|
||||
tmp_path_factory [session scope] -- .../_pytest/tmpdir.py:183
|
||||
Return a :class:`pytest.TempPathFactory` instance for the test session.
|
||||
tmpdir_factory [session scope]
|
||||
Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session.
|
||||
|
||||
tmp_path -- .../_pytest/tmpdir.py:198
|
||||
tmp_path_factory [session scope]
|
||||
Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session.
|
||||
|
||||
tmpdir
|
||||
Return a temporary directory path object which is unique to each test
|
||||
function invocation, created as a sub directory of the base temporary
|
||||
directory.
|
||||
|
||||
By default, a new base temporary directory is created each test session,
|
||||
and old bases are removed after 3 sessions, to aid in debugging. If
|
||||
``--basetemp`` is used then it is cleared each session. See :ref:`base
|
||||
temporary directory`.
|
||||
|
||||
The returned object is a `py.path.local`_ path object.
|
||||
|
||||
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
|
||||
|
||||
tmp_path
|
||||
Return a temporary directory path object which is unique to each test
|
||||
function invocation, created as a sub directory of the base temporary
|
||||
directory.
|
||||
@@ -186,7 +180,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
The returned object is a :class:`pathlib.Path` object.
|
||||
|
||||
|
||||
========================== no tests ran in 0.12s ===========================
|
||||
no tests ran in 0.12s
|
||||
|
||||
You can also interactively ask for help, e.g. by typing on the Python interactive prompt something like:
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
.. _cache:
|
||||
|
||||
|
||||
How to re-run failed tests and maintain state between test runs
|
||||
===============================================================
|
||||
Cache: working with cross-testrun state
|
||||
=======================================
|
||||
|
||||
|
||||
|
||||
@@ -86,8 +86,9 @@ If you then run it with ``--lf``:
|
||||
|
||||
$ pytest --lf
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
run-last-failure: rerun previous 2 failures
|
||||
|
||||
@@ -132,8 +133,9 @@ of ``FF`` and dots):
|
||||
|
||||
$ pytest --ff
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 50 items
|
||||
run-last-failure: rerun previous 2 failures first
|
||||
|
||||
@@ -275,14 +277,73 @@ 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-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
cachedir: /home/sweet/project/.pytest_cache
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
--------------------------- cache values for '*' ---------------------------
|
||||
cache/lastfailed contains:
|
||||
{'test_caching.py::test_function': True}
|
||||
{'test_50.py::test_num[17]': True,
|
||||
'test_50.py::test_num[25]': True,
|
||||
'test_assert1.py::test_function': True,
|
||||
'test_assert2.py::test_set_comparison': True,
|
||||
'test_caching.py::test_function': True,
|
||||
'test_foocompare.py::test_compare': True}
|
||||
cache/nodeids contains:
|
||||
['test_caching.py::test_function']
|
||||
['test_50.py::test_num[0]',
|
||||
'test_50.py::test_num[10]',
|
||||
'test_50.py::test_num[11]',
|
||||
'test_50.py::test_num[12]',
|
||||
'test_50.py::test_num[13]',
|
||||
'test_50.py::test_num[14]',
|
||||
'test_50.py::test_num[15]',
|
||||
'test_50.py::test_num[16]',
|
||||
'test_50.py::test_num[17]',
|
||||
'test_50.py::test_num[18]',
|
||||
'test_50.py::test_num[19]',
|
||||
'test_50.py::test_num[1]',
|
||||
'test_50.py::test_num[20]',
|
||||
'test_50.py::test_num[21]',
|
||||
'test_50.py::test_num[22]',
|
||||
'test_50.py::test_num[23]',
|
||||
'test_50.py::test_num[24]',
|
||||
'test_50.py::test_num[25]',
|
||||
'test_50.py::test_num[26]',
|
||||
'test_50.py::test_num[27]',
|
||||
'test_50.py::test_num[28]',
|
||||
'test_50.py::test_num[29]',
|
||||
'test_50.py::test_num[2]',
|
||||
'test_50.py::test_num[30]',
|
||||
'test_50.py::test_num[31]',
|
||||
'test_50.py::test_num[32]',
|
||||
'test_50.py::test_num[33]',
|
||||
'test_50.py::test_num[34]',
|
||||
'test_50.py::test_num[35]',
|
||||
'test_50.py::test_num[36]',
|
||||
'test_50.py::test_num[37]',
|
||||
'test_50.py::test_num[38]',
|
||||
'test_50.py::test_num[39]',
|
||||
'test_50.py::test_num[3]',
|
||||
'test_50.py::test_num[40]',
|
||||
'test_50.py::test_num[41]',
|
||||
'test_50.py::test_num[42]',
|
||||
'test_50.py::test_num[43]',
|
||||
'test_50.py::test_num[44]',
|
||||
'test_50.py::test_num[45]',
|
||||
'test_50.py::test_num[46]',
|
||||
'test_50.py::test_num[47]',
|
||||
'test_50.py::test_num[48]',
|
||||
'test_50.py::test_num[49]',
|
||||
'test_50.py::test_num[4]',
|
||||
'test_50.py::test_num[5]',
|
||||
'test_50.py::test_num[6]',
|
||||
'test_50.py::test_num[7]',
|
||||
'test_50.py::test_num[8]',
|
||||
'test_50.py::test_num[9]',
|
||||
'test_assert1.py::test_function',
|
||||
'test_assert2.py::test_set_comparison',
|
||||
'test_caching.py::test_function',
|
||||
'test_foocompare.py::test_compare']
|
||||
cache/stepwise contains:
|
||||
[]
|
||||
example/value contains:
|
||||
@@ -297,9 +358,10 @@ filtering:
|
||||
|
||||
$ pytest --cache-show example/*
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
cachedir: /home/sweet/project/.pytest_cache
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
----------------------- cache values for 'example/*' -----------------------
|
||||
example/value contains:
|
||||
42
|
||||
@@ -321,9 +383,7 @@ servers where isolation and correctness is more important
|
||||
than speed.
|
||||
|
||||
|
||||
.. _cache stepwise:
|
||||
|
||||
Stepwise
|
||||
--------
|
||||
|
||||
As an alternative to ``--lf -x``, especially for cases where you expect a large part of the test suite will fail, ``--sw``, ``--stepwise`` allows you to fix them one at a time. The test suite will run until the first failure and then stop. At the next invocation, tests will continue from the last failing test and then run until the next failing test. You may use the ``--stepwise-skip`` option to ignore one failing test and stop the test execution on the second failing test instead. This is useful if you get stuck on a failing test and just want to ignore it until later. Providing ``--stepwise-skip`` will also enable ``--stepwise`` implicitly.
|
||||
As an alternative to ``--lf -x``, especially for cases where you expect a large part of the test suite will fail, ``--sw``, ``--stepwise`` allows you to fix them one at a time. The test suite will run until the first failure and then stop. At the next invocation, tests will continue from the last failing test and then run until the next failing test. You may use the ``--stepwise-skip`` option to ignore one failing test and stop the test execution on the second failing test instead. This is useful if you get stuck on a failing test and just want to ignore it until later.
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
.. _`captures`:
|
||||
|
||||
How to capture stdout/stderr output
|
||||
Capturing of the stdout/stderr output
|
||||
=========================================================
|
||||
|
||||
Default stdout/stderr/stdin capturing behaviour
|
||||
@@ -83,8 +83,9 @@ of the failing function and hide the other one:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
|
||||
test_module.py .F [100%]
|
||||
@@ -98,7 +99,7 @@ of the failing function and hide the other one:
|
||||
|
||||
test_module.py:12: AssertionError
|
||||
-------------------------- Captured stdout setup ---------------------------
|
||||
setting up <function test_func2 at 0xdeadbeef0001>
|
||||
setting up <function test_func2 at 0xdeadbeef>
|
||||
========================= short test summary info ==========================
|
||||
FAILED test_module.py::test_func2 - assert False
|
||||
======================= 1 failed, 1 passed in 0.12s ========================
|
||||
3690
doc/en/changelog.rst
@@ -17,9 +17,7 @@
|
||||
# The short X.Y version.
|
||||
import ast
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
from textwrap import dedent
|
||||
from typing import List
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
@@ -37,26 +35,8 @@ release = ".".join(version.split(".")[:2])
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
autodoc_member_order = "bysource"
|
||||
autodoc_typehints = "description"
|
||||
todo_include_todos = 1
|
||||
|
||||
latex_engine = "lualatex"
|
||||
|
||||
latex_elements = {
|
||||
"preamble": dedent(
|
||||
r"""
|
||||
\directlua{
|
||||
luaotfload.add_fallback("fallbacks", {
|
||||
"Noto Serif CJK SC:style=Regular;",
|
||||
"Symbola:Style=Regular;"
|
||||
})
|
||||
}
|
||||
|
||||
\setmainfont{FreeSerif}[RawFeature={fallback=fallbacks}]
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
@@ -69,7 +49,6 @@ extensions = [
|
||||
"pygments_pytest",
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.autosummary",
|
||||
"sphinx.ext.extlinks",
|
||||
"sphinx.ext.intersphinx",
|
||||
"sphinx.ext.todo",
|
||||
"sphinx.ext.viewcode",
|
||||
@@ -77,13 +56,6 @@ extensions = [
|
||||
"sphinxcontrib_trio",
|
||||
]
|
||||
|
||||
# Building PDF docs on readthedocs requires inkscape for svg to pdf
|
||||
# conversion. The relevant plugin is not useful for normal HTML builds, but
|
||||
# it still raises warnings and fails CI if inkscape is not available. So
|
||||
# only use the plugin if inkscape is actually available.
|
||||
if shutil.which("inkscape"):
|
||||
extensions.append("sphinxcontrib.inkscapeconverter")
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ["_templates"]
|
||||
|
||||
@@ -98,7 +70,7 @@ master_doc = "contents"
|
||||
|
||||
# General information about the project.
|
||||
project = "pytest"
|
||||
copyright = "2015, holger krekel and pytest-dev team"
|
||||
copyright = "2015–2020, holger krekel and pytest-dev team"
|
||||
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
@@ -150,6 +122,7 @@ pygments_style = "sphinx"
|
||||
# A list of regular expressions that match URIs that should not be checked when
|
||||
# doing a linkcheck.
|
||||
linkcheck_ignore = [
|
||||
"https://github.com/numpy/numpy/blob/master/doc/release/1.16.0-notes.rst#new-deprecations",
|
||||
"https://blogs.msdn.microsoft.com/bharry/2017/06/28/testing-in-a-cloud-delivery-cadence/",
|
||||
"http://pythontesting.net/framework/pytest-introduction/",
|
||||
r"https://github.com/pytest-dev/pytest/issues/\d+",
|
||||
@@ -160,16 +133,6 @@ linkcheck_ignore = [
|
||||
linkcheck_workers = 5
|
||||
|
||||
|
||||
_repo = "https://github.com/pytest-dev/pytest"
|
||||
extlinks = {
|
||||
"bpo": ("https://bugs.python.org/issue%s", "bpo-"),
|
||||
"pypi": ("https://pypi.org/project/%s/", ""),
|
||||
"issue": (f"{_repo}/issues/%s", "issue #"),
|
||||
"pull": (f"{_repo}/pull/%s", "pull request #"),
|
||||
"user": ("https://github.com/%s", "@"),
|
||||
}
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
sys.path.append(os.path.abspath("_themes"))
|
||||
@@ -196,7 +159,7 @@ html_short_title = "pytest-%s" % release
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
html_logo = "img/pytest_logo_curves.svg"
|
||||
html_logo = "img/pytest1.png"
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
@@ -288,7 +251,7 @@ latex_documents = [
|
||||
"contents",
|
||||
"pytest.tex",
|
||||
"pytest Documentation",
|
||||
"holger krekel, trainer and consultant, https://merlinux.eu/",
|
||||
"holger krekel, trainer and consultant, http://merlinux.eu",
|
||||
"manual",
|
||||
)
|
||||
]
|
||||
@@ -329,7 +292,7 @@ man_pages = [("usage", "pytest", "pytest usage", ["holger krekel at merlinux eu"
|
||||
epub_title = "pytest"
|
||||
epub_author = "holger krekel at merlinux eu"
|
||||
epub_publisher = "holger krekel at merlinux eu"
|
||||
epub_copyright = "2013, holger krekel et alii"
|
||||
epub_copyright = "2013-2020, holger krekel et alii"
|
||||
|
||||
# The language of the text. It defaults to the language option
|
||||
# or en if the language is not set.
|
||||
@@ -384,17 +347,8 @@ texinfo_documents = [
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {
|
||||
"pluggy": ("https://pluggy.readthedocs.io/en/stable", None),
|
||||
"pluggy": ("https://pluggy.readthedocs.io/en/latest", None),
|
||||
"python": ("https://docs.python.org/3", None),
|
||||
"numpy": ("https://numpy.org/doc/stable", None),
|
||||
"pip": ("https://pip.pypa.io/en/stable", None),
|
||||
"tox": ("https://tox.wiki/en/stable", None),
|
||||
"virtualenv": ("https://virtualenv.pypa.io/en/stable", None),
|
||||
"django": (
|
||||
"http://docs.djangoproject.com/en/stable",
|
||||
"http://docs.djangoproject.com/en/stable/_objects",
|
||||
),
|
||||
"setuptools": ("https://setuptools.pypa.io/en/stable", None),
|
||||
}
|
||||
|
||||
|
||||
@@ -465,7 +419,3 @@ def setup(app: "sphinx.application.Sphinx") -> None:
|
||||
)
|
||||
|
||||
sphinx.pycode.parser.VariableCommentPicker.is_final = patched_is_final
|
||||
|
||||
# legacypath.py monkey-patches pytest.Testdir in. Import the file so
|
||||
# that autodoc can discover references to it.
|
||||
import _pytest.legacypath # noqa: F401
|
||||
|
||||
@@ -7,24 +7,21 @@ 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 discord server <https://discord.com/invite/pytest-dev>`_
|
||||
for pytest development visibility and general assistance.
|
||||
|
||||
- `pytest on stackoverflow.com <http://stackoverflow.com/search?q=pytest>`_
|
||||
to post precise questions with the tag ``pytest``. New Questions will usually
|
||||
to post 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.
|
||||
|
||||
- ``#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>`_).
|
||||
- ``#pylib`` on irc.freenode.net IRC channel for random questions.
|
||||
|
||||
- private mail to Holger.Krekel at gmail com if you want to communicate sensitive issues
|
||||
|
||||
@@ -33,21 +30,19 @@ Contact channels
|
||||
consulting.
|
||||
|
||||
.. _`pytest issue tracker`: https://github.com/pytest-dev/pytest/issues
|
||||
.. _`old issue tracker`: https://bitbucket.org/hpk42/py-trunk/issues/
|
||||
.. _`old issue tracker`: http://bitbucket.org/hpk42/py-trunk/issues/
|
||||
|
||||
.. _`pytest discussions`: https://github.com/pytest-dev/pytest/discussions
|
||||
|
||||
.. _`merlinux.eu`: https://merlinux.eu/
|
||||
.. _`merlinux.eu`: http://merlinux.eu
|
||||
|
||||
.. _`get an account`:
|
||||
|
||||
.. _tetamap: https://tetamap.wordpress.com/
|
||||
.. _tetamap: http://tetamap.wordpress.com
|
||||
|
||||
.. _`@pylibcommit`: https://twitter.com/pylibcommit
|
||||
.. _`@pylibcommit`: http://twitter.com/pylibcommit
|
||||
|
||||
|
||||
.. _`Testing in Python`: http://lists.idyll.org/listinfo/testing-in-python
|
||||
.. _FOAF: https://en.wikipedia.org/wiki/FOAF
|
||||
.. _FOAF: http://en.wikipedia.org/wiki/FOAF
|
||||
.. _`py-dev`:
|
||||
.. _`development mailing list`:
|
||||
.. _`pytest-dev at python.org (mailing list)`: http://mail.python.org/mailman/listinfo/pytest-dev
|
||||
|
||||
@@ -7,81 +7,37 @@ Full pytest documentation
|
||||
|
||||
.. `Download latest version as EPUB <http://media.readthedocs.org/epub/pytest/latest/pytest.epub>`_
|
||||
|
||||
|
||||
Start here
|
||||
-----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
getting-started
|
||||
usage
|
||||
existingtestsuite
|
||||
assert
|
||||
fixture
|
||||
mark
|
||||
monkeypatch
|
||||
tmpdir
|
||||
capture
|
||||
warnings
|
||||
doctest
|
||||
skipping
|
||||
parametrize
|
||||
cache
|
||||
unittest
|
||||
nose
|
||||
xunit_setup
|
||||
plugins
|
||||
writing_plugins
|
||||
logging
|
||||
reference
|
||||
|
||||
|
||||
How-to guides
|
||||
-------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
how-to/usage
|
||||
how-to/assert
|
||||
how-to/fixtures
|
||||
how-to/mark
|
||||
how-to/parametrize
|
||||
how-to/tmp_path
|
||||
how-to/monkeypatch
|
||||
how-to/doctest
|
||||
how-to/cache
|
||||
|
||||
how-to/logging
|
||||
how-to/capture-stdout-stderr
|
||||
how-to/capture-warnings
|
||||
how-to/skipping
|
||||
|
||||
how-to/plugins
|
||||
how-to/writing_plugins
|
||||
how-to/writing_hook_functions
|
||||
|
||||
how-to/existingtestsuite
|
||||
how-to/unittest
|
||||
how-to/nose
|
||||
how-to/xunit_setup
|
||||
|
||||
how-to/bash-completion
|
||||
|
||||
|
||||
Reference guides
|
||||
-----------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
reference/fixtures
|
||||
reference/plugin_list
|
||||
reference/customize
|
||||
reference/reference
|
||||
|
||||
|
||||
Explanation
|
||||
-----------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
explanation/anatomy
|
||||
explanation/fixtures
|
||||
explanation/goodpractices
|
||||
explanation/flaky
|
||||
explanation/pythonpath
|
||||
|
||||
|
||||
Further topics
|
||||
-----------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
goodpractices
|
||||
flaky
|
||||
pythonpath
|
||||
customize
|
||||
example/index
|
||||
bash-completion
|
||||
|
||||
backwards-compatibility
|
||||
deprecations
|
||||
@@ -95,9 +51,9 @@ Further topics
|
||||
license
|
||||
contact
|
||||
|
||||
history
|
||||
historical-notes
|
||||
talks
|
||||
projects
|
||||
|
||||
|
||||
.. only:: html
|
||||
|
||||
@@ -89,7 +89,7 @@ and can also be used to hold pytest configuration if they have a ``[pytest]`` se
|
||||
setup.cfg
|
||||
~~~~~~~~~
|
||||
|
||||
``setup.cfg`` files are general purpose configuration files, used originally by :doc:`distutils <distutils/configfile>`, and can also be used to hold pytest configuration
|
||||
``setup.cfg`` files are general purpose configuration files, used originally by `distutils <https://docs.python.org/3/distutils/configfile.html>`__, and can also be used to hold pytest configuration
|
||||
if they have a ``[tool:pytest]`` section.
|
||||
|
||||
.. code-block:: ini
|
||||
@@ -145,8 +145,6 @@ Finding the ``rootdir``
|
||||
|
||||
Here is the algorithm which finds the rootdir from ``args``:
|
||||
|
||||
- If ``-c`` is passed in the command-line, use that as configuration file, and its directory as ``rootdir``.
|
||||
|
||||
- Determine the common ancestor directory for the specified ``args`` that are
|
||||
recognised as paths that exist in the file system. If no such paths are
|
||||
found, the common ancestor directory is set to the current working directory.
|
||||
@@ -162,7 +160,7 @@ Here is the algorithm which finds the rootdir from ``args``:
|
||||
``setup.cfg`` in each of the specified ``args`` and upwards. If one is
|
||||
matched, it becomes the ``configfile`` and its directory becomes the ``rootdir``.
|
||||
|
||||
- If no ``configfile`` was found and no configuration argument is passed, use the already determined common ancestor as root
|
||||
- If no ``configfile`` was found, use the already determined common ancestor as root
|
||||
directory. This allows the use of pytest in structures that are not part of
|
||||
a package and don't have any particular configuration file.
|
||||
|
||||
@@ -179,12 +177,12 @@ Files will only be matched for configuration if:
|
||||
The files are considered in the order above. Options from multiple ``configfiles`` candidates
|
||||
are never merged - the first match wins.
|
||||
|
||||
The :class:`Config <pytest.Config>` object (accessible via hooks or through the :fixture:`pytestconfig` fixture)
|
||||
The internal :class:`Config <_pytest.config.Config>` object (accessible via hooks or through the :fixture:`pytestconfig` fixture)
|
||||
will subsequently carry these attributes:
|
||||
|
||||
- :attr:`config.rootpath <pytest.Config.rootpath>`: the determined root directory, guaranteed to exist.
|
||||
- :attr:`config.rootpath <_pytest.config.Config.rootpath>`: the determined root directory, guaranteed to exist.
|
||||
|
||||
- :attr:`config.inipath <pytest.Config.inipath>`: the determined ``configfile``, may be ``None``
|
||||
- :attr:`config.inipath <_pytest.config.Config.inipath>`: the determined ``configfile``, may be ``None``
|
||||
(it is named ``inipath`` for historical reasons).
|
||||
|
||||
.. versionadded:: 6.1
|
||||
@@ -226,7 +224,7 @@ check for configuration files as follows:
|
||||
Custom pytest plugin commandline arguments may include a path, as in
|
||||
``pytest --log-output ../../test.log args``. Then ``args`` is mandatory,
|
||||
otherwise pytest uses the folder of test.log for rootdir determination
|
||||
(see also :issue:`1435`).
|
||||
(see also `issue 1435 <https://github.com/pytest-dev/pytest/issues/1435>`_).
|
||||
A dot ``.`` for referencing to the current working directory is also
|
||||
possible.
|
||||
|
||||
@@ -239,11 +237,3 @@ Builtin configuration file options
|
||||
----------------------------------------------
|
||||
|
||||
For the full list of options consult the :ref:`reference documentation <ini options ref>`.
|
||||
|
||||
Syntax highlighting theme customization
|
||||
---------------------------------------
|
||||
|
||||
The syntax highlighting themes used by pytest can be customized using two environment variables:
|
||||
|
||||
- :envvar:`PYTEST_THEME` sets a `pygment style <https://pygments.org/docs/styles/>`_ to use.
|
||||
- :envvar:`PYTEST_THEME_MODE` sets this style to *light* or *dark*.
|
||||
@@ -18,215 +18,6 @@ Deprecated Features
|
||||
Below is a complete list of all pytest features which are considered deprecated. Using those features will issue
|
||||
:class:`PytestWarning` or subclasses, which can be filtered using :ref:`standard warning filters <warnings>`.
|
||||
|
||||
.. _instance-collector-deprecation:
|
||||
|
||||
The ``pytest.Instance`` collector
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionremoved:: 7.0
|
||||
|
||||
The ``pytest.Instance`` collector type has been removed.
|
||||
|
||||
Previously, Python test methods were collected as :class:`~pytest.Class` -> ``Instance`` -> :class:`~pytest.Function`.
|
||||
Now :class:`~pytest.Class` collects the test methods directly.
|
||||
|
||||
Most plugins which reference ``Instance`` do so in order to ignore or skip it,
|
||||
using a check such as ``if isinstance(node, Instance): return``.
|
||||
Such plugins should simply remove consideration of ``Instance`` on pytest>=7.
|
||||
However, to keep such uses working, a dummy type has been instanted in ``pytest.Instance`` and ``_pytest.python.Instance``,
|
||||
and importing it emits a deprecation warning. This will be removed in pytest 8.
|
||||
|
||||
|
||||
.. _node-ctor-fspath-deprecation:
|
||||
|
||||
``fspath`` argument for Node constructors replaced with ``pathlib.Path``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 7.0
|
||||
|
||||
In order to support the transition from ``py.path.local`` to :mod:`pathlib`,
|
||||
the ``fspath`` argument to :class:`~_pytest.nodes.Node` constructors like
|
||||
:func:`pytest.Function.from_parent()` and :func:`pytest.Class.from_parent()`
|
||||
is now deprecated.
|
||||
|
||||
Plugins which construct nodes should pass the ``path`` argument, of type
|
||||
:class:`pathlib.Path`, instead of the ``fspath`` argument.
|
||||
|
||||
Plugins which implement custom items and collectors are encouraged to replace
|
||||
``fspath`` parameters (``py.path.local``) with ``path`` parameters
|
||||
(``pathlib.Path``), and drop any other usage of the ``py`` library if possible.
|
||||
|
||||
.. note::
|
||||
The name of the :class:`~_pytest.nodes.Node` arguments and attributes (the
|
||||
new attribute being ``path``) is **the opposite** of the situation for
|
||||
hooks, :ref:`outlined below <legacy-path-hooks-deprecated>` (the old
|
||||
argument being ``path``).
|
||||
|
||||
This is an unfortunate artifact due to historical reasons, which should be
|
||||
resolved in future versions as we slowly get rid of the :pypi:`py`
|
||||
dependency (see :issue:`9283` for a longer discussion).
|
||||
|
||||
Due to the ongoing migration of methods like :meth:`~_pytest.Item.reportinfo`
|
||||
which still is expected to return a ``py.path.local`` object, nodes still have
|
||||
both ``fspath`` (``py.path.local``) and ``path`` (``pathlib.Path``) attributes,
|
||||
no matter what argument was used in the constructor. We expect to deprecate the
|
||||
``fspath`` attribute in a future release.
|
||||
|
||||
.. _legacy-path-hooks-deprecated:
|
||||
|
||||
``py.path.local`` arguments for hooks replaced with ``pathlib.Path``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 7.0
|
||||
|
||||
In order to support the transition from ``py.path.local`` to :mod:`pathlib`, the following hooks now receive additional arguments:
|
||||
|
||||
* :func:`pytest_ignore_collect(collection_path: pathlib.Path) <_pytest.hookspec.pytest_ignore_collect>` as equivalent to ``path``
|
||||
* :func:`pytest_collect_file(file_path: pathlib.Path) <_pytest.hookspec.pytest_collect_file>` as equivalent to ``path``
|
||||
* :func:`pytest_pycollect_makemodule(module_path: pathlib.Path) <_pytest.hookspec.pytest_pycollect_makemodule>` as equivalent to ``path``
|
||||
* :func:`pytest_report_header(start_path: pathlib.Path) <_pytest.hookspec.pytest_report_header>` as equivalent to ``startdir``
|
||||
* :func:`pytest_report_collectionfinish(start_path: pathlib.Path) <_pytest.hookspec.pytest_report_collectionfinish>` as equivalent to ``startdir``
|
||||
|
||||
The accompanying ``py.path.local`` based paths have been deprecated: plugins which manually invoke those hooks should only pass the new ``pathlib.Path`` arguments, and users should change their hook implementations to use the new ``pathlib.Path`` arguments.
|
||||
|
||||
.. note::
|
||||
The name of the :class:`~_pytest.nodes.Node` arguments and attributes,
|
||||
:ref:`outlined above <node-ctor-fspath-deprecation>` (the new attribute
|
||||
being ``path``) is **the opposite** of the situation for hooks (the old
|
||||
argument being ``path``).
|
||||
|
||||
This is an unfortunate artifact due to historical reasons, which should be
|
||||
resolved in future versions as we slowly get rid of the :pypi:`py`
|
||||
dependency (see :issue:`9283` for a longer discussion).
|
||||
|
||||
Directly constructing internal classes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 7.0
|
||||
|
||||
Directly constructing the following classes is now deprecated:
|
||||
|
||||
- ``_pytest.mark.structures.Mark``
|
||||
- ``_pytest.mark.structures.MarkDecorator``
|
||||
- ``_pytest.mark.structures.MarkGenerator``
|
||||
- ``_pytest.python.Metafunc``
|
||||
- ``_pytest.runner.CallInfo``
|
||||
- ``_pytest._code.ExceptionInfo``
|
||||
- ``_pytest.config.argparsing.Parser``
|
||||
- ``_pytest.config.argparsing.OptionGroup``
|
||||
- ``_pytest.pytester.HookRecorder``
|
||||
|
||||
These constructors have always been considered private, but now issue a deprecation warning, which may become a hard error in pytest 8.
|
||||
|
||||
.. _cmdline-preparse-deprecated:
|
||||
|
||||
Passing ``msg=`` to ``pytest.skip``, ``pytest.fail`` or ``pytest.exit``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 7.0
|
||||
|
||||
Passing the keyword argument ``msg`` to :func:`pytest.skip`, :func:`pytest.fail` or :func:`pytest.exit`
|
||||
is now deprecated and ``reason`` should be used instead. This change is to bring consistency between these
|
||||
functions and the``@pytest.mark.skip`` and ``@pytest.mark.xfail`` markers which already accept a ``reason`` argument.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def test_fail_example():
|
||||
# old
|
||||
pytest.fail(msg="foo")
|
||||
# new
|
||||
pytest.fail(reason="bar")
|
||||
|
||||
|
||||
def test_skip_example():
|
||||
# old
|
||||
pytest.skip(msg="foo")
|
||||
# new
|
||||
pytest.skip(reason="bar")
|
||||
|
||||
|
||||
def test_exit_example():
|
||||
# old
|
||||
pytest.exit(msg="foo")
|
||||
# new
|
||||
pytest.exit(reason="bar")
|
||||
|
||||
|
||||
Implementing the ``pytest_cmdline_preparse`` hook
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 7.0
|
||||
|
||||
Implementing the :func:`pytest_cmdline_preparse <_pytest.hookspec.pytest_cmdline_preparse>` hook has been officially deprecated.
|
||||
Implement the :func:`pytest_load_initial_conftests <_pytest.hookspec.pytest_load_initial_conftests>` hook instead.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_cmdline_preparse(config: Config, args: List[str]) -> None:
|
||||
...
|
||||
|
||||
|
||||
# becomes:
|
||||
|
||||
|
||||
def pytest_load_initial_conftests(
|
||||
early_config: Config, parser: Parser, args: List[str]
|
||||
) -> None:
|
||||
...
|
||||
|
||||
.. _diamond-inheritance-deprecated:
|
||||
|
||||
Diamond inheritance between :class:`pytest.Collector` and :class:`pytest.Item`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 7.0
|
||||
|
||||
Defining a custom pytest node type which is both an :class:`pytest.Item <Item>` and a :class:`pytest.Collector <Collector>` (e.g. :class:`pytest.File <File>`) now issues a warning.
|
||||
It was never sanely supported and triggers hard to debug errors.
|
||||
|
||||
Some plugins providing linting/code analysis have been using this as a hack.
|
||||
Instead, a separate collector node should be used, which collects the item. See
|
||||
:ref:`non-python tests` for an example, as well as an `example pr fixing inheritance`_.
|
||||
|
||||
.. _example pr fixing inheritance: https://github.com/asmeurer/pytest-flakes/pull/40/files
|
||||
|
||||
|
||||
Backward compatibilities in ``Parser.addoption``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 2.4
|
||||
|
||||
Several behaviors of :meth:`Parser.addoption <pytest.Parser.addoption>` are now
|
||||
scheduled for removal in pytest 8 (deprecated since pytest 2.4.0):
|
||||
|
||||
- ``parser.addoption(..., help=".. %default ..")`` - use ``%(default)s`` instead.
|
||||
- ``parser.addoption(..., type="int/string/float/complex")`` - use ``type=int`` etc. instead.
|
||||
|
||||
|
||||
Raising ``unittest.SkipTest`` during collection
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 7.0
|
||||
|
||||
Raising :class:`unittest.SkipTest` to skip collection of tests during the
|
||||
pytest collection phase is deprecated. Use :func:`pytest.skip` instead.
|
||||
|
||||
Note: This deprecation only relates to using `unittest.SkipTest` during test
|
||||
collection. You are probably not doing that. Ordinary usage of
|
||||
:class:`unittest.SkipTest` / :meth:`unittest.TestCase.skipTest` /
|
||||
:func:`unittest.skip` in unittest test cases is fully supported.
|
||||
|
||||
Using ``pytest.warns(None)``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 7.0
|
||||
|
||||
:func:`pytest.warns(None) <pytest.warns>` is now deprecated because many people used
|
||||
it to mean "this code does not emit warnings", but it actually had the effect of
|
||||
checking that the code emits at least one warning of any type - like ``pytest.warns()``
|
||||
or ``pytest.warns(Warning)``.
|
||||
|
||||
|
||||
The ``--strict`` command-line option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -301,7 +92,6 @@ A ``--show-capture`` command-line option was added in ``pytest 3.5.0`` which all
|
||||
display captured output when tests fail: ``no``, ``stdout``, ``stderr``, ``log`` or ``all`` (the default).
|
||||
|
||||
|
||||
.. _resultlog deprecated:
|
||||
|
||||
Result log (``--result-log``)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -339,8 +129,6 @@ with ``py.io.TerminalWriter``.
|
||||
Plugins that used ``TerminalReporter.writer`` directly should instead use ``TerminalReporter``
|
||||
methods that provide the same functionality.
|
||||
|
||||
.. _junit-family changed default value:
|
||||
|
||||
``junit_family`` default value change to "xunit2"
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -428,8 +216,6 @@ in places where we or plugin authors must distinguish between fixture names and
|
||||
names supplied by non-fixture things such as ``pytest.mark.parametrize``.
|
||||
|
||||
|
||||
.. _pytest.config global deprecated:
|
||||
|
||||
``pytest.config`` global
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -474,7 +260,7 @@ Becomes:
|
||||
|
||||
|
||||
If you still have concerns about this deprecation and future removal, please comment on
|
||||
:issue:`3974`.
|
||||
`issue #3974 <https://github.com/pytest-dev/pytest/issues/3974>`__.
|
||||
|
||||
|
||||
.. _raises-warns-exec:
|
||||
@@ -527,8 +313,6 @@ This issue should affect only advanced plugins who create new collection types,
|
||||
message please contact the authors so they can change the code.
|
||||
|
||||
|
||||
.. _marks in pytest.parametrize deprecated:
|
||||
|
||||
marks in ``pytest.mark.parametrize``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -577,8 +361,6 @@ To update the code, use ``pytest.param``:
|
||||
...
|
||||
|
||||
|
||||
.. _pytest_funcarg__ prefix deprecated:
|
||||
|
||||
``pytest_funcarg__`` prefix
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -610,15 +392,13 @@ Switch over to the ``@pytest.fixture`` decorator:
|
||||
to avoid conflicts with other distutils commands.
|
||||
|
||||
|
||||
.. _metafunc.addcall deprecated:
|
||||
|
||||
Metafunc.addcall
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionremoved:: 4.0
|
||||
|
||||
``Metafunc.addcall`` was a precursor to the current parametrized mechanism. Users should use
|
||||
:meth:`pytest.Metafunc.parametrize` instead.
|
||||
``_pytest.python.Metafunc.addcall`` was a precursor to the current parametrized mechanism. Users should use
|
||||
:meth:`_pytest.python.Metafunc.parametrize` instead.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -636,8 +416,6 @@ Becomes:
|
||||
metafunc.parametrize("i", [1, 2], ids=["1", "2"])
|
||||
|
||||
|
||||
.. _cached_setup deprecated:
|
||||
|
||||
``cached_setup``
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -666,12 +444,10 @@ This should be updated to make use of standard fixture mechanisms:
|
||||
session.close()
|
||||
|
||||
|
||||
You can consult :std:doc:`funcarg comparison section in the docs <funcarg_compare>` for
|
||||
You can consult `funcarg comparison section in the docs <https://docs.pytest.org/en/stable/funcarg_compare.html>`_ for
|
||||
more information.
|
||||
|
||||
|
||||
.. _pytest_plugins in non-top-level conftest files deprecated:
|
||||
|
||||
pytest_plugins in non-top-level conftest files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -682,8 +458,6 @@ files because they will activate referenced plugins *globally*, which is surpris
|
||||
features ``conftest.py`` files are only *active* for tests at or below it.
|
||||
|
||||
|
||||
.. _config.warn and node.warn deprecated:
|
||||
|
||||
``Config.warn`` and ``Node.warn``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -711,8 +485,6 @@ Becomes:
|
||||
|
||||
* ``node.warn("CI", "some message")``: this code/message form has been **removed** and should be converted to the warning instance form above.
|
||||
|
||||
.. _record_xml_property deprecated:
|
||||
|
||||
record_xml_property
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -736,8 +508,6 @@ Change to:
|
||||
...
|
||||
|
||||
|
||||
.. _passing command-line string to pytest.main deprecated:
|
||||
|
||||
Passing command-line string to ``pytest.main()``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -760,8 +530,6 @@ By passing a string, users expect that pytest will interpret that command-line u
|
||||
on (for example ``bash`` or ``Powershell``), but this is very hard/impossible to do in a portable way.
|
||||
|
||||
|
||||
.. _calling fixtures directly deprecated:
|
||||
|
||||
Calling fixtures directly
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -815,8 +583,6 @@ with the ``name`` parameter:
|
||||
return cell()
|
||||
|
||||
|
||||
.. _yield tests deprecated:
|
||||
|
||||
``yield`` tests
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -845,8 +611,6 @@ This form of test function doesn't support fixtures properly, and users should s
|
||||
def test_squared(x, y):
|
||||
assert x ** x == y
|
||||
|
||||
.. _internal classes accessed through node deprecated:
|
||||
|
||||
Internal classes accessed through ``Node``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -881,8 +645,6 @@ As part of a large :ref:`marker-revamp` we already deprecated using ``MarkInfo``
|
||||
the only correct way to get markers of an element is via ``node.iter_markers(name)``.
|
||||
|
||||
|
||||
.. _pytest.namespace deprecated:
|
||||
|
||||
``pytest_namespace``
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -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/main/RELEASING.rst>`_.
|
||||
`GitHub <https://github.com/pytest-dev/pytest/blob/master/RELEASING.rst>`_.
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
.. _doctest:
|
||||
|
||||
How to run doctests
|
||||
Doctest integration for modules and test files
|
||||
=========================================================
|
||||
|
||||
By default, all files matching the ``test*.txt`` pattern will
|
||||
be run through the python standard :mod:`doctest` module. You
|
||||
be run through the python standard ``doctest`` module. You
|
||||
can change the pattern by issuing:
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -30,8 +29,9 @@ then you can just invoke ``pytest`` directly:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
|
||||
test_example.txt . [100%]
|
||||
@@ -48,7 +48,7 @@ and functions, including from test modules:
|
||||
|
||||
# content of mymodule.py
|
||||
def something():
|
||||
"""a doctest in a docstring
|
||||
""" a doctest in a docstring
|
||||
>>> something()
|
||||
42
|
||||
"""
|
||||
@@ -58,8 +58,9 @@ and functions, including from test modules:
|
||||
|
||||
$ pytest --doctest-modules
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
|
||||
mymodule.py . [ 50%]
|
||||
@@ -90,12 +91,10 @@ that will be used for those doctest files using the
|
||||
[pytest]
|
||||
doctest_encoding = latin1
|
||||
|
||||
.. _using doctest options:
|
||||
|
||||
Using 'doctest' options
|
||||
-----------------------
|
||||
|
||||
Python's standard :mod:`doctest` module provides some :ref:`options <python:option-flags-and-directives>`
|
||||
Python's standard ``doctest`` module provides some `options <https://docs.python.org/3/library/doctest.html#option-flags>`__
|
||||
to configure the strictness of doctest tests. In pytest, you can enable those flags using the
|
||||
configuration file.
|
||||
|
||||
@@ -194,7 +193,7 @@ It is possible to use fixtures using the ``getfixture`` helper:
|
||||
.. code-block:: text
|
||||
|
||||
# content of example.rst
|
||||
>>> tmp = getfixture('tmp_path')
|
||||
>>> tmp = getfixture('tmpdir')
|
||||
>>> ...
|
||||
>>>
|
||||
|
||||
@@ -252,7 +251,7 @@ For the same reasons one might want to skip normal tests, it is also possible to
|
||||
tests inside doctests.
|
||||
|
||||
To skip a single check inside a doctest you can use the standard
|
||||
:data:`doctest.SKIP` directive:
|
||||
`doctest.SKIP <https://docs.python.org/3/library/doctest.html#doctest.SKIP>`__ directive:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -5,9 +5,9 @@ failure_demo = os.path.join(os.path.dirname(__file__), "failure_demo.py")
|
||||
pytest_plugins = ("pytester",)
|
||||
|
||||
|
||||
def test_failure_demo_fails_properly(pytester):
|
||||
target = pytester.path.joinpath(os.path.basename(failure_demo))
|
||||
def test_failure_demo_fails_properly(testdir):
|
||||
target = testdir.tmpdir.join(os.path.basename(failure_demo))
|
||||
shutil.copy(failure_demo, target)
|
||||
result = pytester.runpytest(target, syspathinsert=True)
|
||||
result = testdir.runpytest(target, syspathinsert=True)
|
||||
result.stdout.fnmatch_lines(["*44 failed*"])
|
||||
assert result.ret != 0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="572" height="542">
|
||||
<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;
|
||||
@@ -37,7 +37,7 @@
|
||||
<path d="M 26,271 A 260 260 0 0 1 546 271" id="testp"/>
|
||||
</defs>
|
||||
<text class="package">
|
||||
<textPath xlink:href="#testp" startOffset="50%">tests</textPath>
|
||||
<textPath href="#testp" startOffset="50%">tests</textPath>
|
||||
</text>
|
||||
|
||||
<!-- subpackage -->
|
||||
@@ -47,7 +47,7 @@
|
||||
<path d="M 56,271 A 130 130 0 0 1 316 271" id="subpackage"/>
|
||||
</defs>
|
||||
<text class="package">
|
||||
<textPath xlink:href="#subpackage" startOffset="50%">subpackage</textPath>
|
||||
<textPath href="#subpackage" startOffset="50%">subpackage</textPath>
|
||||
</text>
|
||||
|
||||
<!-- test_subpackage.py -->
|
||||
@@ -57,7 +57,7 @@
|
||||
<path d="M 106,311 A 80 80 0 0 1 266 311" id="testSubpackage"/>
|
||||
</defs>
|
||||
<text class="module">
|
||||
<textPath xlink:href="#testSubpackage" startOffset="50%">test_subpackage.py</textPath>
|
||||
<textPath href="#testSubpackage" startOffset="50%">test_subpackage.py</textPath>
|
||||
</text>
|
||||
<!-- innermost -->
|
||||
<line x1="186" x2="186" y1="271" y2="351"/>
|
||||
@@ -102,7 +102,7 @@
|
||||
<path d="M 366,271 A 75 75 0 0 1 516 271" id="testTop"/>
|
||||
</defs>
|
||||
<text class="module">
|
||||
<textPath xlink:href="#testTop" startOffset="50%">test_top.py</textPath>
|
||||
<textPath href="#testTop" startOffset="50%">test_top.py</textPath>
|
||||
</text>
|
||||
<!-- innermost -->
|
||||
<line x1="441" x2="441" y1="306" y2="236"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.9 KiB |
@@ -1,4 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="587" height="382">
|
||||
<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;
|
||||
@@ -38,7 +38,7 @@
|
||||
<path d="M 411,86 A 75 75 0 0 1 561 86" id="pluginA"/>
|
||||
</defs>
|
||||
<text class="plugin">
|
||||
<textPath xlink:href="#pluginA" startOffset="50%">plugin_a</textPath>
|
||||
<textPath href="#pluginA" startOffset="50%">plugin_a</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="pluginAOrderMask">
|
||||
@@ -55,7 +55,7 @@
|
||||
<path d="M 411,296 A 75 75 0 0 1 561 296" id="pluginB"/>
|
||||
</defs>
|
||||
<text class="plugin">
|
||||
<textPath xlink:href="#pluginB" startOffset="50%">plugin_b</textPath>
|
||||
<textPath href="#pluginB" startOffset="50%">plugin_b</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="pluginBOrderMask">
|
||||
@@ -72,7 +72,7 @@
|
||||
<path d="M 11,191 A 180 180 0 0 1 371 191" id="testp"/>
|
||||
</defs>
|
||||
<text class="package">
|
||||
<textPath xlink:href="#testp" startOffset="50%">tests</textPath>
|
||||
<textPath href="#testp" startOffset="50%">tests</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="mainOrderMask">
|
||||
@@ -89,7 +89,7 @@
|
||||
<path d="M 61,231 A 130 130 0 0 1 321 231" id="subpackage"/>
|
||||
</defs>
|
||||
<text class="package">
|
||||
<textPath xlink:href="#subpackage" startOffset="50%">subpackage</textPath>
|
||||
<textPath href="#subpackage" startOffset="50%">subpackage</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="subpackageOrderMask">
|
||||
@@ -106,7 +106,7 @@
|
||||
<path d="M 111,271 A 80 80 0 0 1 271 271" id="testSubpackage"/>
|
||||
</defs>
|
||||
<text class="module">
|
||||
<textPath xlink:href="#testSubpackage" startOffset="50%">test_subpackage.py</textPath>
|
||||
<textPath href="#testSubpackage" startOffset="50%">test_subpackage.py</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testSubpackageOrderMask">
|
||||
|
||||
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.3 KiB |
@@ -1,4 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="862" height="402">
|
||||
<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;
|
||||
@@ -48,7 +48,7 @@
|
||||
<path d="M31,201 A 190 190 0 0 1 411 201" id="testClassWith"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath xlink:href="#testClassWith" startOffset="50%">TestWithC1Request</textPath>
|
||||
<textPath href="#testClassWith" startOffset="50%">TestWithC1Request</textPath>
|
||||
</text>
|
||||
|
||||
<!-- TestWithoutC1Request -->
|
||||
@@ -67,7 +67,7 @@
|
||||
<path d="M451,201 A 190 190 0 0 1 831 201" id="testClassWithout"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath xlink:href="#testClassWithout" startOffset="50%">TestWithoutC1Request</textPath>
|
||||
<textPath href="#testClassWithout" startOffset="50%">TestWithoutC1Request</textPath>
|
||||
</text>
|
||||
|
||||
<rect class="autouse" width="862" height="40" x="1" y="181" />
|
||||
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
@@ -1,4 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="862" height="502">
|
||||
<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;
|
||||
@@ -39,7 +39,7 @@
|
||||
<path d="M11,251 A 240 240 0 0 1 491 251" id="testClassWith"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath xlink:href="#testClassWith" startOffset="50%">TestWithAutouse</textPath>
|
||||
<textPath href="#testClassWith" startOffset="50%">TestWithAutouse</textPath>
|
||||
</text>
|
||||
<mask id="autouseScope">
|
||||
<circle fill="white" r="249" cx="251" cy="251" />
|
||||
@@ -79,7 +79,7 @@
|
||||
<path d="M 531,251 A 160 160 0 0 1 851 251" id="testClassWithout"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath xlink:href="#testClassWithout" startOffset="50%">TestWithoutAutouse</textPath>
|
||||
<textPath href="#testClassWithout" startOffset="50%">TestWithoutAutouse</textPath>
|
||||
</text>
|
||||
|
||||
<!-- TestWithoutAutouse.test_req -->
|
||||
|
||||
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.5 KiB |
@@ -1,4 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="262" height="537">
|
||||
<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;
|
||||
@@ -50,6 +50,6 @@
|
||||
<path d="M131,526 A 120 120 0 0 1 136 286" id="testClass"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath xlink:href="#testClass" startOffset="50%">TestClass</textPath>
|
||||
<textPath href="#testClass" startOffset="50%">TestClass</textPath>
|
||||
</text>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -1,4 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="562" height="532">
|
||||
<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;
|
||||
@@ -41,7 +41,7 @@
|
||||
<path d="M 26,266 A 255 255 0 0 1 536 266" id="testModule"/>
|
||||
</defs>
|
||||
<text class="module">
|
||||
<textPath xlink:href="#testModule" startOffset="50%">test_fixtures_request_different_scope.py</textPath>
|
||||
<textPath href="#testModule" startOffset="50%">test_fixtures_request_different_scope.py</textPath>
|
||||
</text>
|
||||
|
||||
<!-- TestOne -->
|
||||
@@ -61,7 +61,7 @@
|
||||
<path d="M 51,266 A 90 90 0 0 1 231 266" id="testOne"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath xlink:href="#testOne" startOffset="50%">TestOne</textPath>
|
||||
<textPath href="#testOne" startOffset="50%">TestOne</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testOneOrderMask">
|
||||
@@ -95,7 +95,7 @@
|
||||
<path d="M 331,266 A 90 90 0 0 1 511 266" id="testTwo"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath xlink:href="#testTwo" startOffset="50%">TestTwo</textPath>
|
||||
<textPath href="#testTwo" startOffset="50%">TestTwo</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testTwoOrderMask">
|
||||
|
||||
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.2 KiB |
@@ -13,12 +13,12 @@ answers.
|
||||
|
||||
For basic examples, see
|
||||
|
||||
- :ref:`get-started` for basic introductory examples
|
||||
- :doc:`../getting-started` for basic introductory examples
|
||||
- :ref:`assert` for basic assertion examples
|
||||
- :ref:`Fixtures <fixtures>` for basic fixture/setup examples
|
||||
- :ref:`parametrize` for basic test function parametrization
|
||||
- :ref:`unittest` for basic unittest integration
|
||||
- :ref:`noseintegration` for basic nosetests integration
|
||||
- :doc:`../unittest` for basic unittest integration
|
||||
- :doc:`../nose` for basic nosetests integration
|
||||
|
||||
The following examples aim at various use cases you might encounter.
|
||||
|
||||
|
||||
@@ -45,9 +45,9 @@ 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-7.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 3 deselected / 1 selected
|
||||
|
||||
test_server.py::test_send_http PASSED [100%]
|
||||
@@ -60,9 +60,9 @@ 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-7.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 1 deselected / 3 selected
|
||||
|
||||
test_server.py::test_something_quick PASSED [ 33%]
|
||||
@@ -82,9 +82,9 @@ 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-7.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 1 item
|
||||
|
||||
test_server.py::TestClass::test_method PASSED [100%]
|
||||
@@ -97,9 +97,9 @@ You can also select on the class:
|
||||
|
||||
$ pytest -v test_server.py::TestClass
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 1 item
|
||||
|
||||
test_server.py::TestClass::test_method PASSED [100%]
|
||||
@@ -112,9 +112,9 @@ 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-7.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 2 items
|
||||
|
||||
test_server.py::TestClass::test_method PASSED [ 50%]
|
||||
@@ -156,9 +156,9 @@ 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-7.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 3 deselected / 1 selected
|
||||
|
||||
test_server.py::test_send_http PASSED [100%]
|
||||
@@ -171,9 +171,9 @@ 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-7.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 1 deselected / 3 selected
|
||||
|
||||
test_server.py::test_something_quick PASSED [ 33%]
|
||||
@@ -188,9 +188,9 @@ Or to select "http" and "quick" tests:
|
||||
|
||||
$ pytest -k "http or quick" -v
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 4 items / 2 deselected / 2 selected
|
||||
|
||||
test_server.py::test_send_http PASSED [ 50%]
|
||||
@@ -234,17 +234,17 @@ You can ask which markers exist for your test suite - the list includes our just
|
||||
|
||||
@pytest.mark.slow: mark test as slow.
|
||||
|
||||
@pytest.mark.filterwarnings(warning): add a warning filter to the given test. see https://docs.pytest.org/en/stable/how-to/capture-warnings.html#pytest-mark-filterwarnings
|
||||
@pytest.mark.filterwarnings(warning): add a warning filter to the given test. see https://docs.pytest.org/en/stable/warnings.html#pytest-mark-filterwarnings
|
||||
|
||||
@pytest.mark.skip(reason=None): skip the given test function with an optional reason. Example: skip(reason="no way of currently testing this") skips the test.
|
||||
|
||||
@pytest.mark.skipif(condition, ..., *, reason=...): skip the given test function if any of the conditions evaluate to True. Example: skipif(sys.platform == 'win32') skips the test if we are on the win32 platform. See https://docs.pytest.org/en/stable/reference/reference.html#pytest-mark-skipif
|
||||
@pytest.mark.skipif(condition, ..., *, reason=...): skip the given test function if any of the conditions evaluate to True. Example: skipif(sys.platform == 'win32') skips the test if we are on the win32 platform. See https://docs.pytest.org/en/stable/reference.html#pytest-mark-skipif
|
||||
|
||||
@pytest.mark.xfail(condition, ..., *, reason=..., run=True, raises=None, strict=xfail_strict): mark the test function as an expected failure if any of the conditions evaluate to True. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See https://docs.pytest.org/en/stable/reference/reference.html#pytest-mark-xfail
|
||||
@pytest.mark.xfail(condition, ..., *, reason=..., run=True, raises=None, strict=xfail_strict): mark the test function as an expected failure if any of the conditions evaluate to True. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See https://docs.pytest.org/en/stable/reference.html#pytest-mark-xfail
|
||||
|
||||
@pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see https://docs.pytest.org/en/stable/how-to/parametrize.html for more info and examples.
|
||||
@pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see https://docs.pytest.org/en/stable/parametrize.html for more info and examples.
|
||||
|
||||
@pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see https://docs.pytest.org/en/stable/explanation/fixtures.html#usefixtures
|
||||
@pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see https://docs.pytest.org/en/stable/fixture.html#usefixtures
|
||||
|
||||
@pytest.mark.tryfirst: mark a hook implementation function such that the plugin machinery will try to call it first/as early as possible.
|
||||
|
||||
@@ -397,8 +397,9 @@ the test needs:
|
||||
|
||||
$ pytest -E stage2
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
|
||||
test_someenv.py s [100%]
|
||||
@@ -411,8 +412,9 @@ and here is one that specifies exactly the environment needed:
|
||||
|
||||
$ pytest -E stage1
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
|
||||
test_someenv.py . [100%]
|
||||
@@ -426,17 +428,17 @@ The ``--markers`` option always gives you a list of available markers:
|
||||
$ pytest --markers
|
||||
@pytest.mark.env(name): mark test to run only on named environment
|
||||
|
||||
@pytest.mark.filterwarnings(warning): add a warning filter to the given test. see https://docs.pytest.org/en/stable/how-to/capture-warnings.html#pytest-mark-filterwarnings
|
||||
@pytest.mark.filterwarnings(warning): add a warning filter to the given test. see https://docs.pytest.org/en/stable/warnings.html#pytest-mark-filterwarnings
|
||||
|
||||
@pytest.mark.skip(reason=None): skip the given test function with an optional reason. Example: skip(reason="no way of currently testing this") skips the test.
|
||||
|
||||
@pytest.mark.skipif(condition, ..., *, reason=...): skip the given test function if any of the conditions evaluate to True. Example: skipif(sys.platform == 'win32') skips the test if we are on the win32 platform. See https://docs.pytest.org/en/stable/reference/reference.html#pytest-mark-skipif
|
||||
@pytest.mark.skipif(condition, ..., *, reason=...): skip the given test function if any of the conditions evaluate to True. Example: skipif(sys.platform == 'win32') skips the test if we are on the win32 platform. See https://docs.pytest.org/en/stable/reference.html#pytest-mark-skipif
|
||||
|
||||
@pytest.mark.xfail(condition, ..., *, reason=..., run=True, raises=None, strict=xfail_strict): mark the test function as an expected failure if any of the conditions evaluate to True. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See https://docs.pytest.org/en/stable/reference/reference.html#pytest-mark-xfail
|
||||
@pytest.mark.xfail(condition, ..., *, reason=..., run=True, raises=None, strict=xfail_strict): mark the test function as an expected failure if any of the conditions evaluate to True. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See https://docs.pytest.org/en/stable/reference.html#pytest-mark-xfail
|
||||
|
||||
@pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see https://docs.pytest.org/en/stable/how-to/parametrize.html for more info and examples.
|
||||
@pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see https://docs.pytest.org/en/stable/parametrize.html for more info and examples.
|
||||
|
||||
@pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see https://docs.pytest.org/en/stable/explanation/fixtures.html#usefixtures
|
||||
@pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see https://docs.pytest.org/en/stable/fixture.html#usefixtures
|
||||
|
||||
@pytest.mark.tryfirst: mark a hook implementation function such that the plugin machinery will try to call it first/as early as possible.
|
||||
|
||||
@@ -486,7 +488,7 @@ The output is as follows:
|
||||
.. code-block:: pytest
|
||||
|
||||
$ pytest -q -s
|
||||
Mark(name='my_marker', args=(<function hello_world at 0xdeadbeef0001>,), kwargs={})
|
||||
Mark(name='my_marker', args=(<function hello_world at 0xdeadbeef>,), kwargs={})
|
||||
.
|
||||
1 passed in 0.12s
|
||||
|
||||
@@ -603,8 +605,9 @@ 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-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items
|
||||
|
||||
test_plat.py s.s. [100%]
|
||||
@@ -619,8 +622,9 @@ 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-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items / 3 deselected / 1 selected
|
||||
|
||||
test_plat.py . [100%]
|
||||
@@ -682,8 +686,9 @@ 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-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items / 2 deselected / 2 selected
|
||||
|
||||
test_module.py FF [100%]
|
||||
@@ -708,8 +713,9 @@ 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-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items / 1 deselected / 3 selected
|
||||
|
||||
test_module.py FFF [100%]
|
||||
|
||||
@@ -12,8 +12,8 @@ pythonlist = ["python3.5", "python3.6", "python3.7"]
|
||||
|
||||
|
||||
@pytest.fixture(params=pythonlist)
|
||||
def python1(request, tmp_path):
|
||||
picklefile = tmp_path / "data.pickle"
|
||||
def python1(request, tmpdir):
|
||||
picklefile = tmpdir.join("data.pickle")
|
||||
return Python(request.param, picklefile)
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@ class Python:
|
||||
self.picklefile = picklefile
|
||||
|
||||
def dumps(self, obj):
|
||||
dumpfile = self.picklefile.with_name("dump.py")
|
||||
dumpfile.write_text(
|
||||
dumpfile = self.picklefile.dirpath("dump.py")
|
||||
dumpfile.write(
|
||||
textwrap.dedent(
|
||||
r"""
|
||||
import pickle
|
||||
@@ -46,8 +46,8 @@ class Python:
|
||||
subprocess.check_call((self.pythonpath, str(dumpfile)))
|
||||
|
||||
def load_and_is_true(self, expression):
|
||||
loadfile = self.picklefile.with_name("load.py")
|
||||
loadfile.write_text(
|
||||
loadfile = self.picklefile.dirpath("load.py")
|
||||
loadfile.write(
|
||||
textwrap.dedent(
|
||||
r"""
|
||||
import pickle
|
||||
|
||||
@@ -10,6 +10,7 @@ A basic example for specifying tests in Yaml files
|
||||
--------------------------------------------------------------
|
||||
|
||||
.. _`pytest-yamlwsgi`: http://bitbucket.org/aafshar/pytest-yamlwsgi/src/tip/pytest_yamlwsgi.py
|
||||
.. _`PyYAML`: https://pypi.org/project/PyYAML/
|
||||
|
||||
Here is an example ``conftest.py`` (extracted from Ali Afshar's special purpose `pytest-yamlwsgi`_ plugin). This ``conftest.py`` will collect ``test*.yaml`` files and will execute the yaml-formatted content as custom tests:
|
||||
|
||||
@@ -21,15 +22,16 @@ You can create a simple example file:
|
||||
.. include:: nonpython/test_simple.yaml
|
||||
:literal:
|
||||
|
||||
and if you installed :pypi:`PyYAML` or a compatible YAML-parser you can
|
||||
and if you installed `PyYAML`_ or a compatible YAML-parser you can
|
||||
now execute the test specification:
|
||||
|
||||
.. code-block:: pytest
|
||||
|
||||
nonpython $ pytest test_simple.yaml
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project/nonpython
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR/nonpython
|
||||
collected 2 items
|
||||
|
||||
test_simple.yaml F. [100%]
|
||||
@@ -64,9 +66,9 @@ consulted when reporting in ``verbose`` mode:
|
||||
|
||||
nonpython $ pytest -v
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /home/sweet/project/nonpython
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR/nonpython
|
||||
collecting ... collected 2 items
|
||||
|
||||
test_simple.yaml::hello FAILED [ 50%]
|
||||
@@ -90,8 +92,9 @@ interesting to just look at the collection tree:
|
||||
|
||||
nonpython $ pytest --collect-only
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project/nonpython
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR/nonpython
|
||||
collected 2 items
|
||||
|
||||
<Package nonpython>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def pytest_collect_file(parent, file_path):
|
||||
if file_path.suffix == ".yaml" and file_path.name.startswith("test"):
|
||||
return YamlFile.from_parent(parent, path=file_path)
|
||||
def pytest_collect_file(parent, path):
|
||||
if path.ext == ".yaml" and path.basename.startswith("test"):
|
||||
return YamlFile.from_parent(parent, fspath=path)
|
||||
|
||||
|
||||
class YamlFile(pytest.File):
|
||||
@@ -12,7 +12,7 @@ class YamlFile(pytest.File):
|
||||
# We need a yaml parser, e.g. PyYAML.
|
||||
import yaml
|
||||
|
||||
raw = yaml.safe_load(self.path.open())
|
||||
raw = yaml.safe_load(self.fspath.open())
|
||||
for name, spec in sorted(raw.items()):
|
||||
yield YamlItem.from_parent(self, name=name, spec=spec)
|
||||
|
||||
@@ -40,7 +40,7 @@ class YamlItem(pytest.Item):
|
||||
)
|
||||
|
||||
def reportinfo(self):
|
||||
return self.path, 0, f"usecase: {self.name}"
|
||||
return self.fspath, 0, f"usecase: {self.name}"
|
||||
|
||||
|
||||
class YamlException(Exception):
|
||||
|
||||
@@ -97,10 +97,10 @@ the argument name:
|
||||
|
||||
# content of test_time.py
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pytest
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
testdata = [
|
||||
(datetime(2001, 12, 12), datetime(2001, 12, 11), timedelta(1)),
|
||||
(datetime(2001, 12, 11), datetime(2001, 12, 12), timedelta(-1)),
|
||||
@@ -160,8 +160,9 @@ 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-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 8 items
|
||||
|
||||
<Module test_time.py>
|
||||
@@ -182,7 +183,9 @@ together with the actual data, instead of listing them separately.
|
||||
A quick port of "testscenarios"
|
||||
------------------------------------
|
||||
|
||||
Here is a quick port to run tests configured with :pypi:`testscenarios`,
|
||||
.. _`test scenarios`: https://pypi.org/project/testscenarios/
|
||||
|
||||
Here is a quick port to run tests configured with `test scenarios`_,
|
||||
an add-on from Robert Collins for the standard unittest framework. We
|
||||
only have to work a bit to construct the correct arguments for pytest's
|
||||
:py:func:`Metafunc.parametrize`:
|
||||
@@ -222,8 +225,9 @@ 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-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items
|
||||
|
||||
test_scenarios.py .... [100%]
|
||||
@@ -236,16 +240,17 @@ 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-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items
|
||||
|
||||
<Module test_scenarios.py>
|
||||
<Class TestSampleWithScenarios>
|
||||
<Function test_demo1[basic]>
|
||||
<Function test_demo2[basic]>
|
||||
<Function test_demo1[advanced]>
|
||||
<Function test_demo2[advanced]>
|
||||
<Function test_demo1[basic]>
|
||||
<Function test_demo2[basic]>
|
||||
<Function test_demo1[advanced]>
|
||||
<Function test_demo2[advanced]>
|
||||
|
||||
======================== 4 tests collected in 0.12s ========================
|
||||
|
||||
@@ -314,8 +319,9 @@ 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-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
|
||||
<Module test_backends.py>
|
||||
@@ -333,7 +339,7 @@ And then when we run the test:
|
||||
================================= FAILURES =================================
|
||||
_________________________ test_db_initialized[d2] __________________________
|
||||
|
||||
db = <conftest.DB2 object at 0xdeadbeef0001>
|
||||
db = <conftest.DB2 object at 0xdeadbeef>
|
||||
|
||||
def test_db_initialized(db):
|
||||
# a dummy test
|
||||
@@ -412,9 +418,9 @@ The result of this test will be successful:
|
||||
|
||||
$ pytest -v test_indirect_list.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 1 item
|
||||
|
||||
test_indirect_list.py::test_indirect[a-b] PASSED [100%]
|
||||
@@ -472,7 +478,7 @@ argument sets to use for each test function. Let's run it:
|
||||
================================= FAILURES =================================
|
||||
________________________ TestClass.test_equals[1-2] ________________________
|
||||
|
||||
self = <test_parametrize.TestClass object at 0xdeadbeef0002>, a = 1, b = 2
|
||||
self = <test_parametrize.TestClass object at 0xdeadbeef>, a = 1, b = 2
|
||||
|
||||
def test_equals(self, a, b):
|
||||
> assert a == b
|
||||
@@ -567,8 +573,9 @@ If you run this with reporting for skips enabled:
|
||||
|
||||
$ pytest -rs test_module.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
|
||||
test_module.py .s [100%]
|
||||
@@ -628,9 +635,9 @@ 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-7.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 24 items / 21 deselected / 3 selected
|
||||
|
||||
test_pytest_param_example.py::test_eval[1+7-8] PASSED [ 33%]
|
||||
|
||||
@@ -147,14 +147,15 @@ The test collection would look like this:
|
||||
|
||||
$ pytest --collect-only
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project, configfile: pytest.ini
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR, configfile: pytest.ini
|
||||
collected 2 items
|
||||
|
||||
<Module check_myapp.py>
|
||||
<Class CheckMyApp>
|
||||
<Function simple_check>
|
||||
<Function complex_check>
|
||||
<Function simple_check>
|
||||
<Function complex_check>
|
||||
|
||||
======================== 2 tests collected in 0.12s ========================
|
||||
|
||||
@@ -208,15 +209,16 @@ 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-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project, configfile: pytest.ini
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR, configfile: pytest.ini
|
||||
collected 3 items
|
||||
|
||||
<Module CWD/pythoncollection.py>
|
||||
<Function test_function>
|
||||
<Class TestClass>
|
||||
<Function test_method>
|
||||
<Function test_anothermethod>
|
||||
<Function test_method>
|
||||
<Function test_anothermethod>
|
||||
|
||||
======================== 3 tests collected in 0.12s ========================
|
||||
|
||||
@@ -289,8 +291,9 @@ file will be left out:
|
||||
|
||||
$ pytest --collect-only
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project, configfile: pytest.ini
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR, configfile: pytest.ini
|
||||
collected 0 items
|
||||
|
||||
======================= no tests collected in 0.12s ========================
|
||||
|
||||
@@ -9,8 +9,9 @@ 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-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project/assertion
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR/assertion
|
||||
collected 44 items
|
||||
|
||||
failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF [100%]
|
||||
@@ -28,7 +29,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:19: AssertionError
|
||||
_________________________ TestFailing.test_simple __________________________
|
||||
|
||||
self = <failure_demo.TestFailing object at 0xdeadbeef0001>
|
||||
self = <failure_demo.TestFailing object at 0xdeadbeef>
|
||||
|
||||
def test_simple(self):
|
||||
def f():
|
||||
@@ -39,13 +40,13 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
|
||||
> assert f() == g()
|
||||
E assert 42 == 43
|
||||
E + where 42 = <function TestFailing.test_simple.<locals>.f at 0xdeadbeef0002>()
|
||||
E + and 43 = <function TestFailing.test_simple.<locals>.g at 0xdeadbeef0003>()
|
||||
E + where 42 = <function TestFailing.test_simple.<locals>.f at 0xdeadbeef>()
|
||||
E + and 43 = <function TestFailing.test_simple.<locals>.g at 0xdeadbeef>()
|
||||
|
||||
failure_demo.py:30: AssertionError
|
||||
____________________ TestFailing.test_simple_multiline _____________________
|
||||
|
||||
self = <failure_demo.TestFailing object at 0xdeadbeef0004>
|
||||
self = <failure_demo.TestFailing object at 0xdeadbeef>
|
||||
|
||||
def test_simple_multiline(self):
|
||||
> otherfunc_multi(42, 6 * 9)
|
||||
@@ -62,7 +63,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:14: AssertionError
|
||||
___________________________ TestFailing.test_not ___________________________
|
||||
|
||||
self = <failure_demo.TestFailing object at 0xdeadbeef0005>
|
||||
self = <failure_demo.TestFailing object at 0xdeadbeef>
|
||||
|
||||
def test_not(self):
|
||||
def f():
|
||||
@@ -70,12 +71,12 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
|
||||
> assert not f()
|
||||
E assert not 42
|
||||
E + where 42 = <function TestFailing.test_not.<locals>.f at 0xdeadbeef0006>()
|
||||
E + where 42 = <function TestFailing.test_not.<locals>.f at 0xdeadbeef>()
|
||||
|
||||
failure_demo.py:39: AssertionError
|
||||
_________________ TestSpecialisedExplanations.test_eq_text _________________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef0007>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_eq_text(self):
|
||||
> assert "spam" == "eggs"
|
||||
@@ -86,7 +87,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:44: AssertionError
|
||||
_____________ TestSpecialisedExplanations.test_eq_similar_text _____________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef0008>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_eq_similar_text(self):
|
||||
> assert "foo 1 bar" == "foo 2 bar"
|
||||
@@ -99,7 +100,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:47: AssertionError
|
||||
____________ TestSpecialisedExplanations.test_eq_multiline_text ____________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef0009>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_eq_multiline_text(self):
|
||||
> assert "foo\nspam\nbar" == "foo\neggs\nbar"
|
||||
@@ -112,7 +113,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:50: AssertionError
|
||||
______________ TestSpecialisedExplanations.test_eq_long_text _______________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef000a>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_eq_long_text(self):
|
||||
a = "1" * 100 + "a" + "2" * 100
|
||||
@@ -129,7 +130,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:55: AssertionError
|
||||
_________ TestSpecialisedExplanations.test_eq_long_text_multiline __________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef000b>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_eq_long_text_multiline(self):
|
||||
a = "1\n" * 100 + "a" + "2\n" * 100
|
||||
@@ -149,7 +150,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:60: AssertionError
|
||||
_________________ TestSpecialisedExplanations.test_eq_list _________________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef000c>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_eq_list(self):
|
||||
> assert [0, 1, 2] == [0, 1, 3]
|
||||
@@ -160,7 +161,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:63: AssertionError
|
||||
______________ TestSpecialisedExplanations.test_eq_list_long _______________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef000d>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_eq_list_long(self):
|
||||
a = [0] * 100 + [1] + [3] * 100
|
||||
@@ -173,7 +174,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:68: AssertionError
|
||||
_________________ TestSpecialisedExplanations.test_eq_dict _________________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef000e>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_eq_dict(self):
|
||||
> assert {"a": 0, "b": 1, "c": 0} == {"a": 0, "b": 2, "d": 0}
|
||||
@@ -191,7 +192,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:71: AssertionError
|
||||
_________________ TestSpecialisedExplanations.test_eq_set __________________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef000f>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_eq_set(self):
|
||||
> assert {0, 10, 11, 12} == {0, 20, 21}
|
||||
@@ -209,7 +210,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:74: AssertionError
|
||||
_____________ TestSpecialisedExplanations.test_eq_longer_list ______________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef0010>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_eq_longer_list(self):
|
||||
> assert [1, 2] == [1, 2, 3]
|
||||
@@ -220,7 +221,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:77: AssertionError
|
||||
_________________ TestSpecialisedExplanations.test_in_list _________________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef0011>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_in_list(self):
|
||||
> assert 1 in [0, 2, 3, 4, 5]
|
||||
@@ -229,7 +230,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:80: AssertionError
|
||||
__________ TestSpecialisedExplanations.test_not_in_text_multiline __________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef0012>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_not_in_text_multiline(self):
|
||||
text = "some multiline\ntext\nwhich\nincludes foo\nand a\ntail"
|
||||
@@ -248,7 +249,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:84: AssertionError
|
||||
___________ TestSpecialisedExplanations.test_not_in_text_single ____________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef0013>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_not_in_text_single(self):
|
||||
text = "single foo line"
|
||||
@@ -261,7 +262,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:88: AssertionError
|
||||
_________ TestSpecialisedExplanations.test_not_in_text_single_long _________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef0014>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_not_in_text_single_long(self):
|
||||
text = "head " * 50 + "foo " + "tail " * 20
|
||||
@@ -274,7 +275,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:92: AssertionError
|
||||
______ TestSpecialisedExplanations.test_not_in_text_single_long_term _______
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef0015>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_not_in_text_single_long_term(self):
|
||||
text = "head " * 50 + "f" * 70 + "tail " * 20
|
||||
@@ -287,7 +288,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:96: AssertionError
|
||||
______________ TestSpecialisedExplanations.test_eq_dataclass _______________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef0016>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_eq_dataclass(self):
|
||||
from dataclasses import dataclass
|
||||
@@ -314,7 +315,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:108: AssertionError
|
||||
________________ TestSpecialisedExplanations.test_eq_attrs _________________
|
||||
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef0017>
|
||||
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
|
||||
|
||||
def test_eq_attrs(self):
|
||||
import attr
|
||||
@@ -348,7 +349,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
i = Foo()
|
||||
> assert i.b == 2
|
||||
E assert 1 == 2
|
||||
E + where 1 = <failure_demo.test_attribute.<locals>.Foo object at 0xdeadbeef0018>.b
|
||||
E + where 1 = <failure_demo.test_attribute.<locals>.Foo object at 0xdeadbeef>.b
|
||||
|
||||
failure_demo.py:128: AssertionError
|
||||
_________________________ test_attribute_instance __________________________
|
||||
@@ -359,8 +360,8 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
|
||||
> assert Foo().b == 2
|
||||
E AssertionError: assert 1 == 2
|
||||
E + where 1 = <failure_demo.test_attribute_instance.<locals>.Foo object at 0xdeadbeef0019>.b
|
||||
E + where <failure_demo.test_attribute_instance.<locals>.Foo object at 0xdeadbeef0019> = <class 'failure_demo.test_attribute_instance.<locals>.Foo'>()
|
||||
E + where 1 = <failure_demo.test_attribute_instance.<locals>.Foo object at 0xdeadbeef>.b
|
||||
E + where <failure_demo.test_attribute_instance.<locals>.Foo object at 0xdeadbeef> = <class 'failure_demo.test_attribute_instance.<locals>.Foo'>()
|
||||
|
||||
failure_demo.py:135: AssertionError
|
||||
__________________________ test_attribute_failure __________________________
|
||||
@@ -378,7 +379,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:146:
|
||||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
|
||||
self = <failure_demo.test_attribute_failure.<locals>.Foo object at 0xdeadbeef001a>
|
||||
self = <failure_demo.test_attribute_failure.<locals>.Foo object at 0xdeadbeef>
|
||||
|
||||
def _get_b(self):
|
||||
> raise Exception("Failed to get attrib")
|
||||
@@ -396,15 +397,15 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
|
||||
> assert Foo().b == Bar().b
|
||||
E AssertionError: assert 1 == 2
|
||||
E + where 1 = <failure_demo.test_attribute_multiple.<locals>.Foo object at 0xdeadbeef001b>.b
|
||||
E + where <failure_demo.test_attribute_multiple.<locals>.Foo object at 0xdeadbeef001b> = <class 'failure_demo.test_attribute_multiple.<locals>.Foo'>()
|
||||
E + and 2 = <failure_demo.test_attribute_multiple.<locals>.Bar object at 0xdeadbeef001c>.b
|
||||
E + where <failure_demo.test_attribute_multiple.<locals>.Bar object at 0xdeadbeef001c> = <class 'failure_demo.test_attribute_multiple.<locals>.Bar'>()
|
||||
E + where 1 = <failure_demo.test_attribute_multiple.<locals>.Foo object at 0xdeadbeef>.b
|
||||
E + where <failure_demo.test_attribute_multiple.<locals>.Foo object at 0xdeadbeef> = <class 'failure_demo.test_attribute_multiple.<locals>.Foo'>()
|
||||
E + and 2 = <failure_demo.test_attribute_multiple.<locals>.Bar object at 0xdeadbeef>.b
|
||||
E + where <failure_demo.test_attribute_multiple.<locals>.Bar object at 0xdeadbeef> = <class 'failure_demo.test_attribute_multiple.<locals>.Bar'>()
|
||||
|
||||
failure_demo.py:156: AssertionError
|
||||
__________________________ TestRaises.test_raises __________________________
|
||||
|
||||
self = <failure_demo.TestRaises object at 0xdeadbeef001d>
|
||||
self = <failure_demo.TestRaises object at 0xdeadbeef>
|
||||
|
||||
def test_raises(self):
|
||||
s = "qwe"
|
||||
@@ -414,7 +415,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:166: ValueError
|
||||
______________________ TestRaises.test_raises_doesnt _______________________
|
||||
|
||||
self = <failure_demo.TestRaises object at 0xdeadbeef001e>
|
||||
self = <failure_demo.TestRaises object at 0xdeadbeef>
|
||||
|
||||
def test_raises_doesnt(self):
|
||||
> raises(OSError, int, "3")
|
||||
@@ -423,7 +424,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:169: Failed
|
||||
__________________________ TestRaises.test_raise ___________________________
|
||||
|
||||
self = <failure_demo.TestRaises object at 0xdeadbeef001f>
|
||||
self = <failure_demo.TestRaises object at 0xdeadbeef>
|
||||
|
||||
def test_raise(self):
|
||||
> raise ValueError("demo error")
|
||||
@@ -432,7 +433,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:172: ValueError
|
||||
________________________ TestRaises.test_tupleerror ________________________
|
||||
|
||||
self = <failure_demo.TestRaises object at 0xdeadbeef0020>
|
||||
self = <failure_demo.TestRaises object at 0xdeadbeef>
|
||||
|
||||
def test_tupleerror(self):
|
||||
> a, b = [1] # NOQA
|
||||
@@ -441,7 +442,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:175: ValueError
|
||||
______ TestRaises.test_reinterpret_fails_with_print_for_the_fun_of_it ______
|
||||
|
||||
self = <failure_demo.TestRaises object at 0xdeadbeef0021>
|
||||
self = <failure_demo.TestRaises object at 0xdeadbeef>
|
||||
|
||||
def test_reinterpret_fails_with_print_for_the_fun_of_it(self):
|
||||
items = [1, 2, 3]
|
||||
@@ -454,7 +455,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
items is [1, 2, 3]
|
||||
________________________ TestRaises.test_some_error ________________________
|
||||
|
||||
self = <failure_demo.TestRaises object at 0xdeadbeef0022>
|
||||
self = <failure_demo.TestRaises object at 0xdeadbeef>
|
||||
|
||||
def test_some_error(self):
|
||||
> if namenotexi: # NOQA
|
||||
@@ -485,7 +486,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
abc-123:2: AssertionError
|
||||
____________________ TestMoreErrors.test_complex_error _____________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef0023>
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
|
||||
|
||||
def test_complex_error(self):
|
||||
def f():
|
||||
@@ -511,7 +512,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:6: AssertionError
|
||||
___________________ TestMoreErrors.test_z1_unpack_error ____________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef0024>
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
|
||||
|
||||
def test_z1_unpack_error(self):
|
||||
items = []
|
||||
@@ -521,7 +522,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:217: ValueError
|
||||
____________________ TestMoreErrors.test_z2_type_error _____________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef0025>
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
|
||||
|
||||
def test_z2_type_error(self):
|
||||
items = 3
|
||||
@@ -531,20 +532,20 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:221: TypeError
|
||||
______________________ TestMoreErrors.test_startswith ______________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef0026>
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
|
||||
|
||||
def test_startswith(self):
|
||||
s = "123"
|
||||
g = "456"
|
||||
> assert s.startswith(g)
|
||||
E AssertionError: assert False
|
||||
E + where False = <built-in method startswith of str object at 0xdeadbeef0027>('456')
|
||||
E + where <built-in method startswith of str object at 0xdeadbeef0027> = '123'.startswith
|
||||
E + where False = <built-in method startswith of str object at 0xdeadbeef>('456')
|
||||
E + where <built-in method startswith of str object at 0xdeadbeef> = '123'.startswith
|
||||
|
||||
failure_demo.py:226: AssertionError
|
||||
__________________ TestMoreErrors.test_startswith_nested ___________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef0028>
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
|
||||
|
||||
def test_startswith_nested(self):
|
||||
def f():
|
||||
@@ -555,15 +556,15 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
|
||||
> assert f().startswith(g())
|
||||
E AssertionError: assert False
|
||||
E + where False = <built-in method startswith of str object at 0xdeadbeef0027>('456')
|
||||
E + where <built-in method startswith of str object at 0xdeadbeef0027> = '123'.startswith
|
||||
E + where '123' = <function TestMoreErrors.test_startswith_nested.<locals>.f at 0xdeadbeef0029>()
|
||||
E + and '456' = <function TestMoreErrors.test_startswith_nested.<locals>.g at 0xdeadbeef002a>()
|
||||
E + where False = <built-in method startswith of str object at 0xdeadbeef>('456')
|
||||
E + where <built-in method startswith of str object at 0xdeadbeef> = '123'.startswith
|
||||
E + where '123' = <function TestMoreErrors.test_startswith_nested.<locals>.f at 0xdeadbeef>()
|
||||
E + and '456' = <function TestMoreErrors.test_startswith_nested.<locals>.g at 0xdeadbeef>()
|
||||
|
||||
failure_demo.py:235: AssertionError
|
||||
_____________________ TestMoreErrors.test_global_func ______________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef002b>
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
|
||||
|
||||
def test_global_func(self):
|
||||
> assert isinstance(globf(42), float)
|
||||
@@ -574,18 +575,18 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:238: AssertionError
|
||||
_______________________ TestMoreErrors.test_instance _______________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef002c>
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
|
||||
|
||||
def test_instance(self):
|
||||
self.x = 6 * 7
|
||||
> assert self.x != 42
|
||||
E assert 42 != 42
|
||||
E + where 42 = <failure_demo.TestMoreErrors object at 0xdeadbeef002c>.x
|
||||
E + where 42 = <failure_demo.TestMoreErrors object at 0xdeadbeef>.x
|
||||
|
||||
failure_demo.py:242: AssertionError
|
||||
_______________________ TestMoreErrors.test_compare ________________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef002d>
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
|
||||
|
||||
def test_compare(self):
|
||||
> assert globf(10) < 5
|
||||
@@ -595,7 +596,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:245: AssertionError
|
||||
_____________________ TestMoreErrors.test_try_finally ______________________
|
||||
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef002e>
|
||||
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
|
||||
|
||||
def test_try_finally(self):
|
||||
x = 1
|
||||
@@ -606,7 +607,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:250: AssertionError
|
||||
___________________ TestCustomAssertMsg.test_single_line ___________________
|
||||
|
||||
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef002f>
|
||||
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
|
||||
|
||||
def test_single_line(self):
|
||||
class A:
|
||||
@@ -621,7 +622,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:261: AssertionError
|
||||
____________________ TestCustomAssertMsg.test_multiline ____________________
|
||||
|
||||
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef0030>
|
||||
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
|
||||
|
||||
def test_multiline(self):
|
||||
class A:
|
||||
@@ -640,7 +641,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
failure_demo.py:268: AssertionError
|
||||
___________________ TestCustomAssertMsg.test_custom_repr ___________________
|
||||
|
||||
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef0031>
|
||||
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
|
||||
|
||||
def test_custom_repr(self):
|
||||
class JSON:
|
||||
|
||||
@@ -69,7 +69,7 @@ Here is a basic pattern to achieve this:
|
||||
|
||||
|
||||
For this to work we need to add a command line option and
|
||||
provide the ``cmdopt`` through a :ref:`fixture function <fixture>`:
|
||||
provide the ``cmdopt`` through a :ref:`fixture function <fixture function>`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -139,67 +139,10 @@ And now with supplying a command line option:
|
||||
FAILED test_sample.py::test_answer - assert 0
|
||||
1 failed in 0.12s
|
||||
|
||||
You can see that the command line option arrived in our test.
|
||||
|
||||
We could add simple validation for the input by listing the choices:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# content of conftest.py
|
||||
import pytest
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption(
|
||||
"--cmdopt",
|
||||
action="store",
|
||||
default="type1",
|
||||
help="my option: type1 or type2",
|
||||
choices=("type1", "type2"),
|
||||
)
|
||||
|
||||
Now we'll get feedback on a bad argument:
|
||||
|
||||
.. code-block:: pytest
|
||||
|
||||
$ pytest -q --cmdopt=type3
|
||||
ERROR: usage: pytest [options] [file_or_dir] [file_or_dir] [...]
|
||||
pytest: error: argument --cmdopt: invalid choice: 'type3' (choose from 'type1', 'type2')
|
||||
|
||||
|
||||
If you need to provide more detailed error messages, you can use the
|
||||
``type`` parameter and raise ``pytest.UsageError``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# content of conftest.py
|
||||
import pytest
|
||||
|
||||
|
||||
def type_checker(value):
|
||||
msg = "cmdopt must specify a numeric type as typeNNN"
|
||||
if not value.startswith("type"):
|
||||
raise pytest.UsageError(msg)
|
||||
try:
|
||||
int(value[4:])
|
||||
except ValueError:
|
||||
raise pytest.UsageError(msg)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption(
|
||||
"--cmdopt",
|
||||
action="store",
|
||||
default="type1",
|
||||
help="my option: type1 or type2",
|
||||
type=type_checker,
|
||||
)
|
||||
|
||||
This completes the basic pattern. However, one often rather wants to
|
||||
process command line options outside of the test and rather pass in
|
||||
different or more complex objects.
|
||||
You can see that the command line option arrived in our test. This
|
||||
completes the basic pattern. However, one often rather wants to process
|
||||
command line options outside of the test and rather pass in different or
|
||||
more complex objects.
|
||||
|
||||
Dynamically adding command line options
|
||||
--------------------------------------------------------------
|
||||
@@ -223,7 +166,7 @@ the command line arguments before they get processed:
|
||||
num = max(multiprocessing.cpu_count() / 2, 1)
|
||||
args[:] = ["-n", str(num)] + args
|
||||
|
||||
If you have the :pypi:`xdist plugin <pytest-xdist>` installed
|
||||
If you have the `xdist plugin <https://pypi.org/project/pytest-xdist/>`_ installed
|
||||
you will now always perform test runs using a number
|
||||
of subprocesses close to your CPU. Running in an empty
|
||||
directory with the above conftest.py:
|
||||
@@ -232,8 +175,9 @@ directory with the above conftest.py:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 0 items
|
||||
|
||||
========================== no tests ran in 0.12s ===========================
|
||||
@@ -296,8 +240,9 @@ 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-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
|
||||
test_module.py .s [100%]
|
||||
@@ -312,8 +257,9 @@ Or run it including the ``slow`` marked test:
|
||||
|
||||
$ pytest --runslow
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
|
||||
test_module.py .. [100%]
|
||||
@@ -455,9 +401,10 @@ which will add the string to the test header accordingly:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
project deps: mylib-1.1
|
||||
rootdir: /home/sweet/project
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 0 items
|
||||
|
||||
========================== no tests ran in 0.12s ===========================
|
||||
@@ -483,11 +430,11 @@ which will add info only when run with "--v":
|
||||
|
||||
$ pytest -v
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: .pytest_cache
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
info1: did you know that ...
|
||||
did you?
|
||||
rootdir: /home/sweet/project
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collecting ... collected 0 items
|
||||
|
||||
========================== no tests ran in 0.12s ===========================
|
||||
@@ -498,8 +445,9 @@ and nothing when run plainly:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 0 items
|
||||
|
||||
========================== no tests ran in 0.12s ===========================
|
||||
@@ -537,8 +485,9 @@ Now we can profile which test functions execute the slowest:
|
||||
|
||||
$ pytest --durations=3
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 3 items
|
||||
|
||||
test_some_are_slow.py ... [100%]
|
||||
@@ -642,8 +591,9 @@ If we run this:
|
||||
|
||||
$ pytest -rx
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 4 items
|
||||
|
||||
test_step.py .Fx. [100%]
|
||||
@@ -651,7 +601,7 @@ If we run this:
|
||||
================================= FAILURES =================================
|
||||
____________________ TestUserHandling.test_modification ____________________
|
||||
|
||||
self = <test_step.TestUserHandling object at 0xdeadbeef0001>
|
||||
self = <test_step.TestUserHandling object at 0xdeadbeef>
|
||||
|
||||
def test_modification(self):
|
||||
> assert 0
|
||||
@@ -671,7 +621,7 @@ Package/Directory-level fixtures (setups)
|
||||
-------------------------------------------------------
|
||||
|
||||
If you have nested test directories, you can have per-directory fixture scopes
|
||||
by placing fixture functions in a ``conftest.py`` file in that directory.
|
||||
by placing fixture functions in a ``conftest.py`` file in that directory
|
||||
You can use all types of fixtures including :ref:`autouse fixtures
|
||||
<autouse fixtures>` which are the equivalent of xUnit's setup/teardown
|
||||
concept. It's however recommended to have explicit fixture references in your
|
||||
@@ -725,8 +675,9 @@ We can run this:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 7 items
|
||||
|
||||
test_step.py .Fx. [ 57%]
|
||||
@@ -736,17 +687,17 @@ We can run this:
|
||||
|
||||
================================== ERRORS ==================================
|
||||
_______________________ ERROR at setup of test_root ________________________
|
||||
file /home/sweet/project/b/test_error.py, line 1
|
||||
file $REGENDOC_TMPDIR/b/test_error.py, line 1
|
||||
def test_root(db): # no db here, will error out
|
||||
E fixture 'db' not found
|
||||
> available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
|
||||
> use 'pytest --fixtures [testpath]' for help on them.
|
||||
|
||||
/home/sweet/project/b/test_error.py:1
|
||||
$REGENDOC_TMPDIR/b/test_error.py:1
|
||||
================================= FAILURES =================================
|
||||
____________________ TestUserHandling.test_modification ____________________
|
||||
|
||||
self = <test_step.TestUserHandling object at 0xdeadbeef0002>
|
||||
self = <test_step.TestUserHandling object at 0xdeadbeef>
|
||||
|
||||
def test_modification(self):
|
||||
> assert 0
|
||||
@@ -755,21 +706,21 @@ We can run this:
|
||||
test_step.py:11: AssertionError
|
||||
_________________________________ test_a1 __________________________________
|
||||
|
||||
db = <conftest.DB object at 0xdeadbeef0003>
|
||||
db = <conftest.DB object at 0xdeadbeef>
|
||||
|
||||
def test_a1(db):
|
||||
> assert 0, db # to show value
|
||||
E AssertionError: <conftest.DB object at 0xdeadbeef0003>
|
||||
E AssertionError: <conftest.DB object at 0xdeadbeef>
|
||||
E assert 0
|
||||
|
||||
a/test_db.py:2: AssertionError
|
||||
_________________________________ test_a2 __________________________________
|
||||
|
||||
db = <conftest.DB object at 0xdeadbeef0003>
|
||||
db = <conftest.DB object at 0xdeadbeef>
|
||||
|
||||
def test_a2(db):
|
||||
> assert 0, db # to show value
|
||||
E AssertionError: <conftest.DB object at 0xdeadbeef0003>
|
||||
E AssertionError: <conftest.DB object at 0xdeadbeef>
|
||||
E assert 0
|
||||
|
||||
a/test_db2.py:2: AssertionError
|
||||
@@ -817,8 +768,8 @@ case we just write some information out to a ``failures`` file:
|
||||
mode = "a" if os.path.exists("failures") else "w"
|
||||
with open("failures", mode) as f:
|
||||
# let's also access a fixture for the fun of it
|
||||
if "tmp_path" in item.fixturenames:
|
||||
extra = " ({})".format(item.funcargs["tmp_path"])
|
||||
if "tmpdir" in item.fixturenames:
|
||||
extra = " ({})".format(item.funcargs["tmpdir"])
|
||||
else:
|
||||
extra = ""
|
||||
|
||||
@@ -830,7 +781,7 @@ if you then have failing tests:
|
||||
.. code-block:: python
|
||||
|
||||
# content of test_module.py
|
||||
def test_fail1(tmp_path):
|
||||
def test_fail1(tmpdir):
|
||||
assert 0
|
||||
|
||||
|
||||
@@ -843,8 +794,9 @@ and run them:
|
||||
|
||||
$ pytest test_module.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 2 items
|
||||
|
||||
test_module.py FF [100%]
|
||||
@@ -852,9 +804,9 @@ and run them:
|
||||
================================= FAILURES =================================
|
||||
________________________________ test_fail1 ________________________________
|
||||
|
||||
tmp_path = PosixPath('PYTEST_TMPDIR/test_fail10')
|
||||
tmpdir = local('PYTEST_TMPDIR/test_fail10')
|
||||
|
||||
def test_fail1(tmp_path):
|
||||
def test_fail1(tmpdir):
|
||||
> assert 0
|
||||
E assert 0
|
||||
|
||||
@@ -949,8 +901,9 @@ and run it:
|
||||
|
||||
$ pytest -s test_module.py
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 3 items
|
||||
|
||||
test_module.py Esetting up a test failed! test_module.py::test_setup_fails
|
||||
@@ -1004,7 +957,8 @@ which test got stuck, for example if pytest was run in quiet mode (``-q``) or yo
|
||||
output. This is particularly a problem if the problem happens only sporadically, the famous "flaky" kind of tests.
|
||||
|
||||
``pytest`` sets the :envvar:`PYTEST_CURRENT_TEST` environment variable when running tests, which can be inspected
|
||||
by process monitoring utilities or libraries like :pypi:`psutil` to discover which test got stuck if necessary:
|
||||
by process monitoring utilities or libraries like `psutil <https://pypi.org/project/psutil/>`_ to discover which
|
||||
test got stuck if necessary:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -1058,7 +1012,7 @@ your frozen program work as the pytest runner by some clever
|
||||
argument handling during program startup. This allows you to
|
||||
have a single executable, which is usually more convenient.
|
||||
Please note that the mechanism for plugin discovery used by pytest
|
||||
(setuptools entry points) doesn't work with frozen executables so pytest
|
||||
(setupttools entry points) doesn't work with frozen executables so pytest
|
||||
can't find any third party plugins automatically. To include third party plugins
|
||||
like ``pytest-timeout`` they must be imported explicitly and passed on to pytest.main.
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ will be called ahead of running any tests:
|
||||
print("test_method1 called")
|
||||
|
||||
def test_method2(self):
|
||||
print("test_method2 called")
|
||||
print("test_method1 called")
|
||||
|
||||
|
||||
class TestOther:
|
||||
@@ -77,7 +77,7 @@ If you run this without output capturing:
|
||||
callme other called
|
||||
SomeTest callme called
|
||||
test_method1 called
|
||||
.test_method2 called
|
||||
.test_method1 called
|
||||
.test other
|
||||
.test_unit1 method called
|
||||
.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.. _existingtestsuite:
|
||||
|
||||
How to use pytest with an existing test suite
|
||||
==============================================
|
||||
Using pytest with an existing test suite
|
||||
===========================================
|
||||
|
||||
Pytest can be used with most existing test suites, but its
|
||||
behavior differs from other test runners such as :ref:`nose <noseintegration>` or
|
||||
@@ -1,46 +0,0 @@
|
||||
.. _test-anatomy:
|
||||
|
||||
Anatomy of a test
|
||||
=================
|
||||
|
||||
In the simplest terms, a test is meant to look at the result of a particular
|
||||
behavior, and make sure that result aligns with what you would expect.
|
||||
Behavior is not something that can be empirically measured, which is why writing
|
||||
tests can be challenging.
|
||||
|
||||
"Behavior" is the way in which some system **acts in response** to a particular
|
||||
situation and/or stimuli. But exactly *how* or *why* something is done is not
|
||||
quite as important as *what* was done.
|
||||
|
||||
You can think of a test as being broken down into four steps:
|
||||
|
||||
1. **Arrange**
|
||||
2. **Act**
|
||||
3. **Assert**
|
||||
4. **Cleanup**
|
||||
|
||||
**Arrange** is where we prepare everything for our test. This means pretty
|
||||
much everything except for the "**act**". It's lining up the dominoes so that
|
||||
the **act** can do its thing in one, state-changing step. This can mean
|
||||
preparing objects, starting/killing services, entering records into a database,
|
||||
or even things like defining a URL to query, generating some credentials for a
|
||||
user that doesn't exist yet, or just waiting for some process to finish.
|
||||
|
||||
**Act** is the singular, state-changing action that kicks off the **behavior**
|
||||
we want to test. This behavior is what carries out the changing of the state of
|
||||
the system under test (SUT), and it's the resulting changed state that we can
|
||||
look at to make a judgement about the behavior. This typically takes the form of
|
||||
a function/method call.
|
||||
|
||||
**Assert** is where we look at that resulting state and check if it looks how
|
||||
we'd expect after the dust has settled. It's where we gather evidence to say the
|
||||
behavior does or does not aligns with what we expect. The ``assert`` in our test
|
||||
is where we take that measurement/observation and apply our judgement to it. If
|
||||
something should be green, we'd say ``assert thing == "green"``.
|
||||
|
||||
**Cleanup** is where the test picks up after itself, so other tests aren't being
|
||||
accidentally influenced by it.
|
||||
|
||||
At its core, the test is ultimately the **act** and **assert** steps, with the
|
||||
**arrange** step only providing the context. **Behavior** exists between **act**
|
||||
and **assert**.
|
||||
@@ -1,174 +0,0 @@
|
||||
.. _about-fixtures:
|
||||
|
||||
About fixtures
|
||||
===============
|
||||
|
||||
.. seealso:: :ref:`how-to-fixtures`
|
||||
.. seealso:: :ref:`Fixtures reference <reference-fixtures>`
|
||||
|
||||
pytest fixtures are designed to be explicit, modular and scalable.
|
||||
|
||||
What fixtures are
|
||||
-----------------
|
||||
|
||||
In testing, a `fixture <https://en.wikipedia.org/wiki/Test_fixture#Software>`_
|
||||
provides a defined, reliable and consistent context for the tests. This could
|
||||
include environment (for example a database configured with known parameters)
|
||||
or content (such as a dataset).
|
||||
|
||||
Fixtures define the steps and data that constitute the *arrange* phase of a
|
||||
test (see :ref:`test-anatomy`). In pytest, they are functions you define that
|
||||
serve this purpose. They can also be used to define a test's *act* phase; this
|
||||
is a powerful technique for designing more complex tests.
|
||||
|
||||
The services, state, or other operating environments set up by fixtures are
|
||||
accessed by test functions through arguments. For each fixture used by a test
|
||||
function there is typically a parameter (named after the fixture) in the test
|
||||
function's definition.
|
||||
|
||||
We can tell pytest that a particular function is a fixture by decorating it with
|
||||
:py:func:`@pytest.fixture <pytest.fixture>`. Here's a simple example of
|
||||
what a fixture in pytest might look like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
class Fruit:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.name == other.name
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def my_fruit():
|
||||
return Fruit("apple")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fruit_basket(my_fruit):
|
||||
return [Fruit("banana"), my_fruit]
|
||||
|
||||
|
||||
def test_my_fruit_in_basket(my_fruit, fruit_basket):
|
||||
assert my_fruit in fruit_basket
|
||||
|
||||
Tests don't have to be limited to a single fixture, either. They can depend on
|
||||
as many fixtures as you want, and fixtures can use other fixtures, as well. This
|
||||
is where pytest's fixture system really shines.
|
||||
|
||||
|
||||
Improvements over xUnit-style setup/teardown functions
|
||||
-----------------------------------------------------------
|
||||
|
||||
pytest fixtures offer dramatic improvements over the classic xUnit
|
||||
style of setup/teardown functions:
|
||||
|
||||
* fixtures have explicit names and are activated by declaring their use
|
||||
from test functions, modules, classes or whole projects.
|
||||
|
||||
* fixtures are implemented in a modular manner, as each fixture name
|
||||
triggers a *fixture function* which can itself use other fixtures.
|
||||
|
||||
* fixture management scales from simple unit to complex
|
||||
functional testing, allowing to parametrize fixtures and tests according
|
||||
to configuration and component options, or to re-use fixtures
|
||||
across function, class, module or whole test session scopes.
|
||||
|
||||
* teardown logic can be easily, and safely managed, no matter how many fixtures
|
||||
are used, without the need to carefully handle errors by hand or micromanage
|
||||
the order that cleanup steps are added.
|
||||
|
||||
In addition, pytest continues to support :ref:`xunitsetup`. You can mix
|
||||
both styles, moving incrementally from classic to new style, as you
|
||||
prefer. You can also start out from existing :ref:`unittest.TestCase
|
||||
style <unittest.TestCase>` or :ref:`nose based <nosestyle>` projects.
|
||||
|
||||
|
||||
|
||||
Fixture errors
|
||||
--------------
|
||||
|
||||
pytest does its best to put all the fixtures for a given test in a linear order
|
||||
so that it can see which fixture happens first, second, third, and so on. If an
|
||||
earlier fixture has a problem, though, and raises an exception, pytest will stop
|
||||
executing fixtures for that test and mark the test as having an error.
|
||||
|
||||
When a test is marked as having an error, it doesn't mean the test failed,
|
||||
though. It just means the test couldn't even be attempted because one of the
|
||||
things it depends on had a problem.
|
||||
|
||||
This is one reason why it's a good idea to cut out as many unnecessary
|
||||
dependencies as possible for a given test. That way a problem in something
|
||||
unrelated isn't causing us to have an incomplete picture of what may or may not
|
||||
have issues.
|
||||
|
||||
Here's a quick example to help explain:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def order():
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def append_first(order):
|
||||
order.append(1)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def append_second(order, append_first):
|
||||
order.extend([2])
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def append_third(order, append_second):
|
||||
order += [3]
|
||||
|
||||
|
||||
def test_order(order):
|
||||
assert order == [1, 2, 3]
|
||||
|
||||
|
||||
If, for whatever reason, ``order.append(1)`` had a bug and it raises an exception,
|
||||
we wouldn't be able to know if ``order.extend([2])`` or ``order += [3]`` would
|
||||
also have problems. After ``append_first`` throws an exception, pytest won't run
|
||||
any more fixtures for ``test_order``, and it won't even try to run
|
||||
``test_order`` itself. The only things that would've run would be ``order`` and
|
||||
``append_first``.
|
||||
|
||||
|
||||
Sharing test data
|
||||
-----------------
|
||||
|
||||
If you want to make test data from files available to your tests, a good way
|
||||
to do this is by loading these data in a fixture for use by your tests.
|
||||
This makes use of the automatic caching mechanisms of pytest.
|
||||
|
||||
Another good approach is by adding the data files in the ``tests`` folder.
|
||||
There are also community plugins available to help to manage this aspect of
|
||||
testing, e.g. :pypi:`pytest-datadir` and :pypi:`pytest-datafiles`.
|
||||
|
||||
.. _fixtures-signal-cleanup:
|
||||
|
||||
A note about fixture cleanup
|
||||
----------------------------
|
||||
|
||||
pytest does not do any special processing for :data:`SIGTERM <signal.SIGTERM>` and
|
||||
:data:`SIGQUIT <signal.SIGQUIT>` signals (:data:`SIGINT <signal.SIGINT>` is handled naturally
|
||||
by the Python runtime via :class:`KeyboardInterrupt`), so fixtures that manage external resources which are important
|
||||
to be cleared when the Python process is terminated (by those signals) might leak resources.
|
||||
|
||||
The reason pytest does not handle those signals to perform fixture cleanup is that signal handlers are global,
|
||||
and changing them might interfere with the code under execution.
|
||||
|
||||
If fixtures in your suite need special care regarding termination in those scenarios,
|
||||
see :issue:`this comment <5243#issuecomment-491522595>` in the issue
|
||||
tracker for a possible workaround.
|
||||
@@ -1,15 +0,0 @@
|
||||
:orphan:
|
||||
|
||||
.. _explanation:
|
||||
|
||||
Explanation
|
||||
================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
anatomy
|
||||
fixtures
|
||||
goodpractices
|
||||
flaky
|
||||
pythonpath
|
||||
@@ -28,7 +28,7 @@ Flaky tests sometimes appear when a test suite is run in parallel (such as use o
|
||||
Overly strict assertion
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Overly strict assertions can cause problems with floating point comparison as well as timing issues. :func:`pytest.approx` is useful here.
|
||||
Overly strict assertions can cause problems with floating point comparison as well as timing issues. `pytest.approx <https://docs.pytest.org/en/stable/reference.html#pytest-approx>`_ is useful here.
|
||||
|
||||
|
||||
Pytest features
|
||||
@@ -113,7 +113,7 @@ Resources
|
||||
|
||||
* `Eradicating Non-Determinism in Tests <https://martinfowler.com/articles/nonDeterminism.html>`_ by Martin Fowler, 2011
|
||||
* `No more flaky tests on the Go team <https://www.thoughtworks.com/insights/blog/no-more-flaky-tests-go-team>`_ by Pavan Sudarshan, 2012
|
||||
* `The Build That Cried Broken: Building Trust in your Continuous Integration Tests <https://www.youtube.com/embed/VotJqV4n8ig>`_ talk (video) by `Angie Jones <https://angiejones.tech/>`_ at SeleniumConf Austin 2017
|
||||
* `The Build That Cried Broken: Building Trust in your Continuous Integration Tests <https://www.youtube.com/embed/VotJqV4n8ig>`_ talk (video) by `Angie Jones <http://angiejones.tech/>`_ at SeleniumConf Austin 2017
|
||||
* `Test and Code Podcast: Flaky Tests and How to Deal with Them <https://testandcode.com/50>`_ by Brian Okken and Anthony Shaw, 2018
|
||||
* Microsoft:
|
||||
|
||||
@@ -7,7 +7,7 @@ pytest-2.3: reasoning for fixture/funcarg evolution
|
||||
|
||||
**Target audience**: Reading this document requires basic knowledge of
|
||||
python testing, xUnit setup methods and the (previous) basic pytest
|
||||
funcarg mechanism, see :ref:`historical funcargs and pytest.funcargs`.
|
||||
funcarg mechanism, see https://docs.pytest.org/en/stable/historical-notes.html#funcargs-and-pytest-funcarg.
|
||||
If you are new to pytest, then you can simply ignore this
|
||||
section and read the other sections.
|
||||
|
||||
@@ -47,7 +47,7 @@ There are several limitations and difficulties with this approach:
|
||||
2. parametrizing the "db" resource is not straight forward:
|
||||
you need to apply a "parametrize" decorator or implement a
|
||||
:py:func:`~hookspec.pytest_generate_tests` hook
|
||||
calling :py:func:`~pytest.Metafunc.parametrize` which
|
||||
calling :py:func:`~python.Metafunc.parametrize` which
|
||||
performs parametrization at the places where the resource
|
||||
is used. Moreover, you need to modify the factory to use an
|
||||
``extrakey`` parameter containing ``request.param`` to the
|
||||
@@ -113,7 +113,7 @@ This new way of parametrizing funcarg factories should in many cases
|
||||
allow to re-use already written factories because effectively
|
||||
``request.param`` was already used when test functions/classes were
|
||||
parametrized via
|
||||
:py:func:`metafunc.parametrize(indirect=True) <pytest.Metafunc.parametrize>` calls.
|
||||
:py:func:`metafunc.parametrize(indirect=True) <_pytest.python.Metafunc.parametrize>` calls.
|
||||
|
||||
Of course it's perfectly fine to combine parametrization and scoping:
|
||||
|
||||
@@ -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 managing process would setup test resources
|
||||
1. in distributed testing the master process would setup test resources
|
||||
that are never needed because it only co-ordinates the test run
|
||||
activities of the worker processes.
|
||||
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
.. _get-started:
|
||||
|
||||
Get Started
|
||||
Installation and Getting Started
|
||||
===================================
|
||||
|
||||
**Pythons**: Python 3.6, 3.7, 3.8, 3.9, PyPy3
|
||||
|
||||
**Platforms**: Linux and Windows
|
||||
|
||||
**PyPI package name**: `pytest <https://pypi.org/project/pytest/>`_
|
||||
|
||||
**Documentation as PDF**: `download latest <https://media.readthedocs.org/pdf/pytest/latest/pytest.pdf>`_
|
||||
|
||||
``pytest`` is a framework that makes building simple and scalable tests easy. Tests are expressive and readable—no boilerplate code required. Get started in minutes with a small unit test or complex functional test for your application or library.
|
||||
|
||||
.. _`getstarted`:
|
||||
.. _`installation`:
|
||||
|
||||
Install ``pytest``
|
||||
----------------------------------------
|
||||
|
||||
``pytest`` requires: Python 3.6, 3.7, 3.8, 3.9, or PyPy3.
|
||||
|
||||
1. Run the following command in your command line:
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -22,14 +28,14 @@ Install ``pytest``
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest --version
|
||||
pytest 7.0.0rc1
|
||||
pytest 6.2.3
|
||||
|
||||
.. _`simpletest`:
|
||||
|
||||
Create your first test
|
||||
----------------------------------------------------------
|
||||
|
||||
Create a new file called ``test_sample.py``, containing a function, and a test:
|
||||
Create a simple test function with just four lines of code:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -41,14 +47,15 @@ Create a new file called ``test_sample.py``, containing a function, and a test:
|
||||
def test_answer():
|
||||
assert func(3) == 5
|
||||
|
||||
The test
|
||||
That’s it. You can now execute the test function:
|
||||
|
||||
.. code-block:: pytest
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
|
||||
test_sample.py F [100%]
|
||||
@@ -70,7 +77,7 @@ The ``[100%]`` refers to the overall progress of running all test cases. After i
|
||||
|
||||
.. note::
|
||||
|
||||
You can use the ``assert`` statement to verify test expectations. pytest’s :ref:`Advanced assertion introspection <python:assert>` will intelligently report intermediate values of the assert expression so you can avoid the many names :ref:`of JUnit legacy methods <testcase-objects>`.
|
||||
You can use the ``assert`` statement to verify test expectations. pytest’s `Advanced assertion introspection <http://docs.python.org/reference/simple_stmts.html#the-assert-statement>`_ will intelligently report intermediate values of the assert expression so you can avoid the many names `of JUnit legacy methods <http://docs.python.org/library/unittest.html#test-cases>`_.
|
||||
|
||||
Run multiple tests
|
||||
----------------------------------------------------------
|
||||
@@ -137,7 +144,7 @@ Once you develop multiple tests, you may want to group them into a class. pytest
|
||||
================================= FAILURES =================================
|
||||
____________________________ TestClass.test_two ____________________________
|
||||
|
||||
self = <test_class.TestClass object at 0xdeadbeef0001>
|
||||
self = <test_class.TestClass object at 0xdeadbeef>
|
||||
|
||||
def test_two(self):
|
||||
x = "hello"
|
||||
@@ -168,73 +175,77 @@ This is outlined below:
|
||||
|
||||
# content of test_class_demo.py
|
||||
class TestClassDemoInstance:
|
||||
value = 0
|
||||
|
||||
def test_one(self):
|
||||
self.value = 1
|
||||
assert self.value == 1
|
||||
assert 0
|
||||
|
||||
def test_two(self):
|
||||
assert self.value == 1
|
||||
assert 0
|
||||
|
||||
|
||||
.. code-block:: pytest
|
||||
|
||||
$ pytest -k TestClassDemoInstance -q
|
||||
.F [100%]
|
||||
FF [100%]
|
||||
================================= FAILURES =================================
|
||||
______________________ TestClassDemoInstance.test_one ______________________
|
||||
|
||||
self = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef>
|
||||
|
||||
def test_one(self):
|
||||
> assert 0
|
||||
E assert 0
|
||||
|
||||
test_class_demo.py:3: AssertionError
|
||||
______________________ TestClassDemoInstance.test_two ______________________
|
||||
|
||||
self = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef0002>
|
||||
self = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef>
|
||||
|
||||
def test_two(self):
|
||||
> assert self.value == 1
|
||||
E assert 0 == 1
|
||||
E + where 0 = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef0002>.value
|
||||
> assert 0
|
||||
E assert 0
|
||||
|
||||
test_class_demo.py:9: AssertionError
|
||||
test_class_demo.py:6: AssertionError
|
||||
========================= short test summary info ==========================
|
||||
FAILED test_class_demo.py::TestClassDemoInstance::test_two - assert 0 == 1
|
||||
1 failed, 1 passed in 0.12s
|
||||
|
||||
Note that attributes added at class level are *class attributes*, so they will be shared between tests.
|
||||
FAILED test_class_demo.py::TestClassDemoInstance::test_one - assert 0
|
||||
FAILED test_class_demo.py::TestClassDemoInstance::test_two - assert 0
|
||||
2 failed in 0.12s
|
||||
|
||||
Request a unique temporary directory for functional tests
|
||||
--------------------------------------------------------------
|
||||
|
||||
``pytest`` provides :std:doc:`Builtin fixtures/function arguments <builtin>` to request arbitrary resources, like a unique temporary directory:
|
||||
``pytest`` provides `Builtin fixtures/function arguments <https://docs.pytest.org/en/stable/builtin.html>`_ to request arbitrary resources, like a unique temporary directory:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# content of test_tmp_path.py
|
||||
def test_needsfiles(tmp_path):
|
||||
print(tmp_path)
|
||||
# content of test_tmpdir.py
|
||||
def test_needsfiles(tmpdir):
|
||||
print(tmpdir)
|
||||
assert 0
|
||||
|
||||
List the name ``tmp_path`` in the test function signature and ``pytest`` will lookup and call a fixture factory to create the resource before performing the test function call. Before the test runs, ``pytest`` creates a unique-per-test-invocation temporary directory:
|
||||
List the name ``tmpdir`` in the test function signature and ``pytest`` will lookup and call a fixture factory to create the resource before performing the test function call. Before the test runs, ``pytest`` creates a unique-per-test-invocation temporary directory:
|
||||
|
||||
.. code-block:: pytest
|
||||
|
||||
$ pytest -q test_tmp_path.py
|
||||
$ pytest -q test_tmpdir.py
|
||||
F [100%]
|
||||
================================= FAILURES =================================
|
||||
_____________________________ test_needsfiles ______________________________
|
||||
|
||||
tmp_path = PosixPath('PYTEST_TMPDIR/test_needsfiles0')
|
||||
tmpdir = local('PYTEST_TMPDIR/test_needsfiles0')
|
||||
|
||||
def test_needsfiles(tmp_path):
|
||||
print(tmp_path)
|
||||
def test_needsfiles(tmpdir):
|
||||
print(tmpdir)
|
||||
> assert 0
|
||||
E assert 0
|
||||
|
||||
test_tmp_path.py:3: AssertionError
|
||||
test_tmpdir.py:3: AssertionError
|
||||
--------------------------- Captured stdout call ---------------------------
|
||||
PYTEST_TMPDIR/test_needsfiles0
|
||||
========================= short test summary info ==========================
|
||||
FAILED test_tmp_path.py::test_needsfiles - assert 0
|
||||
FAILED test_tmpdir.py::test_needsfiles - assert 0
|
||||
1 failed in 0.12s
|
||||
|
||||
More info on temporary directory handling is available at :ref:`Temporary directories and files <tmp_path handling>`.
|
||||
More info on tmpdir handling is available at :ref:`Temporary directories and files <tmpdir handling>`.
|
||||
|
||||
Find out what kind of builtin :ref:`pytest fixtures <fixtures>` exist with the command:
|
||||
|
||||
@@ -249,7 +260,7 @@ Continue reading
|
||||
|
||||
Check out additional pytest resources to help you customize tests for your unique workflow:
|
||||
|
||||
* ":ref:`usage`" for command line invocation examples
|
||||
* ":ref:`cmdline`" for command line invocation examples
|
||||
* ":ref:`existingtestsuite`" for working with pre-existing tests
|
||||
* ":ref:`mark`" for information on the ``pytest.mark`` mechanism
|
||||
* ":ref:`fixtures`" for providing a functional baseline to your tests
|
||||
|
||||
@@ -7,48 +7,28 @@ Good Integration Practices
|
||||
Install package with pip
|
||||
-------------------------------------------------
|
||||
|
||||
For development, we recommend you use :mod:`venv` for virtual environments and
|
||||
:doc:`pip:index` for installing your application and any dependencies,
|
||||
For development, we recommend you use venv_ for virtual environments and
|
||||
pip_ for installing your application and any dependencies,
|
||||
as well as the ``pytest`` package itself.
|
||||
This ensures your code and dependencies are isolated from your system Python installation.
|
||||
|
||||
Next, place a ``pyproject.toml`` file in the root of your package:
|
||||
Next, place a ``setup.py`` file in the root of your package with the following minimum content:
|
||||
|
||||
.. code-block:: toml
|
||||
.. code-block:: python
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=42", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
and a ``setup.cfg`` file containing your package's metadata with the following minimum content:
|
||||
setup(name="PACKAGENAME", packages=find_packages())
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[metadata]
|
||||
name = PACKAGENAME
|
||||
|
||||
[options]
|
||||
packages = find:
|
||||
|
||||
where ``PACKAGENAME`` is the name of your package.
|
||||
|
||||
.. note::
|
||||
|
||||
If your pip version is older than ``21.3``, you'll also need a ``setup.py`` file:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
setup()
|
||||
|
||||
You can then install your package in "editable" mode by running from the same directory:
|
||||
Where ``PACKAGENAME`` is the name of your package. You can then install your package in "editable" mode by running from the same directory:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install -e .
|
||||
|
||||
which lets you change your source code (both tests and application) and rerun tests at will.
|
||||
This is similar to running ``python setup.py develop`` or ``conda develop`` in that it installs
|
||||
your package using a symlink to your development code.
|
||||
|
||||
.. _`test discovery`:
|
||||
.. _`Python test discovery`:
|
||||
@@ -68,7 +48,7 @@ Conventions for Python test discovery
|
||||
* ``test`` prefixed test functions or methods outside of class
|
||||
* ``test`` prefixed test functions or methods inside ``Test`` prefixed test classes (without an ``__init__`` method)
|
||||
|
||||
For examples of how to customize your test discovery :doc:`/example/pythoncollection`.
|
||||
For examples of how to customize your test discovery :doc:`example/pythoncollection`.
|
||||
|
||||
Within Python modules, ``pytest`` also discovers tests using the standard
|
||||
:ref:`unittest.TestCase <unittest.TestCase>` subclassing technique.
|
||||
@@ -88,8 +68,7 @@ to keep tests separate from actual application code (often a good idea):
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
pyproject.toml
|
||||
setup.cfg
|
||||
setup.py
|
||||
mypkg/
|
||||
__init__.py
|
||||
app.py
|
||||
@@ -103,7 +82,7 @@ This has the following benefits:
|
||||
|
||||
* Your tests can run against an installed version after executing ``pip install .``.
|
||||
* Your tests can run against the local copy with an editable install after executing ``pip install --editable .``.
|
||||
* If you don't use an editable install and are relying on the fact that Python by default puts the current
|
||||
* If you don't have a ``setup.py`` file and are relying on the fact that Python by default puts the current
|
||||
directory in ``sys.path`` to import your package, you can execute ``python -m pytest`` to execute the tests against the
|
||||
local copy directly, without using ``pip``.
|
||||
|
||||
@@ -124,8 +103,7 @@ If you need to have test modules with the same name, you might add ``__init__.py
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
pyproject.toml
|
||||
setup.cfg
|
||||
setup.py
|
||||
mypkg/
|
||||
...
|
||||
tests/
|
||||
@@ -152,8 +130,7 @@ sub-directory of your root:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
pyproject.toml
|
||||
setup.cfg
|
||||
setup.py
|
||||
src/
|
||||
mypkg/
|
||||
__init__.py
|
||||
@@ -174,7 +151,7 @@ This layout prevents a lot of common pitfalls and has many benefits, which are b
|
||||
|
||||
.. note::
|
||||
The new ``--import-mode=importlib`` (see :ref:`import-modes`) doesn't have
|
||||
any of the drawbacks above because ``sys.path`` is not changed when importing
|
||||
any of the drawbacks above because ``sys.path`` and ``sys.modules`` are not changed when importing
|
||||
test modules, so users that run
|
||||
into this issue are strongly encouraged to try it and report if the new option works well for them.
|
||||
|
||||
@@ -190,8 +167,7 @@ want to distribute them along with your application:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
pyproject.toml
|
||||
setup.cfg
|
||||
setup.py
|
||||
mypkg/
|
||||
__init__.py
|
||||
app.py
|
||||
@@ -215,11 +191,11 @@ Note that this layout also works in conjunction with the ``src`` layout mentione
|
||||
|
||||
.. note::
|
||||
|
||||
You can use namespace packages (PEP420) for your application
|
||||
You can use Python3 namespace packages (PEP420) for your application
|
||||
but pytest will still perform `test package name`_ discovery based on the
|
||||
presence of ``__init__.py`` files. If you use one of the
|
||||
two recommended file system layouts above but leave away the ``__init__.py``
|
||||
files from your directories, it should just work. From
|
||||
files from your directories it should just work on Python3.3 and above. From
|
||||
"inlined tests", however, you will need to use absolute imports for
|
||||
getting at your application code.
|
||||
|
||||
@@ -254,35 +230,23 @@ Note that this layout also works in conjunction with the ``src`` layout mentione
|
||||
much less surprising.
|
||||
|
||||
|
||||
.. _`buildout`: http://www.buildout.org/en/latest/
|
||||
.. _`virtualenv`: https://pypi.org/project/virtualenv/
|
||||
.. _`buildout`: http://www.buildout.org/
|
||||
.. _pip: https://pypi.org/project/pip/
|
||||
|
||||
.. _`use tox`:
|
||||
|
||||
tox
|
||||
---
|
||||
------
|
||||
|
||||
Once you are done with your work and want to make sure that your actual
|
||||
package passes all tests you may want to look into :doc:`tox <tox:index>`, the
|
||||
virtualenv test automation tool and its :doc:`pytest support <tox:example/pytest>`.
|
||||
package passes all tests you may want to look into `tox`_, the
|
||||
virtualenv test automation tool and its `pytest support
|
||||
<https://tox.readthedocs.io/en/latest/example/pytest.html>`_.
|
||||
tox helps you to setup virtualenv environments with pre-defined
|
||||
dependencies and then executing a pre-configured test command with
|
||||
options. It will run tests against the installed package and not
|
||||
against your source code checkout, helping to detect packaging
|
||||
glitches.
|
||||
|
||||
Do not run via setuptools
|
||||
-------------------------
|
||||
|
||||
Integration with setuptools is **not recommended**,
|
||||
i.e. you should not be using ``python setup.py test`` or ``pytest-runner``,
|
||||
and may stop working in the future.
|
||||
|
||||
This is deprecated since it depends on deprecated features of setuptools
|
||||
and relies on features that break security mechanisms in pip.
|
||||
For example 'setup_requires' and 'tests_require' bypass ``pip --require-hashes``.
|
||||
For more information and migration instructions,
|
||||
see the `pytest-runner notice <https://github.com/pytest-dev/pytest-runner#deprecation-notice>`_.
|
||||
See also `pypa/setuptools#1684 <https://github.com/pypa/setuptools/issues/1684>`_.
|
||||
|
||||
setuptools intends to
|
||||
`remove the test command <https://github.com/pypa/setuptools/issues/931>`_.
|
||||
.. _`venv`: https://docs.python.org/3/library/venv.html
|
||||
@@ -76,38 +76,38 @@ order doesn't even matter. You probably want to think of your marks as a set her
|
||||
|
||||
|
||||
If you are unsure or have any questions, please consider opening
|
||||
:issue:`an issue <new>`.
|
||||
`an issue <https://github.com/pytest-dev/pytest/issues>`_.
|
||||
|
||||
Related issues
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Here is a non-exhaustive list of issues fixed by the new implementation:
|
||||
|
||||
* Marks don't pick up nested classes (:issue:`199`).
|
||||
* Marks don't pick up nested classes (`#199 <https://github.com/pytest-dev/pytest/issues/199>`_).
|
||||
|
||||
* Markers stain on all related classes (:issue:`568`).
|
||||
* Markers stain on all related classes (`#568 <https://github.com/pytest-dev/pytest/issues/568>`_).
|
||||
|
||||
* Combining marks - args and kwargs calculation (:issue:`2897`).
|
||||
* Combining marks - args and kwargs calculation (`#2897 <https://github.com/pytest-dev/pytest/issues/2897>`_).
|
||||
|
||||
* ``request.node.get_marker('name')`` returns ``None`` for markers applied in classes (:issue:`902`).
|
||||
* ``request.node.get_marker('name')`` returns ``None`` for markers applied in classes (`#902 <https://github.com/pytest-dev/pytest/issues/902>`_).
|
||||
|
||||
* Marks applied in parametrize are stored as markdecorator (:issue:`2400`).
|
||||
* Marks applied in parametrize are stored as markdecorator (`#2400 <https://github.com/pytest-dev/pytest/issues/2400>`_).
|
||||
|
||||
* Fix marker interaction in a backward incompatible way (:issue:`1670`).
|
||||
* Fix marker interaction in a backward incompatible way (`#1670 <https://github.com/pytest-dev/pytest/issues/1670>`_).
|
||||
|
||||
* Refactor marks to get rid of the current "marks transfer" mechanism (:issue:`2363`).
|
||||
* Refactor marks to get rid of the current "marks transfer" mechanism (`#2363 <https://github.com/pytest-dev/pytest/issues/2363>`_).
|
||||
|
||||
* Introduce FunctionDefinition node, use it in generate_tests (:issue:`2522`).
|
||||
* Introduce FunctionDefinition node, use it in generate_tests (`#2522 <https://github.com/pytest-dev/pytest/issues/2522>`_).
|
||||
|
||||
* Remove named marker attributes and collect markers in items (:issue:`891`).
|
||||
* Remove named marker attributes and collect markers in items (`#891 <https://github.com/pytest-dev/pytest/issues/891>`_).
|
||||
|
||||
* skipif mark from parametrize hides module level skipif mark (:issue:`1540`).
|
||||
* skipif mark from parametrize hides module level skipif mark (`#1540 <https://github.com/pytest-dev/pytest/issues/1540>`_).
|
||||
|
||||
* skipif + parametrize not skipping tests (:issue:`1296`).
|
||||
* skipif + parametrize not skipping tests (`#1296 <https://github.com/pytest-dev/pytest/issues/1296>`_).
|
||||
|
||||
* Marker transfer incompatible with inheritance (:issue:`535`).
|
||||
* Marker transfer incompatible with inheritance (`#535 <https://github.com/pytest-dev/pytest/issues/535>`_).
|
||||
|
||||
More details can be found in the :pull:`original PR <3317>`.
|
||||
More details can be found in the `original PR <https://github.com/pytest-dev/pytest/pull/3317>`_.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -125,7 +125,6 @@ as a third party plugin named ``pytest-cache``. The core plugin
|
||||
is compatible regarding command line options and API usage except that you
|
||||
can only store/receive data between test runs that is json-serializable.
|
||||
|
||||
.. _historical funcargs and pytest.funcargs:
|
||||
|
||||
funcargs and ``pytest_funcarg__``
|
||||
---------------------------------
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
History
|
||||
=======
|
||||
|
||||
pytest has a long and interesting history. The `first commit
|
||||
<https://github.com/pytest-dev/pytest/commit/5992a8ef21424d7571305a8d7e2a3431ee7e1e23>`__
|
||||
in this repository is from January 2007, and even that commit alone already
|
||||
tells a lot: The repository originally was from the :pypi:`py`
|
||||
library (later split off to pytest), and it
|
||||
originally was a SVN revision, migrated to Mercurial, and finally migrated to
|
||||
git.
|
||||
|
||||
However, the commit says “create the new development trunk” and is
|
||||
already quite big: *435 files changed, 58640 insertions(+)*. This is because
|
||||
pytest originally was born as part of `PyPy <https://www.pypy.org/>`__, to make
|
||||
it easier to write tests for it. Here's how it evolved from there to its own
|
||||
project:
|
||||
|
||||
|
||||
- Late 2002 / early 2003, `PyPy was
|
||||
born <https://morepypy.blogspot.com/2018/09/the-first-15-years-of-pypy.html>`__.
|
||||
- Like that blog post mentioned, from very early on, there was a big
|
||||
focus on testing. There were various ``testsupport`` files on top of
|
||||
unittest.py, and as early as June 2003, Holger Krekel (:user:`hpk42`)
|
||||
`refactored <https://mail.python.org/pipermail/pypy-dev/2003-June/000787.html>`__
|
||||
its test framework to clean things up (``pypy.tool.test``, but still
|
||||
on top of ``unittest.py``, with nothing pytest-like yet).
|
||||
- In December 2003, there was `another
|
||||
iteration <https://foss.heptapod.net/pypy/pypy/-/commit/02752373e1b29d89c6bb0a97e5f940caa22bdd63>`__
|
||||
at improving their testing situation, by Stefan Schwarzer, called
|
||||
``pypy.tool.newtest``.
|
||||
- However, it didn’t seem to be around for long, as around June/July
|
||||
2004, efforts started on a thing called ``utest``, offering plain
|
||||
assertions. This seems like the start of something pytest-like, but
|
||||
unfortunately, it's unclear where the test runner's code was at the time.
|
||||
The closest thing still around is `this
|
||||
file <https://foss.heptapod.net/pypy/pypy/-/commit/0735f9ed287ec20950a7dd0a16fc10810d4f6847>`__,
|
||||
but that doesn’t seem like a complete test runner at all. What can be seen
|
||||
is that there were `various
|
||||
efforts <https://foss.heptapod.net/pypy/pypy/-/commits/branch/default?utf8=%E2%9C%93&search=utest>`__
|
||||
by Laura Creighton and Samuele Pedroni (:user:`pedronis`) at automatically
|
||||
converting existing tests to the new ``utest`` framework.
|
||||
- Around the same time, for Europython 2004, @hpk42 `started a
|
||||
project <http://web.archive.org/web/20041020215353/http://codespeak.net/svn/user/hpk/talks/std-talk.txt>`__
|
||||
originally called “std”, intended to be a “complementary standard
|
||||
library” - already laying out the principles behind what later became
|
||||
pytest:
|
||||
|
||||
- current “batteries included” are very useful, but
|
||||
|
||||
- some of them are written in a pretty much java-like style,
|
||||
especially the unittest-framework
|
||||
- […]
|
||||
- the best API is one that doesn’t exist
|
||||
|
||||
[…]
|
||||
|
||||
- a testing package should require as few boilerplate code as
|
||||
possible and offer much flexibility
|
||||
- it should provide premium quality tracebacks and debugging aid
|
||||
|
||||
[…]
|
||||
|
||||
- first of all … forget about limited “assertXYZ APIs” and use the
|
||||
real thing, e.g.::
|
||||
|
||||
assert x == y
|
||||
|
||||
- this works with plain python but you get unhelpful “assertion
|
||||
failed” errors with no information
|
||||
|
||||
- std.utest (magic!) actually reinterprets the assertion expression
|
||||
and offers detailed information about underlying values
|
||||
|
||||
- In September 2004, the ``py-dev`` mailinglist gets born, which `is
|
||||
now <https://mail.python.org/pipermail/pytest-dev/>`__ ``pytest-dev``,
|
||||
but thankfully with all the original archives still intact.
|
||||
|
||||
- Around September/October 2004, the ``std`` project `was renamed
|
||||
<https://mail.python.org/pipermail/pypy-dev/2004-September/001565.html>`__ to
|
||||
``py`` and ``std.utest`` became ``py.test``. This is also the first time the
|
||||
`entire source
|
||||
code <https://foss.heptapod.net/pypy/pypy/-/commit/42cf50c412026028e20acd23d518bd92e623ac11>`__,
|
||||
seems to be available, with much of the API still being around today:
|
||||
|
||||
- ``py.path.local``, which is being phased out of pytest (in favour of
|
||||
pathlib) some 16-17 years later
|
||||
- The idea of the collection tree, including ``Collector``,
|
||||
``FSCollector``, ``Directory``, ``PyCollector``, ``Module``,
|
||||
``Class``
|
||||
- Arguments like ``-x`` / ``--exitfirst``, ``-l`` /
|
||||
``--showlocals``, ``--fulltrace``, ``--pdb``, ``-S`` /
|
||||
``--nocapture`` (``-s`` / ``--capture=off`` today),
|
||||
``--collectonly`` (``--collect-only`` today)
|
||||
|
||||
- In the same month, the ``py`` library `gets split off
|
||||
<https://foss.heptapod.net/pypy/pypy/-/commit/6bdafe9203ad92eb259270b267189141c53bce33>`__
|
||||
from ``PyPy``
|
||||
|
||||
- It seemed to get rather quiet for a while, and little seemed to happen
|
||||
between October 2004 (removing ``py`` from PyPy) and January
|
||||
2007 (first commit in the now-pytest repository). However, there were
|
||||
various discussions about features/ideas on the mailinglist, and
|
||||
:pypi:`a couple of releases <py/0.8.0-alpha2/#history>` every
|
||||
couple of months:
|
||||
|
||||
- March 2006: py 0.8.0-alpha2
|
||||
- May 2007: py 0.9.0
|
||||
- March 2008: py 0.9.1 (first release to be found `in the pytest
|
||||
changelog <https://github.com/pytest-dev/pytest/blob/main/doc/en/changelog.rst#091>`__!)
|
||||
- August 2008: py 0.9.2
|
||||
|
||||
- In August 2009, py 1.0.0 was released, `introducing a lot of
|
||||
fundamental
|
||||
features <https://holgerkrekel.net/2009/08/04/pylib-1-0-0-released-the-testing-with-python-innovations-continue/>`__:
|
||||
|
||||
- funcargs/fixtures
|
||||
- A `plugin
|
||||
architecture <http://web.archive.org/web/20090629032718/https://codespeak.net/py/dist/test/extend.html>`__
|
||||
which still looks very much the same today!
|
||||
- Various `default
|
||||
plugins <http://web.archive.org/web/20091005181132/https://codespeak.net/py/dist/test/plugin/index.html>`__,
|
||||
including
|
||||
`monkeypatch <http://web.archive.org/web/20091012022829/http://codespeak.net/py/dist/test/plugin/how-to/monkeypatch.html>`__
|
||||
|
||||
- Even back there, the
|
||||
`FAQ <http://web.archive.org/web/20091005222413/http://codespeak.net/py/dist/faq.html>`__
|
||||
said:
|
||||
|
||||
Clearly, [a second standard library] was ambitious and the naming has
|
||||
maybe haunted the project rather than helping it. There may be a
|
||||
project name change and possibly a split up into different projects
|
||||
sometime.
|
||||
|
||||
and that finally happened in November 2010, when pytest 2.0.0 `was
|
||||
released <https://mail.python.org/pipermail/pytest-dev/2010-November/001687.html>`__
|
||||
as a package separate from ``py`` (but still called ``py.test``).
|
||||
|
||||
- In August 2016, pytest 3.0.0 :std:ref:`was released <release-3.0.0>`,
|
||||
which adds ``pytest`` (rather than ``py.test``) as the recommended
|
||||
command-line entry point
|
||||
|
||||
Due to this history, it's diffcult to answer the question when pytest was started.
|
||||
It depends what point should really be seen as the start of it all. One
|
||||
possible interpretation is to pick Europython 2004, i.e. around June/July
|
||||
2004.
|
||||
@@ -1,160 +0,0 @@
|
||||
.. _how-to-handle-failures:
|
||||
|
||||
How to handle test failures
|
||||
=============================
|
||||
|
||||
.. _maxfail:
|
||||
|
||||
Stopping after the first (or N) failures
|
||||
---------------------------------------------------
|
||||
|
||||
To stop the testing process after the first (N) failures:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest -x # stop after first failure
|
||||
pytest --maxfail=2 # stop after two failures
|
||||
|
||||
|
||||
.. _pdb-option:
|
||||
|
||||
Using :doc:`python:library/pdb` with pytest
|
||||
-------------------------------------------
|
||||
|
||||
Dropping to :doc:`pdb <python:library/pdb>` on failures
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Python comes with a builtin Python debugger called :doc:`pdb <python:library/pdb>`. ``pytest``
|
||||
allows one to drop into the :doc:`pdb <python:library/pdb>` prompt via a command line option:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest --pdb
|
||||
|
||||
This will invoke the Python debugger on every failure (or KeyboardInterrupt).
|
||||
Often you might only want to do this for the first failing test to understand
|
||||
a certain failure situation:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest -x --pdb # drop to PDB on first failure, then end test session
|
||||
pytest --pdb --maxfail=3 # drop to PDB for first three failures
|
||||
|
||||
Note that on any failure the exception information is stored on
|
||||
``sys.last_value``, ``sys.last_type`` and ``sys.last_traceback``. In
|
||||
interactive use, this allows one to drop into postmortem debugging with
|
||||
any debug tool. One can also manually access the exception information,
|
||||
for example::
|
||||
|
||||
>>> import sys
|
||||
>>> sys.last_traceback.tb_lineno
|
||||
42
|
||||
>>> sys.last_value
|
||||
AssertionError('assert result == "ok"',)
|
||||
|
||||
|
||||
.. _trace-option:
|
||||
|
||||
Dropping to :doc:`pdb <python:library/pdb>` at the start of a test
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``pytest`` allows one to drop into the :doc:`pdb <python:library/pdb>` prompt immediately at the start of each test via a command line option:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest --trace
|
||||
|
||||
This will invoke the Python debugger at the start of every test.
|
||||
|
||||
.. _breakpoints:
|
||||
|
||||
Setting breakpoints
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionadded: 2.4.0
|
||||
|
||||
To set a breakpoint in your code use the native Python ``import pdb;pdb.set_trace()`` call
|
||||
in your code and pytest automatically disables its output capture for that test:
|
||||
|
||||
* Output capture in other tests is not affected.
|
||||
* Any prior test output that has already been captured and will be processed as
|
||||
such.
|
||||
* Output capture gets resumed when ending the debugger session (via the
|
||||
``continue`` command).
|
||||
|
||||
|
||||
.. _`breakpoint-builtin`:
|
||||
|
||||
Using the builtin breakpoint function
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Python 3.7 introduces a builtin ``breakpoint()`` function.
|
||||
Pytest supports the use of ``breakpoint()`` with the following behaviours:
|
||||
|
||||
- When ``breakpoint()`` is called and ``PYTHONBREAKPOINT`` is set to the default value, pytest will use the custom internal PDB trace UI instead of the system default ``Pdb``.
|
||||
- When tests are complete, the system will default back to the system ``Pdb`` trace UI.
|
||||
- With ``--pdb`` passed to pytest, the custom internal Pdb trace UI is used with both ``breakpoint()`` and failed tests/unhandled exceptions.
|
||||
- ``--pdbcls`` can be used to specify a custom debugger class.
|
||||
|
||||
|
||||
.. _faulthandler:
|
||||
|
||||
Fault Handler
|
||||
-------------
|
||||
|
||||
.. versionadded:: 5.0
|
||||
|
||||
The :mod:`faulthandler` standard module
|
||||
can be used to dump Python tracebacks on a segfault or after a timeout.
|
||||
|
||||
The module is automatically enabled for pytest runs, unless the ``-p no:faulthandler`` is given
|
||||
on the command-line.
|
||||
|
||||
Also the :confval:`faulthandler_timeout=X<faulthandler_timeout>` configuration option can be used
|
||||
to dump the traceback of all threads if a test takes longer than ``X``
|
||||
seconds to finish (not available on Windows).
|
||||
|
||||
.. note::
|
||||
|
||||
This functionality has been integrated from the external
|
||||
`pytest-faulthandler <https://github.com/pytest-dev/pytest-faulthandler>`__ plugin, with two
|
||||
small differences:
|
||||
|
||||
* To disable it, use ``-p no:faulthandler`` instead of ``--no-faulthandler``: the former
|
||||
can be used with any plugin, so it saves one option.
|
||||
|
||||
* The ``--faulthandler-timeout`` command-line option has become the
|
||||
:confval:`faulthandler_timeout` configuration option. It can still be configured from
|
||||
the command-line using ``-o faulthandler_timeout=X``.
|
||||
|
||||
|
||||
.. _unraisable:
|
||||
|
||||
Warning about unraisable exceptions and unhandled thread exceptions
|
||||
-------------------------------------------------------------------
|
||||
|
||||
.. versionadded:: 6.2
|
||||
|
||||
.. note::
|
||||
|
||||
These features only work on Python>=3.8.
|
||||
|
||||
Unhandled exceptions are exceptions that are raised in a situation in which
|
||||
they cannot propagate to a caller. The most common case is an exception raised
|
||||
in a :meth:`__del__ <object.__del__>` implementation.
|
||||
|
||||
Unhandled thread exceptions are exceptions raised in a :class:`~threading.Thread`
|
||||
but not handled, causing the thread to terminate uncleanly.
|
||||
|
||||
Both types of exceptions are normally considered bugs, but may go unnoticed
|
||||
because they don't cause the program itself to crash. Pytest detects these
|
||||
conditions and issues a warning that is visible in the test run summary.
|
||||
|
||||
The plugins are automatically enabled for pytest runs, unless the
|
||||
``-p no:unraisableexception`` (for unraisable exceptions) and
|
||||
``-p no:threadexception`` (for thread exceptions) options are given on the
|
||||
command-line.
|
||||
|
||||
The warnings may be silenced selectively using the :ref:`pytest.mark.filterwarnings ref`
|
||||
mark. The warning categories are :class:`pytest.PytestUnraisableExceptionWarning` and
|
||||
:class:`pytest.PytestUnhandledThreadExceptionWarning`.
|
||||
@@ -1,64 +0,0 @@
|
||||
:orphan:
|
||||
|
||||
.. _how-to:
|
||||
|
||||
How-to guides
|
||||
================
|
||||
|
||||
Core pytest functionality
|
||||
-------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
usage
|
||||
assert
|
||||
fixtures
|
||||
mark
|
||||
parametrize
|
||||
tmp_path
|
||||
monkeypatch
|
||||
doctest
|
||||
cache
|
||||
|
||||
Test output and outcomes
|
||||
----------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
failures
|
||||
output
|
||||
logging
|
||||
capture-stdout-stderr
|
||||
capture-warnings
|
||||
skipping
|
||||
|
||||
Plugins
|
||||
----------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
plugins
|
||||
writing_plugins
|
||||
writing_hook_functions
|
||||
|
||||
pytest and other test systems
|
||||
-----------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
existingtestsuite
|
||||
unittest
|
||||
nose
|
||||
xunit_setup
|
||||
|
||||
pytest development environment
|
||||
------------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
bash-completion
|
||||
@@ -1,214 +0,0 @@
|
||||
|
||||
.. _usage:
|
||||
|
||||
How to invoke pytest
|
||||
==========================================
|
||||
|
||||
.. seealso:: :ref:`Complete pytest command-line flag reference <command-line-flags>`
|
||||
|
||||
In general, pytest is invoked with the command ``pytest`` (see below for :ref:`other ways to invoke pytest
|
||||
<invoke-other>`). This will execute all tests in all files whose names follow the form ``test_*.py`` or ``\*_test.py``
|
||||
in the current directory and its subdirectories. More generally, pytest follows :ref:`standard test discovery rules
|
||||
<test discovery>`.
|
||||
|
||||
|
||||
.. _select-tests:
|
||||
|
||||
Specifying which tests to run
|
||||
------------------------------
|
||||
|
||||
Pytest supports several ways to run and select tests from the command-line.
|
||||
|
||||
**Run tests in a module**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest test_mod.py
|
||||
|
||||
**Run tests in a directory**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest testing/
|
||||
|
||||
**Run tests by keyword expressions**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest -k "MyClass and not method"
|
||||
|
||||
This will run tests which contain names that match the given *string expression* (case-insensitive),
|
||||
which can include Python operators that use filenames, class names and function names as variables.
|
||||
The example above will run ``TestMyClass.test_something`` but not ``TestMyClass.test_method_simple``.
|
||||
|
||||
.. _nodeids:
|
||||
|
||||
**Run tests by node ids**
|
||||
|
||||
Each collected test is assigned a unique ``nodeid`` which consist of the module filename followed
|
||||
by specifiers like class names, function names and parameters from parametrization, separated by ``::`` characters.
|
||||
|
||||
To run a specific test within a module:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest test_mod.py::test_func
|
||||
|
||||
|
||||
Another example specifying a test method in the command line:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest test_mod.py::TestClass::test_method
|
||||
|
||||
**Run tests by marker expressions**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest -m slow
|
||||
|
||||
Will run all tests which are decorated with the ``@pytest.mark.slow`` decorator.
|
||||
|
||||
For more information see :ref:`marks <mark>`.
|
||||
|
||||
**Run tests from packages**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest --pyargs pkg.testing
|
||||
|
||||
This will import ``pkg.testing`` and use its filesystem location to find and run tests from.
|
||||
|
||||
|
||||
Getting help on version, option names, environment variables
|
||||
--------------------------------------------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest --version # shows where pytest was imported from
|
||||
pytest --fixtures # show available builtin function arguments
|
||||
pytest -h | --help # show help on command line and config file options
|
||||
|
||||
|
||||
.. _durations:
|
||||
|
||||
Profiling test execution duration
|
||||
-------------------------------------
|
||||
|
||||
.. versionchanged:: 6.0
|
||||
|
||||
To get a list of the slowest 10 test durations over 1.0s long:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest --durations=10 --durations-min=1.0
|
||||
|
||||
By default, pytest will not show test durations that are too small (<0.005s) unless ``-vv`` is passed on the command-line.
|
||||
|
||||
|
||||
Managing loading of plugins
|
||||
-------------------------------
|
||||
|
||||
Early loading plugins
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can early-load plugins (internal and external) explicitly in the command-line with the ``-p`` option::
|
||||
|
||||
pytest -p mypluginmodule
|
||||
|
||||
The option receives a ``name`` parameter, which can be:
|
||||
|
||||
* A full module dotted name, for example ``myproject.plugins``. This dotted name must be importable.
|
||||
* The entry-point name of a plugin. This is the name passed to ``setuptools`` when the plugin is
|
||||
registered. For example to early-load the :pypi:`pytest-cov` plugin you can use::
|
||||
|
||||
pytest -p pytest_cov
|
||||
|
||||
|
||||
Disabling plugins
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To disable loading specific plugins at invocation time, use the ``-p`` option
|
||||
together with the prefix ``no:``.
|
||||
|
||||
Example: to disable loading the plugin ``doctest``, which is responsible for
|
||||
executing doctest tests from text files, invoke pytest like this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest -p no:doctest
|
||||
|
||||
|
||||
.. _invoke-other:
|
||||
|
||||
Other ways of calling pytest
|
||||
-----------------------------------------------------
|
||||
|
||||
.. _invoke-python:
|
||||
|
||||
Calling pytest through ``python -m pytest``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can invoke testing through the Python interpreter from the command line:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
python -m pytest [...]
|
||||
|
||||
This is almost equivalent to invoking the command line script ``pytest [...]``
|
||||
directly, except that calling via ``python`` will also add the current directory to ``sys.path``.
|
||||
|
||||
|
||||
.. _`pytest.main-usage`:
|
||||
|
||||
Calling pytest from Python code
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can invoke ``pytest`` from Python code directly:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
retcode = pytest.main()
|
||||
|
||||
this acts as if you would call "pytest" from the command line.
|
||||
It will not raise :class:`SystemExit` but return the :ref:`exit code <exit-codes>` instead.
|
||||
You can pass in options and arguments:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
retcode = pytest.main(["-x", "mytestdir"])
|
||||
|
||||
You can specify additional plugins to ``pytest.main``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# content of myinvoke.py
|
||||
import pytest
|
||||
import sys
|
||||
|
||||
|
||||
class MyPlugin:
|
||||
def pytest_sessionfinish(self):
|
||||
print("*** test run reporting finishing")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(pytest.main(["-qq"], plugins=[MyPlugin()]))
|
||||
|
||||
Running it will show that ``MyPlugin`` was added and its
|
||||
hook was invoked:
|
||||
|
||||
.. code-block:: pytest
|
||||
|
||||
$ python myinvoke.py
|
||||
*** test run reporting finishing
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Calling ``pytest.main()`` will result in importing your tests and any modules
|
||||
that they import. Due to the caching mechanism of python's import system,
|
||||
making subsequent calls to ``pytest.main()`` from the same process will not
|
||||
reflect changes to those files between the calls. For this reason, making
|
||||
multiple calls to ``pytest.main()`` from the same process (in order to re-run
|
||||
tests, for example) is not recommended.
|
||||
@@ -1,352 +0,0 @@
|
||||
.. _`writinghooks`:
|
||||
|
||||
Writing hook functions
|
||||
======================
|
||||
|
||||
|
||||
.. _validation:
|
||||
|
||||
hook function validation and execution
|
||||
--------------------------------------
|
||||
|
||||
pytest calls hook functions from registered plugins for any
|
||||
given hook specification. Let's look at a typical hook function
|
||||
for the ``pytest_collection_modifyitems(session, config,
|
||||
items)`` hook which pytest calls after collection of all test items is
|
||||
completed.
|
||||
|
||||
When we implement a ``pytest_collection_modifyitems`` function in our plugin
|
||||
pytest will during registration verify that you use argument
|
||||
names which match the specification and bail out if not.
|
||||
|
||||
Let's look at a possible implementation:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_collection_modifyitems(config, items):
|
||||
# called after collection is completed
|
||||
# you can modify the ``items`` list
|
||||
...
|
||||
|
||||
Here, ``pytest`` will pass in ``config`` (the pytest config object)
|
||||
and ``items`` (the list of collected test items) but will not pass
|
||||
in the ``session`` argument because we didn't list it in the function
|
||||
signature. This dynamic "pruning" of arguments allows ``pytest`` to
|
||||
be "future-compatible": we can introduce new hook named parameters without
|
||||
breaking the signatures of existing hook implementations. It is one of
|
||||
the reasons for the general long-lived compatibility of pytest plugins.
|
||||
|
||||
Note that hook functions other than ``pytest_runtest_*`` are not
|
||||
allowed to raise exceptions. Doing so will break the pytest run.
|
||||
|
||||
|
||||
|
||||
.. _firstresult:
|
||||
|
||||
firstresult: stop at first non-None result
|
||||
-------------------------------------------
|
||||
|
||||
Most calls to ``pytest`` hooks result in a **list of results** which contains
|
||||
all non-None results of the called hook functions.
|
||||
|
||||
Some hook specifications use the ``firstresult=True`` option so that the hook
|
||||
call only executes until the first of N registered functions returns a
|
||||
non-None result which is then taken as result of the overall hook call.
|
||||
The remaining hook functions will not be called in this case.
|
||||
|
||||
.. _`hookwrapper`:
|
||||
|
||||
hookwrapper: executing around other hooks
|
||||
-------------------------------------------------
|
||||
|
||||
.. currentmodule:: _pytest.core
|
||||
|
||||
|
||||
|
||||
pytest plugins can implement hook wrappers which wrap the execution
|
||||
of other hook implementations. A hook wrapper is a generator function
|
||||
which yields exactly once. When pytest invokes hooks it first executes
|
||||
hook wrappers and passes the same arguments as to the regular hooks.
|
||||
|
||||
At the yield point of the hook wrapper pytest will execute the next hook
|
||||
implementations and return their result to the yield point in the form of
|
||||
a :py:class:`Result <pluggy._Result>` instance which encapsulates a result or
|
||||
exception info. The yield point itself will thus typically not raise
|
||||
exceptions (unless there are bugs).
|
||||
|
||||
Here is an example definition of a hook wrapper:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
def pytest_pyfunc_call(pyfuncitem):
|
||||
do_something_before_next_hook_executes()
|
||||
|
||||
outcome = yield
|
||||
# outcome.excinfo may be None or a (cls, val, tb) tuple
|
||||
|
||||
res = outcome.get_result() # will raise if outcome was exception
|
||||
|
||||
post_process_result(res)
|
||||
|
||||
outcome.force_result(new_res) # to override the return value to the plugin system
|
||||
|
||||
Note that hook wrappers don't return results themselves, they merely
|
||||
perform tracing or other side effects around the actual hook implementations.
|
||||
If the result of the underlying hook is a mutable object, they may modify
|
||||
that result but it's probably better to avoid it.
|
||||
|
||||
For more information, consult the
|
||||
:ref:`pluggy documentation about hookwrappers <pluggy:hookwrappers>`.
|
||||
|
||||
.. _plugin-hookorder:
|
||||
|
||||
Hook function ordering / call example
|
||||
-------------------------------------
|
||||
|
||||
For any given hook specification there may be more than one
|
||||
implementation and we thus generally view ``hook`` execution as a
|
||||
``1:N`` function call where ``N`` is the number of registered functions.
|
||||
There are ways to influence if a hook implementation comes before or
|
||||
after others, i.e. the position in the ``N``-sized list of functions:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Plugin 1
|
||||
@pytest.hookimpl(tryfirst=True)
|
||||
def pytest_collection_modifyitems(items):
|
||||
# will execute as early as possible
|
||||
...
|
||||
|
||||
|
||||
# Plugin 2
|
||||
@pytest.hookimpl(trylast=True)
|
||||
def pytest_collection_modifyitems(items):
|
||||
# will execute as late as possible
|
||||
...
|
||||
|
||||
|
||||
# Plugin 3
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
def pytest_collection_modifyitems(items):
|
||||
# will execute even before the tryfirst one above!
|
||||
outcome = yield
|
||||
# will execute after all non-hookwrappers executed
|
||||
|
||||
Here is the order of execution:
|
||||
|
||||
1. Plugin3's pytest_collection_modifyitems called until the yield point
|
||||
because it is a hook wrapper.
|
||||
|
||||
2. Plugin1's pytest_collection_modifyitems is called because it is marked
|
||||
with ``tryfirst=True``.
|
||||
|
||||
3. Plugin2's pytest_collection_modifyitems is called because it is marked
|
||||
with ``trylast=True`` (but even without this mark it would come after
|
||||
Plugin1).
|
||||
|
||||
4. Plugin3's pytest_collection_modifyitems then executing the code after the yield
|
||||
point. The yield receives a :py:class:`Result <pluggy._Result>` instance which encapsulates
|
||||
the result from calling the non-wrappers. Wrappers shall not modify the result.
|
||||
|
||||
It's possible to use ``tryfirst`` and ``trylast`` also in conjunction with
|
||||
``hookwrapper=True`` in which case it will influence the ordering of hookwrappers
|
||||
among each other.
|
||||
|
||||
|
||||
Declaring new hooks
|
||||
------------------------
|
||||
|
||||
.. note::
|
||||
|
||||
This is a quick overview on how to add new hooks and how they work in general, but a more complete
|
||||
overview can be found in `the pluggy documentation <https://pluggy.readthedocs.io/en/latest/>`__.
|
||||
|
||||
.. currentmodule:: _pytest.hookspec
|
||||
|
||||
Plugins and ``conftest.py`` files may declare new hooks that can then be
|
||||
implemented by other plugins in order to alter behaviour or interact with
|
||||
the new plugin:
|
||||
|
||||
.. autofunction:: pytest_addhooks
|
||||
:noindex:
|
||||
|
||||
Hooks are usually declared as do-nothing functions that contain only
|
||||
documentation describing when the hook will be called and what return values
|
||||
are expected. The names of the functions must start with `pytest_` otherwise pytest won't recognize them.
|
||||
|
||||
Here's an example. Let's assume this code is in the ``sample_hook.py`` module.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_my_hook(config):
|
||||
"""
|
||||
Receives the pytest config and does things with it
|
||||
"""
|
||||
|
||||
To register the hooks with pytest they need to be structured in their own module or class. This
|
||||
class or module can then be passed to the ``pluginmanager`` using the ``pytest_addhooks`` function
|
||||
(which itself is a hook exposed by pytest).
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_addhooks(pluginmanager):
|
||||
""" This example assumes the hooks are grouped in the 'sample_hook' module. """
|
||||
from my_app.tests import sample_hook
|
||||
|
||||
pluginmanager.add_hookspecs(sample_hook)
|
||||
|
||||
For a real world example, see `newhooks.py`_ from `xdist <https://github.com/pytest-dev/pytest-xdist>`_.
|
||||
|
||||
.. _`newhooks.py`: https://github.com/pytest-dev/pytest-xdist/blob/974bd566c599dc6a9ea291838c6f226197208b46/xdist/newhooks.py
|
||||
|
||||
Hooks may be called both from fixtures or from other hooks. In both cases, hooks are called
|
||||
through the ``hook`` object, available in the ``config`` object. Most hooks receive a
|
||||
``config`` object directly, while fixtures may use the ``pytestconfig`` fixture which provides the same object.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@pytest.fixture()
|
||||
def my_fixture(pytestconfig):
|
||||
# call the hook called "pytest_my_hook"
|
||||
# 'result' will be a list of return values from all registered functions.
|
||||
result = pytestconfig.hook.pytest_my_hook(config=pytestconfig)
|
||||
|
||||
.. note::
|
||||
Hooks receive parameters using only keyword arguments.
|
||||
|
||||
Now your hook is ready to be used. To register a function at the hook, other plugins or users must
|
||||
now simply define the function ``pytest_my_hook`` with the correct signature in their ``conftest.py``.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_my_hook(config):
|
||||
"""
|
||||
Print all active hooks to the screen.
|
||||
"""
|
||||
print(config.hook)
|
||||
|
||||
|
||||
.. _`addoptionhooks`:
|
||||
|
||||
|
||||
Using hooks in pytest_addoption
|
||||
-------------------------------
|
||||
|
||||
Occasionally, it is necessary to change the way in which command line options
|
||||
are defined by one plugin based on hooks in another plugin. For example,
|
||||
a plugin may expose a command line option for which another plugin needs
|
||||
to define the default value. The pluginmanager can be used to install and
|
||||
use hooks to accomplish this. The plugin would define and add the hooks
|
||||
and use pytest_addoption as follows:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# contents of hooks.py
|
||||
|
||||
# Use firstresult=True because we only want one plugin to define this
|
||||
# default value
|
||||
@hookspec(firstresult=True)
|
||||
def pytest_config_file_default_value():
|
||||
""" Return the default value for the config file command line option. """
|
||||
|
||||
|
||||
# contents of myplugin.py
|
||||
|
||||
|
||||
def pytest_addhooks(pluginmanager):
|
||||
""" This example assumes the hooks are grouped in the 'hooks' module. """
|
||||
from . import hooks
|
||||
|
||||
pluginmanager.add_hookspecs(hooks)
|
||||
|
||||
|
||||
def pytest_addoption(parser, pluginmanager):
|
||||
default_value = pluginmanager.hook.pytest_config_file_default_value()
|
||||
parser.addoption(
|
||||
"--config-file",
|
||||
help="Config file to use, defaults to %(default)s",
|
||||
default=default_value,
|
||||
)
|
||||
|
||||
The conftest.py that is using myplugin would simply define the hook as follows:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_config_file_default_value():
|
||||
return "config.yaml"
|
||||
|
||||
|
||||
Optionally using hooks from 3rd party plugins
|
||||
---------------------------------------------
|
||||
|
||||
Using new hooks from plugins as explained above might be a little tricky
|
||||
because of the standard :ref:`validation mechanism <validation>`:
|
||||
if you depend on a plugin that is not installed, validation will fail and
|
||||
the error message will not make much sense to your users.
|
||||
|
||||
One approach is to defer the hook implementation to a new plugin instead of
|
||||
declaring the hook functions directly in your plugin module, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# contents of myplugin.py
|
||||
|
||||
|
||||
class DeferPlugin:
|
||||
"""Simple plugin to defer pytest-xdist hook functions."""
|
||||
|
||||
def pytest_testnodedown(self, node, error):
|
||||
"""standard xdist hook function."""
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
if config.pluginmanager.hasplugin("xdist"):
|
||||
config.pluginmanager.register(DeferPlugin())
|
||||
|
||||
This has the added benefit of allowing you to conditionally install hooks
|
||||
depending on which plugins are installed.
|
||||
|
||||
.. _plugin-stash:
|
||||
|
||||
Storing data on items across hook functions
|
||||
-------------------------------------------
|
||||
|
||||
Plugins often need to store data on :class:`~pytest.Item`\s in one hook
|
||||
implementation, and access it in another. One common solution is to just
|
||||
assign some private attribute directly on the item, but type-checkers like
|
||||
mypy frown upon this, and it may also cause conflicts with other plugins.
|
||||
So pytest offers a better way to do this, :attr:`_pytest.nodes.Node.stash <item.stash>`.
|
||||
|
||||
To use the "stash" in your plugins, first create "stash keys" somewhere at the
|
||||
top level of your plugin:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
been_there_key = pytest.StashKey[bool]()
|
||||
done_that_key = pytest.StashKey[str]()
|
||||
|
||||
then use the keys to stash your data at some point:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_runtest_setup(item: pytest.Item) -> None:
|
||||
item.stash[been_there_key] = True
|
||||
item.stash[done_that_key] = "no"
|
||||
|
||||
and retrieve them at another point:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def pytest_runtest_teardown(item: pytest.Item) -> None:
|
||||
if not item.stash[been_there_key]:
|
||||
print("Oh?")
|
||||
item.stash[done_that_key] = "yes!"
|
||||
|
||||
Stashes are available on all node types (like :class:`~pytest.Class`,
|
||||
:class:`~pytest.Session`) and also on :class:`~pytest.Config`, if needed.
|
||||
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 5.9 KiB |
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="1500" height="1500" viewBox="0, 0, 1500, 1500">
|
||||
<g id="pytest_logo">
|
||||
<g id="graphics">
|
||||
<path d="M521.576,213.75 L952.616,213.75 C964.283,213.75 973.741,223.208 973.741,234.875 L973.741,234.875 C973.741,246.542 964.283,256 952.616,256 L521.576,256 C509.909,256 500.451,246.542 500.451,234.875 L500.451,234.875 C500.451,223.208 509.909,213.75 521.576,213.75 z" fill="#696969" id="horizontal_bar"/>
|
||||
<g id="top_bars">
|
||||
<path d="M525.333,171 L612,171 L612,191 L525.333,191 L525.333,171 z" fill="#009FE3"/>
|
||||
<path d="M638.667,171 L725.333,171 L725.333,191 L638.667,191 L638.667,171 z" fill="#C7D302"/>
|
||||
<path d="M750.5,171 L837.167,171 L837.167,191 L750.5,191 L750.5,171 z" fill="#F07E16"/>
|
||||
<path d="M861.861,171 L948.528,171 L948.528,191 L861.861,191 L861.861,171 z" fill="#DF2815"/>
|
||||
</g>
|
||||
<g id="bottom_bars">
|
||||
<path d="M861.861,278 L948.528,278 L948.528,424.5 L861.861,424.5 L861.861,278 z" fill="#DF2815"/>
|
||||
<path d="M750.5,278 L837.328,278 L837.328,516 L750.5,516 L750.5,278 z" fill="#F07E16"/>
|
||||
<path d="M638.667,278 L725.328,278 L725.328,634.5 L638.667,634.5 L638.667,278 z" fill="#C7D302"/>
|
||||
<path d="M525.333,278 L612,278 L612,712.5 L525.333,712.5 L525.333,278 z" fill="#009FE3"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="pytest">
|
||||
<path d="M252.959,1173.846 Q240.139,1173.846 229.71,1171.021 Q219.28,1168.196 210.914,1163.525 Q202.549,1158.853 196.139,1152.552 Q189.729,1146.25 184.732,1139.297 L182.124,1139.297 Q182.776,1146.685 183.428,1153.421 Q183.862,1159.07 184.297,1165.046 Q184.732,1171.021 184.732,1174.498 L184.732,1276.404 L145.186,1276.404 L145.186,930.921 L177.344,930.921 L182.993,963.079 L184.732,963.079 Q189.729,955.474 196.03,948.847 Q202.332,942.22 210.697,937.331 Q219.063,932.442 229.492,929.509 Q239.922,926.575 252.959,926.575 Q273.384,926.575 290.115,934.397 Q306.846,942.22 318.688,957.756 Q330.53,973.292 337.048,996.324 Q343.567,1019.356 343.567,1049.776 Q343.567,1080.413 337.048,1103.554 Q330.53,1126.695 318.688,1142.339 Q306.846,1157.984 290.115,1165.915 Q273.384,1173.846 252.959,1173.846 z M245.354,959.385 Q228.84,959.385 217.433,964.383 Q206.025,969.38 198.964,979.593 Q191.902,989.805 188.534,1005.015 Q185.166,1020.225 184.732,1040.867 L184.732,1049.776 Q184.732,1071.722 187.665,1088.779 Q190.598,1105.835 197.66,1117.46 Q204.722,1129.085 216.455,1135.06 Q228.189,1141.036 245.789,1141.036 Q275.122,1141.036 288.92,1117.352 Q302.717,1093.667 302.717,1049.341 Q302.717,1004.146 288.92,981.766 Q275.122,959.385 245.354,959.385 z" fill="#696969"/>
|
||||
<path d="M370.293,930.921 L411.36,930.921 L458.076,1064.117 Q461.118,1072.808 464.269,1082.369 Q467.42,1091.929 470.136,1101.49 Q472.852,1111.05 474.807,1119.959 Q476.763,1128.868 477.632,1136.473 L478.936,1136.473 Q480.022,1131.041 482.412,1121.697 Q484.802,1112.354 487.736,1101.816 Q490.669,1091.277 493.82,1081.065 Q496.97,1070.853 499.36,1063.682 L542.6,930.921 L583.45,930.921 L489.148,1200.572 Q483.064,1218.172 476.002,1232.187 Q468.941,1246.202 459.597,1255.979 Q450.254,1265.757 437.651,1271.081 Q425.049,1276.404 407.666,1276.404 Q396.367,1276.404 388.11,1275.209 Q379.854,1274.014 373.987,1272.71 L373.987,1241.204 Q378.55,1242.291 385.503,1243.051 Q392.456,1243.812 400.061,1243.812 Q410.491,1243.812 418.096,1241.313 Q425.701,1238.814 431.35,1234.034 Q437,1229.253 441.019,1222.3 Q445.039,1215.347 448.298,1206.438 L460.684,1171.673 z" fill="#696969"/>
|
||||
<path d="M695.568,1141.47 Q699.479,1141.47 704.368,1141.036 Q709.257,1140.601 713.82,1139.949 Q718.383,1139.297 722.186,1138.428 Q725.988,1137.559 727.944,1136.907 L727.944,1166.893 Q725.119,1168.196 720.773,1169.5 Q716.428,1170.804 711.213,1171.781 Q705.998,1172.759 700.349,1173.302 Q694.699,1173.846 689.267,1173.846 Q675.795,1173.846 664.279,1170.369 Q652.763,1166.893 644.398,1158.418 Q636.032,1149.944 631.252,1135.495 Q626.472,1121.045 626.472,1099.1 L626.472,960.689 L592.792,960.689 L592.792,943.089 L626.472,926.141 L643.42,876.165 L666.235,876.165 L666.235,930.921 L726.206,930.921 L726.206,960.689 L666.235,960.689 L666.235,1099.1 Q666.235,1120.176 673.079,1130.823 Q679.924,1141.47 695.568,1141.47 z" fill="#009FE3"/>
|
||||
<path d="M868.527,1173.846 Q844.626,1173.846 824.853,1165.806 Q805.08,1157.767 790.848,1142.339 Q776.616,1126.912 768.793,1104.097 Q760.971,1081.282 760.971,1051.949 Q760.971,1022.398 768.142,999.148 Q775.312,975.899 788.349,959.711 Q801.386,943.523 819.529,935.049 Q837.673,926.575 859.619,926.575 Q881.13,926.575 898.295,934.289 Q915.461,942.002 927.412,956.017 Q939.362,970.032 945.772,989.697 Q952.182,1009.361 952.182,1033.262 L952.182,1057.815 L801.821,1057.815 Q802.907,1099.751 819.529,1119.524 Q836.152,1139.297 868.962,1139.297 Q880.043,1139.297 889.495,1138.211 Q898.947,1137.125 907.747,1135.06 Q916.547,1132.996 924.804,1129.845 Q933.061,1126.695 941.535,1122.784 L941.535,1157.984 Q932.844,1162.112 924.478,1165.154 Q916.113,1168.196 907.313,1170.152 Q898.513,1172.107 889.061,1172.977 Q879.609,1173.846 868.527,1173.846 z M858.749,959.385 Q833.979,959.385 819.529,976.333 Q805.08,993.282 802.69,1025.657 L909.594,1025.657 Q909.594,1010.882 906.661,998.605 Q903.727,986.329 897.535,977.637 Q891.342,968.946 881.782,964.166 Q872.221,959.385 858.749,959.385 z" fill="#009FE3"/>
|
||||
<path d="M1155.126,1104.097 Q1155.126,1121.48 1148.825,1134.517 Q1142.524,1147.554 1130.682,1156.354 Q1118.84,1165.154 1102.109,1169.5 Q1085.378,1173.846 1064.518,1173.846 Q1040.834,1173.846 1023.886,1170.043 Q1006.938,1166.241 994.118,1158.853 L994.118,1122.784 Q1000.854,1126.26 1009.111,1129.628 Q1017.368,1132.996 1026.494,1135.604 Q1035.62,1138.211 1045.289,1139.841 Q1054.958,1141.47 1064.518,1141.47 Q1078.642,1141.47 1088.528,1139.08 Q1098.415,1136.69 1104.608,1132.236 Q1110.8,1127.781 1113.625,1121.371 Q1116.45,1114.961 1116.45,1107.139 Q1116.45,1100.403 1114.277,1094.971 Q1112.104,1089.539 1106.346,1084.216 Q1100.588,1078.892 1090.593,1073.46 Q1080.598,1068.028 1064.953,1061.292 Q1049.308,1054.556 1036.815,1048.038 Q1024.321,1041.519 1015.629,1033.479 Q1006.938,1025.44 1002.266,1014.902 Q997.595,1004.363 997.595,989.805 Q997.595,974.595 1003.57,962.753 Q1009.545,950.911 1020.41,942.872 Q1031.274,934.832 1046.484,930.704 Q1061.694,926.575 1080.38,926.575 Q1101.457,926.575 1118.948,931.138 Q1136.44,935.701 1152.084,943.089 L1138.395,975.03 Q1124.272,968.729 1109.388,964.057 Q1094.504,959.385 1079.077,959.385 Q1056.913,959.385 1046.266,966.664 Q1035.62,973.943 1035.62,987.415 Q1035.62,995.02 1038.118,1000.669 Q1040.617,1006.319 1046.701,1011.316 Q1052.785,1016.314 1062.997,1021.42 Q1073.21,1026.526 1088.42,1032.828 Q1104.064,1039.346 1116.341,1045.865 Q1128.618,1052.383 1137.309,1060.531 Q1146,1068.68 1150.563,1079.109 Q1155.126,1089.539 1155.126,1104.097 z" fill="#009FE3"/>
|
||||
<path d="M1285.28,1141.47 Q1289.191,1141.47 1294.08,1141.036 Q1298.969,1140.601 1303.532,1139.949 Q1308.095,1139.297 1311.898,1138.428 Q1315.7,1137.559 1317.656,1136.907 L1317.656,1166.893 Q1314.831,1168.196 1310.485,1169.5 Q1306.14,1170.804 1300.925,1171.781 Q1295.71,1172.759 1290.06,1173.302 Q1284.411,1173.846 1278.979,1173.846 Q1265.507,1173.846 1253.991,1170.369 Q1242.475,1166.893 1234.109,1158.418 Q1225.744,1149.944 1220.964,1135.495 Q1216.183,1121.045 1216.183,1099.1 L1216.183,960.689 L1182.504,960.689 L1182.504,943.089 L1216.183,926.141 L1233.132,876.165 L1255.947,876.165 L1255.947,930.921 L1315.917,930.921 L1315.917,960.689 L1255.947,960.689 L1255.947,1099.1 Q1255.947,1120.176 1262.791,1130.823 Q1269.636,1141.47 1285.28,1141.47 z" fill="#009FE3"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 7.6 KiB |
@@ -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 <https://www.python-academy.com/>`_, February 1st to 3rd, 2022, Leipzig (Germany) and remote.
|
||||
- `Professional testing with Python <https://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_, via Python Academy, February 1-3 2021, remote and Leipzig (Germany). **Early-bird discount available until January 15th**.
|
||||
|
||||
Also see `previous talks and blogposts <talks.html>`_.
|
||||
|
||||
@@ -13,19 +13,10 @@ pytest: helps you write better programs
|
||||
|
||||
.. module:: pytest
|
||||
|
||||
The ``pytest`` framework makes it easy to write small, readable tests, and can
|
||||
scale to support complex functional testing for applications and libraries.
|
||||
The ``pytest`` framework makes it easy to write small tests, yet
|
||||
scales to support complex functional testing for applications and libraries.
|
||||
|
||||
|
||||
**Pythons**: ``pytest`` requires: Python 3.6, 3.7, 3.8, 3.9, or PyPy3.
|
||||
|
||||
**PyPI package name**: :pypi:`pytest`
|
||||
|
||||
**Documentation as PDF**: `download latest <https://media.readthedocs.org/pdf/pytest/latest/pytest.pdf>`_
|
||||
|
||||
|
||||
A quick example
|
||||
---------------
|
||||
An example of a simple test:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -44,8 +35,9 @@ To execute it:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 1 item
|
||||
|
||||
test_sample.py F [100%]
|
||||
@@ -64,7 +56,7 @@ To execute it:
|
||||
============================ 1 failed in 0.12s =============================
|
||||
|
||||
Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used.
|
||||
See :ref:`Get started <getstarted>` for a basic introduction to using pytest.
|
||||
See :ref:`Getting Started <getstarted>` for more examples.
|
||||
|
||||
|
||||
Features
|
||||
@@ -80,16 +72,13 @@ Features
|
||||
|
||||
- Python 3.6+ and PyPy 3
|
||||
|
||||
- Rich plugin architecture, with over 800+ :ref:`external plugins <plugin-list>` and thriving community
|
||||
- Rich plugin architecture, with over 315+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
* :ref:`Get started <get-started>` - install pytest and grasp its basics just twenty minutes
|
||||
* :ref:`How-to guides <how-to>` - step-by-step guides, covering a vast range of use-cases and needs
|
||||
* :ref:`Reference guides <reference>` - includes the complete pytest API reference, lists of plugins and more
|
||||
* :ref:`Explanation <explanation>` - background, discussion of key topics, answers to higher-level questions
|
||||
Please see :ref:`Contents <toc>` for full documentation, including installation, tutorials and PDF documents.
|
||||
|
||||
|
||||
Bugs/Requests
|
||||
@@ -107,7 +96,7 @@ Support pytest
|
||||
--------------
|
||||
|
||||
`Open Collective`_ is an online funding platform for open and transparent communities.
|
||||
It provides tools to raise money and share your finances in full transparency.
|
||||
It provide tools to raise money and share your finances in full transparency.
|
||||
|
||||
It is the platform of choice for individuals and companies that want to make one-time or
|
||||
monthly donations directly to the project.
|
||||
@@ -130,7 +119,7 @@ Save time, reduce risk, and improve code health, while paying the maintainers of
|
||||
`Learn more. <https://tidelift.com/subscription/pkg/pypi-pytest?utm_source=pypi-pytest&utm_medium=referral&utm_campaign=enterprise&utm_term=repo>`_
|
||||
|
||||
Security
|
||||
~~~~~~~~
|
||||
^^^^^^^^
|
||||
|
||||
pytest has never been associated with a security vulnerability, but in any case, to report a
|
||||
security vulnerability please use the `Tidelift security contact <https://tidelift.com/security>`_.
|
||||
@@ -140,8 +129,8 @@ Tidelift will coordinate the fix and disclosure.
|
||||
License
|
||||
-------
|
||||
|
||||
Copyright Holger Krekel and others, 2004.
|
||||
Copyright Holger Krekel and others, 2004-2020.
|
||||
|
||||
Distributed under the terms of the `MIT`_ license, pytest is free and open source software.
|
||||
|
||||
.. _`MIT`: https://github.com/pytest-dev/pytest/blob/main/LICENSE
|
||||
.. _`MIT`: https://github.com/pytest-dev/pytest/blob/master/LICENSE
|
||||
|
||||
@@ -9,7 +9,7 @@ Distributed under the terms of the `MIT`_ license, pytest is free and open sourc
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2004 Holger Krekel and others
|
||||
Copyright (c) 2004-2020 Holger Krekel and others
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
@@ -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/main/LICENSE
|
||||
.. _`MIT`: https://github.com/pytest-dev/pytest/blob/master/LICENSE
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
.. _logging:
|
||||
|
||||
How to manage logging
|
||||
---------------------
|
||||
Logging
|
||||
-------
|
||||
|
||||
|
||||
|
||||
|
||||
pytest captures log messages of level ``WARNING`` or above automatically and displays them in their own section
|
||||
for each failed test in the same manner as captured stdout and stderr.
|
||||
@@ -167,7 +170,7 @@ the records for the ``setup`` and ``call`` stages during teardown like so:
|
||||
|
||||
|
||||
|
||||
The full API is available at :class:`pytest.LogCaptureFixture`.
|
||||
The full API is available at :class:`_pytest.logging.LogCaptureFixture`.
|
||||
|
||||
|
||||
.. _live_logs:
|
||||
@@ -219,37 +222,13 @@ option names are:
|
||||
You can call ``set_log_path()`` to customize the log_file path dynamically. This functionality
|
||||
is considered **experimental**.
|
||||
|
||||
.. _log_colors:
|
||||
|
||||
Customizing Colors
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Log levels are colored if colored terminal output is enabled. Changing
|
||||
from default colors or putting color on custom log levels is supported
|
||||
through ``add_color_level()``. Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@pytest.hookimpl
|
||||
def pytest_configure(config):
|
||||
logging_plugin = config.pluginmanager.get_plugin("logging-plugin")
|
||||
|
||||
# Change color on existing log level
|
||||
logging_plugin.log_cli_handler.formatter.add_color_level(logging.INFO, "cyan")
|
||||
|
||||
# Add color to a custom log level (a custom log level `SPAM` is already set up)
|
||||
logging_plugin.log_cli_handler.formatter.add_color_level(logging.SPAM, "blue")
|
||||
.. warning::
|
||||
|
||||
This feature and its API are considered **experimental** and might change
|
||||
between releases without a deprecation notice.
|
||||
.. _log_release_notes:
|
||||
|
||||
Release notes
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
This feature was introduced as a drop-in replacement for the
|
||||
:pypi:`pytest-catchlog` plugin and they conflict
|
||||
This feature was introduced as a drop-in replacement for the `pytest-catchlog
|
||||
<https://pypi.org/project/pytest-catchlog/>`_ plugin and they conflict
|
||||
with each other. The backward compatibility API with ``pytest-capturelog``
|
||||
has been dropped when this feature was introduced, so if for that reason you
|
||||
still need ``pytest-catchlog`` you can disable the internal feature by
|
||||
@@ -289,4 +268,5 @@ file:
|
||||
log_cli=true
|
||||
log_level=NOTSET
|
||||
|
||||
More details about the discussion that lead to this changes can be read in :issue:`3013`.
|
||||
More details about the discussion that lead to this changes can be read in
|
||||
issue `#3013 <https://github.com/pytest-dev/pytest/issues/3013>`_.
|
||||
@@ -1,7 +1,7 @@
|
||||
.. _mark:
|
||||
|
||||
How to mark test functions with attributes
|
||||
===========================================
|
||||
Marking test functions with attributes
|
||||
======================================
|
||||
|
||||
By using the ``pytest.mark`` helper you can easily set
|
||||
metadata on your test functions. You can find the full list of builtin markers
|
||||
@@ -1,6 +1,5 @@
|
||||
.. _monkeypatching:
|
||||
|
||||
How to monkeypatch/mock modules and environments
|
||||
Monkeypatching/mocking modules and environments
|
||||
================================================================
|
||||
|
||||
.. currentmodule:: _pytest.monkeypatch
|
||||
@@ -17,11 +16,10 @@ functionality in tests:
|
||||
.. code-block:: python
|
||||
|
||||
monkeypatch.setattr(obj, name, value, raising=True)
|
||||
monkeypatch.setattr("somemodule.obj.name", value, raising=True)
|
||||
monkeypatch.delattr(obj, name, raising=True)
|
||||
monkeypatch.setitem(mapping, name, value)
|
||||
monkeypatch.delitem(obj, name, raising=True)
|
||||
monkeypatch.setenv(name, value, prepend=None)
|
||||
monkeypatch.setenv(name, value, prepend=False)
|
||||
monkeypatch.delenv(name, raising=True)
|
||||
monkeypatch.syspath_prepend(path)
|
||||
monkeypatch.chdir(path)
|
||||
@@ -58,7 +56,7 @@ call ``pkg_resources.fixup_namespace_packages`` and :py:func:`importlib.invalida
|
||||
See the `monkeypatch blog post`_ for some introduction material
|
||||
and a discussion of its motivation.
|
||||
|
||||
.. _`monkeypatch blog post`: https://tetamap.wordpress.com//2009/03/03/monkeypatching-in-unit-tests-done-right/
|
||||
.. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/
|
||||
|
||||
Simple example: monkeypatching functions
|
||||
----------------------------------------
|
||||
@@ -252,7 +250,7 @@ so that any attempts within tests to create http requests will fail.
|
||||
m.setattr(functools, "partial", 3)
|
||||
assert functools.partial == 3
|
||||
|
||||
See :issue:`3290` for details.
|
||||
See issue `#3290 <https://github.com/pytest-dev/pytest/issues/3290>`_ for details.
|
||||
|
||||
|
||||
Monkeypatching environment variables
|
||||
@@ -1,6 +1,6 @@
|
||||
.. _`noseintegration`:
|
||||
|
||||
How to run tests written for nose
|
||||
Running tests written for nose
|
||||
=======================================
|
||||
|
||||
``pytest`` has basic support for running tests written for nose_.
|
||||
@@ -39,13 +39,14 @@ Unsupported idioms / known issues
|
||||
both support ``setup_class, teardown_class, setup_method, teardown_method``
|
||||
it doesn't seem useful to duplicate the unittest-API like nose does.
|
||||
If you however rather think pytest should support the unittest-spelling on
|
||||
plain classes please post to :issue:`377`.
|
||||
plain classes please post `to this issue
|
||||
<https://github.com/pytest-dev/pytest/issues/377/>`_.
|
||||
|
||||
- nose imports test modules with the same import path (e.g.
|
||||
``tests.test_mode``) but different file system paths
|
||||
(e.g. ``tests/test_mode.py`` and ``other/tests/test_mode.py``)
|
||||
by extending sys.path/import semantics. pytest does not do that
|
||||
but there is discussion in :issue:`268` for adding some support. Note that
|
||||
but there is discussion in `#268 <https://github.com/pytest-dev/pytest/issues/268>`_ for adding some support. Note that
|
||||
`nose2 choose to avoid this sys.path/import hackery <https://nose2.readthedocs.io/en/latest/differences.html#test-discovery-and-loading>`_.
|
||||
|
||||
If you place a conftest.py file in the root directory of your project
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
.. _`parametrize-basics`:
|
||||
|
||||
How to parametrize fixtures and test functions
|
||||
Parametrizing fixtures and test functions
|
||||
==========================================================================
|
||||
|
||||
pytest enables test parametrization at several levels:
|
||||
@@ -56,8 +56,9 @@ them in turn:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 3 items
|
||||
|
||||
test_expectation.py ..F [100%]
|
||||
@@ -109,41 +110,7 @@ the simple test function. And as usual with test function arguments,
|
||||
you can see the ``input`` and ``output`` values in the traceback.
|
||||
|
||||
Note that you could also use the parametrize marker on a class or a module
|
||||
(see :ref:`mark`) which would invoke several functions with the argument sets,
|
||||
for instance:
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize("n,expected", [(1, 2), (3, 4)])
|
||||
class TestClass:
|
||||
def test_simple_case(self, n, expected):
|
||||
assert n + 1 == expected
|
||||
|
||||
def test_weird_simple_case(self, n, expected):
|
||||
assert (n * 1) + 1 == expected
|
||||
|
||||
|
||||
To parametrize all tests in a module, you can assign to the :globalvar:`pytestmark` global variable:
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.parametrize("n,expected", [(1, 2), (3, 4)])
|
||||
|
||||
|
||||
class TestClass:
|
||||
def test_simple_case(self, n, expected):
|
||||
assert n + 1 == expected
|
||||
|
||||
def test_weird_simple_case(self, n, expected):
|
||||
assert (n * 1) + 1 == expected
|
||||
|
||||
(see :ref:`mark`) which would invoke several functions with the argument sets.
|
||||
|
||||
It is also possible to mark individual test instances within parametrize,
|
||||
for example with the builtin ``mark.xfail``:
|
||||
@@ -167,8 +134,9 @@ Let's run this:
|
||||
|
||||
$ pytest
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
|
||||
rootdir: /home/sweet/project
|
||||
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
|
||||
cachedir: $PYTHON_PREFIX/.pytest_cache
|
||||
rootdir: $REGENDOC_TMPDIR
|
||||
collected 3 items
|
||||
|
||||
test_expectation.py ..x [100%]
|
||||
@@ -266,8 +234,8 @@ Let's also run with a stringinput that will lead to a failing test:
|
||||
def test_valid_string(stringinput):
|
||||
> assert stringinput.isalpha()
|
||||
E AssertionError: assert False
|
||||
E + where False = <built-in method isalpha of str object at 0xdeadbeef0001>()
|
||||
E + where <built-in method isalpha of str object at 0xdeadbeef0001> = '!'.isalpha
|
||||
E + where False = <built-in method isalpha of str object at 0xdeadbeef>()
|
||||
E + where <built-in method isalpha of str object at 0xdeadbeef> = '!'.isalpha
|
||||
|
||||
test_strings.py:4: AssertionError
|
||||
========================= short test summary info ==========================
|
||||
@@ -285,7 +253,7 @@ list:
|
||||
$ pytest -q -rs test_strings.py
|
||||
s [100%]
|
||||
========================= short test summary info ==========================
|
||||
SKIPPED [1] test_strings.py: got empty parameter set ['stringinput'], function test_valid_string at /home/sweet/project/test_strings.py:2
|
||||
SKIPPED [1] test_strings.py: got empty parameter set ['stringinput'], function test_valid_string at $REGENDOC_TMPDIR/test_strings.py:2
|
||||
1 skipped in 0.12s
|
||||
|
||||
Note that when calling ``metafunc.parametrize`` multiple times with different parameter sets, all parameter names across
|
||||
@@ -2,8 +2,8 @@
|
||||
.. _`extplugins`:
|
||||
.. _`using plugins`:
|
||||
|
||||
How to install and use plugins
|
||||
===============================
|
||||
Installing and Using plugins
|
||||
============================
|
||||
|
||||
This section talks about installing and using third party plugins.
|
||||
For writing your own plugins, please refer to :ref:`writing-plugins`.
|
||||
@@ -20,43 +20,45 @@ there is no need to activate it.
|
||||
|
||||
Here is a little annotated list for some popular plugins:
|
||||
|
||||
* :pypi:`pytest-django`: write tests
|
||||
for :std:doc:`django <django:index>` apps, using pytest integration.
|
||||
.. _`django`: https://www.djangoproject.com/
|
||||
|
||||
* :pypi:`pytest-twisted`: write tests
|
||||
for `twisted <https://twistedmatrix.com/>`_ apps, starting a reactor and
|
||||
* `pytest-django <https://pypi.org/project/pytest-django/>`_: write tests
|
||||
for `django`_ apps, using pytest integration.
|
||||
|
||||
* `pytest-twisted <https://pypi.org/project/pytest-twisted/>`_: write tests
|
||||
for `twisted <http://twistedmatrix.com>`_ apps, starting a reactor and
|
||||
processing deferreds from test functions.
|
||||
|
||||
* :pypi:`pytest-cov`:
|
||||
* `pytest-cov <https://pypi.org/project/pytest-cov/>`__:
|
||||
coverage reporting, compatible with distributed testing
|
||||
|
||||
* :pypi:`pytest-xdist`:
|
||||
* `pytest-xdist <https://pypi.org/project/pytest-xdist/>`_:
|
||||
to distribute tests to CPUs and remote hosts, to run in boxed
|
||||
mode which allows to survive segmentation faults, to run in
|
||||
looponfailing mode, automatically re-running failing tests
|
||||
on file changes.
|
||||
|
||||
* :pypi:`pytest-instafail`:
|
||||
* `pytest-instafail <https://pypi.org/project/pytest-instafail/>`_:
|
||||
to report failures while the test run is happening.
|
||||
|
||||
* :pypi:`pytest-bdd`:
|
||||
* `pytest-bdd <https://pypi.org/project/pytest-bdd/>`_:
|
||||
to write tests using behaviour-driven testing.
|
||||
|
||||
* :pypi:`pytest-timeout`:
|
||||
* `pytest-timeout <https://pypi.org/project/pytest-timeout/>`_:
|
||||
to timeout tests based on function marks or global definitions.
|
||||
|
||||
* :pypi:`pytest-pep8`:
|
||||
* `pytest-pep8 <https://pypi.org/project/pytest-pep8/>`_:
|
||||
a ``--pep8`` option to enable PEP8 compliance checking.
|
||||
|
||||
* :pypi:`pytest-flakes`:
|
||||
* `pytest-flakes <https://pypi.org/project/pytest-flakes/>`_:
|
||||
check source code with pyflakes.
|
||||
|
||||
* :pypi:`oejskit`:
|
||||
* `oejskit <https://pypi.org/project/oejskit/>`_:
|
||||
a plugin to run javascript unittests in live browsers.
|
||||
|
||||
To see a complete list of all plugins with their latest testing
|
||||
status against different pytest and Python versions, please visit
|
||||
:ref:`plugin-list`.
|
||||
`plugincompat <http://plugincompat.herokuapp.com/>`_.
|
||||
|
||||
You may also discover more plugins through a `pytest- pypi.org search`_.
|
||||
|
||||
83
doc/en/projects.rst
Normal file
@@ -0,0 +1,83 @@
|
||||
.. _projects:
|
||||
|
||||
.. image:: img/gaynor3.png
|
||||
:width: 400px
|
||||
:align: right
|
||||
|
||||
.. image:: img/theuni.png
|
||||
:width: 400px
|
||||
:align: right
|
||||
|
||||
.. image:: img/cramer2.png
|
||||
:width: 400px
|
||||
:align: right
|
||||
|
||||
.. image:: img/keleshev.png
|
||||
:width: 400px
|
||||
:align: right
|
||||
|
||||
|
||||
Project examples
|
||||
==========================
|
||||
|
||||
Here are some examples of projects using ``pytest`` (please send notes via :ref:`contact`):
|
||||
|
||||
* `PyPy <http://pypy.org>`_, Python with a JIT compiler, running over
|
||||
`21000 tests <http://buildbot.pypy.org/summary?branch=%3Ctrunk%3E>`_
|
||||
* the `MoinMoin <http://moinmo.in>`_ Wiki Engine
|
||||
* `sentry <https://getsentry.com/welcome/>`_, realtime app-maintenance and exception tracking
|
||||
* `Astropy <http://www.astropy.org/>`_ and `affiliated packages <http://www.astropy.org/affiliated/index.html>`_
|
||||
* `tox <http://testrun.org/tox>`_, virtualenv/Hudson integration tool
|
||||
* `PyPM <http://code.activestate.com/pypm/>`_ ActiveState's package manager
|
||||
* `Fom <http://packages.python.org/Fom/>`_ a fluid object mapper for FluidDB
|
||||
* `applib <https://github.com/ActiveState/applib>`_ cross-platform utilities
|
||||
* `six <https://pypi.org/project/six/>`_ Python 2 and 3 compatibility utilities
|
||||
* `pediapress <http://code.pediapress.com/wiki/wiki>`_ MediaWiki articles
|
||||
* `mwlib <https://pypi.org/project/mwlib/>`_ mediawiki parser and utility library
|
||||
* `The Translate Toolkit <http://translate.sourceforge.net/wiki/toolkit/index>`_ for localization and conversion
|
||||
* `execnet <http://codespeak.net/execnet>`_ rapid multi-Python deployment
|
||||
* `pylib <https://pylib.readthedocs.io/en/stable/>`_ cross-platform path, IO, dynamic code library
|
||||
* `bbfreeze <https://pypi.org/project/bbfreeze/>`_ create standalone executables from Python scripts
|
||||
* `pdb++ <https://github.com/pdbpp/pdbpp>`_ a fancier version of PDB
|
||||
* `pudb <https://github.com/inducer/pudb>`_ full-screen console debugger for python
|
||||
* `py-s3fuse <http://code.google.com/p/py-s3fuse/>`_ Amazon S3 FUSE based filesystem
|
||||
* `waskr <http://code.google.com/p/waskr/>`_ WSGI Stats Middleware
|
||||
* `guachi <http://code.google.com/p/guachi/>`_ global persistent configs for Python modules
|
||||
* `Circuits <https://pypi.org/project/circuits/>`_ lightweight Event Driven Framework
|
||||
* `pygtk-helpers <http://bitbucket.org/aafshar/pygtkhelpers-main/>`_ easy interaction with PyGTK
|
||||
* `QuantumCore <http://quantumcore.org/>`_ statusmessage and repoze openid plugin
|
||||
* `pydataportability <http://pydataportability.net/>`_ libraries for managing the open web
|
||||
* `XIST <http://www.livinglogic.de/Python/xist/>`_ extensible HTML/XML generator
|
||||
* `tiddlyweb <https://pypi.org/project/tiddlyweb/>`_ optionally headless, extensible RESTful datastore
|
||||
* `fancycompleter <http://bitbucket.org/antocuni/fancycompleter/src>`_ for colorful tab-completion
|
||||
* `Paludis <http://paludis.exherbo.org/>`_ tools for Gentoo Paludis package manager
|
||||
* `Gerald <http://halfcooked.com/code/gerald/>`_ schema comparison tool
|
||||
* `abjad <http://code.google.com/p/abjad/>`_ Python API for Formalized Score control
|
||||
* `bu <http://packages.python.org/bu/>`_ a microscopic build system
|
||||
* `katcp <https://bitbucket.org/hodgestar/katcp>`_ Telescope communication protocol over Twisted
|
||||
* `kss plugin timer <https://pypi.org/project/kss.plugin.timer/>`_
|
||||
* `pyudev <https://pyudev.readthedocs.io/en/latest/tests/plugins.html>`_ a pure Python binding to the Linux library libudev
|
||||
* `pytest-localserver <https://bitbucket.org/pytest-dev/pytest-localserver/>`_ a plugin for pytest that provides an httpserver and smtpserver
|
||||
* `pytest-monkeyplus <https://pypi.org/project/pytest-monkeyplus/>`_ a plugin that extends monkeypatch
|
||||
|
||||
These projects help integrate ``pytest`` into other Python frameworks:
|
||||
|
||||
* `pytest-django <https://pypi.org/project/pytest-django/>`_ for Django
|
||||
* `zope.pytest <http://packages.python.org/zope.pytest/>`_ for Zope and Grok
|
||||
* `pytest_gae <https://pypi.org/project/pytest_gae/0.2.1/>`_ for Google App Engine
|
||||
* There is `some work <https://github.com/Kotti/Kotti/blob/master/kotti/testing.py>`_ underway for Kotti, a CMS built in Pyramid/Pylons
|
||||
|
||||
|
||||
Some organisations using pytest
|
||||
-----------------------------------
|
||||
|
||||
* `Square Kilometre Array, Cape Town <http://ska.ac.za/>`_
|
||||
* `Some Mozilla QA people <https://www.theautomatedtester.co.uk/blog/2011/pytest_and_xdist_plugin/>`_ use pytest to distribute their Selenium tests
|
||||
* `Shootq <http://web.shootq.com/>`_
|
||||
* `Stups department of Heinrich Heine University Duesseldorf <http://www.stups.uni-duesseldorf.de/projects.php>`_
|
||||
* cellzome
|
||||
* `Open End, Gothenborg <http://www.openend.se>`_
|
||||
* `Laboratory of Bioinformatics, Warsaw <http://genesilico.pl/>`_
|
||||
* `merlinux, Germany <http://merlinux.eu>`_
|
||||
* `ESSS, Brazil <http://www.esss.com.br>`_
|
||||
* many more ... (please be so kind to send a note via :ref:`contact`)
|
||||
@@ -120,7 +120,7 @@ all parameters marked as a fixture.
|
||||
|
||||
.. note::
|
||||
|
||||
The :pypi:`pytest-lazy-fixture` plugin implements a very
|
||||
The `pytest-lazy-fixture <https://pypi.org/project/pytest-lazy-fixture/>`_ plugin implements a very
|
||||
similar solution to the proposal below, make sure to check it out.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -8,10 +8,10 @@ features only made possible on newer Python versions.
|
||||
In case of Python 2 and 3, the difference between the languages makes it even more prominent,
|
||||
because many new Python 3 features cannot be used in a Python 2/3 compatible code base.
|
||||
|
||||
Python 2.7 EOL has been reached :pep:`in 2020 <0373#maintenance-releases>`, with
|
||||
Python 2.7 EOL has been reached `in 2020 <https://legacy.python.org/dev/peps/pep-0373/#id4>`__, with
|
||||
the last release made in April, 2020.
|
||||
|
||||
Python 3.4 EOL has been reached :pep:`in 2019 <0429#release-schedule>`, with the last release made in March, 2019.
|
||||
Python 3.4 EOL has been reached `in 2019 <https://www.python.org/dev/peps/pep-0429/#release-schedule>`__, with the last release made in March, 2019.
|
||||
|
||||
For those reasons, in Jun 2019 it was decided that **pytest 4.6** series will be the last to support Python 2.7 and 3.4.
|
||||
|
||||
@@ -43,12 +43,10 @@ for critical bugs).
|
||||
Technical aspects
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
(This section is a transcript from :issue:`5275`).
|
||||
(This section is a transcript from `#5275 <https://github.com/pytest-dev/pytest/issues/5275>`__).
|
||||
|
||||
In this section we describe the technical aspects of the Python 2.7 and 3.4 support plan.
|
||||
|
||||
.. _what goes into 4.6.x releases:
|
||||
|
||||
What goes into 4.6.X releases
|
||||
+++++++++++++++++++++++++++++
|
||||
|
||||
|
||||
@@ -11,19 +11,19 @@ Import modes
|
||||
pytest as a testing framework needs to import test modules and ``conftest.py`` files for execution.
|
||||
|
||||
Importing files in Python (at least until recently) is a non-trivial processes, often requiring
|
||||
changing :data:`sys.path`. Some aspects of the
|
||||
changing `sys.path <https://docs.python.org/3/library/sys.html#sys.path>`__. Some aspects of the
|
||||
import process can be controlled through the ``--import-mode`` command-line flag, which can assume
|
||||
these values:
|
||||
|
||||
* ``prepend`` (default): the directory path containing each module will be inserted into the *beginning*
|
||||
of :py:data:`sys.path` if not already there, and then imported with the :func:`__import__ <__import__>` builtin.
|
||||
of ``sys.path`` if not already there, and then imported with the `__import__ <https://docs.python.org/3/library/functions.html#__import__>`__ builtin.
|
||||
|
||||
This requires test module names to be unique when the test directory tree is not arranged in
|
||||
packages, because the modules will put in :py:data:`sys.modules` after importing.
|
||||
packages, because the modules will put in ``sys.modules`` after importing.
|
||||
|
||||
This is the classic mechanism, dating back from the time Python 2 was still supported.
|
||||
|
||||
* ``append``: the directory containing each module is appended to the end of :py:data:`sys.path` if not already
|
||||
* ``append``: the directory containing each module is appended to the end of ``sys.path`` if not already
|
||||
there, and imported with ``__import__``.
|
||||
|
||||
This better allows to run test modules against installed versions of a package even if the
|
||||
@@ -41,14 +41,17 @@ these values:
|
||||
we advocate for using :ref:`src <src-layout>` layouts.
|
||||
|
||||
Same as ``prepend``, requires test module names to be unique when the test directory tree is
|
||||
not arranged in packages, because the modules will put in :py:data:`sys.modules` after importing.
|
||||
not arranged in packages, because the modules will put in ``sys.modules`` after importing.
|
||||
|
||||
* ``importlib``: new in pytest-6.0, this mode uses :mod:`importlib` to import test modules. This gives full control over the import process, and doesn't require changing :py:data:`sys.path`.
|
||||
* ``importlib``: new in pytest-6.0, this mode uses `importlib <https://docs.python.org/3/library/importlib.html>`__ to import test modules. This gives full control over the import process, and doesn't require
|
||||
changing ``sys.path`` or ``sys.modules`` at all.
|
||||
|
||||
For this reason this doesn't require test module names to be unique, but also makes test
|
||||
modules non-importable by each other.
|
||||
For this reason this doesn't require test module names to be unique at all, but also makes test
|
||||
modules non-importable by each other. This was made possible in previous modes, for tests not residing
|
||||
in Python packages, because of the side-effects of changing ``sys.path`` and ``sys.modules``
|
||||
mentioned above. Users which require this should turn their tests into proper packages instead.
|
||||
|
||||
We intend to make ``importlib`` the default in future releases, depending on feedback.
|
||||
We intend to make ``importlib`` the default in future releases.
|
||||
|
||||
``prepend`` and ``append`` import modes scenarios
|
||||
-------------------------------------------------
|
||||
@@ -130,4 +133,4 @@ Running pytest with ``pytest [...]`` instead of ``python -m pytest [...]`` yield
|
||||
equivalent behaviour, except that the latter will add the current directory to ``sys.path``, which
|
||||
is standard ``python`` behavior.
|
||||
|
||||
See also :ref:`invoke-python`.
|
||||
See also :ref:`cmdline`.
|
||||
@@ -1,4 +1,4 @@
|
||||
.. _`api-reference`:
|
||||
.. _`reference`:
|
||||
|
||||
API Reference
|
||||
=============
|
||||
@@ -22,12 +22,12 @@ pytest.fail
|
||||
|
||||
**Tutorial**: :ref:`skipping`
|
||||
|
||||
.. autofunction:: pytest.fail(reason, [pytrace=True, msg=None])
|
||||
.. autofunction:: pytest.fail
|
||||
|
||||
pytest.skip
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. autofunction:: pytest.skip(reason, [allow_module_level=False, msg=None])
|
||||
.. autofunction:: pytest.skip(msg, [allow_module_level=False])
|
||||
|
||||
.. _`pytest.importorskip ref`:
|
||||
|
||||
@@ -44,7 +44,7 @@ pytest.xfail
|
||||
pytest.exit
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. autofunction:: pytest.exit(reason, [returncode=False, msg=None])
|
||||
.. autofunction:: pytest.exit
|
||||
|
||||
pytest.main
|
||||
~~~~~~~~~~~
|
||||
@@ -118,7 +118,7 @@ Add warning filters to marked test items.
|
||||
|
||||
:keyword str filter:
|
||||
A *warning specification string*, which is composed of contents of the tuple ``(action, message, category, module, lineno)``
|
||||
as specified in :ref:`python:warning-filter` section of
|
||||
as specified in `The Warnings filter <https://docs.python.org/3/library/warnings.html#warning-filter>`_ section of
|
||||
the Python documentation, separated by ``":"``. Optional fields can be omitted.
|
||||
Module names passed for filtering are not regex-escaped.
|
||||
|
||||
@@ -136,9 +136,9 @@ Add warning filters to marked test items.
|
||||
pytest.mark.parametrize
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:ref:`parametrize`.
|
||||
**Tutorial**: :doc:`parametrize`.
|
||||
|
||||
This mark has the same signature as :py:meth:`pytest.Metafunc.parametrize`; see there.
|
||||
This mark has the same signature as :py:meth:`_pytest.python.Metafunc.parametrize`; see there.
|
||||
|
||||
|
||||
.. _`pytest.mark.skip ref`:
|
||||
@@ -146,11 +146,11 @@ This mark has the same signature as :py:meth:`pytest.Metafunc.parametrize`; see
|
||||
pytest.mark.skip
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
:ref:`skip`.
|
||||
**Tutorial**: :ref:`skip`.
|
||||
|
||||
Unconditionally skip a test function.
|
||||
|
||||
.. py:function:: pytest.mark.skip(reason=None)
|
||||
.. py:function:: pytest.mark.skip(*, reason=None)
|
||||
|
||||
:keyword str reason: Reason why the test function is being skipped.
|
||||
|
||||
@@ -160,7 +160,7 @@ Unconditionally skip a test function.
|
||||
pytest.mark.skipif
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:ref:`skipif`.
|
||||
**Tutorial**: :ref:`skipif`.
|
||||
|
||||
Skip a test function if a condition is ``True``.
|
||||
|
||||
@@ -226,37 +226,6 @@ Marks a test function as *expected to fail*.
|
||||
a new release of a library fixes a known bug).
|
||||
|
||||
|
||||
pytest.__version__
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The current pytest version, as a string::
|
||||
|
||||
>>> import pytest
|
||||
>>> pytest.__version__
|
||||
'7.0.0'
|
||||
|
||||
|
||||
.. _`version-tuple`:
|
||||
|
||||
pytest.version_tuple
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionadded:: 7.0
|
||||
|
||||
The current pytest version, as a tuple::
|
||||
|
||||
>>> import pytest
|
||||
>>> pytest.version_tuple
|
||||
(7, 0, 0)
|
||||
|
||||
For pre-releases, the last component will be a string with the prerelease version::
|
||||
|
||||
>>> import pytest
|
||||
>>> pytest.version_tuple
|
||||
(7, 0, '0rc1')
|
||||
|
||||
|
||||
|
||||
Custom marks
|
||||
~~~~~~~~~~~~
|
||||
|
||||
@@ -270,7 +239,7 @@ For example:
|
||||
def test_function():
|
||||
...
|
||||
|
||||
Will create and attach a :class:`Mark <pytest.Mark>` object to the collected
|
||||
Will create and attach a :class:`Mark <_pytest.mark.structures.Mark>` object to the collected
|
||||
:class:`Item <pytest.Item>`, which can then be accessed by fixtures or hooks with
|
||||
:meth:`Node.iter_markers <_pytest.nodes.Node.iter_markers>`. The ``mark`` object will have the following attributes:
|
||||
|
||||
@@ -315,9 +284,9 @@ Example of a fixture requiring another fixture:
|
||||
.. code-block:: python
|
||||
|
||||
@pytest.fixture
|
||||
def db_session(tmp_path):
|
||||
fn = tmp_path / "db.file"
|
||||
return connect(fn)
|
||||
def db_session(tmpdir):
|
||||
fn = tmpdir / "db.file"
|
||||
return connect(str(fn))
|
||||
|
||||
For more details, consult the full :ref:`fixtures docs <fixture>`.
|
||||
|
||||
@@ -356,7 +325,7 @@ Under the hood, the cache plugin uses the simple
|
||||
capsys
|
||||
~~~~~~
|
||||
|
||||
:ref:`captures`.
|
||||
**Tutorial**: :doc:`capture`.
|
||||
|
||||
.. autofunction:: _pytest.capture.capsys()
|
||||
:no-auto-options:
|
||||
@@ -381,7 +350,7 @@ capsys
|
||||
capsysbinary
|
||||
~~~~~~~~~~~~
|
||||
|
||||
:ref:`captures`.
|
||||
**Tutorial**: :doc:`capture`.
|
||||
|
||||
.. autofunction:: _pytest.capture.capsysbinary()
|
||||
:no-auto-options:
|
||||
@@ -403,7 +372,7 @@ capsysbinary
|
||||
capfd
|
||||
~~~~~~
|
||||
|
||||
:ref:`captures`.
|
||||
**Tutorial**: :doc:`capture`.
|
||||
|
||||
.. autofunction:: _pytest.capture.capfd()
|
||||
:no-auto-options:
|
||||
@@ -425,7 +394,7 @@ capfd
|
||||
capfdbinary
|
||||
~~~~~~~~~~~~
|
||||
|
||||
:ref:`captures`.
|
||||
**Tutorial**: :doc:`capture`.
|
||||
|
||||
.. autofunction:: _pytest.capture.capfdbinary()
|
||||
:no-auto-options:
|
||||
@@ -447,7 +416,7 @@ capfdbinary
|
||||
doctest_namespace
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
:ref:`doctest`.
|
||||
**Tutorial**: :doc:`doctest`.
|
||||
|
||||
.. autofunction:: _pytest.doctest.doctest_namespace()
|
||||
|
||||
@@ -467,7 +436,7 @@ doctest_namespace
|
||||
request
|
||||
~~~~~~~
|
||||
|
||||
:ref:`request example`.
|
||||
**Tutorial**: :ref:`request example`.
|
||||
|
||||
The ``request`` fixture is a special fixture providing information of the requesting test function.
|
||||
|
||||
@@ -508,7 +477,7 @@ record_testsuite_property
|
||||
caplog
|
||||
~~~~~~
|
||||
|
||||
:ref:`logging`.
|
||||
**Tutorial**: :doc:`logging`.
|
||||
|
||||
.. autofunction:: _pytest.logging.caplog()
|
||||
:no-auto-options:
|
||||
@@ -524,7 +493,7 @@ caplog
|
||||
monkeypatch
|
||||
~~~~~~~~~~~
|
||||
|
||||
:ref:`monkeypatching`.
|
||||
**Tutorial**: :doc:`monkeypatch`.
|
||||
|
||||
.. autofunction:: _pytest.monkeypatch.monkeypatch()
|
||||
:no-auto-options:
|
||||
@@ -558,17 +527,14 @@ To use it, include in your topmost ``conftest.py`` file:
|
||||
.. autoclass:: pytest.Pytester()
|
||||
:members:
|
||||
|
||||
.. autoclass:: pytest.RunResult()
|
||||
.. autoclass:: _pytest.pytester.RunResult()
|
||||
:members:
|
||||
|
||||
.. autoclass:: pytest.LineMatcher()
|
||||
.. autoclass:: _pytest.pytester.LineMatcher()
|
||||
:members:
|
||||
:special-members: __str__
|
||||
|
||||
.. autoclass:: pytest.HookRecorder()
|
||||
:members:
|
||||
|
||||
.. autoclass:: pytest.RecordedHookCall()
|
||||
.. autoclass:: _pytest.pytester.HookRecorder()
|
||||
:members:
|
||||
|
||||
.. fixture:: testdir
|
||||
@@ -610,25 +576,24 @@ Each recorded warning is an instance of :class:`warnings.WarningMessage`.
|
||||
tmp_path
|
||||
~~~~~~~~
|
||||
|
||||
:ref:`tmp_path`
|
||||
**Tutorial**: :doc:`tmpdir`
|
||||
|
||||
.. autofunction:: _pytest.tmpdir.tmp_path()
|
||||
:no-auto-options:
|
||||
|
||||
|
||||
.. fixture:: tmp_path_factory
|
||||
.. fixture:: _pytest.tmpdir.tmp_path_factory
|
||||
|
||||
tmp_path_factory
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
:ref:`tmp_path_factory example`
|
||||
**Tutorial**: :ref:`tmp_path_factory example`
|
||||
|
||||
.. _`tmp_path_factory factory api`:
|
||||
|
||||
``tmp_path_factory`` is an instance of :class:`~pytest.TempPathFactory`:
|
||||
|
||||
.. autoclass:: pytest.TempPathFactory()
|
||||
:members:
|
||||
|
||||
|
||||
.. fixture:: tmpdir
|
||||
@@ -636,9 +601,9 @@ tmp_path_factory
|
||||
tmpdir
|
||||
~~~~~~
|
||||
|
||||
:ref:`tmpdir and tmpdir_factory`
|
||||
**Tutorial**: :doc:`tmpdir`
|
||||
|
||||
.. autofunction:: _pytest.legacypath.LegacyTmpdirPlugin.tmpdir()
|
||||
.. autofunction:: _pytest.tmpdir.tmpdir()
|
||||
:no-auto-options:
|
||||
|
||||
|
||||
@@ -647,12 +612,13 @@ tmpdir
|
||||
tmpdir_factory
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
:ref:`tmpdir and tmpdir_factory`
|
||||
**Tutorial**: :ref:`tmpdir factory example`
|
||||
|
||||
``tmpdir_factory`` is an instance of :class:`~pytest.TempdirFactory`:
|
||||
.. _`tmpdir factory api`:
|
||||
|
||||
``tmp_path_factory`` is an instance of :class:`~pytest.TempdirFactory`:
|
||||
|
||||
.. autoclass:: pytest.TempdirFactory()
|
||||
:members:
|
||||
|
||||
|
||||
.. _`hook-reference`:
|
||||
@@ -660,7 +626,7 @@ tmpdir_factory
|
||||
Hooks
|
||||
-----
|
||||
|
||||
:ref:`writing-plugins`.
|
||||
**Tutorial**: :doc:`writing_plugins`.
|
||||
|
||||
.. currentmodule:: _pytest.hookspec
|
||||
|
||||
@@ -792,7 +758,7 @@ Full reference to objects accessible from :ref:`fixtures <fixture>` or :ref:`hoo
|
||||
CallInfo
|
||||
~~~~~~~~
|
||||
|
||||
.. autoclass:: pytest.CallInfo()
|
||||
.. autoclass:: _pytest.runner.CallInfo()
|
||||
:members:
|
||||
|
||||
|
||||
@@ -813,7 +779,7 @@ Collector
|
||||
CollectReport
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: pytest.CollectReport()
|
||||
.. autoclass:: _pytest.reports.CollectReport()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
@@ -821,13 +787,13 @@ CollectReport
|
||||
Config
|
||||
~~~~~~
|
||||
|
||||
.. autoclass:: pytest.Config()
|
||||
.. autoclass:: _pytest.config.Config()
|
||||
:members:
|
||||
|
||||
ExceptionInfo
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: pytest.ExceptionInfo()
|
||||
.. autoclass:: _pytest._code.ExceptionInfo
|
||||
:members:
|
||||
|
||||
|
||||
@@ -883,28 +849,28 @@ Item
|
||||
MarkDecorator
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: pytest.MarkDecorator()
|
||||
.. autoclass:: _pytest.mark.MarkDecorator
|
||||
:members:
|
||||
|
||||
|
||||
MarkGenerator
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: pytest.MarkGenerator()
|
||||
.. autoclass:: _pytest.mark.MarkGenerator
|
||||
:members:
|
||||
|
||||
|
||||
Mark
|
||||
~~~~
|
||||
|
||||
.. autoclass:: pytest.Mark()
|
||||
.. autoclass:: _pytest.mark.structures.Mark
|
||||
:members:
|
||||
|
||||
|
||||
Metafunc
|
||||
~~~~~~~~
|
||||
|
||||
.. autoclass:: pytest.Metafunc()
|
||||
.. autoclass:: _pytest.python.Metafunc
|
||||
:members:
|
||||
|
||||
Module
|
||||
@@ -923,19 +889,14 @@ Node
|
||||
Parser
|
||||
~~~~~~
|
||||
|
||||
.. autoclass:: pytest.Parser()
|
||||
.. autoclass:: _pytest.config.argparsing.Parser()
|
||||
:members:
|
||||
|
||||
OptionGroup
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: pytest.OptionGroup()
|
||||
:members:
|
||||
|
||||
PytestPluginManager
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: pytest.PytestPluginManager()
|
||||
.. autoclass:: _pytest.config.PytestPluginManager()
|
||||
:members:
|
||||
:undoc-members:
|
||||
:inherited-members:
|
||||
@@ -951,7 +912,7 @@ Session
|
||||
TestReport
|
||||
~~~~~~~~~~
|
||||
|
||||
.. autoclass:: pytest.TestReport()
|
||||
.. autoclass:: _pytest.reports.TestReport()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
@@ -959,19 +920,11 @@ TestReport
|
||||
_Result
|
||||
~~~~~~~
|
||||
|
||||
Result object used within :ref:`hook wrappers <hookwrapper>`, see :py:class:`_Result in the pluggy documentation <pluggy._callers._Result>` for more information.
|
||||
|
||||
Stash
|
||||
~~~~~
|
||||
|
||||
.. autoclass:: pytest.Stash
|
||||
:special-members: __setitem__, __getitem__, __delitem__, __contains__, __len__
|
||||
:members:
|
||||
|
||||
.. autoclass:: pytest.StashKey
|
||||
:show-inheritance:
|
||||
:members:
|
||||
Result used within :ref:`hook wrappers <hookwrapper>`.
|
||||
|
||||
.. autoclass:: pluggy.callers._Result
|
||||
.. automethod:: pluggy.callers._Result.get_result
|
||||
.. automethod:: pluggy.callers._Result.force_result
|
||||
|
||||
Global Variables
|
||||
----------------
|
||||
@@ -985,7 +938,7 @@ pytest treats some global variables in a special manner when defined in a test m
|
||||
**Tutorial**: :ref:`customizing-test-collection`
|
||||
|
||||
Can be declared in *conftest.py files* to exclude test directories or modules.
|
||||
Needs to be a list of paths (``str``, :class:`pathlib.Path` or any :class:`os.PathLike`).
|
||||
Needs to be ``list[str]``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -1074,14 +1027,6 @@ Contains comma-separated list of modules that should be loaded as plugins:
|
||||
|
||||
export PYTEST_PLUGINS=mymodule.plugin,xdist
|
||||
|
||||
.. envvar:: PYTEST_THEME
|
||||
|
||||
Sets a `pygment style <https://pygments.org/docs/styles/>`_ to use for the code output.
|
||||
|
||||
.. envvar:: PYTEST_THEME_MODE
|
||||
|
||||
Sets the :envvar:`PYTEST_THEME` to be either *dark* or *light*.
|
||||
|
||||
.. envvar:: PY_COLORS
|
||||
|
||||
When set to ``1``, pytest will use color in terminal output.
|
||||
@@ -1199,8 +1144,19 @@ passed multiple times. The expected format is ``name=value``. For example::
|
||||
variables, that will be expanded. For more information about cache plugin
|
||||
please refer to :ref:`cache_provider`.
|
||||
|
||||
|
||||
.. confval:: confcutdir
|
||||
|
||||
Sets a directory where search upwards for ``conftest.py`` files stops.
|
||||
By default, pytest will stop searching for ``conftest.py`` files upwards
|
||||
from ``pytest.ini``/``tox.ini``/``setup.cfg`` of the project if any,
|
||||
or up to the file-system root.
|
||||
|
||||
|
||||
.. confval:: console_output_style
|
||||
|
||||
|
||||
|
||||
Sets the console output style while running tests:
|
||||
|
||||
* ``classic``: classic pytest output.
|
||||
@@ -1222,13 +1178,13 @@ passed multiple times. The expected format is ``name=value``. For example::
|
||||
|
||||
|
||||
Default encoding to use to decode text files with docstrings.
|
||||
:ref:`See how pytest handles doctests <doctest>`.
|
||||
:doc:`See how pytest handles doctests <doctest>`.
|
||||
|
||||
|
||||
.. confval:: doctest_optionflags
|
||||
|
||||
One or more doctest flag names from the standard ``doctest`` module.
|
||||
:ref:`See how pytest handles doctests <doctest>`.
|
||||
:doc:`See how pytest handles doctests <doctest>`.
|
||||
|
||||
|
||||
.. confval:: empty_parameter_set_mark
|
||||
@@ -1250,13 +1206,14 @@ passed multiple times. The expected format is ``name=value``. For example::
|
||||
.. note::
|
||||
|
||||
The default value of this option is planned to change to ``xfail`` in future releases
|
||||
as this is considered less error prone, see :issue:`3155` for more details.
|
||||
as this is considered less error prone, see `#3155 <https://github.com/pytest-dev/pytest/issues/3155>`_
|
||||
for more details.
|
||||
|
||||
|
||||
.. confval:: faulthandler_timeout
|
||||
|
||||
Dumps the tracebacks of all threads if a test takes longer than ``X`` seconds to run (including
|
||||
fixture setup and teardown). Implemented using the :func:`faulthandler.dump_traceback_later` function,
|
||||
fixture setup and teardown). Implemented using the `faulthandler.dump_traceback_later`_ function,
|
||||
so all caveats there apply.
|
||||
|
||||
.. code-block:: ini
|
||||
@@ -1267,6 +1224,9 @@ passed multiple times. The expected format is ``name=value``. For example::
|
||||
|
||||
For more information please refer to :ref:`faulthandler`.
|
||||
|
||||
.. _`faulthandler.dump_traceback_later`: https://docs.python.org/3/library/faulthandler.html#faulthandler.dump_traceback_later
|
||||
|
||||
|
||||
.. confval:: filterwarnings
|
||||
|
||||
|
||||
@@ -1660,28 +1620,13 @@ passed multiple times. The expected format is ``name=value``. For example::
|
||||
[pytest]
|
||||
python_functions = *_test
|
||||
|
||||
Note that this has no effect on methods that live on a ``unittest.TestCase``
|
||||
derived class, as ``unittest``'s own collection framework is used
|
||||
Note that this has no effect on methods that live on a ``unittest
|
||||
.TestCase`` derived class, as ``unittest``'s own collection framework is used
|
||||
to collect those tests.
|
||||
|
||||
See :ref:`change naming conventions` for more detailed examples.
|
||||
|
||||
|
||||
.. confval:: pythonpath
|
||||
|
||||
Sets list of directories that should be added to the python search path.
|
||||
Directories will be added to the head of :data:`sys.path`.
|
||||
Similar to the :envvar:`PYTHONPATH` environment variable, the directories will be
|
||||
included in where Python will look for imported modules.
|
||||
Paths are relative to the :ref:`rootdir <rootdir>` directory.
|
||||
Directories remain in path for the duration of the test session.
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[pytest]
|
||||
pythonpath = src1 src2
|
||||
|
||||
|
||||
.. confval:: required_plugins
|
||||
|
||||
A space separated list of plugins that must be present for pytest to run.
|
||||
@@ -1780,8 +1725,8 @@ All the command-line flags can be obtained by running ``pytest --help``::
|
||||
--pdb start the interactive Python debugger on errors or
|
||||
KeyboardInterrupt.
|
||||
--pdbcls=modulename:classname
|
||||
specify a custom interactive Python debugger for use
|
||||
with --pdb.For example:
|
||||
start a custom interactive Python debugger on
|
||||
errors. For example:
|
||||
--pdbcls=IPython.terminal.debugger:TerminalPdb
|
||||
--trace Immediately break when running each test.
|
||||
--capture=method per-test capturing method: one of fd|sys|no|tee-sys.
|
||||
@@ -1806,8 +1751,7 @@ All the command-line flags can be obtained by running ``pytest --help``::
|
||||
test next time
|
||||
--sw-skip, --stepwise-skip
|
||||
ignore the first failing test but stop on the next
|
||||
failing test.
|
||||
implicitly enables --stepwise.
|
||||
failing test
|
||||
|
||||
reporting:
|
||||
--durations=N show N slowest setup/test durations (N=0 for all).
|
||||
@@ -1894,7 +1838,7 @@ All the command-line flags can be obtained by running ``pytest --help``::
|
||||
--basetemp=dir base temporary directory for this test run.(warning:
|
||||
this directory is removed if it exists)
|
||||
-V, --version display pytest version and information about
|
||||
plugins. When given twice, also display information
|
||||
plugins.When given twice, also display information
|
||||
about plugins.
|
||||
-h, --help show help message and configuration info
|
||||
-p name early-load given plugin module name or entry point
|
||||
@@ -1902,12 +1846,8 @@ All the command-line flags can be obtained by running ``pytest --help``::
|
||||
To avoid loading of plugins, use the `no:` prefix,
|
||||
e.g. `no:doctest`.
|
||||
--trace-config trace considerations of conftest.py files.
|
||||
--debug=[DEBUG_FILE_NAME]
|
||||
store internal tracing debug information in this log
|
||||
file.
|
||||
This file is opened with 'w' and truncated as a
|
||||
result, care advised.
|
||||
Defaults to 'pytestdebug.log'.
|
||||
--debug store internal tracing debug information in
|
||||
'pytestdebug.log'.
|
||||
-o OVERRIDE_INI, --override-ini=OVERRIDE_INI
|
||||
override ini option with "option=value" style, e.g.
|
||||
`-o xfail_strict=True -o cache_dir=cache`.
|
||||
@@ -2019,7 +1959,6 @@ All the command-line flags can be obtained by running ``pytest --help``::
|
||||
default value for --log-file-date-format
|
||||
log_auto_indent (string):
|
||||
default value for --log-auto-indent
|
||||
pythonpath (paths): Add paths to sys.path
|
||||
faulthandler_timeout (string):
|
||||
Dump the traceback of all threads if a test takes
|
||||
more than TIMEOUT seconds to finish.
|
||||
@@ -1,26 +0,0 @@
|
||||
.. _exit-codes:
|
||||
|
||||
Exit codes
|
||||
========================================================
|
||||
|
||||
Running ``pytest`` can result in six different exit codes:
|
||||
|
||||
:Exit code 0: All tests were collected and passed successfully
|
||||
:Exit code 1: Tests were collected and run but some of the tests failed
|
||||
:Exit code 2: Test execution was interrupted by the user
|
||||
:Exit code 3: Internal error happened while executing tests
|
||||
:Exit code 4: pytest command line usage error
|
||||
:Exit code 5: No tests were collected
|
||||
|
||||
They are represented by the :class:`pytest.ExitCode` enum. The exit codes being a part of the public API can be imported and accessed directly using:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pytest import ExitCode
|
||||
|
||||
.. note::
|
||||
|
||||
If you would like to customize the exit code in some scenarios, specially when
|
||||
no tests are collected, consider using the
|
||||
`pytest-custom_exit_code <https://github.com/yashtodi94/pytest-custom_exit_code>`__
|
||||
plugin.
|
||||
@@ -1,452 +0,0 @@
|
||||
.. _reference-fixtures:
|
||||
.. _fixture:
|
||||
.. _fixtures:
|
||||
.. _`@pytest.fixture`:
|
||||
.. _`pytest.fixture`:
|
||||
|
||||
|
||||
Fixtures reference
|
||||
========================================================
|
||||
|
||||
.. seealso:: :ref:`about-fixtures`
|
||||
.. seealso:: :ref:`how-to-fixtures`
|
||||
|
||||
|
||||
.. currentmodule:: _pytest.python
|
||||
|
||||
.. _`Dependency injection`: https://en.wikipedia.org/wiki/Dependency_injection
|
||||
|
||||
|
||||
Built-in fixtures
|
||||
-----------------
|
||||
|
||||
:ref:`Fixtures <fixtures-api>` are defined using the :ref:`@pytest.fixture
|
||||
<pytest.fixture-api>` decorator. Pytest has several useful built-in fixtures:
|
||||
|
||||
:fixture:`capfd`
|
||||
Capture, as text, output to file descriptors ``1`` and ``2``.
|
||||
|
||||
:fixture:`capfdbinary`
|
||||
Capture, as bytes, output to file descriptors ``1`` and ``2``.
|
||||
|
||||
:fixture:`caplog`
|
||||
Control logging and access log entries.
|
||||
|
||||
:fixture:`capsys`
|
||||
Capture, as text, output to ``sys.stdout`` and ``sys.stderr``.
|
||||
|
||||
:fixture:`capsysbinary`
|
||||
Capture, as bytes, output to ``sys.stdout`` and ``sys.stderr``.
|
||||
|
||||
:fixture:`cache`
|
||||
Store and retrieve values across pytest runs.
|
||||
|
||||
:fixture:`doctest_namespace`
|
||||
Provide a dict injected into the docstests namespace.
|
||||
|
||||
:fixture:`monkeypatch`
|
||||
Temporarily modify classes, functions, dictionaries,
|
||||
``os.environ``, and other objects.
|
||||
|
||||
:fixture:`pytestconfig`
|
||||
Access to configuration values, pluginmanager and plugin hooks.
|
||||
|
||||
:fixture:`record_property`
|
||||
Add extra properties to the test.
|
||||
|
||||
:fixture:`record_testsuite_property`
|
||||
Add extra properties to the test suite.
|
||||
|
||||
:fixture:`recwarn`
|
||||
Record warnings emitted by test functions.
|
||||
|
||||
:fixture:`request`
|
||||
Provide information on the executing test function.
|
||||
|
||||
:fixture:`testdir`
|
||||
Provide a temporary test directory to aid in running, and
|
||||
testing, pytest plugins.
|
||||
|
||||
:fixture:`tmp_path`
|
||||
Provide a :class:`pathlib.Path` object to a temporary directory
|
||||
which is unique to each test function.
|
||||
|
||||
:fixture:`tmp_path_factory`
|
||||
Make session-scoped temporary directories and return
|
||||
:class:`pathlib.Path` objects.
|
||||
|
||||
:fixture:`tmpdir`
|
||||
Provide a :class:`py.path.local` object to a temporary
|
||||
directory which is unique to each test function;
|
||||
replaced by :fixture:`tmp_path`.
|
||||
|
||||
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
|
||||
|
||||
:fixture:`tmpdir_factory`
|
||||
Make session-scoped temporary directories and return
|
||||
:class:`py.path.local` objects;
|
||||
replaced by :fixture:`tmp_path_factory`.
|
||||
|
||||
|
||||
.. _`conftest.py`:
|
||||
.. _`conftest`:
|
||||
|
||||
Fixture availability
|
||||
---------------------
|
||||
|
||||
Fixture availability is determined from the perspective of the test. A fixture
|
||||
is only available for tests to request if they are in the scope that fixture is
|
||||
defined in. If a fixture is defined inside a class, it can only be requested by
|
||||
tests inside that class. But if a fixture is defined inside the global scope of
|
||||
the module, than every test in that module, even if it's defined inside a class,
|
||||
can request it.
|
||||
|
||||
Similarly, a test can also only be affected by an autouse fixture if that test
|
||||
is in the same scope that autouse fixture is defined in (see
|
||||
:ref:`autouse order`).
|
||||
|
||||
A fixture can also request any other fixture, no matter where it's defined, so
|
||||
long as the test requesting them can see all fixtures involved.
|
||||
|
||||
For example, here's a test file with a fixture (``outer``) that requests a
|
||||
fixture (``inner``) from a scope it wasn't defined in:
|
||||
|
||||
.. literalinclude:: /example/fixtures/test_fixtures_request_different_scope.py
|
||||
|
||||
From the tests' perspectives, they have no problem seeing each of the fixtures
|
||||
they're dependent on:
|
||||
|
||||
.. image:: /example/fixtures/test_fixtures_request_different_scope.*
|
||||
:align: center
|
||||
|
||||
So when they run, ``outer`` will have no problem finding ``inner``, because
|
||||
pytest searched from the tests' perspectives.
|
||||
|
||||
.. note::
|
||||
The scope a fixture is defined in has no bearing on the order it will be
|
||||
instantiated in: the order is mandated by the logic described
|
||||
:ref:`here <fixture order>`.
|
||||
|
||||
``conftest.py``: sharing fixtures across multiple files
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The ``conftest.py`` file serves as a means of providing fixtures for an entire
|
||||
directory. Fixtures defined in a ``conftest.py`` can be used by any test
|
||||
in that package without needing to import them (pytest will automatically
|
||||
discover them).
|
||||
|
||||
You can have multiple nested directories/packages containing your tests, and
|
||||
each directory can have its own ``conftest.py`` with its own fixtures, adding on
|
||||
to the ones provided by the ``conftest.py`` files in parent directories.
|
||||
|
||||
For example, given a test file structure like this:
|
||||
|
||||
::
|
||||
|
||||
tests/
|
||||
__init__.py
|
||||
|
||||
conftest.py
|
||||
# content of tests/conftest.py
|
||||
import pytest
|
||||
|
||||
@pytest.fixture
|
||||
def order():
|
||||
return []
|
||||
|
||||
@pytest.fixture
|
||||
def top(order, innermost):
|
||||
order.append("top")
|
||||
|
||||
test_top.py
|
||||
# content of tests/test_top.py
|
||||
import pytest
|
||||
|
||||
@pytest.fixture
|
||||
def innermost(order):
|
||||
order.append("innermost top")
|
||||
|
||||
def test_order(order, top):
|
||||
assert order == ["innermost top", "top"]
|
||||
|
||||
subpackage/
|
||||
__init__.py
|
||||
|
||||
conftest.py
|
||||
# content of tests/subpackage/conftest.py
|
||||
import pytest
|
||||
|
||||
@pytest.fixture
|
||||
def mid(order):
|
||||
order.append("mid subpackage")
|
||||
|
||||
test_subpackage.py
|
||||
# content of tests/subpackage/test_subpackage.py
|
||||
import pytest
|
||||
|
||||
@pytest.fixture
|
||||
def innermost(order, mid):
|
||||
order.append("innermost subpackage")
|
||||
|
||||
def test_order(order, top):
|
||||
assert order == ["mid subpackage", "innermost subpackage", "top"]
|
||||
|
||||
The boundaries of the scopes can be visualized like this:
|
||||
|
||||
.. image:: /example/fixtures/fixture_availability.*
|
||||
:align: center
|
||||
|
||||
The directories become their own sort of scope where fixtures that are defined
|
||||
in a ``conftest.py`` file in that directory become available for that whole
|
||||
scope.
|
||||
|
||||
Tests are allowed to search upward (stepping outside a circle) for fixtures, but
|
||||
can never go down (stepping inside a circle) to continue their search. So
|
||||
``tests/subpackage/test_subpackage.py::test_order`` would be able to find the
|
||||
``innermost`` fixture defined in ``tests/subpackage/test_subpackage.py``, but
|
||||
the one defined in ``tests/test_top.py`` would be unavailable to it because it
|
||||
would have to step down a level (step inside a circle) to find it.
|
||||
|
||||
The first fixture the test finds is the one that will be used, so
|
||||
:ref:`fixtures can be overriden <override fixtures>` if you need to change or
|
||||
extend what one does for a particular scope.
|
||||
|
||||
You can also use the ``conftest.py`` file to implement
|
||||
:ref:`local per-directory plugins <conftest.py plugins>`.
|
||||
|
||||
Fixtures from third-party plugins
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Fixtures don't have to be defined in this structure to be available for tests,
|
||||
though. They can also be provided by third-party plugins that are installed, and
|
||||
this is how many pytest plugins operate. As long as those plugins are installed,
|
||||
the fixtures they provide can be requested from anywhere in your test suite.
|
||||
|
||||
Because they're provided from outside the structure of your test suite,
|
||||
third-party plugins don't really provide a scope like `conftest.py` files and
|
||||
the directories in your test suite do. As a result, pytest will search for
|
||||
fixtures stepping out through scopes as explained previously, only reaching
|
||||
fixtures defined in plugins *last*.
|
||||
|
||||
For example, given the following file structure:
|
||||
|
||||
::
|
||||
|
||||
tests/
|
||||
__init__.py
|
||||
|
||||
conftest.py
|
||||
# content of tests/conftest.py
|
||||
import pytest
|
||||
|
||||
@pytest.fixture
|
||||
def order():
|
||||
return []
|
||||
|
||||
subpackage/
|
||||
__init__.py
|
||||
|
||||
conftest.py
|
||||
# content of tests/subpackage/conftest.py
|
||||
import pytest
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mid(order, b_fix):
|
||||
order.append("mid subpackage")
|
||||
|
||||
test_subpackage.py
|
||||
# content of tests/subpackage/test_subpackage.py
|
||||
import pytest
|
||||
|
||||
@pytest.fixture
|
||||
def inner(order, mid, a_fix):
|
||||
order.append("inner subpackage")
|
||||
|
||||
def test_order(order, inner):
|
||||
assert order == ["b_fix", "mid subpackage", "a_fix", "inner subpackage"]
|
||||
|
||||
If ``plugin_a`` is installed and provides the fixture ``a_fix``, and
|
||||
``plugin_b`` is installed and provides the fixture ``b_fix``, then this is what
|
||||
the test's search for fixtures would look like:
|
||||
|
||||
.. image:: /example/fixtures/fixture_availability_plugins.svg
|
||||
:align: center
|
||||
|
||||
pytest will only search for ``a_fix`` and ``b_fix`` in the plugins after
|
||||
searching for them first in the scopes inside ``tests/``.
|
||||
|
||||
.. note:
|
||||
|
||||
pytest can tell you what fixtures are available for a given test if you call
|
||||
``pytests`` along with the test's name (or the scope it's in), and provide
|
||||
the ``--fixtures`` flag, e.g. ``pytest --fixtures test_something.py``
|
||||
(fixtures with names that start with ``_`` will only be shown if you also
|
||||
provide the ``-v`` flag).
|
||||
|
||||
|
||||
.. _`fixture order`:
|
||||
|
||||
Fixture instantiation order
|
||||
---------------------------
|
||||
|
||||
When pytest wants to execute a test, once it knows what fixtures will be
|
||||
executed, it has to figure out the order they'll be executed in. To do this, it
|
||||
considers 3 factors:
|
||||
|
||||
1. scope
|
||||
2. dependencies
|
||||
3. autouse
|
||||
|
||||
Names of fixtures or tests, where they're defined, the order they're defined in,
|
||||
and the order fixtures are requested in have no bearing on execution order
|
||||
beyond coincidence. While pytest will try to make sure coincidences like these
|
||||
stay consistent from run to run, it's not something that should be depended on.
|
||||
If you want to control the order, it's safest to rely on these 3 things and make
|
||||
sure dependencies are clearly established.
|
||||
|
||||
Higher-scoped fixtures are executed first
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Within a function request for fixtures, those of higher-scopes (such as
|
||||
``session``) are executed before lower-scoped fixtures (such as ``function`` or
|
||||
``class``).
|
||||
|
||||
Here's an example:
|
||||
|
||||
.. literalinclude:: /example/fixtures/test_fixtures_order_scope.py
|
||||
|
||||
The test will pass because the larger scoped fixtures are executing first.
|
||||
|
||||
The order breaks down to this:
|
||||
|
||||
.. image:: /example/fixtures/test_fixtures_order_scope.*
|
||||
:align: center
|
||||
|
||||
Fixtures of the same order execute based on dependencies
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When a fixture requests another fixture, the other fixture is executed first.
|
||||
So if fixture ``a`` requests fixture ``b``, fixture ``b`` will execute first,
|
||||
because ``a`` depends on ``b`` and can't operate without it. Even if ``a``
|
||||
doesn't need the result of ``b``, it can still request ``b`` if it needs to make
|
||||
sure it is executed after ``b``.
|
||||
|
||||
For example:
|
||||
|
||||
.. literalinclude:: /example/fixtures/test_fixtures_order_dependencies.py
|
||||
|
||||
If we map out what depends on what, we get something that look like this:
|
||||
|
||||
.. image:: /example/fixtures/test_fixtures_order_dependencies.*
|
||||
:align: center
|
||||
|
||||
The rules provided by each fixture (as to what fixture(s) each one has to come
|
||||
after) are comprehensive enough that it can be flattened to this:
|
||||
|
||||
.. image:: /example/fixtures/test_fixtures_order_dependencies_flat.*
|
||||
:align: center
|
||||
|
||||
Enough information has to be provided through these requests in order for pytest
|
||||
to be able to figure out a clear, linear chain of dependencies, and as a result,
|
||||
an order of operations for a given test. If there's any ambiguity, and the order
|
||||
of operations can be interpreted more than one way, you should assume pytest
|
||||
could go with any one of those interpretations at any point.
|
||||
|
||||
For example, if ``d`` didn't request ``c``, i.e.the graph would look like this:
|
||||
|
||||
.. image:: /example/fixtures/test_fixtures_order_dependencies_unclear.*
|
||||
:align: center
|
||||
|
||||
Because nothing requested ``c`` other than ``g``, and ``g`` also requests ``f``,
|
||||
it's now unclear if ``c`` should go before/after ``f``, ``e``, or ``d``. The
|
||||
only rules that were set for ``c`` is that it must execute after ``b`` and
|
||||
before ``g``.
|
||||
|
||||
pytest doesn't know where ``c`` should go in the case, so it should be assumed
|
||||
that it could go anywhere between ``g`` and ``b``.
|
||||
|
||||
This isn't necessarily bad, but it's something to keep in mind. If the order
|
||||
they execute in could affect the behavior a test is targeting, or could
|
||||
otherwise influence the result of a test, then the order should be defined
|
||||
explicitly in a way that allows pytest to linearize/"flatten" that order.
|
||||
|
||||
.. _`autouse order`:
|
||||
|
||||
Autouse fixtures are executed first within their scope
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Autouse fixtures are assumed to apply to every test that could reference them,
|
||||
so they are executed before other fixtures in that scope. Fixtures that are
|
||||
requested by autouse fixtures effectively become autouse fixtures themselves for
|
||||
the tests that the real autouse fixture applies to.
|
||||
|
||||
So if fixture ``a`` is autouse and fixture ``b`` is not, but fixture ``a``
|
||||
requests fixture ``b``, then fixture ``b`` will effectively be an autouse
|
||||
fixture as well, but only for the tests that ``a`` applies to.
|
||||
|
||||
In the last example, the graph became unclear if ``d`` didn't request ``c``. But
|
||||
if ``c`` was autouse, then ``b`` and ``a`` would effectively also be autouse
|
||||
because ``c`` depends on them. As a result, they would all be shifted above
|
||||
non-autouse fixtures within that scope.
|
||||
|
||||
So if the test file looked like this:
|
||||
|
||||
.. literalinclude:: /example/fixtures/test_fixtures_order_autouse.py
|
||||
|
||||
the graph would look like this:
|
||||
|
||||
.. image:: /example/fixtures/test_fixtures_order_autouse.*
|
||||
:align: center
|
||||
|
||||
Because ``c`` can now be put above ``d`` in the graph, pytest can once again
|
||||
linearize the graph to this:
|
||||
|
||||
In this example, ``c`` makes ``b`` and ``a`` effectively autouse fixtures as
|
||||
well.
|
||||
|
||||
Be careful with autouse, though, as an autouse fixture will automatically
|
||||
execute for every test that can reach it, even if they don't request it. For
|
||||
example, consider this file:
|
||||
|
||||
.. literalinclude:: /example/fixtures/test_fixtures_order_autouse_multiple_scopes.py
|
||||
|
||||
Even though nothing in ``TestClassWithoutC1Request`` is requesting ``c1``, it still
|
||||
is executed for the tests inside it anyway:
|
||||
|
||||
.. image:: /example/fixtures/test_fixtures_order_autouse_multiple_scopes.*
|
||||
:align: center
|
||||
|
||||
But just because one autouse fixture requested a non-autouse fixture, that
|
||||
doesn't mean the non-autouse fixture becomes an autouse fixture for all contexts
|
||||
that it can apply to. It only effectively becomes an autouse fixture for the
|
||||
contexts the real autouse fixture (the one that requested the non-autouse
|
||||
fixture) can apply to.
|
||||
|
||||
For example, take a look at this test file:
|
||||
|
||||
.. literalinclude:: /example/fixtures/test_fixtures_order_autouse_temp_effects.py
|
||||
|
||||
It would break down to something like this:
|
||||
|
||||
.. image:: /example/fixtures/test_fixtures_order_autouse_temp_effects.*
|
||||
:align: center
|
||||
|
||||
For ``test_req`` and ``test_no_req`` inside ``TestClassWithAutouse``, ``c3``
|
||||
effectively makes ``c2`` an autouse fixture, which is why ``c2`` and ``c3`` are
|
||||
executed for both tests, despite not being requested, and why ``c2`` and ``c3``
|
||||
are executed before ``c1`` for ``test_req``.
|
||||
|
||||
If this made ``c2`` an *actual* autouse fixture, then ``c2`` would also execute
|
||||
for the tests inside ``TestClassWithoutAutouse``, since they can reference
|
||||
``c2`` if they wanted to. But it doesn't, because from the perspective of the
|
||||
``TestClassWithoutAutouse`` tests, ``c2`` isn't an autouse fixture, since they
|
||||
can't see ``c3``.
|
||||
|
||||
|
||||
.. note:
|
||||
|
||||
pytest can tell you what order the fixtures will execute in for a given test
|
||||
if you call ``pytests`` along with the test's name (or the scope it's in),
|
||||
and provide the ``--setup-plan`` flag, e.g.
|
||||
``pytest --setup-plan test_something.py`` (fixtures with names that start
|
||||
with ``_`` will only be shown if you also provide the ``-v`` flag).
|
||||
@@ -1,15 +0,0 @@
|
||||
:orphan:
|
||||
|
||||
.. _reference:
|
||||
|
||||
Reference guides
|
||||
================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
fixtures
|
||||
plugin_list
|
||||
customize
|
||||
reference
|
||||
exit-codes
|
||||