Compare commits
1 Commits
expose-fix
...
6.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
868bc003ec |
@@ -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( |$)
|
||||
|
||||
20
.github/ISSUE_TEMPLATE/2_feature_request.md
vendored
@@ -3,23 +3,3 @@ name: 🚀 Feature Request
|
||||
about: Ideas for new features and improvements
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Thanks for suggesting a feature!
|
||||
|
||||
Quick check-list while suggesting features:
|
||||
-->
|
||||
|
||||
#### What's the problem this feature will solve?
|
||||
<!-- What are you trying to do, that you are unable to achieve with pytest as it currently stands? -->
|
||||
|
||||
#### Describe the solution you'd like
|
||||
<!-- A clear and concise description of what you want to happen. -->
|
||||
|
||||
<!-- Provide examples of real-world use cases that this would enable and how it solves the problem described above. -->
|
||||
|
||||
#### Alternative Solutions
|
||||
<!-- Have you tried to workaround the problem using a pytest plugin or other tools? Or a different approach to solving this issue? Please elaborate here. -->
|
||||
|
||||
#### Additional context
|
||||
<!-- Add any other context, links, etc. about the feature here. -->
|
||||
|
||||
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:
|
||||
|
||||
|
||||
11
.github/dependabot.yml
vendored
@@ -1,11 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: pip
|
||||
directory: "/testing/plugins_integration"
|
||||
schedule:
|
||||
interval: weekly
|
||||
time: "03:00"
|
||||
open-pull-requests-limit: 10
|
||||
allow:
|
||||
- dependency-type: direct
|
||||
- dependency-type: indirect
|
||||
51
.github/workflows/backport.yml
vendored
@@ -1,51 +0,0 @@
|
||||
name: backport
|
||||
|
||||
on:
|
||||
# Note that `pull_request_target` has security implications:
|
||||
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
|
||||
# In particular:
|
||||
# - Only allow triggers that can be used only be trusted users
|
||||
# - Don't execute any code from the target branch
|
||||
# - Don't use cache
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
backport:
|
||||
if: startsWith(github.event.label.name, 'backport ') && github.event.pull_request.merged
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: true
|
||||
|
||||
- name: Create backport PR
|
||||
run: |
|
||||
set -eux
|
||||
|
||||
git config --global user.name "pytest bot"
|
||||
git config --global user.email "pytestbot@gmail.com"
|
||||
|
||||
label='${{ github.event.label.name }}'
|
||||
target_branch="${label#backport }"
|
||||
backport_branch=backport-${{ github.event.number }}-to-"${target_branch}"
|
||||
subject="[$target_branch] $(gh pr view --json title -q .title ${{ github.event.number }})"
|
||||
|
||||
git checkout origin/"${target_branch}" -b "${backport_branch}"
|
||||
git cherry-pick -x --mainline 1 ${{ github.event.pull_request.merge_commit_sha }}
|
||||
git commit --amend --message "$subject"
|
||||
git push --set-upstream origin --force-with-lease "${backport_branch}"
|
||||
gh pr create \
|
||||
--base "${target_branch}" \
|
||||
--title "${subject}" \
|
||||
--body "Backport of PR #${{ github.event.number }} to $target_branch branch. PR created by backport workflow."
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
126
.github/workflows/main.yml
vendored
@@ -3,47 +3,37 @@ name: main
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
- "[0-9]+.[0-9]+.x"
|
||||
- "test-me-*"
|
||||
tags:
|
||||
- "[0-9]+.[0-9]+.[0-9]+"
|
||||
- "[0-9]+.[0-9]+.[0-9]+rc[0-9]+"
|
||||
- "*"
|
||||
|
||||
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
|
||||
matrix:
|
||||
name: [
|
||||
"windows-py35",
|
||||
"windows-py36",
|
||||
"windows-py37",
|
||||
"windows-py37-pluggy",
|
||||
"windows-py38",
|
||||
"windows-py39",
|
||||
"windows-py310",
|
||||
|
||||
"ubuntu-py35",
|
||||
"ubuntu-py36",
|
||||
"ubuntu-py37",
|
||||
"ubuntu-py37-pluggy",
|
||||
"ubuntu-py37-freeze",
|
||||
"ubuntu-py38",
|
||||
"ubuntu-py39",
|
||||
"ubuntu-py310",
|
||||
"ubuntu-pypy3",
|
||||
|
||||
"macos-py37",
|
||||
@@ -55,6 +45,15 @@ jobs:
|
||||
]
|
||||
|
||||
include:
|
||||
- name: "windows-py35"
|
||||
python: "3.5"
|
||||
os: windows-latest
|
||||
tox_env: "py35-xdist"
|
||||
use_coverage: true
|
||||
- name: "windows-py36"
|
||||
python: "3.6"
|
||||
os: windows-latest
|
||||
tox_env: "py36-xdist"
|
||||
- name: "windows-py37"
|
||||
python: "3.7"
|
||||
os: windows-latest
|
||||
@@ -62,30 +61,30 @@ 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.1"
|
||||
os: windows-latest
|
||||
tox_env: "py310-xdist"
|
||||
|
||||
- name: "ubuntu-py35"
|
||||
python: "3.5"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py35-xdist"
|
||||
- name: "ubuntu-py36"
|
||||
python: "3.6"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py36-xdist"
|
||||
- name: "ubuntu-py37"
|
||||
python: "3.7"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py37-lsof-numpy-pexpect"
|
||||
tox_env: "py37-lsof-numpy-oldattrs-pexpect"
|
||||
use_coverage: true
|
||||
- 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
|
||||
@@ -95,15 +94,11 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
tox_env: "py38-xdist"
|
||||
- name: "ubuntu-py39"
|
||||
python: "3.9"
|
||||
python: "3.9-dev"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py39-xdist"
|
||||
- name: "ubuntu-py310"
|
||||
python: "3.10.1"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py310-xdist"
|
||||
- name: "ubuntu-pypy3"
|
||||
python: "pypy-3.7"
|
||||
python: "pypy3"
|
||||
os: ubuntu-latest
|
||||
tox_env: "pypy3-xdist"
|
||||
|
||||
@@ -118,7 +113,7 @@ jobs:
|
||||
use_coverage: true
|
||||
|
||||
- name: "plugins"
|
||||
python: "3.9"
|
||||
python: "3.7"
|
||||
os: ubuntu-latest
|
||||
tox_env: "plugins"
|
||||
|
||||
@@ -136,13 +131,16 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python ${{ matrix.python }}
|
||||
uses: actions/setup-python@v2
|
||||
if: matrix.python != '3.9-dev'
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
- name: Set up Python ${{ matrix.python }} (deadsnakes)
|
||||
uses: deadsnakes/action@v2.0.0
|
||||
if: matrix.python == '3.9-dev'
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
@@ -154,27 +152,41 @@ 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 "::set-env name=PY::$(python -c 'import hashlib, sys;print(hashlib.sha256(sys.version.encode()+sys.executable.encode()).hexdigest())')"
|
||||
- uses: actions/cache@v1
|
||||
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') }}
|
||||
- run: 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]
|
||||
|
||||
@@ -182,31 +194,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'
|
||||
4
.gitignore
vendored
@@ -34,7 +34,6 @@ issue/
|
||||
env/
|
||||
.env/
|
||||
.venv/
|
||||
/pythonenv*/
|
||||
3rdparty/
|
||||
.tox
|
||||
.cache
|
||||
@@ -53,6 +52,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.12b0
|
||||
rev: 19.10b0
|
||||
hooks:
|
||||
- id: black
|
||||
args: [--safe, --quiet]
|
||||
- repo: https://github.com/asottile/blacken-docs
|
||||
rev: v1.12.0
|
||||
rev: v1.7.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.1.0
|
||||
rev: v3.1.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.2
|
||||
hooks:
|
||||
- id: flake8
|
||||
language_version: python3
|
||||
@@ -29,38 +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.0
|
||||
hooks:
|
||||
- id: reorder-python-imports
|
||||
args: ['--application-directories=.:src', --py37-plus]
|
||||
args: ['--application-directories=.:src', --py3-plus]
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.31.0
|
||||
rev: v2.4.4
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py37-plus]
|
||||
args: [--py3-plus]
|
||||
- repo: https://github.com/asottile/setup-cfg-fmt
|
||||
rev: v1.20.0
|
||||
hooks:
|
||||
- id: setup-cfg-fmt
|
||||
args: [--max-py-version=3.10]
|
||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||
rev: v1.9.0
|
||||
hooks:
|
||||
- id: python-use-type-annotations
|
||||
- id: setup-cfg-fmt
|
||||
# TODO: when upgrading setup-cfg-fmt this can be removed
|
||||
args: [--max-py-version=3.9]
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v0.931
|
||||
rev: v0.780 # NOTE: keep this in sync with setup.cfg.
|
||||
hooks:
|
||||
- id: mypy
|
||||
files: ^(src/|testing/)
|
||||
args: []
|
||||
additional_dependencies:
|
||||
- iniconfig>=1.1.0
|
||||
- py>=1.8.2
|
||||
- attrs>=19.2.0
|
||||
- packaging
|
||||
- tomli
|
||||
- types-atomicwrites
|
||||
- types-pkg_resources
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: rst
|
||||
@@ -91,9 +80,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
|
||||
|
||||
60
.travis.yml
Normal file
@@ -0,0 +1,60 @@
|
||||
language: python
|
||||
dist: trusty
|
||||
python: '3.5.1'
|
||||
cache: false
|
||||
|
||||
env:
|
||||
global:
|
||||
- PYTEST_ADDOPTS=-vv
|
||||
|
||||
# setuptools-scm needs all tags in order to obtain a proper version
|
||||
git:
|
||||
depth: false
|
||||
|
||||
install:
|
||||
- python -m pip install --upgrade --pre tox
|
||||
|
||||
jobs:
|
||||
include:
|
||||
# Coverage for Python 3.5.{0,1} specific code, mostly typing related.
|
||||
- env: TOXENV=py35 PYTEST_COVERAGE=1 PYTEST_ADDOPTS="-k test_raises_cyclic_reference"
|
||||
before_install:
|
||||
# Work around https://github.com/jaraco/zipp/issues/40.
|
||||
- python -m pip install -U 'setuptools>=34.4.0' virtualenv==16.7.9
|
||||
|
||||
before_script:
|
||||
- |
|
||||
# Do not (re-)upload coverage with cron runs.
|
||||
if [[ "$TRAVIS_EVENT_TYPE" = cron ]]; then
|
||||
PYTEST_COVERAGE=0
|
||||
fi
|
||||
- |
|
||||
if [[ "$PYTEST_COVERAGE" = 1 ]]; then
|
||||
export COVERAGE_FILE="$PWD/.coverage"
|
||||
export COVERAGE_PROCESS_START="$PWD/.coveragerc"
|
||||
export _PYTEST_TOX_COVERAGE_RUN="coverage run -m"
|
||||
export _PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess
|
||||
fi
|
||||
|
||||
script: tox
|
||||
|
||||
after_success:
|
||||
- |
|
||||
if [[ "$PYTEST_COVERAGE" = 1 ]]; then
|
||||
env CODECOV_NAME="$TOXENV-$TRAVIS_OS_NAME" scripts/report-coverage.sh -F Travis
|
||||
fi
|
||||
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "chat.freenode.net#pytest"
|
||||
on_success: change
|
||||
on_failure: change
|
||||
skip_join: true
|
||||
email:
|
||||
- pytest-commit@python.org
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /^\d+\.\d+\.x$/
|
||||
45
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
|
||||
@@ -23,10 +21,7 @@ Anders Hovmöller
|
||||
Andras Mitzki
|
||||
Andras Tim
|
||||
Andrea Cimatoribus
|
||||
Andreas Motl
|
||||
Andreas Zeidler
|
||||
Andrew Shapton
|
||||
Andrew Svetlov
|
||||
Andrey Paramonov
|
||||
Andrzej Klajnert
|
||||
Andrzej Ostrowski
|
||||
@@ -34,19 +29,15 @@ 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
|
||||
Aron Curzon
|
||||
Aviral Verma
|
||||
Aviv Palivoda
|
||||
Barney Gale
|
||||
Ben Gartner
|
||||
Ben Webb
|
||||
Benjamin Peterson
|
||||
Bernard Pratz
|
||||
@@ -64,28 +55,23 @@ Charles Cloud
|
||||
Charles Machalow
|
||||
Charnjit SiNGH (CCSJ)
|
||||
Chris Lamb
|
||||
Chris NeJame
|
||||
Chris Rose
|
||||
Christian Boelsen
|
||||
Christian Fetzer
|
||||
Christian Neumüller
|
||||
Christian Theunert
|
||||
Christian Tismer
|
||||
Christine Mecklenborg
|
||||
Christoph Buelter
|
||||
Christopher Dignam
|
||||
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
|
||||
@@ -97,23 +83,18 @@ David Vierra
|
||||
Daw-Ran Liou
|
||||
Debi Mishra
|
||||
Denis Kirisov
|
||||
Denivy Braiam Rück
|
||||
Dhiren Serai
|
||||
Diego Russo
|
||||
Dmitry Dygalo
|
||||
Dmitry Pribysh
|
||||
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
|
||||
@@ -126,13 +107,10 @@ Florian Bruhin
|
||||
Florian Dahlitz
|
||||
Floris Bruynooghe
|
||||
Gabriel Reis
|
||||
Garvit Shubham
|
||||
Gene Wood
|
||||
George Kussumoto
|
||||
Georgy Dyuldin
|
||||
Gergely Kalmár
|
||||
Gleb Nikonorov
|
||||
Graeme Smecher
|
||||
Graham Horler
|
||||
Greg Price
|
||||
Gregory Lee
|
||||
@@ -141,7 +119,6 @@ Grigorii Eremeev (budulianin)
|
||||
Guido Wesdorp
|
||||
Guoqiang Zhang
|
||||
Harald Armin Massa
|
||||
Harshna
|
||||
Henk-Jaap Wagenaar
|
||||
Holger Kohr
|
||||
Hugo van Kemenade
|
||||
@@ -152,9 +129,7 @@ Ilya Konstantinov
|
||||
Ionuț Turturică
|
||||
Iwan Briquemont
|
||||
Jaap Broekhuizen
|
||||
Jakob van Santen
|
||||
Jakub Mitoraj
|
||||
James Bourbeau
|
||||
Jan Balster
|
||||
Janne Vanhala
|
||||
Jason R. Coombs
|
||||
@@ -175,18 +150,15 @@ Josh Karpel
|
||||
Joshua Bronson
|
||||
Jurko Gospodnetić
|
||||
Justyna Janczyszyn
|
||||
Justice Ndou
|
||||
Kale Kundert
|
||||
Kamran Ahmad
|
||||
Karl O. Pinc
|
||||
Karthikeyan Singaravelan
|
||||
Katarzyna Jachim
|
||||
Katarzyna Król
|
||||
Katerina Koukiou
|
||||
Keri Volans
|
||||
Kevin Cox
|
||||
Kevin J. Foley
|
||||
Kian-Meng Ang
|
||||
Kodi B. Arfer
|
||||
Kostis Anagnostopoulos
|
||||
Kristoffer Nordström
|
||||
@@ -223,7 +195,6 @@ Matthias Hafner
|
||||
Maxim Filipenko
|
||||
Maximilian Cosmo Sitter
|
||||
mbyt
|
||||
Mickey Pashov
|
||||
Michael Aquilina
|
||||
Michael Birtwell
|
||||
Michael Droettboom
|
||||
@@ -231,7 +202,6 @@ Michael Goerz
|
||||
Michael Krebs
|
||||
Michael Seifert
|
||||
Michal Wajszczuk
|
||||
Michał Zięba
|
||||
Mihai Capotă
|
||||
Mike Hoyle (hoylemd)
|
||||
Mike Lundy
|
||||
@@ -245,7 +215,6 @@ Nicholas Murphy
|
||||
Niclas Olofsson
|
||||
Nicolas Delaby
|
||||
Nikolay Kondratyev
|
||||
Olga Matoula
|
||||
Oleg Pidsadnyi
|
||||
Oleg Sushchenko
|
||||
Oliver Bestwalter
|
||||
@@ -253,20 +222,16 @@ Omar Kohl
|
||||
Omer Hadari
|
||||
Ondřej Súkup
|
||||
Oscar Benjamin
|
||||
Parth Patel
|
||||
Patrick Hayes
|
||||
Pauli Virtanen
|
||||
Pavel Karateev
|
||||
Paweł Adamczak
|
||||
Pedro Algarvio
|
||||
Petter Strandmark
|
||||
Philipp Loose
|
||||
Pieter Mulder
|
||||
Piotr Banaszkiewicz
|
||||
Piotr Helm
|
||||
Prakhar Gurunani
|
||||
Prashant Anand
|
||||
Prashant Sharma
|
||||
Pulkit Goyal
|
||||
Punyashloka Biswal
|
||||
Quentin Pradet
|
||||
@@ -288,17 +253,13 @@ Ross Lawley
|
||||
Ruaridh Williamson
|
||||
Russel Winder
|
||||
Ryan Wooden
|
||||
Saiprasad Kale
|
||||
Samuel Dion-Girardeau
|
||||
Samuel Searles-Bryant
|
||||
Samuele Pedroni
|
||||
Sanket Duthade
|
||||
Sankt Petersbug
|
||||
Segev Finer
|
||||
Serhii Mozghovyi
|
||||
Seth Junot
|
||||
Shantanu Jain
|
||||
Shubham Adep
|
||||
Simon Gomizelj
|
||||
Simon Kerr
|
||||
Skylar Downes
|
||||
@@ -313,12 +274,9 @@ 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
|
||||
@@ -350,8 +308,5 @@ Xixi Zhao
|
||||
Xuan Luong
|
||||
Xuecong Liao
|
||||
Yoav Caspi
|
||||
Yuval Shimon
|
||||
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
|
||||
|
||||
@@ -299,6 +299,12 @@ Here is a simple overview, with pytest-specific bits:
|
||||
|
||||
$ pytest testing/test_config.py
|
||||
|
||||
|
||||
#. Commit and push once your tests pass and you are happy with your change(s)::
|
||||
|
||||
$ git commit -a -m "<commit message>"
|
||||
$ git push -u
|
||||
|
||||
#. Create a new changelog entry in ``changelog``. The file should be named ``<issueid>.<type>.rst``,
|
||||
where *issueid* is the number of the issue related to the change and *type* is one of
|
||||
``feature``, ``improvement``, ``bugfix``, ``doc``, ``deprecation``, ``breaking``, ``vendor``
|
||||
@@ -307,37 +313,32 @@ Here is a simple overview, with pytest-specific bits:
|
||||
|
||||
#. Add yourself to ``AUTHORS`` file if not there yet, in alphabetical order.
|
||||
|
||||
#. Commit and push once your tests pass and you are happy with your change(s)::
|
||||
|
||||
$ git commit -a -m "<commit message>"
|
||||
$ git push -u
|
||||
|
||||
#. Finally, submit a pull request through the GitHub website using this data::
|
||||
|
||||
head-fork: YOUR_GITHUB_USERNAME/pytest
|
||||
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 +347,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,22 +388,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.
|
||||
|
||||
Automatic method:
|
||||
|
||||
Add a ``backport 1.2.x`` label to the PR you want to backport. This will create
|
||||
a backport PR against the ``1.2.x`` branch.
|
||||
|
||||
Manual method:
|
||||
|
||||
#. ``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``).
|
||||
|
||||
@@ -415,8 +409,8 @@ Manual method:
|
||||
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
|
||||
@@ -424,8 +418,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.
|
||||
@@ -454,7 +448,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.
|
||||
@@ -466,15 +460,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
|
||||
|
||||
39
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.7+ or PyPy3
|
||||
- Python 3.5+ 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
|
||||
|
||||
116
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,22 +114,14 @@ 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 (or the first prerelease of it), tag the release cherry-pick merge commit in main with
|
||||
a dev tag for the next feature release::
|
||||
|
||||
git checkout main
|
||||
git pull
|
||||
git tag MAJOR.{MINOR+1}.0.dev0
|
||||
git push git@github.com:pytest-dev/pytest.git MAJOR.{MINOR+1}.0.dev0
|
||||
|
||||
#. Send an email announcement with the contents from::
|
||||
|
||||
doc/en/announce/release-<VERSION>.rst
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
from unittest import TestCase # noqa: F401
|
||||
|
||||
for i in range(15000):
|
||||
exec(
|
||||
f"""
|
||||
class Test{i}(TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls): pass
|
||||
def test_1(self): pass
|
||||
def test_2(self): pass
|
||||
def test_3(self): pass
|
||||
"""
|
||||
)
|
||||
@@ -1,11 +0,0 @@
|
||||
for i in range(5000):
|
||||
exec(
|
||||
f"""
|
||||
class Test{i}:
|
||||
@classmethod
|
||||
def setup_class(cls): pass
|
||||
def test_1(self): pass
|
||||
def test_2(self): pass
|
||||
def test_3(self): pass
|
||||
"""
|
||||
)
|
||||
@@ -1,15 +0,0 @@
|
||||
As per our policy, the following features have been deprecated in the 6.X series and are now
|
||||
removed:
|
||||
|
||||
* ``pytest._fillfuncargs`` function.
|
||||
|
||||
* ``pytest_warning_captured`` hook - use ``pytest_warning_recorded`` instead.
|
||||
|
||||
* ``-k -foobar`` syntax - use ``-k 'not foobar'`` instead.
|
||||
|
||||
* ``-k foobar:`` syntax.
|
||||
|
||||
* ``pytest.collect`` module - import from ``pytest`` directly.
|
||||
|
||||
For more information consult
|
||||
`Deprecations and Removals <https://docs.pytest.org/en/latest/deprecations.html>`__ in the docs.
|
||||
@@ -1 +0,0 @@
|
||||
Pytest will now avoid specialized assert formatting when it is detected that the default __eq__ is overridden
|
||||
@@ -1 +0,0 @@
|
||||
Fixed error message prints function decorators when using assert in Python 3.8 and above.
|
||||
@@ -1 +0,0 @@
|
||||
Ensure :attr:`pytest.Config.inifile` is available during the :func:`pytest_cmdline_main <_pytest.hookspec.pytest_cmdline_main>` hook (regression during ``7.0.0rc1``).
|
||||
@@ -1 +0,0 @@
|
||||
Added extra documentation on alternatives to common misuses of `pytest.warns(None)` ahead of its deprecation.
|
||||
@@ -1 +0,0 @@
|
||||
Dropped support for Python 3.6, which reached `end-of-life <https://devguide.python.org/#status-of-python-branches>`__ at 2021-12-23.
|
||||
@@ -1,10 +0,0 @@
|
||||
Symbolic link components are no longer resolved in conftest paths.
|
||||
This means that if a conftest appears twice in collection tree, using symlinks, it will be executed twice.
|
||||
For example, given
|
||||
|
||||
tests/real/conftest.py
|
||||
tests/real/test_it.py
|
||||
tests/link -> tests/real
|
||||
|
||||
running ``pytest tests`` now imports the conftest twice, once as ``tests/real/conftest.py`` and once as ``tests/link/conftest.py``.
|
||||
This is a fix to match a similar change made to test collection itself in pytest 6.0 (see :pull:`6523` for details).
|
||||
@@ -1,2 +0,0 @@
|
||||
Clarify where the configuration files are located. To avoid confusions documentation mentions
|
||||
that configuration file is located in the root of the repository.
|
||||
@@ -1,9 +0,0 @@
|
||||
Fixture types are now exported so the may be used in pytest plugin hooks.
|
||||
|
||||
The newly-exported types are:
|
||||
|
||||
- ``pytest.FixtureDef`` for :class:`FixtureDef <pytest.FixtureDef>`
|
||||
- ``pytest.SubRequest`` for ``_pytest.fixtures.SubRequest`` (derived from :class:`FixtureRequest <pytest.FixtureRequest`).
|
||||
|
||||
|
||||
They are used by ``pytest_fixture_setup`` and ``pytest_fixture_post_finalizer`` hook definitions.
|
||||
@@ -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,15 +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
|
||||
release-6.2.0
|
||||
release-6.1.2
|
||||
release-6.1.1
|
||||
release-6.1.0
|
||||
release-6.0.2
|
||||
release-6.0.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
|
||||
|
||||
@@ -11,7 +11,7 @@ clear information about the circumstances and a simple example which
|
||||
reproduces the problem.
|
||||
|
||||
The issue tracker is of course not empty now. We have many remaining
|
||||
"enhancement" issues which we'll hopefully can tackle in 2014 with your
|
||||
"enhacement" issues which we'll hopefully can tackle in 2014 with your
|
||||
help.
|
||||
|
||||
For those who use older Python versions, please note that pytest is not
|
||||
|
||||
@@ -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,18 +0,0 @@
|
||||
pytest-6.1.1
|
||||
=======================================
|
||||
|
||||
pytest 6.1.1 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Ran Benita
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -1,22 +0,0 @@
|
||||
pytest-6.1.2
|
||||
=======================================
|
||||
|
||||
pytest 6.1.2 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Bruno Oliveira
|
||||
* Manuel Mariñez
|
||||
* Ran Benita
|
||||
* Vasilis Gerakaris
|
||||
* William Jamir Silva
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -1,76 +0,0 @@
|
||||
pytest-6.2.0
|
||||
=======================================
|
||||
|
||||
The pytest team is proud to announce the 6.2.0 release!
|
||||
|
||||
This release contains new features, improvements, bug fixes, and breaking changes, so users
|
||||
are encouraged to take a look at the CHANGELOG carefully:
|
||||
|
||||
https://docs.pytest.org/en/stable/changelog.html
|
||||
|
||||
For complete documentation, please visit:
|
||||
|
||||
https://docs.pytest.org/en/stable/
|
||||
|
||||
As usual, you can upgrade from PyPI via:
|
||||
|
||||
pip install -U pytest
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Adam Johnson
|
||||
* Albert Villanova del Moral
|
||||
* Anthony Sottile
|
||||
* Anton
|
||||
* Ariel Pillemer
|
||||
* Bruno Oliveira
|
||||
* Charles Aracil
|
||||
* Christine M
|
||||
* Christine Mecklenborg
|
||||
* Cserna Zsolt
|
||||
* Dominic Mortlock
|
||||
* Emiel van de Laar
|
||||
* Florian Bruhin
|
||||
* Garvit Shubham
|
||||
* Gustavo Camargo
|
||||
* Hugo Martins
|
||||
* Hugo van Kemenade
|
||||
* Jakob van Santen
|
||||
* Josias Aurel
|
||||
* Jürgen Gmach
|
||||
* Karthikeyan Singaravelan
|
||||
* Katarzyna
|
||||
* Kyle Altendorf
|
||||
* Manuel Mariñez
|
||||
* Matthew Hughes
|
||||
* Matthias Gabriel
|
||||
* Max Voitko
|
||||
* Maximilian Cosmo Sitter
|
||||
* Mikhail Fesenko
|
||||
* Nimesh Vashistha
|
||||
* Pedro Algarvio
|
||||
* Petter Strandmark
|
||||
* Prakhar Gurunani
|
||||
* Prashant Sharma
|
||||
* Ran Benita
|
||||
* Ronny Pfannschmidt
|
||||
* Sanket Duthade
|
||||
* Shubham Adep
|
||||
* Simon K
|
||||
* Tanvi Mehta
|
||||
* Thomas Grainger
|
||||
* Tim Hoffmann
|
||||
* Vasilis Gerakaris
|
||||
* William Jamir Silva
|
||||
* Zac Hatfield-Dodds
|
||||
* crricks
|
||||
* dependabot[bot]
|
||||
* duthades
|
||||
* frankgerhardt
|
||||
* kwgchi
|
||||
* mickeypash
|
||||
* symonk
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -1,20 +0,0 @@
|
||||
pytest-6.2.1
|
||||
=======================================
|
||||
|
||||
pytest 6.2.1 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Bruno Oliveira
|
||||
* Jakob van Santen
|
||||
* Ran Benita
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -1,21 +0,0 @@
|
||||
pytest-6.2.2
|
||||
=======================================
|
||||
|
||||
pytest 6.2.2 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Adam Johnson
|
||||
* Bruno Oliveira
|
||||
* Chris NeJame
|
||||
* Ran Benita
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -1,19 +0,0 @@
|
||||
pytest-6.2.3
|
||||
=======================================
|
||||
|
||||
pytest 6.2.3 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Bruno Oliveira
|
||||
* Ran Benita
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -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/7.0.x/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%]
|
||||
@@ -71,7 +74,7 @@ Assertions about expected exceptions
|
||||
------------------------------------------
|
||||
|
||||
In order to write assertions about raised exceptions, you can use
|
||||
:func:`pytest.raises` as a context manager like this:
|
||||
``pytest.raises`` as a context manager like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -120,7 +123,7 @@ The regexp parameter of the ``match`` method is matched with the ``re.search``
|
||||
function, so in the above example ``match='123'`` would have worked as
|
||||
well.
|
||||
|
||||
There's an alternate form of the :func:`pytest.raises` function where you pass
|
||||
There's an alternate form of the ``pytest.raises`` function where you pass
|
||||
a function that will be executed with the given ``*args`` and ``**kwargs`` and
|
||||
assert that the given exception is raised:
|
||||
|
||||
@@ -141,8 +144,8 @@ specific way than just having any exception raised:
|
||||
def test_f():
|
||||
f()
|
||||
|
||||
Using :func:`pytest.raises` is likely to be better for cases where you are
|
||||
testing exceptions your own code is deliberately raising, whereas using
|
||||
Using ``pytest.raises`` is likely to be better for cases where you are testing
|
||||
exceptions your own code is deliberately raising, whereas using
|
||||
``@pytest.mark.xfail`` with a check function is probably better for something
|
||||
like documenting unfixed bugs (where the test describes what "should" happen)
|
||||
or bugs in dependencies.
|
||||
@@ -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>`_.
|
||||
@@ -10,7 +10,7 @@ we keep learning about new and better structures to express different details ab
|
||||
|
||||
While we implement those modifications we try to ensure an easy transition and don't want to impose unnecessary churn on our users and community/plugin authors.
|
||||
|
||||
As of now, pytest considers multiple types of backward compatibility transitions:
|
||||
As of now, pytest considers multipe types of backward compatibility transitions:
|
||||
|
||||
a) trivial: APIs which trivially translate to the new mechanism,
|
||||
and do not cause problematic changes.
|
||||
@@ -22,29 +22,27 @@ 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.
|
||||
c) true breakage: should only to be considered when normal transition is unreasonably unsustainable and would offset important development/features by years.
|
||||
In addition, they should be limited to APIs where the number of actual users is very small (for example only impacting some plugins), and can be coordinated with the community in advance.
|
||||
|
||||
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.
|
||||
|
||||
This POC serves as both a coordination point to assess impact and potential inspiration to come up with a transitional solution after all.
|
||||
This POC serves as both a coordination point to assess impact and potential inspriation to come up with a transitional solution after all.
|
||||
|
||||
After a reasonable amount of time the PR can be merged to base a new major release.
|
||||
|
||||
@@ -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,29 +141,40 @@ 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.
|
||||
|
||||
The returned object is a :class:`pathlib.Path` object.
|
||||
|
||||
.. note::
|
||||
|
||||
========================== no tests ran in 0.12s ===========================
|
||||
In python < 3.6 this is a pathlib2.Path.
|
||||
|
||||
|
||||
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 ========================
|
||||
3927
doc/en/changelog.rst
@@ -15,15 +15,11 @@
|
||||
#
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
# 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
|
||||
|
||||
from _pytest import __version__ as version
|
||||
from _pytest.compat import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import sphinx.application
|
||||
@@ -37,26 +33,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 +47,6 @@ extensions = [
|
||||
"pygments_pytest",
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.autosummary",
|
||||
"sphinx.ext.extlinks",
|
||||
"sphinx.ext.intersphinx",
|
||||
"sphinx.ext.todo",
|
||||
"sphinx.ext.viewcode",
|
||||
@@ -77,13 +54,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 +68,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 +120,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 +131,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 +157,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 +249,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 +290,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 +345,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),
|
||||
}
|
||||
|
||||
|
||||
@@ -445,34 +397,4 @@ def setup(app: "sphinx.application.Sphinx") -> None:
|
||||
indextemplate="pair: %s; global variable interpreted by pytest",
|
||||
)
|
||||
|
||||
app.add_crossref_type(
|
||||
directivename="hook",
|
||||
rolename="hook",
|
||||
objname="pytest hook",
|
||||
indextemplate="pair: %s; hook",
|
||||
)
|
||||
|
||||
configure_logging(app)
|
||||
|
||||
# Make Sphinx mark classes with "final" when decorated with @final.
|
||||
# We need this because we import final from pytest._compat, not from
|
||||
# typing (for Python < 3.8 compat), so Sphinx doesn't detect it.
|
||||
# To keep things simple we accept any `@final` decorator.
|
||||
# Ref: https://github.com/pytest-dev/pytest/pull/7780
|
||||
import sphinx.pycode.ast
|
||||
import sphinx.pycode.parser
|
||||
|
||||
original_is_final = sphinx.pycode.parser.VariableCommentPicker.is_final
|
||||
|
||||
def patched_is_final(self, decorators: List[ast.expr]) -> bool:
|
||||
if original_is_final(self, decorators):
|
||||
return True
|
||||
return any(
|
||||
sphinx.pycode.ast.unparse(decorator) == "final" for decorator in decorators
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
@@ -20,7 +20,8 @@ Configuration file formats
|
||||
--------------------------
|
||||
|
||||
Many :ref:`pytest settings <ini options ref>` can be set in a *configuration file*, which
|
||||
by convention resides in the root directory of your repository.
|
||||
by convention resides on the root of your repository or in your
|
||||
tests folder.
|
||||
|
||||
A quick example of the configuration files supported by pytest:
|
||||
|
||||
@@ -88,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
|
||||
@@ -144,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.
|
||||
@@ -161,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.
|
||||
|
||||
@@ -178,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
|
||||
@@ -225,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.
|
||||
|
||||
@@ -238,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,274 +18,30 @@ 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:
|
||||
|
||||
* :hook:`pytest_ignore_collect(collection_path: pathlib.Path) <pytest_ignore_collect>` as equivalent to ``path``
|
||||
* :hook:`pytest_collect_file(file_path: pathlib.Path) <pytest_collect_file>` as equivalent to ``path``
|
||||
* :hook:`pytest_pycollect_makemodule(module_path: pathlib.Path) <pytest_pycollect_makemodule>` as equivalent to ``path``
|
||||
* :hook:`pytest_report_header(start_path: pathlib.Path) <pytest_report_header>` as equivalent to ``startdir``
|
||||
* :hook:`pytest_report_collectionfinish(start_path: pathlib.Path) <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 :hook:`pytest_cmdline_preparse` hook has been officially deprecated.
|
||||
Implement the :hook:`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 it was frequently misused.
|
||||
Its correct usage was checking that the code emits at least one warning of any type - like ``pytest.warns()``
|
||||
or ``pytest.warns(Warning)``.
|
||||
|
||||
See :ref:`warns use cases` for examples.
|
||||
|
||||
The ``--strict`` command-line option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 6.2
|
||||
|
||||
The ``--strict`` command-line option has been deprecated in favor of ``--strict-markers``, which
|
||||
better conveys what the option does.
|
||||
|
||||
We have plans to maybe in the future to reintroduce ``--strict`` and make it an encompassing
|
||||
flag for all strictness related options (``--strict-markers`` and ``--strict-config``
|
||||
at the moment, more might be introduced in the future).
|
||||
|
||||
|
||||
The ``yield_fixture`` function/decorator
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 6.2
|
||||
|
||||
``pytest.yield_fixture`` is a deprecated alias for :func:`pytest.fixture`.
|
||||
|
||||
It has been so for a very long time, so can be search/replaced safely.
|
||||
|
||||
|
||||
Removed Features
|
||||
----------------
|
||||
|
||||
As stated in our :ref:`backwards-compatibility` policy, deprecated features are removed only in major releases after
|
||||
an appropriate period of deprecation has passed.
|
||||
|
||||
|
||||
The ``pytest.collect`` module
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 6.0
|
||||
.. versionremoved:: 7.0
|
||||
|
||||
The ``pytest.collect`` module is no longer part of the public API, all its names
|
||||
should now be imported from ``pytest`` directly instead.
|
||||
|
||||
|
||||
|
||||
The ``pytest_warning_captured`` hook
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 6.0
|
||||
.. versionremoved:: 7.0
|
||||
|
||||
This hook has an `item` parameter which cannot be serialized by ``pytest-xdist``.
|
||||
|
||||
Use the ``pytest_warning_recored`` hook instead, which replaces the ``item`` parameter
|
||||
by a ``nodeid`` parameter.
|
||||
|
||||
The ``pytest.collect`` module
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 6.0
|
||||
|
||||
The ``pytest.collect`` module is no longer part of the public API, all its names
|
||||
should now be imported from ``pytest`` directly instead.
|
||||
|
||||
|
||||
The ``pytest._fillfuncargs`` function
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 6.0
|
||||
.. versionremoved:: 7.0
|
||||
|
||||
This function was kept for backward compatibility with an older plugin.
|
||||
|
||||
@@ -294,6 +50,12 @@ it, use `function._request._fillfixtures()` instead, though note this is not
|
||||
a public API and may break in the future.
|
||||
|
||||
|
||||
Removed Features
|
||||
----------------
|
||||
|
||||
As stated in our :ref:`backwards-compatibility` policy, deprecated features are removed only in major releases after
|
||||
an appropriate period of deprecation has passed.
|
||||
|
||||
``--no-print-logs`` command-line option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -308,7 +70,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``)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -331,8 +92,8 @@ at some point, depending on the plans for the plugins and number of users using
|
||||
|
||||
.. versionremoved:: 6.0
|
||||
|
||||
The ``pytest_collect_directory`` hook has not worked properly for years (it was called
|
||||
but the results were ignored). Users may consider using :hook:`pytest_collection_modifyitems` instead.
|
||||
The ``pytest_collect_directory`` has not worked properly for years (it was called
|
||||
but the results were ignored). Users may consider using :func:`pytest_collection_modifyitems <_pytest.hookspec.pytest_collection_modifyitems>` instead.
|
||||
|
||||
TerminalReporter.writer
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -346,8 +107,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"
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -435,8 +194,6 @@ in places where we or plugin authors must distinguish between fixture names and
|
||||
names supplied by non-fixture things such as ``pytest.mark.parametrize``.
|
||||
|
||||
|
||||
.. _pytest.config global deprecated:
|
||||
|
||||
``pytest.config`` global
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -481,7 +238,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:
|
||||
@@ -534,8 +291,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``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -584,8 +339,6 @@ To update the code, use ``pytest.param``:
|
||||
...
|
||||
|
||||
|
||||
.. _pytest_funcarg__ prefix deprecated:
|
||||
|
||||
``pytest_funcarg__`` prefix
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -617,15 +370,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:
|
||||
|
||||
@@ -643,8 +394,6 @@ Becomes:
|
||||
metafunc.parametrize("i", [1, 2], ids=["1", "2"])
|
||||
|
||||
|
||||
.. _cached_setup deprecated:
|
||||
|
||||
``cached_setup``
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -673,12 +422,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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -689,8 +436,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``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -718,8 +463,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
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -743,8 +486,6 @@ Change to:
|
||||
...
|
||||
|
||||
|
||||
.. _passing command-line string to pytest.main deprecated:
|
||||
|
||||
Passing command-line string to ``pytest.main()``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -767,8 +508,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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -822,8 +561,6 @@ with the ``name`` parameter:
|
||||
return cell()
|
||||
|
||||
|
||||
.. _yield tests deprecated:
|
||||
|
||||
``yield`` tests
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -852,8 +589,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``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -888,8 +623,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
|
||||
By default all files matching the ``test*.txt`` pattern will
|
||||
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%]
|
||||
@@ -76,6 +77,15 @@ putting them into a pytest.ini file like this:
|
||||
[pytest]
|
||||
addopts = --doctest-modules
|
||||
|
||||
.. note::
|
||||
|
||||
The builtin pytest doctest supports only ``doctest`` blocks, but if you are looking
|
||||
for more advanced checking over *all* your documentation,
|
||||
including doctests, ``.. codeblock:: python`` Sphinx directive support,
|
||||
and any other examples your documentation may include, you may wish to
|
||||
consider `Sybil <https://sybil.readthedocs.io/en/latest/index.html>`__.
|
||||
It provides pytest integration out of the box.
|
||||
|
||||
|
||||
Encoding
|
||||
--------
|
||||
@@ -90,12 +100,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.
|
||||
|
||||
@@ -105,7 +113,7 @@ lengthy exception stack traces you can just write:
|
||||
.. code-block:: ini
|
||||
|
||||
[pytest]
|
||||
doctest_optionflags = NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL
|
||||
doctest_optionflags= NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL
|
||||
|
||||
Alternatively, options can be enabled by an inline comment in the doc test
|
||||
itself:
|
||||
@@ -194,11 +202,11 @@ It is possible to use fixtures using the ``getfixture`` helper:
|
||||
.. code-block:: text
|
||||
|
||||
# content of example.rst
|
||||
>>> tmp = getfixture('tmp_path')
|
||||
>>> tmp = getfixture('tmpdir')
|
||||
>>> ...
|
||||
>>>
|
||||
|
||||
Note that the fixture needs to be defined in a place visible by pytest, for example, a `conftest.py`
|
||||
Note that the fixture needs to be defined in a place visible by pytest, for example a `conftest.py`
|
||||
file or plugin; normal python files containing docstrings are not normally scanned for fixtures
|
||||
unless explicitly configured by :confval:`python_files`.
|
||||
|
||||
@@ -245,32 +253,12 @@ Note that like the normal ``conftest.py``, the fixtures are discovered in the di
|
||||
Meaning that if you put your doctest with your source code, the relevant conftest.py needs to be in the same directory tree.
|
||||
Fixtures will not be discovered in a sibling directory tree!
|
||||
|
||||
Skipping tests
|
||||
^^^^^^^^^^^^^^
|
||||
Skipping tests dynamically
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For the same reasons one might want to skip normal tests, it is also possible to skip
|
||||
tests inside doctests.
|
||||
|
||||
To skip a single check inside a doctest you can use the standard
|
||||
:data:`doctest.SKIP` directive:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def test_random(y):
|
||||
"""
|
||||
>>> random.random() # doctest: +SKIP
|
||||
0.156231223
|
||||
|
||||
>>> 1 + 1
|
||||
2
|
||||
"""
|
||||
|
||||
This will skip the first check, but not the second.
|
||||
|
||||
pytest also allows using the standard pytest functions :func:`pytest.skip` and
|
||||
:func:`pytest.xfail` inside doctests, which might be useful because you can
|
||||
then skip/xfail tests based on external conditions:
|
||||
.. versionadded:: 4.4
|
||||
|
||||
You can use ``pytest.skip`` to dynamically skip doctests. For example:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
@@ -278,35 +266,3 @@ then skip/xfail tests based on external conditions:
|
||||
>>> if sys.platform.startswith('win'):
|
||||
... pytest.skip('this doctest does not work on Windows')
|
||||
...
|
||||
>>> import fcntl
|
||||
>>> ...
|
||||
|
||||
However using those functions is discouraged because it reduces the readability of the
|
||||
docstring.
|
||||
|
||||
.. note::
|
||||
|
||||
:func:`pytest.skip` and :func:`pytest.xfail` behave differently depending
|
||||
if the doctests are in a Python file (in docstrings) or a text file containing
|
||||
doctests intermingled with text:
|
||||
|
||||
* Python modules (docstrings): the functions only act in that specific docstring,
|
||||
letting the other docstrings in the same module execute as normal.
|
||||
|
||||
* Text files: the functions will skip/xfail the checks for the rest of the entire
|
||||
file.
|
||||
|
||||
|
||||
Alternatives
|
||||
------------
|
||||
|
||||
While the built-in pytest support provides a good set of functionalities for using
|
||||
doctests, if you use them extensively you might be interested in those external packages
|
||||
which add many more features, and include pytest integration:
|
||||
|
||||
* `pytest-doctestplus <https://github.com/astropy/pytest-doctestplus>`__: provides
|
||||
advanced doctest support and enables the testing of reStructuredText (".rst") files.
|
||||
|
||||
* `Sybil <https://sybil.readthedocs.io>`__: provides a way to test examples in
|
||||
your documentation by parsing them from the documentation source and evaluating
|
||||
the parsed examples as part of your normal test run.
|
||||
@@ -176,7 +176,7 @@ class TestRaises:
|
||||
|
||||
def test_reinterpret_fails_with_print_for_the_fun_of_it(self):
|
||||
items = [1, 2, 3]
|
||||
print(f"items is {items!r}")
|
||||
print("items is {!r}".format(items))
|
||||
a, b = items.pop()
|
||||
|
||||
def test_some_error(self):
|
||||
|
||||
@@ -11,4 +11,4 @@ def pytest_runtest_setup(item):
|
||||
return
|
||||
mod = item.getparent(pytest.Module).obj
|
||||
if hasattr(mod, "hello"):
|
||||
print(f"mod.hello {mod.hello!r}")
|
||||
print("mod.hello {!r}".format(mod.hello))
|
||||
|
||||
@@ -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,132 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="572" height="542">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class, circle.module, circle.package {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class, text.module, text.package {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
line, path {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- main scope -->
|
||||
<circle class="package" r="270" cx="286" cy="271" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 26,271 A 260 260 0 0 1 546 271" id="testp"/>
|
||||
</defs>
|
||||
<text class="package">
|
||||
<textPath xlink:href="#testp" startOffset="50%">tests</textPath>
|
||||
</text>
|
||||
|
||||
<!-- subpackage -->
|
||||
<circle class="package" r="140" cx="186" cy="271" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 56,271 A 130 130 0 0 1 316 271" id="subpackage"/>
|
||||
</defs>
|
||||
<text class="package">
|
||||
<textPath xlink:href="#subpackage" startOffset="50%">subpackage</textPath>
|
||||
</text>
|
||||
|
||||
<!-- test_subpackage.py -->
|
||||
<circle class="module" r="90" cx="186" cy="311" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 106,311 A 80 80 0 0 1 266 311" id="testSubpackage"/>
|
||||
</defs>
|
||||
<text class="module">
|
||||
<textPath xlink:href="#testSubpackage" startOffset="50%">test_subpackage.py</textPath>
|
||||
</text>
|
||||
<!-- innermost -->
|
||||
<line x1="186" x2="186" y1="271" y2="351"/>
|
||||
<!-- mid -->
|
||||
<path d="M 186 351 L 136 351 L 106 331 L 106 196" />
|
||||
<!-- order -->
|
||||
<path d="M 186 351 L 256 351 L 316 291 L 316 136" />
|
||||
<!-- top -->
|
||||
<path d="M 186 351 L 186 391 L 231 436 L 331 436" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="186" cy="271" />
|
||||
<text x="186" y="271">innermost</text>
|
||||
<rect class="test" width="110" height="50" x="131" y="326" />
|
||||
<text x="186" y="351">test_order</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="126" cy="196" />
|
||||
<text x="126" y="196">mid</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testSubpackageOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="90" cx="186" cy="311" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="96" cy="311" mask="url(#testSubpackageOrderMask)"/>
|
||||
<text class="module" x="96" y="311">1</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="subpackageOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="140" cx="186" cy="271" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="46" cy="271" mask="url(#subpackageOrderMask)"/>
|
||||
<text class="module" x="46" y="271">2</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testsOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="270" cx="286" cy="271" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="16" cy="271" mask="url(#testsOrderMask)"/>
|
||||
<text class="module" x="16" y="271">3</text>
|
||||
|
||||
<!-- test_top.py -->
|
||||
<circle class="module" r="85" cx="441" cy="271" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 366,271 A 75 75 0 0 1 516 271" id="testTop"/>
|
||||
</defs>
|
||||
<text class="module">
|
||||
<textPath xlink:href="#testTop" startOffset="50%">test_top.py</textPath>
|
||||
</text>
|
||||
<!-- innermost -->
|
||||
<line x1="441" x2="441" y1="306" y2="236"/>
|
||||
<!-- order -->
|
||||
<path d="M 441 306 L 376 306 L 346 276 L 346 136" />
|
||||
<!-- top -->
|
||||
<path d="M 441 306 L 441 411 L 411 436 L 331 436" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="441" cy="236" />
|
||||
<text x="441" y="236">innermost</text>
|
||||
<rect class="test" width="110" height="50" x="386" y="281" />
|
||||
<text x="441" y="306">test_order</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testTopOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="85" cx="441" cy="271" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="526" cy="271" mask="url(#testTopOrderMask)"/>
|
||||
<text class="module" x="526" y="271">1</text>
|
||||
<!-- scope order number -->
|
||||
<circle class="module" r="15" cx="556" cy="271" mask="url(#testsOrderMask)"/>
|
||||
<text class="module" x="556" y="271">2</text>
|
||||
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="331" cy="436" />
|
||||
<text x="331" y="436">top</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="331" cy="136" />
|
||||
<text x="331" y="136">order</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.0 KiB |
@@ -1,142 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="587" height="382">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
alignment-baseline: center;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class, circle.module, circle.package, circle.plugin {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class, text.module, text.package, text.plugin {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
line, path {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- plugin_a.py scope -->
|
||||
<circle class="plugin" r="85" cx="486" cy="86" />
|
||||
<!-- plugin name -->
|
||||
<defs>
|
||||
<path d="M 411,86 A 75 75 0 0 1 561 86" id="pluginA"/>
|
||||
</defs>
|
||||
<text class="plugin">
|
||||
<textPath xlink:href="#pluginA" startOffset="50%">plugin_a</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="pluginAOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="85" cx="486" cy="86" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="571" cy="86" mask="url(#pluginAOrderMask)"/>
|
||||
<text class="module" x="571" y="86">4</text>
|
||||
|
||||
<!-- plugin_b.py scope -->
|
||||
<circle class="plugin" r="85" cx="486" cy="296" />
|
||||
<!-- plugin name -->
|
||||
<defs>
|
||||
<path d="M 411,296 A 75 75 0 0 1 561 296" id="pluginB"/>
|
||||
</defs>
|
||||
<text class="plugin">
|
||||
<textPath xlink:href="#pluginB" startOffset="50%">plugin_b</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="pluginBOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="85" cx="486" cy="296" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="571" cy="296" mask="url(#pluginBOrderMask)"/>
|
||||
<text class="module" x="571" y="296">4</text>
|
||||
|
||||
<!-- main scope -->
|
||||
<circle class="package" r="190" cx="191" cy="191" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 11,191 A 180 180 0 0 1 371 191" id="testp"/>
|
||||
</defs>
|
||||
<text class="package">
|
||||
<textPath xlink:href="#testp" startOffset="50%">tests</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="mainOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="190" cx="191" cy="191" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="381" cy="191" mask="url(#mainOrderMask)"/>
|
||||
<text class="module" x="381" y="191">3</text>
|
||||
|
||||
<!-- subpackage -->
|
||||
<circle class="package" r="140" cx="191" cy="231" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 61,231 A 130 130 0 0 1 321 231" id="subpackage"/>
|
||||
</defs>
|
||||
<text class="package">
|
||||
<textPath xlink:href="#subpackage" startOffset="50%">subpackage</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="subpackageOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="140" cx="191" cy="231" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="331" cy="231" mask="url(#subpackageOrderMask)"/>
|
||||
<text class="module" x="331" y="231">2</text>
|
||||
|
||||
<!-- test_subpackage.py -->
|
||||
<circle class="module" r="90" cx="191" cy="271" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 111,271 A 80 80 0 0 1 271 271" id="testSubpackage"/>
|
||||
</defs>
|
||||
<text class="module">
|
||||
<textPath xlink:href="#testSubpackage" startOffset="50%">test_subpackage.py</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testSubpackageOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="90" cx="191" cy="271" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="281" cy="271" mask="url(#testSubpackageOrderMask)"/>
|
||||
<text class="module" x="281" y="271">1</text>
|
||||
|
||||
<!-- innermost -->
|
||||
<line x1="191" x2="191" y1="231" y2="311"/>
|
||||
<!-- mid -->
|
||||
<path d="M 191 306 L 101 306 L 91 296 L 91 156 L 101 146 L 191 146" />
|
||||
<!-- order -->
|
||||
<path d="M 191 316 L 91 316 L 81 306 L 81 61 L 91 51 L 191 51" />
|
||||
<!-- a_fix -->
|
||||
<path d="M 191 306 L 291 306 L 301 296 L 301 96 L 311 86 L 486 86" />
|
||||
<!-- b_fix -->
|
||||
<path d="M 191 316 L 316 316 L 336 296 L 486 296" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="191" cy="231" />
|
||||
<text x="191" y="231">inner</text>
|
||||
<rect class="test" width="110" height="50" x="136" y="286" />
|
||||
<text x="191" y="311">test_order</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="191" cy="146" />
|
||||
<text x="191" y="146">mid</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="191" cy="51" />
|
||||
<text x="191" y="51">order</text>
|
||||
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="486" cy="86" />
|
||||
<text x="486" y="86">a_fix</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="486" cy="296" />
|
||||
<text x="486" y="296">b_fix</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.4 KiB |
38
doc/en/example/fixtures/test_fixtures_order.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import pytest
|
||||
|
||||
# fixtures documentation order example
|
||||
order = []
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def s1():
|
||||
order.append("s1")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def m1():
|
||||
order.append("m1")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def f1(f3):
|
||||
order.append("f1")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def f3():
|
||||
order.append("f3")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def a1():
|
||||
order.append("a1")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def f2():
|
||||
order.append("f2")
|
||||
|
||||
|
||||
def test_order(f1, m1, f2, s1):
|
||||
assert order == ["s1", "m1", "a1", "f3", "f1", "f2"]
|
||||
@@ -1,45 +0,0 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def order():
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def a(order):
|
||||
order.append("a")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def b(a, order):
|
||||
order.append("b")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def c(b, order):
|
||||
order.append("c")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def d(b, order):
|
||||
order.append("d")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def e(d, order):
|
||||
order.append("e")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def f(e, order):
|
||||
order.append("f")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def g(f, c, order):
|
||||
order.append("g")
|
||||
|
||||
|
||||
def test_order_and_g(g, order):
|
||||
assert order == ["a", "b", "c", "d", "e", "f", "g"]
|
||||
@@ -1,64 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="252" height="682">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
path, line {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
rect.autouse {
|
||||
fill: #ca7f3d;
|
||||
}
|
||||
</style>
|
||||
<path d="M126,586 L26,506 L26,236" />
|
||||
<path d="M226,446 L226,236 L126,166" />
|
||||
<line x1="126" x2="126" y1="656" y2="516" />
|
||||
<line x1="126" x2="226" y1="516" y2="446" />
|
||||
<line x1="226" x2="126" y1="446" y2="376" />
|
||||
<line x1="126" x2="126" y1="376" y2="166" />
|
||||
<line x1="26" x2="126" y1="236" y2="166" />
|
||||
<line x1="126" x2="126" y1="166" y2="26" />
|
||||
<line x1="126" x2="126" y1="96" y2="26" />
|
||||
<rect class="autouse" width="251" height="40" x="0" y="286" />
|
||||
<text x="126" y="306">autouse</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="126" cy="26" />
|
||||
<text x="126" y="26">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="96" />
|
||||
<text x="126" y="96">a</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="166" />
|
||||
<text x="126" y="166">b</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="26" cy="236" />
|
||||
<text x="26" y="236">c</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="376" />
|
||||
<text x="126" y="376">d</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="446" />
|
||||
<text x="226" y="446">e</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="516" />
|
||||
<text x="126" y="516">f</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="586" />
|
||||
<text x="126" y="586">g</text>
|
||||
<rect class="test" width="110" height="50" x="71" y="631" />
|
||||
<text x="126" y="656">test_order</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -1,31 +0,0 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def order():
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture(scope="class", autouse=True)
|
||||
def c1(order):
|
||||
order.append("c1")
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def c2(order):
|
||||
order.append("c2")
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def c3(order, c1):
|
||||
order.append("c3")
|
||||
|
||||
|
||||
class TestClassWithC1Request:
|
||||
def test_order(self, order, c1, c3):
|
||||
assert order == ["c1", "c3"]
|
||||
|
||||
|
||||
class TestClassWithoutC1Request:
|
||||
def test_order(self, order, c2):
|
||||
assert order == ["c1", "c2"]
|
||||
@@ -1,76 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="862" height="402">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
line {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
}
|
||||
rect.autouse {
|
||||
fill: #ca7f3d;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- TestWithC1Request -->
|
||||
<circle class="class" r="200" cx="221" cy="201" />
|
||||
<line x1="221" x2="221" y1="61" y2="316"/>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="221" cy="61" />
|
||||
<text x="221" y="61">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="221" cy="131" />
|
||||
<text x="221" y="131">c1</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="221" cy="271" />
|
||||
<text x="221" y="271">c3</text>
|
||||
<rect class="test" width="110" height="50" x="166" y="316" />
|
||||
<text x="221" y="341">test_order</text>
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M31,201 A 190 190 0 0 1 411 201" id="testClassWith"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath xlink:href="#testClassWith" startOffset="50%">TestWithC1Request</textPath>
|
||||
</text>
|
||||
|
||||
<!-- TestWithoutC1Request -->
|
||||
<circle class="class" r="200" cx="641" cy="201" />
|
||||
<line x1="641" x2="641" y1="61" y2="316"/>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="641" cy="61" />
|
||||
<text x="641" y="61">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="641" cy="131" />
|
||||
<text x="641" y="131">c1</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="641" cy="271" />
|
||||
<text x="641" y="271">c2</text>
|
||||
<rect class="test" width="110" height="50" x="586" y="316" />
|
||||
<text x="641" y="341">test_order</text>
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M451,201 A 190 190 0 0 1 831 201" id="testClassWithout"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath xlink:href="#testClassWithout" startOffset="50%">TestWithoutC1Request</textPath>
|
||||
</text>
|
||||
|
||||
<rect class="autouse" width="862" height="40" x="1" y="181" />
|
||||
<rect width="10" height="100" class="autouse" x="426" y="151" />
|
||||
<text x="431" y="201">autouse</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.6 KiB |
@@ -1,36 +0,0 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def order():
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def c1(order):
|
||||
order.append("c1")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def c2(order):
|
||||
order.append("c2")
|
||||
|
||||
|
||||
class TestClassWithAutouse:
|
||||
@pytest.fixture(autouse=True)
|
||||
def c3(self, order, c2):
|
||||
order.append("c3")
|
||||
|
||||
def test_req(self, order, c1):
|
||||
assert order == ["c2", "c3", "c1"]
|
||||
|
||||
def test_no_req(self, order):
|
||||
assert order == ["c2", "c3"]
|
||||
|
||||
|
||||
class TestClassWithoutAutouse:
|
||||
def test_req(self, order, c1):
|
||||
assert order == ["c1"]
|
||||
|
||||
def test_no_req(self, order):
|
||||
assert order == []
|
||||
@@ -1,100 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="862" height="502">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
line {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
}
|
||||
rect.autouse {
|
||||
fill: #ca7f3d;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- TestWithAutouse -->
|
||||
<circle class="class" r="250" cx="251" cy="251" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M11,251 A 240 240 0 0 1 491 251" id="testClassWith"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath xlink:href="#testClassWith" startOffset="50%">TestWithAutouse</textPath>
|
||||
</text>
|
||||
<mask id="autouseScope">
|
||||
<circle fill="white" r="249" cx="251" cy="251" />
|
||||
</mask>
|
||||
|
||||
<!-- TestWithAutouse.test_req -->
|
||||
<line x1="176" x2="176" y1="76" y2="426"/>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="176" cy="76" />
|
||||
<text x="176" y="76">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="176" cy="146" />
|
||||
<text x="176" y="146">c2</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="176" cy="216" />
|
||||
<text x="176" y="216">c3</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="176" cy="356" />
|
||||
<text x="176" y="356">c1</text>
|
||||
<rect class="test" width="100" height="50" x="126" y="401" />
|
||||
<text x="176" y="426">test_req</text>
|
||||
|
||||
<!-- TestWithAutouse.test_no_req -->
|
||||
<line x1="326" x2="326" y1="76" y2="346"/>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="326" cy="76" />
|
||||
<text x="326" y="76">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="326" cy="146" />
|
||||
<text x="326" y="146">c2</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="326" cy="216" />
|
||||
<text x="326" y="216">c3</text>
|
||||
<rect class="test" width="120" height="50" x="266" y="331" />
|
||||
<text x="326" y="356">test_no_req</text>
|
||||
|
||||
<rect class="autouse" width="500" height="40" x="1" y="266" mask="url(#autouseScope)"/>
|
||||
<text x="261" y="286">autouse</text>
|
||||
|
||||
<!-- TestWithoutAutouse -->
|
||||
<circle class="class" r="170" cx="691" cy="251" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 531,251 A 160 160 0 0 1 851 251" id="testClassWithout"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath xlink:href="#testClassWithout" startOffset="50%">TestWithoutAutouse</textPath>
|
||||
</text>
|
||||
|
||||
<!-- TestWithoutAutouse.test_req -->
|
||||
<line x1="616" x2="616" y1="181" y2="321"/>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="616" cy="181" />
|
||||
<text x="616" y="181">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="616" cy="251" />
|
||||
<text x="616" y="251">c1</text>
|
||||
<rect class="test" width="100" height="50" x="566" y="296" />
|
||||
<text x="616" y="321">test_req</text>
|
||||
|
||||
<!-- TestWithoutAutouse.test_no_req -->
|
||||
<line x1="766" x2="766" y1="181" y2="251"/>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="766" cy="181" />
|
||||
<text x="766" y="181">order</text>
|
||||
<rect class="test" width="120" height="50" x="706" y="226" />
|
||||
<text x="766" y="251">test_no_req</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.6 KiB |
@@ -1,45 +0,0 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def order():
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def a(order):
|
||||
order.append("a")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def b(a, order):
|
||||
order.append("b")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def c(a, b, order):
|
||||
order.append("c")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def d(c, b, order):
|
||||
order.append("d")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def e(d, b, order):
|
||||
order.append("e")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def f(e, order):
|
||||
order.append("f")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def g(f, c, order):
|
||||
order.append("g")
|
||||
|
||||
|
||||
def test_order(g, order):
|
||||
assert order == ["a", "b", "c", "d", "e", "f", "g"]
|
||||
@@ -1,60 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="252" height="612">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
path, line {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
</style>
|
||||
<path d="M126,516 L26,436 L26,236" />
|
||||
<path d="M226,376 L226,236 L126,166" />
|
||||
<line x1="126" x2="126" y1="586" y2="446" />
|
||||
<line x1="126" x2="226" y1="446" y2="376" />
|
||||
<line x1="226" x2="126" y1="376" y2="306" />
|
||||
<line x1="126" x2="26" y1="306" y2="236" />
|
||||
<line x1="126" x2="126" y1="306" y2="166" />
|
||||
<line x1="26" x2="126" y1="236" y2="166" />
|
||||
<line x1="126" x2="126" y1="166" y2="26" />
|
||||
<line x1="126" x2="126" y1="96" y2="26" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="126" cy="26" />
|
||||
<text x="126" y="26">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="96" />
|
||||
<text x="126" y="96">a</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="166" />
|
||||
<text x="126" y="166">b</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="26" cy="236" />
|
||||
<text x="26" y="236">c</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="306" />
|
||||
<text x="126" y="306">d</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="376" />
|
||||
<text x="226" y="376">e</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="446" />
|
||||
<text x="126" y="446">f</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="516" />
|
||||
<text x="126" y="516">g</text>
|
||||
<rect class="test" width="110" height="50" x="71" y="561" />
|
||||
<text x="126" y="586">test_order</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.2 KiB |
@@ -1,51 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="112" height="612">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
path, line {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
</style>
|
||||
<line x1="56" x2="56" y1="611" y2="26" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="56" cy="26" />
|
||||
<text x="56" y="26">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="96" />
|
||||
<text x="56" y="96">a</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="166" />
|
||||
<text x="56" y="166">b</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="236" />
|
||||
<text x="56" y="236">c</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="306" />
|
||||
<text x="56" y="306">d</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="376" />
|
||||
<text x="56" y="376">e</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="446" />
|
||||
<text x="56" y="446">f</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="516" />
|
||||
<text x="56" y="516">g</text>
|
||||
<rect class="test" width="110" height="50" x="1" y="561" />
|
||||
<text x="56" y="586">test_order</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,60 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="252" height="542">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
path, line {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
</style>
|
||||
<path d="M126,446 L26,376 L26,236" />
|
||||
<path d="M226,306 L126,236 L126,166" />
|
||||
<line x1="126" x2="126" y1="516" y2="446" />
|
||||
<line x1="226" x2="226" y1="376" y2="306" />
|
||||
<line x1="226" x2="226" y1="306" y2="236" />
|
||||
<line x1="226" x2="126" y1="236" y2="166" />
|
||||
<line x1="126" x2="226" y1="446" y2="376" />
|
||||
<line x1="26" x2="126" y1="236" y2="166" />
|
||||
<line x1="126" x2="126" y1="166" y2="96" />
|
||||
<line x1="126" x2="126" y1="96" y2="26" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="126" cy="26" />
|
||||
<text x="126" y="26">order</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="96" />
|
||||
<text x="126" y="96">a</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="166" />
|
||||
<text x="126" y="166">b</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="26" cy="236" />
|
||||
<text x="26" y="236">c</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="236" />
|
||||
<text x="226" y="236">d</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="306" />
|
||||
<text x="226" y="306">e</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="376" />
|
||||
<text x="226" y="376">f</text>
|
||||
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="446" />
|
||||
<text x="126" y="446">g</text>
|
||||
<rect class="test" width="110" height="50" x="71" y="491" />
|
||||
<text x="126" y="516">test_order</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.2 KiB |
@@ -1,36 +0,0 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def order():
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def func(order):
|
||||
order.append("function")
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def cls(order):
|
||||
order.append("class")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def mod(order):
|
||||
order.append("module")
|
||||
|
||||
|
||||
@pytest.fixture(scope="package")
|
||||
def pack(order):
|
||||
order.append("package")
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def sess(order):
|
||||
order.append("session")
|
||||
|
||||
|
||||
class TestClass:
|
||||
def test_order(self, func, cls, mod, pack, sess, order):
|
||||
assert order == ["session", "package", "module", "class", "function"]
|
||||
@@ -1,55 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="262" height="537">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
line {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
}
|
||||
</style>
|
||||
<!-- TestClass -->
|
||||
<circle class="class" r="130" cx="131" cy="406" />
|
||||
<line x1="131" x2="131" y1="21" y2="446"/>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="26" />
|
||||
<text x="131" y="26">order</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="96" />
|
||||
<text x="131" y="96">sess</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="166" />
|
||||
<text x="131" y="166">pack</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="236" />
|
||||
<text x="131" y="236">mod</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="306" />
|
||||
<text x="131" y="306">cls</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="376" />
|
||||
<text x="131" y="376">func</text>
|
||||
<rect class="test" width="110" height="50" x="76" y="421" />
|
||||
<text x="131" y="446">test_order</text>
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M131,526 A 120 120 0 0 1 136 286" id="testClass"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath xlink:href="#testClass" startOffset="50%">TestClass</textPath>
|
||||
</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB |
@@ -1,29 +0,0 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def order():
|
||||
return []
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def outer(order, inner):
|
||||
order.append("outer")
|
||||
|
||||
|
||||
class TestOne:
|
||||
@pytest.fixture
|
||||
def inner(self, order):
|
||||
order.append("one")
|
||||
|
||||
def test_order(self, order, outer):
|
||||
assert order == ["one", "outer"]
|
||||
|
||||
|
||||
class TestTwo:
|
||||
@pytest.fixture
|
||||
def inner(self, order):
|
||||
order.append("two")
|
||||
|
||||
def test_order(self, order, outer):
|
||||
assert order == ["two", "outer"]
|
||||
@@ -1,115 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="562" height="532">
|
||||
<style>
|
||||
text {
|
||||
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
fill: #062886;
|
||||
font-size: medium;
|
||||
}
|
||||
ellipse.fixture, rect.test {
|
||||
fill: #eeffcc;
|
||||
stroke: #007020;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.fixture {
|
||||
color: #06287e;
|
||||
}
|
||||
circle.class {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
circle.module {
|
||||
fill: #c3e0ec;
|
||||
stroke: #0e84b5;
|
||||
stroke-width: 2;
|
||||
}
|
||||
text.class, text.module {
|
||||
fill: #0e84b5;
|
||||
}
|
||||
line, path {
|
||||
stroke: black;
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
</style>
|
||||
<!-- main scope -->
|
||||
<circle class="module" r="265" cx="281" cy="266" />
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 26,266 A 255 255 0 0 1 536 266" id="testModule"/>
|
||||
</defs>
|
||||
<text class="module">
|
||||
<textPath xlink:href="#testModule" startOffset="50%">test_fixtures_request_different_scope.py</textPath>
|
||||
</text>
|
||||
|
||||
<!-- TestOne -->
|
||||
<circle class="class" r="100" cx="141" cy="266" />
|
||||
<!-- inner -->
|
||||
<line x1="141" x2="141" y1="231" y2="301"/>
|
||||
<!-- order -->
|
||||
<path d="M 141 296 L 201 296 L 211 286 L 211 146 L 221 136 L 281 136" />
|
||||
<!-- outer -->
|
||||
<path d="M 141 306 L 201 306 L 211 316 L 211 386 L 221 396 L 281 396" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="141" cy="231" />
|
||||
<text x="141" y="231">inner</text>
|
||||
<rect class="test" width="110" height="50" x="86" y="276" />
|
||||
<text x="141" y="301">test_order</text>
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 51,266 A 90 90 0 0 1 231 266" id="testOne"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath xlink:href="#testOne" startOffset="50%">TestOne</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testOneOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="100" cx="141" cy="266" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="41" cy="266" mask="url(#testOneOrderMask)"/>
|
||||
<text class="module" x="41" y="266">1</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testMainOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="265" cx="281" cy="266" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="16" cy="266" mask="url(#testMainOrderMask)"/>
|
||||
<text class="module" x="16" y="266">2</text>
|
||||
|
||||
<!-- TestTwo -->
|
||||
<circle class="class" r="100" cx="421" cy="266" />
|
||||
<!-- inner -->
|
||||
<line x1="421" x2="421" y1="231" y2="301"/>
|
||||
<!-- order -->
|
||||
<path d="M 421 296 L 361 296 L 351 286 L 351 146 L 341 136 L 281 136" />
|
||||
<!-- outer -->
|
||||
<path d="M 421 306 L 361 306 L 351 316 L 351 386 L 341 396 L 281 396" />
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="421" cy="231" />
|
||||
<text x="421" y="231">inner</text>
|
||||
<rect class="test" width="110" height="50" x="366" y="276" />
|
||||
<text x="421" y="301">test_order</text>
|
||||
<!-- scope name -->
|
||||
<defs>
|
||||
<path d="M 331,266 A 90 90 0 0 1 511 266" id="testTwo"/>
|
||||
</defs>
|
||||
<text class="class">
|
||||
<textPath xlink:href="#testTwo" startOffset="50%">TestTwo</textPath>
|
||||
</text>
|
||||
<!-- scope order number -->
|
||||
<mask id="testTwoOrderMask">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
|
||||
<circle fill="black" stroke="white" stroke-width="2" r="100" cx="421" cy="266" />
|
||||
</mask>
|
||||
<circle class="module" r="15" cx="521" cy="266" mask="url(#testTwoOrderMask)"/>
|
||||
<text class="module" x="521" y="266">1</text>
|
||||
<!-- scope order number -->
|
||||
<circle class="module" r="15" cx="546" cy="266" mask="url(#testMainOrderMask)"/>
|
||||
<text class="module" x="546" y="266">2</text>
|
||||
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="281" cy="396" />
|
||||
<text x="281" y="396">outer</text>
|
||||
<ellipse class="fixture" rx="50" ry="25" cx="281" cy="136" />
|
||||
<text x="281" y="136">order</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.3 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%]
|
||||
@@ -221,30 +221,25 @@ Registering markers for your test suite is simple:
|
||||
[pytest]
|
||||
markers =
|
||||
webtest: mark a test as a webtest.
|
||||
slow: mark test as slow.
|
||||
|
||||
Multiple custom markers can be registered, by defining each one in its own line, as shown in above example.
|
||||
|
||||
You can ask which markers exist for your test suite - the list includes our just defined ``webtest`` and ``slow`` markers:
|
||||
You can ask which markers exist for your test suite - the list includes our just defined ``webtest`` markers:
|
||||
|
||||
.. code-block:: pytest
|
||||
|
||||
$ pytest --markers
|
||||
@pytest.mark.webtest: mark a test as a webtest.
|
||||
|
||||
@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 +392,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 +407,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 +423,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 +483,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
|
||||
|
||||
@@ -542,7 +539,7 @@ Let's run this without capturing output and see what we get:
|
||||
.
|
||||
1 passed in 0.12s
|
||||
|
||||
Marking platform specific tests with pytest
|
||||
marking platform specific tests with pytest
|
||||
--------------------------------------------------------------
|
||||
|
||||
.. regendoc:wipe
|
||||
@@ -603,8 +600,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 +617,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 +681,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 +708,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)
|
||||
|
||||
|
||||
@@ -26,12 +26,12 @@ class Python:
|
||||
def __init__(self, version, picklefile):
|
||||
self.pythonpath = shutil.which(version)
|
||||
if not self.pythonpath:
|
||||
pytest.skip(f"{version!r} not found")
|
||||
pytest.skip("{!r} not found".format(version))
|
||||
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
|
||||
@@ -69,4 +69,4 @@ class Python:
|
||||
@pytest.mark.parametrize("obj", [42, {}, {1: 3}])
|
||||
def test_basic_objects(python1, python2, obj):
|
||||
python1.dumps(obj)
|
||||
python2.load_and_is_true(f"obj == {obj}")
|
||||
python2.load_and_is_true("obj == {}".format(obj))
|
||||
|
||||
@@ -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>
|
||||
@@ -99,4 +102,4 @@ interesting to just look at the collection tree:
|
||||
<YamlItem hello>
|
||||
<YamlItem ok>
|
||||
|
||||
======================== 2 tests collected in 0.12s ========================
|
||||
========================== no tests ran in 0.12s ===========================
|
||||
|
||||
@@ -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, "usecase: {}".format(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>
|
||||
@@ -174,7 +175,7 @@ objects, they are still using the default pytest representation:
|
||||
<Function test_timedistance_v3[forward]>
|
||||
<Function test_timedistance_v3[backward]>
|
||||
|
||||
======================== 8 tests collected in 0.12s ========================
|
||||
========================== no tests ran in 0.12s ===========================
|
||||
|
||||
In ``test_timedistance_v3``, we used ``pytest.param`` to specify the test IDs
|
||||
together with the actual data, instead of listing them separately.
|
||||
@@ -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,18 +240,19 @@ 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 ========================
|
||||
========================== no tests ran in 0.12s ===========================
|
||||
|
||||
Note that we told ``metafunc.parametrize()`` that your scenario values
|
||||
should be considered class-scoped. With pytest-2.3 this leads to a
|
||||
@@ -314,15 +319,16 @@ 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>
|
||||
<Function test_db_initialized[d1]>
|
||||
<Function test_db_initialized[d2]>
|
||||
|
||||
======================== 2 tests collected in 0.12s ========================
|
||||
========================== no tests ran in 0.12s ===========================
|
||||
|
||||
And then when we run the test:
|
||||
|
||||
@@ -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
|
||||
@@ -502,12 +508,11 @@ Running it results in some skips if we don't have all the python interpreters in
|
||||
.. code-block:: pytest
|
||||
|
||||
. $ pytest -rs -q multipython.py
|
||||
sssssssssssssssssssssssssss [100%]
|
||||
ssssssssssss...ssssssssssss [100%]
|
||||
========================= short test summary info ==========================
|
||||
SKIPPED [9] multipython.py:29: 'python3.5' not found
|
||||
SKIPPED [9] multipython.py:29: 'python3.6' not found
|
||||
SKIPPED [9] multipython.py:29: 'python3.7' not found
|
||||
27 skipped in 0.12s
|
||||
SKIPPED [12] multipython.py:29: 'python3.5' not found
|
||||
SKIPPED [12] multipython.py:29: 'python3.7' not found
|
||||
3 passed, 24 skipped in 0.12s
|
||||
|
||||
Indirect parametrization of optional implementations/imports
|
||||
--------------------------------------------------------------------
|
||||
@@ -567,8 +572,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,16 +634,16 @@ Then run ``pytest`` with verbose mode and with only the ``basic`` marker:
|
||||
|
||||
$ pytest -v -m basic
|
||||
=========================== test session starts ============================
|
||||
platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y -- $PYTHON_PREFIX/bin/python
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /home/sweet/project
|
||||
collecting ... collected 24 items / 21 deselected / 3 selected
|
||||
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 14 items / 11 deselected / 3 selected
|
||||
|
||||
test_pytest_param_example.py::test_eval[1+7-8] PASSED [ 33%]
|
||||
test_pytest_param_example.py::test_eval[basic_2+4] PASSED [ 66%]
|
||||
test_pytest_param_example.py::test_eval[basic_6*9] XFAIL [100%]
|
||||
|
||||
=============== 2 passed, 21 deselected, 1 xfailed in 0.12s ================
|
||||
=============== 2 passed, 11 deselected, 1 xfailed in 0.12s ================
|
||||
|
||||
As the result:
|
||||
|
||||
|
||||
@@ -147,16 +147,17 @@ 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 ========================
|
||||
========================== no tests ran in 0.12s ===========================
|
||||
|
||||
You can check for multiple glob patterns by adding a space between the patterns:
|
||||
|
||||
@@ -208,17 +209,18 @@ 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 ========================
|
||||
========================== no tests ran in 0.12s ===========================
|
||||
|
||||
.. _customizing-test-collection:
|
||||
|
||||
@@ -280,7 +282,7 @@ leave out the ``setup.py`` file:
|
||||
<Module 'pkg/module_py2.py'>
|
||||
<Function 'test_only_on_python2'>
|
||||
|
||||
====== 1 tests found in 0.04 seconds ======
|
||||
====== no tests ran in 0.04 seconds ======
|
||||
|
||||
If you run with a Python 3 interpreter both the one test and the ``setup.py``
|
||||
file will be left out:
|
||||
@@ -289,11 +291,12 @@ 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 ========================
|
||||
========================== no tests ran in 0.12s ===========================
|
||||
|
||||
It's also possible to ignore files based on Unix shell-style wildcards by adding
|
||||
patterns to :globalvar:`collect_ignore_glob`.
|
||||
|
||||
@@ -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,11 +442,11 @@ 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]
|
||||
print(f"items is {items!r}")
|
||||
print("items is {!r}".format(items))
|
||||
> a, b = items.pop()
|
||||
E TypeError: cannot unpack non-iterable int object
|
||||
|
||||
@@ -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:
|
||||
|
||||