Merge branch 'main' into improve-high-scope-fixtures-teardown-issue-3806
This commit is contained in:
commit
3bc20b6750
|
@ -13,39 +13,53 @@ on:
|
||||||
permissions: {}
|
permissions: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
build:
|
||||||
deploy:
|
|
||||||
if: github.repository == 'pytest-dev/pytest'
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 30
|
timeout-minutes: 10
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Build and Check Package
|
- name: Build and Check Package
|
||||||
uses: hynek/build-and-inspect-python-package@v1.5
|
uses: hynek/build-and-inspect-python-package@v1.5
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
if: github.repository == 'pytest-dev/pytest'
|
||||||
|
needs: [build]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 30
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
steps:
|
||||||
- name: Download Package
|
- name: Download Package
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: Packages
|
name: Packages
|
||||||
path: dist
|
path: dist
|
||||||
|
|
||||||
- name: Publish package to PyPI
|
- name: Publish package to PyPI
|
||||||
uses: pypa/gh-action-pypi-publish@release/v1
|
uses: pypa/gh-action-pypi-publish@v1.8.7
|
||||||
with:
|
|
||||||
password: ${{ secrets.pypi_token }}
|
|
||||||
|
|
||||||
|
release-notes:
|
||||||
|
|
||||||
|
# todo: generate the content in the build job
|
||||||
|
# the goal being of using a github action script to push the release data
|
||||||
|
# after success instead of creating a complete python/tox env
|
||||||
|
needs: [deploy]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 30
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
persist-credentials: false
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.7"
|
python-version: "3.11"
|
||||||
|
|
||||||
|
|
||||||
- name: Install tox
|
- name: Install tox
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -37,25 +37,23 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
name: [
|
name: [
|
||||||
"windows-py37",
|
|
||||||
"windows-py37-pluggy",
|
|
||||||
"windows-py38",
|
"windows-py38",
|
||||||
|
"windows-py38-pluggy",
|
||||||
"windows-py39",
|
"windows-py39",
|
||||||
"windows-py310",
|
"windows-py310",
|
||||||
"windows-py311",
|
"windows-py311",
|
||||||
"windows-py312",
|
"windows-py312",
|
||||||
|
|
||||||
"ubuntu-py37",
|
|
||||||
"ubuntu-py37-pluggy",
|
|
||||||
"ubuntu-py37-freeze",
|
|
||||||
"ubuntu-py38",
|
"ubuntu-py38",
|
||||||
|
"ubuntu-py38-pluggy",
|
||||||
|
"ubuntu-py38-freeze",
|
||||||
"ubuntu-py39",
|
"ubuntu-py39",
|
||||||
"ubuntu-py310",
|
"ubuntu-py310",
|
||||||
"ubuntu-py311",
|
"ubuntu-py311",
|
||||||
"ubuntu-py312",
|
"ubuntu-py312",
|
||||||
"ubuntu-pypy3",
|
"ubuntu-pypy3",
|
||||||
|
|
||||||
"macos-py37",
|
"macos-py38",
|
||||||
"macos-py39",
|
"macos-py39",
|
||||||
"macos-py310",
|
"macos-py310",
|
||||||
"macos-py312",
|
"macos-py312",
|
||||||
|
@ -66,19 +64,15 @@ jobs:
|
||||||
]
|
]
|
||||||
|
|
||||||
include:
|
include:
|
||||||
- name: "windows-py37"
|
|
||||||
python: "3.7"
|
|
||||||
os: windows-latest
|
|
||||||
tox_env: "py37-numpy"
|
|
||||||
- name: "windows-py37-pluggy"
|
|
||||||
python: "3.7"
|
|
||||||
os: windows-latest
|
|
||||||
tox_env: "py37-pluggymain-pylib-xdist"
|
|
||||||
- name: "windows-py38"
|
- name: "windows-py38"
|
||||||
python: "3.8"
|
python: "3.8"
|
||||||
os: windows-latest
|
os: windows-latest
|
||||||
tox_env: "py38-unittestextras"
|
tox_env: "py38-unittestextras"
|
||||||
use_coverage: true
|
use_coverage: true
|
||||||
|
- name: "windows-py38-pluggy"
|
||||||
|
python: "3.8"
|
||||||
|
os: windows-latest
|
||||||
|
tox_env: "py38-pluggymain-pylib-xdist"
|
||||||
- name: "windows-py39"
|
- name: "windows-py39"
|
||||||
python: "3.9"
|
python: "3.9"
|
||||||
os: windows-latest
|
os: windows-latest
|
||||||
|
@ -96,23 +90,19 @@ jobs:
|
||||||
os: windows-latest
|
os: windows-latest
|
||||||
tox_env: "py312"
|
tox_env: "py312"
|
||||||
|
|
||||||
- name: "ubuntu-py37"
|
|
||||||
python: "3.7"
|
|
||||||
os: ubuntu-latest
|
|
||||||
tox_env: "py37-lsof-numpy-pexpect"
|
|
||||||
use_coverage: true
|
|
||||||
- name: "ubuntu-py37-pluggy"
|
|
||||||
python: "3.7"
|
|
||||||
os: ubuntu-latest
|
|
||||||
tox_env: "py37-pluggymain-pylib-xdist"
|
|
||||||
- name: "ubuntu-py37-freeze"
|
|
||||||
python: "3.7"
|
|
||||||
os: ubuntu-latest
|
|
||||||
tox_env: "py37-freeze"
|
|
||||||
- name: "ubuntu-py38"
|
- name: "ubuntu-py38"
|
||||||
python: "3.8"
|
python: "3.8"
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
tox_env: "py38-xdist"
|
tox_env: "py38-lsof-numpy-pexpect"
|
||||||
|
use_coverage: true
|
||||||
|
- name: "ubuntu-py38-pluggy"
|
||||||
|
python: "3.8"
|
||||||
|
os: ubuntu-latest
|
||||||
|
tox_env: "py38-pluggymain-pylib-xdist"
|
||||||
|
- name: "ubuntu-py38-freeze"
|
||||||
|
python: "3.8"
|
||||||
|
os: ubuntu-latest
|
||||||
|
tox_env: "py38-freeze"
|
||||||
- name: "ubuntu-py39"
|
- name: "ubuntu-py39"
|
||||||
python: "3.9"
|
python: "3.9"
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
|
@ -132,14 +122,14 @@ jobs:
|
||||||
tox_env: "py312"
|
tox_env: "py312"
|
||||||
use_coverage: true
|
use_coverage: true
|
||||||
- name: "ubuntu-pypy3"
|
- name: "ubuntu-pypy3"
|
||||||
python: "pypy-3.7"
|
python: "pypy-3.8"
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
tox_env: "pypy3-xdist"
|
tox_env: "pypy3-xdist"
|
||||||
|
|
||||||
- name: "macos-py37"
|
- name: "macos-py38"
|
||||||
python: "3.7"
|
python: "3.8"
|
||||||
os: macos-latest
|
os: macos-latest
|
||||||
tox_env: "py37-xdist"
|
tox_env: "py38-xdist"
|
||||||
- name: "macos-py39"
|
- name: "macos-py39"
|
||||||
python: "3.9"
|
python: "3.9"
|
||||||
os: macos-latest
|
os: macos-latest
|
||||||
|
@ -160,11 +150,11 @@ jobs:
|
||||||
tox_env: "plugins"
|
tox_env: "plugins"
|
||||||
|
|
||||||
- name: "docs"
|
- name: "docs"
|
||||||
python: "3.7"
|
python: "3.8"
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
tox_env: "docs"
|
tox_env: "docs"
|
||||||
- name: "doctesting"
|
- name: "doctesting"
|
||||||
python: "3.7"
|
python: "3.8"
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
tox_env: "doctesting"
|
tox_env: "doctesting"
|
||||||
use_coverage: true
|
use_coverage: true
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 23.3.0
|
rev: 23.7.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
args: [--safe, --quiet]
|
args: [--safe, --quiet]
|
||||||
- repo: https://github.com/asottile/blacken-docs
|
- repo: https://github.com/asottile/blacken-docs
|
||||||
rev: 1.14.0
|
rev: 1.15.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: blacken-docs
|
- id: blacken-docs
|
||||||
additional_dependencies: [black==23.1.0]
|
additional_dependencies: [black==23.7.0]
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.4.0
|
rev: v4.4.0
|
||||||
hooks:
|
hooks:
|
||||||
|
@ -40,14 +40,14 @@ repos:
|
||||||
rev: v3.10.0
|
rev: v3.10.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: reorder-python-imports
|
- id: reorder-python-imports
|
||||||
args: ['--application-directories=.:src', --py37-plus]
|
args: ['--application-directories=.:src', --py38-plus]
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v3.7.0
|
rev: v3.9.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [--py37-plus]
|
args: [--py38-plus]
|
||||||
- repo: https://github.com/asottile/setup-cfg-fmt
|
- repo: https://github.com/asottile/setup-cfg-fmt
|
||||||
rev: v2.3.0
|
rev: v2.4.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: setup-cfg-fmt
|
- id: setup-cfg-fmt
|
||||||
args: ["--max-py-version=3.12", "--include-version-classifiers"]
|
args: ["--max-py-version=3.12", "--include-version-classifiers"]
|
||||||
|
|
4
AUTHORS
4
AUTHORS
|
@ -11,6 +11,7 @@ Adam Johnson
|
||||||
Adam Stewart
|
Adam Stewart
|
||||||
Adam Uhlir
|
Adam Uhlir
|
||||||
Ahn Ki-Wook
|
Ahn Ki-Wook
|
||||||
|
Akhilesh Ramakrishnan
|
||||||
Akiomi Kamakura
|
Akiomi Kamakura
|
||||||
Alan Velasco
|
Alan Velasco
|
||||||
Alessio Izzo
|
Alessio Izzo
|
||||||
|
@ -262,6 +263,7 @@ Mickey Pashov
|
||||||
Mihai Capotă
|
Mihai Capotă
|
||||||
Mike Hoyle (hoylemd)
|
Mike Hoyle (hoylemd)
|
||||||
Mike Lundy
|
Mike Lundy
|
||||||
|
Milan Lesnek
|
||||||
Miro Hrončok
|
Miro Hrončok
|
||||||
Nathaniel Compton
|
Nathaniel Compton
|
||||||
Nathaniel Waisbrot
|
Nathaniel Waisbrot
|
||||||
|
@ -311,6 +313,7 @@ Raphael Pierzina
|
||||||
Rafal Semik
|
Rafal Semik
|
||||||
Raquel Alegre
|
Raquel Alegre
|
||||||
Ravi Chandra
|
Ravi Chandra
|
||||||
|
Reagan Lee
|
||||||
Robert Holt
|
Robert Holt
|
||||||
Roberto Aldera
|
Roberto Aldera
|
||||||
Roberto Polli
|
Roberto Polli
|
||||||
|
@ -372,6 +375,7 @@ Tomer Keren
|
||||||
Tony Narlock
|
Tony Narlock
|
||||||
Tor Colvin
|
Tor Colvin
|
||||||
Trevor Bekolay
|
Trevor Bekolay
|
||||||
|
Tushar Sadhwani
|
||||||
Tyler Goodlet
|
Tyler Goodlet
|
||||||
Tzu-ping Chung
|
Tzu-ping Chung
|
||||||
Vasily Kuznetsov
|
Vasily Kuznetsov
|
||||||
|
|
|
@ -201,7 +201,7 @@ Short version
|
||||||
#. Follow **PEP-8** for naming and `black <https://github.com/psf/black>`_ for formatting.
|
#. Follow **PEP-8** for naming and `black <https://github.com/psf/black>`_ for formatting.
|
||||||
#. Tests are run using ``tox``::
|
#. Tests are run using ``tox``::
|
||||||
|
|
||||||
tox -e linting,py37
|
tox -e linting,py39
|
||||||
|
|
||||||
The test environments above are usually enough to cover most cases locally.
|
The test environments above are usually enough to cover most cases locally.
|
||||||
|
|
||||||
|
@ -272,24 +272,24 @@ Here is a simple overview, with pytest-specific bits:
|
||||||
|
|
||||||
#. Run all the tests
|
#. Run all the tests
|
||||||
|
|
||||||
You need to have Python 3.7 available in your system. Now
|
You need to have Python 3.8 or later available in your system. Now
|
||||||
running tests is as simple as issuing this command::
|
running tests is as simple as issuing this command::
|
||||||
|
|
||||||
$ tox -e linting,py37
|
$ tox -e linting,py39
|
||||||
|
|
||||||
This command will run tests via the "tox" tool against Python 3.7
|
This command will run tests via the "tox" tool against Python 3.9
|
||||||
and also perform "lint" coding-style checks.
|
and also perform "lint" coding-style checks.
|
||||||
|
|
||||||
#. You can now edit your local working copy and run the tests again as necessary. Please follow PEP-8 for naming.
|
#. You can now edit your local working copy and run the tests again as necessary. Please follow PEP-8 for naming.
|
||||||
|
|
||||||
You can pass different options to ``tox``. For example, to run tests on Python 3.7 and pass options to pytest
|
You can pass different options to ``tox``. For example, to run tests on Python 3.9 and pass options to pytest
|
||||||
(e.g. enter pdb on failure) to pytest you can do::
|
(e.g. enter pdb on failure) to pytest you can do::
|
||||||
|
|
||||||
$ tox -e py37 -- --pdb
|
$ tox -e py39 -- --pdb
|
||||||
|
|
||||||
Or to only run tests in a particular test module on Python 3.7::
|
Or to only run tests in a particular test module on Python 3.9::
|
||||||
|
|
||||||
$ tox -e py37 -- testing/test_config.py
|
$ tox -e py39 -- testing/test_config.py
|
||||||
|
|
||||||
|
|
||||||
When committing, ``pre-commit`` will re-format the files if necessary.
|
When committing, ``pre-commit`` will re-format the files if necessary.
|
||||||
|
|
|
@ -100,7 +100,7 @@ Features
|
||||||
- Can run `unittest <https://docs.pytest.org/en/stable/how-to/unittest.html>`_ (or trial),
|
- 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
|
`nose <https://docs.pytest.org/en/stable/how-to/nose.html>`_ test suites out of the box
|
||||||
|
|
||||||
- Python 3.7+ or PyPy3
|
- Python 3.8+ or 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 <https://docs.pytest.org/en/latest/reference/plugin_list.html>`_ and thriving community
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fixed that fake intermediate modules generated by ``--import-mode=importlib`` would not include the
|
||||||
|
child modules as attributes of the parent modules.
|
|
@ -0,0 +1,2 @@
|
||||||
|
markers are now considered in the reverse mro order to ensure base class markers are considered first
|
||||||
|
this resolves a regression.
|
|
@ -0,0 +1,2 @@
|
||||||
|
:meth:`pytest.WarningsRecorder.pop` will return the most-closely-matched warning in the list,
|
||||||
|
rather than the first warning which is an instance of the requested type.
|
|
@ -0,0 +1 @@
|
||||||
|
Fixed error assertion handling in :func:`pytest.approx` when ``None`` is an expected or received value when comparing dictionaries.
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fixed issue when using ``--import-mode=importlib`` together with ``--doctest-modules`` that caused modules
|
||||||
|
to be imported more than once, causing problems with modules that have import side effects.
|
|
@ -0,0 +1,6 @@
|
||||||
|
``pluggy>=1.2.0`` is now required.
|
||||||
|
|
||||||
|
pytest now uses "new-style" hook wrappers internally, available since pluggy 1.2.0.
|
||||||
|
See `pluggy's 1.2.0 changelog <https://pluggy.readthedocs.io/en/latest/changelog.html#pluggy-1-2-0-2023-06-21>`_ and the :ref:`updated docs <hookwrapper>` for details.
|
||||||
|
|
||||||
|
Plugins which want to use new-style wrappers can do so if they require this version of pytest or later.
|
|
@ -0,0 +1 @@
|
||||||
|
- Prevent constants at the top of file from being detected as docstrings.
|
|
@ -0,0 +1,2 @@
|
||||||
|
Dropped support for Python 3.7, which `reached end-of-life on 2023-06-27
|
||||||
|
<https://devguide.python.org/versions/>`__.
|
|
@ -0,0 +1 @@
|
||||||
|
``pytest.warns`` and similar functions now capture warnings when an exception is raised inside a ``with`` block.
|
|
@ -0,0 +1,7 @@
|
||||||
|
:func:`pytest.warns <warns>` now re-emits unmatched warnings when the context
|
||||||
|
closes -- previously it would consume all warnings, hiding those that were not
|
||||||
|
matched by the function.
|
||||||
|
|
||||||
|
While this is a new feature, we decided to announce this as a breaking change
|
||||||
|
because many test suites are configured to error-out on warnings, and will
|
||||||
|
therefore fail on the newly-re-emitted warnings.
|
|
@ -87,6 +87,7 @@ Released pytest versions support all Python versions that are actively maintaine
|
||||||
============== ===================
|
============== ===================
|
||||||
pytest version min. Python version
|
pytest version min. Python version
|
||||||
============== ===================
|
============== ===================
|
||||||
|
8.0+ 3.8+
|
||||||
7.1+ 3.7+
|
7.1+ 3.7+
|
||||||
6.2 - 7.0 3.6+
|
6.2 - 7.0 3.6+
|
||||||
5.0 - 6.1 3.5+
|
5.0 - 6.1 3.5+
|
||||||
|
|
|
@ -15,12 +15,10 @@
|
||||||
#
|
#
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
import ast
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from typing import List
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from _pytest import __version__ as version
|
from _pytest import __version__ as version
|
||||||
|
@ -451,25 +449,6 @@ def setup(app: "sphinx.application.Sphinx") -> None:
|
||||||
|
|
||||||
configure_logging(app)
|
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
|
# legacypath.py monkey-patches pytest.Testdir in. Import the file so
|
||||||
# that autodoc can discover references to it.
|
# that autodoc can discover references to it.
|
||||||
import _pytest.legacypath # noqa: F401
|
import _pytest.legacypath # noqa: F401
|
||||||
|
|
|
@ -12,7 +12,7 @@ class YamlFile(pytest.File):
|
||||||
# We need a yaml parser, e.g. PyYAML.
|
# We need a yaml parser, e.g. PyYAML.
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
raw = yaml.safe_load(self.path.open())
|
raw = yaml.safe_load(self.path.open(encoding="utf-8"))
|
||||||
for name, spec in sorted(raw.items()):
|
for name, spec in sorted(raw.items()):
|
||||||
yield YamlItem.from_parent(self, name=name, spec=spec)
|
yield YamlItem.from_parent(self, name=name, spec=spec)
|
||||||
|
|
||||||
|
|
|
@ -808,16 +808,15 @@ case we just write some information out to a ``failures`` file:
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
|
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_runtest_makereport(item, call):
|
def pytest_runtest_makereport(item, call):
|
||||||
# execute all other hooks to obtain the report object
|
# execute all other hooks to obtain the report object
|
||||||
outcome = yield
|
rep = yield
|
||||||
rep = outcome.get_result()
|
|
||||||
|
|
||||||
# we only look at actual failing test calls, not setup/teardown
|
# we only look at actual failing test calls, not setup/teardown
|
||||||
if rep.when == "call" and rep.failed:
|
if rep.when == "call" and rep.failed:
|
||||||
mode = "a" if os.path.exists("failures") else "w"
|
mode = "a" if os.path.exists("failures") else "w"
|
||||||
with open("failures", mode) as f:
|
with open("failures", mode, encoding="utf-8") as f:
|
||||||
# let's also access a fixture for the fun of it
|
# let's also access a fixture for the fun of it
|
||||||
if "tmp_path" in item.fixturenames:
|
if "tmp_path" in item.fixturenames:
|
||||||
extra = " ({})".format(item.funcargs["tmp_path"])
|
extra = " ({})".format(item.funcargs["tmp_path"])
|
||||||
|
@ -826,6 +825,8 @@ case we just write some information out to a ``failures`` file:
|
||||||
|
|
||||||
f.write(rep.nodeid + extra + "\n")
|
f.write(rep.nodeid + extra + "\n")
|
||||||
|
|
||||||
|
return rep
|
||||||
|
|
||||||
|
|
||||||
if you then have failing tests:
|
if you then have failing tests:
|
||||||
|
|
||||||
|
@ -899,16 +900,17 @@ here is a little example implemented via a local plugin:
|
||||||
phase_report_key = StashKey[Dict[str, CollectReport]]()
|
phase_report_key = StashKey[Dict[str, CollectReport]]()
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
|
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_runtest_makereport(item, call):
|
def pytest_runtest_makereport(item, call):
|
||||||
# execute all other hooks to obtain the report object
|
# execute all other hooks to obtain the report object
|
||||||
outcome = yield
|
rep = yield
|
||||||
rep = outcome.get_result()
|
|
||||||
|
|
||||||
# store test results for each phase of a call, which can
|
# store test results for each phase of a call, which can
|
||||||
# be "setup", "call", "teardown"
|
# be "setup", "call", "teardown"
|
||||||
item.stash.setdefault(phase_report_key, {})[rep.when] = rep
|
item.stash.setdefault(phase_report_key, {})[rep.when] = rep
|
||||||
|
|
||||||
|
return rep
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def something(request):
|
def something(request):
|
||||||
|
|
|
@ -9,7 +9,7 @@ Get Started
|
||||||
Install ``pytest``
|
Install ``pytest``
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
``pytest`` requires: Python 3.7+ or PyPy3.
|
``pytest`` requires: Python 3.8+ or PyPy3.
|
||||||
|
|
||||||
1. Run the following command in your command line:
|
1. Run the following command in your command line:
|
||||||
|
|
||||||
|
|
|
@ -135,10 +135,6 @@ Warning about unraisable exceptions and unhandled thread exceptions
|
||||||
|
|
||||||
.. versionadded:: 6.2
|
.. versionadded:: 6.2
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
These features only work on Python>=3.8.
|
|
||||||
|
|
||||||
Unhandled exceptions are exceptions that are raised in a situation in which
|
Unhandled exceptions are exceptions that are raised in a situation in which
|
||||||
they cannot propagate to a caller. The most common case is an exception raised
|
they cannot propagate to a caller. The most common case is an exception raised
|
||||||
in a :meth:`__del__ <object.__del__>` implementation.
|
in a :meth:`__del__ <object.__del__>` implementation.
|
||||||
|
|
|
@ -1698,7 +1698,7 @@ and declare its use in a test module via a ``usefixtures`` marker:
|
||||||
class TestDirectoryInit:
|
class TestDirectoryInit:
|
||||||
def test_cwd_starts_empty(self):
|
def test_cwd_starts_empty(self):
|
||||||
assert os.listdir(os.getcwd()) == []
|
assert os.listdir(os.getcwd()) == []
|
||||||
with open("myfile", "w") as f:
|
with open("myfile", "w", encoding="utf-8") as f:
|
||||||
f.write("hello")
|
f.write("hello")
|
||||||
|
|
||||||
def test_cwd_again_starts_empty(self):
|
def test_cwd_again_starts_empty(self):
|
||||||
|
|
|
@ -47,8 +47,7 @@ Unsupported idioms / known issues
|
||||||
- nose imports test modules with the same import path (e.g.
|
- nose imports test modules with the same import path (e.g.
|
||||||
``tests.test_mode``) but different file system paths
|
``tests.test_mode``) but different file system paths
|
||||||
(e.g. ``tests/test_mode.py`` and ``other/tests/test_mode.py``)
|
(e.g. ``tests/test_mode.py`` and ``other/tests/test_mode.py``)
|
||||||
by extending sys.path/import semantics. pytest does not do that
|
by extending sys.path/import semantics. pytest does not do that. Note that
|
||||||
but there is discussion in :issue:`268` for adding some support. Note that
|
|
||||||
`nose2 choose to avoid this sys.path/import hackery <https://nose2.readthedocs.io/en/latest/differences.html#test-discovery-and-loading>`_.
|
`nose2 choose to avoid this sys.path/import hackery <https://nose2.readthedocs.io/en/latest/differences.html#test-discovery-and-loading>`_.
|
||||||
|
|
||||||
If you place a conftest.py file in the root directory of your project
|
If you place a conftest.py file in the root directory of your project
|
||||||
|
@ -66,16 +65,34 @@ Unsupported idioms / known issues
|
||||||
|
|
||||||
- no nose-configuration is recognized.
|
- no nose-configuration is recognized.
|
||||||
|
|
||||||
- ``yield``-based methods are unsupported as of pytest 4.1.0. They are
|
- ``yield``-based methods are
|
||||||
fundamentally incompatible with pytest because they don't support fixtures
|
fundamentally incompatible with pytest because they don't support fixtures
|
||||||
properly since collection and test execution are separated.
|
properly since collection and test execution are separated.
|
||||||
|
|
||||||
|
Here is a table comparing the default supported naming conventions for both
|
||||||
|
nose and pytest.
|
||||||
|
|
||||||
|
========= ========================== ======= =====
|
||||||
|
what default naming convention pytest nose
|
||||||
|
========= ========================== ======= =====
|
||||||
|
module ``test*.py`` ✅
|
||||||
|
module ``test_*.py`` ✅ ✅
|
||||||
|
module ``*_test.py`` ✅
|
||||||
|
module ``*_tests.py``
|
||||||
|
class ``*(unittest.TestCase)`` ✅ ✅
|
||||||
|
method ``test_*`` ✅ ✅
|
||||||
|
class ``Test*`` ✅
|
||||||
|
method ``test_*`` ✅
|
||||||
|
function ``test_*`` ✅
|
||||||
|
========= ========================== ======= =====
|
||||||
|
|
||||||
|
|
||||||
Migrating from nose to pytest
|
Migrating from nose to pytest
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
`nose2pytest <https://github.com/pytest-dev/nose2pytest>`_ is a Python script
|
`nose2pytest <https://github.com/pytest-dev/nose2pytest>`_ is a Python script
|
||||||
and pytest plugin to help convert Nose-based tests into pytest-based tests.
|
and pytest plugin to help convert Nose-based tests into pytest-based tests.
|
||||||
Specifically, the script transforms nose.tools.assert_* function calls into
|
Specifically, the script transforms ``nose.tools.assert_*`` function calls into
|
||||||
raw assert statements, while preserving format of original arguments
|
raw assert statements, while preserving format of original arguments
|
||||||
as much as possible.
|
as much as possible.
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,8 @@ created in the `base temporary directory`_.
|
||||||
d = tmp_path / "sub"
|
d = tmp_path / "sub"
|
||||||
d.mkdir()
|
d.mkdir()
|
||||||
p = d / "hello.txt"
|
p = d / "hello.txt"
|
||||||
p.write_text(CONTENT)
|
p.write_text(CONTENT, encoding="utf-8")
|
||||||
assert p.read_text() == CONTENT
|
assert p.read_text(encoding="utf-8") == CONTENT
|
||||||
assert len(list(tmp_path.iterdir())) == 1
|
assert len(list(tmp_path.iterdir())) == 1
|
||||||
assert 0
|
assert 0
|
||||||
|
|
||||||
|
|
|
@ -207,10 +207,10 @@ creation of a per-test temporary directory:
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def initdir(self, tmp_path, monkeypatch):
|
def initdir(self, tmp_path, monkeypatch):
|
||||||
monkeypatch.chdir(tmp_path) # change to pytest-provided temporary directory
|
monkeypatch.chdir(tmp_path) # change to pytest-provided temporary directory
|
||||||
tmp_path.joinpath("samplefile.ini").write_text("# testdata")
|
tmp_path.joinpath("samplefile.ini").write_text("# testdata", encoding="utf-8")
|
||||||
|
|
||||||
def test_method(self):
|
def test_method(self):
|
||||||
with open("samplefile.ini") as f:
|
with open("samplefile.ini", encoding="utf-8") as f:
|
||||||
s = f.read()
|
s = f.read()
|
||||||
assert "testdata" in s
|
assert "testdata" in s
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,8 @@ You can invoke ``pytest`` from Python code directly:
|
||||||
|
|
||||||
this acts as if you would call "pytest" from the command line.
|
this acts as if you would call "pytest" from the command line.
|
||||||
It will not raise :class:`SystemExit` but return the :ref:`exit code <exit-codes>` instead.
|
It will not raise :class:`SystemExit` but return the :ref:`exit code <exit-codes>` instead.
|
||||||
You can pass in options and arguments:
|
If you don't pass it any arguments, ``main`` reads the arguments from the command line arguments of the process (:data:`sys.argv`), which may be undesirable.
|
||||||
|
You can pass in options and arguments explicitly:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ The remaining hook functions will not be called in this case.
|
||||||
|
|
||||||
.. _`hookwrapper`:
|
.. _`hookwrapper`:
|
||||||
|
|
||||||
hookwrapper: executing around other hooks
|
hook wrappers: executing around other hooks
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
.. currentmodule:: _pytest.core
|
.. currentmodule:: _pytest.core
|
||||||
|
@ -69,10 +69,8 @@ which yields exactly once. When pytest invokes hooks it first executes
|
||||||
hook wrappers and passes the same arguments as to the regular hooks.
|
hook wrappers and passes the same arguments as to the regular hooks.
|
||||||
|
|
||||||
At the yield point of the hook wrapper pytest will execute the next hook
|
At the yield point of the hook wrapper pytest will execute the next hook
|
||||||
implementations and return their result to the yield point in the form of
|
implementations and return their result to the yield point, or will
|
||||||
a :py:class:`Result <pluggy._Result>` instance which encapsulates a result or
|
propagate an exception if they raised.
|
||||||
exception info. The yield point itself will thus typically not raise
|
|
||||||
exceptions (unless there are bugs).
|
|
||||||
|
|
||||||
Here is an example definition of a hook wrapper:
|
Here is an example definition of a hook wrapper:
|
||||||
|
|
||||||
|
@ -81,26 +79,35 @@ Here is an example definition of a hook wrapper:
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_pyfunc_call(pyfuncitem):
|
def pytest_pyfunc_call(pyfuncitem):
|
||||||
do_something_before_next_hook_executes()
|
do_something_before_next_hook_executes()
|
||||||
|
|
||||||
outcome = yield
|
# If the outcome is an exception, will raise the exception.
|
||||||
# outcome.excinfo may be None or a (cls, val, tb) tuple
|
res = yield
|
||||||
|
|
||||||
res = outcome.get_result() # will raise if outcome was exception
|
new_res = post_process_result(res)
|
||||||
|
|
||||||
post_process_result(res)
|
# Override the return value to the plugin system.
|
||||||
|
return new_res
|
||||||
|
|
||||||
outcome.force_result(new_res) # to override the return value to the plugin system
|
The hook wrapper needs to return a result for the hook, or raise an exception.
|
||||||
|
|
||||||
Note that hook wrappers don't return results themselves, they merely
|
In many cases, the wrapper only needs to perform tracing or other side effects
|
||||||
perform tracing or other side effects around the actual hook implementations.
|
around the actual hook implementations, in which case it can return the result
|
||||||
If the result of the underlying hook is a mutable object, they may modify
|
value of the ``yield``. The simplest (though useless) hook wrapper is
|
||||||
that result but it's probably better to avoid it.
|
``return (yield)``.
|
||||||
|
|
||||||
|
In other cases, the wrapper wants the adjust or adapt the result, in which case
|
||||||
|
it can return a new value. If the result of the underlying hook is a mutable
|
||||||
|
object, the wrapper may modify that result, but it's probably better to avoid it.
|
||||||
|
|
||||||
|
If the hook implementation failed with an exception, the wrapper can handle that
|
||||||
|
exception using a ``try-catch-finally`` around the ``yield``, by propagating it,
|
||||||
|
supressing it, or raising a different exception entirely.
|
||||||
|
|
||||||
For more information, consult the
|
For more information, consult the
|
||||||
:ref:`pluggy documentation about hookwrappers <pluggy:hookwrappers>`.
|
:ref:`pluggy documentation about hook wrappers <pluggy:hookwrappers>`.
|
||||||
|
|
||||||
.. _plugin-hookorder:
|
.. _plugin-hookorder:
|
||||||
|
|
||||||
|
@ -130,11 +137,14 @@ after others, i.e. the position in the ``N``-sized list of functions:
|
||||||
|
|
||||||
|
|
||||||
# Plugin 3
|
# Plugin 3
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_collection_modifyitems(items):
|
def pytest_collection_modifyitems(items):
|
||||||
# will execute even before the tryfirst one above!
|
# will execute even before the tryfirst one above!
|
||||||
outcome = yield
|
try:
|
||||||
# will execute after all non-hookwrappers executed
|
return (yield)
|
||||||
|
finally:
|
||||||
|
# will execute after all non-wrappers executed
|
||||||
|
...
|
||||||
|
|
||||||
Here is the order of execution:
|
Here is the order of execution:
|
||||||
|
|
||||||
|
@ -149,12 +159,11 @@ Here is the order of execution:
|
||||||
Plugin1).
|
Plugin1).
|
||||||
|
|
||||||
4. Plugin3's pytest_collection_modifyitems then executing the code after the yield
|
4. Plugin3's pytest_collection_modifyitems then executing the code after the yield
|
||||||
point. The yield receives a :py:class:`Result <pluggy._Result>` instance which encapsulates
|
point. The yield receives the result from calling the non-wrappers, or raises
|
||||||
the result from calling the non-wrappers. Wrappers shall not modify the result.
|
an exception if the non-wrappers raised.
|
||||||
|
|
||||||
It's possible to use ``tryfirst`` and ``trylast`` also in conjunction with
|
It's possible to use ``tryfirst`` and ``trylast`` also on hook wrappers
|
||||||
``hookwrapper=True`` in which case it will influence the ordering of hookwrappers
|
in which case it will influence the ordering of hook wrappers among each other.
|
||||||
among each other.
|
|
||||||
|
|
||||||
|
|
||||||
Declaring new hooks
|
Declaring new hooks
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
.. sidebar:: Next Open Trainings
|
.. sidebar:: Next Open Trainings
|
||||||
|
|
||||||
- `pytest tips and tricks for a better testsuite <https://ep2023.europython.eu/session/pytest-tips-and-tricks-for-a-better-testsuite>`_, at `Europython 2023 <https://ep2023.europython.eu/>`_, July 18th (3h), Prague/Remote
|
- `pytest tips and tricks for a better testsuite <https://ep2023.europython.eu/session/pytest-tips-and-tricks-for-a-better-testsuite>`_, at `Europython 2023 <https://ep2023.europython.eu/>`_, **July 18th** (3h), **Prague, Czech Republic / Remote**
|
||||||
- `Professional Testing with Python <https://python-academy.com/courses/python_course_testing.html>`_, via `Python Academy <https://www.python-academy.com/>`_, March 5th to 7th 2024 (3 day in-depth training), Leipzig/Remote
|
- `pytest: Professionelles Testen (nicht nur) für Python <https://workshoptage.ch/workshops/2023/pytest-professionelles-testen-nicht-nur-fuer-python-2/>`_, at `Workshoptage 2023 <https://workshoptage.ch/>`_, **September 5th**, `OST <https://www.ost.ch/en>`_ Campus **Rapperswil, Switzerland**
|
||||||
|
- `Professional Testing with Python <https://python-academy.com/courses/python_course_testing.html>`_, via `Python Academy <https://www.python-academy.com/>`_, **March 5th to 7th 2024** (3 day in-depth training), **Leipzig, Germany / Remote**
|
||||||
|
|
||||||
Also see :doc:`previous talks and blogposts <talks>`.
|
Also see :doc:`previous talks and blogposts <talks>`.
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ The ``pytest`` framework makes it easy to write small, readable tests, and can
|
||||||
scale to support complex functional testing for applications and libraries.
|
scale to support complex functional testing for applications and libraries.
|
||||||
|
|
||||||
|
|
||||||
``pytest`` requires: Python 3.7+ or PyPy3.
|
``pytest`` requires: Python 3.8+ or PyPy3.
|
||||||
|
|
||||||
**PyPI package name**: :pypi:`pytest`
|
**PyPI package name**: :pypi:`pytest`
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ Features
|
||||||
|
|
||||||
- Can run :ref:`unittest <unittest>` (including trial) and :ref:`nose <noseintegration>` test suites out of the box
|
- Can run :ref:`unittest <unittest>` (including trial) and :ref:`nose <noseintegration>` test suites out of the box
|
||||||
|
|
||||||
- Python 3.7+ or PyPy 3
|
- Python 3.8+ or PyPy 3
|
||||||
|
|
||||||
- Rich plugin architecture, with over 800+ :ref:`external plugins <plugin-list>` and thriving community
|
- Rich plugin architecture, with over 800+ :ref:`external plugins <plugin-list>` and thriving community
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ Packages classified as inactive are excluded.
|
||||||
creating a PDF, because otherwise the table gets far too wide for the
|
creating a PDF, because otherwise the table gets far too wide for the
|
||||||
page.
|
page.
|
||||||
|
|
||||||
This list contains 1272 plugins.
|
This list contains 1282 plugins.
|
||||||
|
|
||||||
.. only:: not latex
|
.. only:: not latex
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-aioworkers` A plugin to test aioworkers project with pytest May 01, 2023 5 - Production/Stable pytest>=6.1.0
|
:pypi:`pytest-aioworkers` A plugin to test aioworkers project with pytest May 01, 2023 5 - Production/Stable pytest>=6.1.0
|
||||||
:pypi:`pytest-airflow` pytest support for airflow. Apr 03, 2019 3 - Alpha pytest (>=4.4.0)
|
:pypi:`pytest-airflow` pytest support for airflow. Apr 03, 2019 3 - Alpha pytest (>=4.4.0)
|
||||||
:pypi:`pytest-airflow-utils` Nov 15, 2021 N/A N/A
|
:pypi:`pytest-airflow-utils` Nov 15, 2021 N/A N/A
|
||||||
:pypi:`pytest-alembic` A pytest plugin for verifying alembic migrations. May 23, 2023 N/A pytest (>=6.0)
|
:pypi:`pytest-alembic` A pytest plugin for verifying alembic migrations. Jul 06, 2023 N/A pytest (>=6.0)
|
||||||
:pypi:`pytest-allclose` Pytest fixture extending Numpy's allclose function Jul 30, 2019 5 - Production/Stable pytest
|
:pypi:`pytest-allclose` Pytest fixture extending Numpy's allclose function Jul 30, 2019 5 - Production/Stable pytest
|
||||||
:pypi:`pytest-allure-adaptor` Plugin for py.test to generate allure xml reports Jan 10, 2018 N/A pytest (>=2.7.3)
|
:pypi:`pytest-allure-adaptor` Plugin for py.test to generate allure xml reports Jan 10, 2018 N/A pytest (>=2.7.3)
|
||||||
:pypi:`pytest-allure-adaptor2` Plugin for py.test to generate allure xml reports Oct 14, 2020 N/A pytest (>=2.7.3)
|
:pypi:`pytest-allure-adaptor2` Plugin for py.test to generate allure xml reports Oct 14, 2020 N/A pytest (>=2.7.3)
|
||||||
|
@ -85,6 +85,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-astropy` Meta-package containing dependencies for testing Apr 12, 2022 5 - Production/Stable pytest (>=4.6)
|
:pypi:`pytest-astropy` Meta-package containing dependencies for testing Apr 12, 2022 5 - Production/Stable pytest (>=4.6)
|
||||||
:pypi:`pytest-astropy-header` pytest plugin to add diagnostic information to the header of the test output Sep 06, 2022 3 - Alpha pytest (>=4.6)
|
:pypi:`pytest-astropy-header` pytest plugin to add diagnostic information to the header of the test output Sep 06, 2022 3 - Alpha pytest (>=4.6)
|
||||||
:pypi:`pytest-ast-transformer` May 04, 2019 3 - Alpha pytest
|
:pypi:`pytest-ast-transformer` May 04, 2019 3 - Alpha pytest
|
||||||
|
:pypi:`pytest-async-generators` Pytest fixtures for async generators Jul 05, 2023 N/A N/A
|
||||||
:pypi:`pytest-asyncio` Pytest support for asyncio Mar 19, 2023 4 - Beta pytest (>=7.0.0)
|
:pypi:`pytest-asyncio` Pytest support for asyncio Mar 19, 2023 4 - Beta pytest (>=7.0.0)
|
||||||
:pypi:`pytest-asyncio-cooperative` Run all your asynchronous tests cooperatively. May 31, 2023 N/A N/A
|
:pypi:`pytest-asyncio-cooperative` Run all your asynchronous tests cooperatively. May 31, 2023 N/A N/A
|
||||||
:pypi:`pytest-asyncio-network-simulator` pytest-asyncio-network-simulator: Plugin for pytest for simulator the network in tests Jul 31, 2018 3 - Alpha pytest (<3.7.0,>=3.3.2)
|
:pypi:`pytest-asyncio-network-simulator` pytest-asyncio-network-simulator: Plugin for pytest for simulator the network in tests Jul 31, 2018 3 - Alpha pytest (<3.7.0,>=3.3.2)
|
||||||
|
@ -112,13 +113,13 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-base-url` pytest plugin for URL based testing Mar 27, 2022 5 - Production/Stable pytest (>=3.0.0,<8.0.0)
|
:pypi:`pytest-base-url` pytest plugin for URL based testing Mar 27, 2022 5 - Production/Stable pytest (>=3.0.0,<8.0.0)
|
||||||
:pypi:`pytest-bdd` BDD for pytest Nov 08, 2022 6 - Mature pytest (>=6.2.0)
|
:pypi:`pytest-bdd` BDD for pytest Nov 08, 2022 6 - Mature pytest (>=6.2.0)
|
||||||
:pypi:`pytest-bdd-html` pytest plugin to display BDD info in HTML test report Nov 22, 2022 3 - Alpha pytest (!=6.0.0,>=5.0)
|
:pypi:`pytest-bdd-html` pytest plugin to display BDD info in HTML test report Nov 22, 2022 3 - Alpha pytest (!=6.0.0,>=5.0)
|
||||||
:pypi:`pytest-bdd-ng` BDD for pytest Oct 06, 2022 4 - Beta pytest (>=5.0)
|
:pypi:`pytest-bdd-ng` BDD for pytest Jul 01, 2023 4 - Beta pytest (>=5.0)
|
||||||
:pypi:`pytest-bdd-splinter` Common steps for pytest bdd and splinter integration Aug 12, 2019 5 - Production/Stable pytest (>=4.0.0)
|
:pypi:`pytest-bdd-splinter` Common steps for pytest bdd and splinter integration Aug 12, 2019 5 - Production/Stable pytest (>=4.0.0)
|
||||||
:pypi:`pytest-bdd-web` A simple plugin to use with pytest Jan 02, 2020 4 - Beta pytest (>=3.5.0)
|
:pypi:`pytest-bdd-web` A simple plugin to use with pytest Jan 02, 2020 4 - Beta pytest (>=3.5.0)
|
||||||
:pypi:`pytest-bdd-wrappers` Feb 11, 2020 2 - Pre-Alpha N/A
|
:pypi:`pytest-bdd-wrappers` Feb 11, 2020 2 - Pre-Alpha N/A
|
||||||
:pypi:`pytest-beakerlib` A pytest plugin that reports test results to the BeakerLib framework Mar 17, 2017 5 - Production/Stable pytest
|
:pypi:`pytest-beakerlib` A pytest plugin that reports test results to the BeakerLib framework Mar 17, 2017 5 - Production/Stable pytest
|
||||||
:pypi:`pytest-beds` Fixtures for testing Google Appengine (GAE) apps Jun 07, 2016 4 - Beta N/A
|
:pypi:`pytest-beds` Fixtures for testing Google Appengine (GAE) apps Jun 07, 2016 4 - Beta N/A
|
||||||
:pypi:`pytest-beeprint` use icdiff for better error messages in pytest assertions Jun 09, 2023 4 - Beta N/A
|
:pypi:`pytest-beeprint` use icdiff for better error messages in pytest assertions Jul 04, 2023 4 - Beta N/A
|
||||||
:pypi:`pytest-bench` Benchmark utility that plugs into pytest. Jul 21, 2014 3 - Alpha N/A
|
:pypi:`pytest-bench` Benchmark utility that plugs into pytest. Jul 21, 2014 3 - Alpha N/A
|
||||||
:pypi:`pytest-benchmark` A \`\`pytest\`\` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer. Oct 25, 2022 5 - Production/Stable pytest (>=3.8)
|
:pypi:`pytest-benchmark` A \`\`pytest\`\` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer. Oct 25, 2022 5 - Production/Stable pytest (>=3.8)
|
||||||
:pypi:`pytest-better-datadir` A small example package Mar 13, 2023 N/A N/A
|
:pypi:`pytest-better-datadir` A small example package Mar 13, 2023 N/A N/A
|
||||||
|
@ -206,7 +207,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-codegen` Automatically create pytest test signatures Aug 23, 2020 2 - Pre-Alpha N/A
|
:pypi:`pytest-codegen` Automatically create pytest test signatures Aug 23, 2020 2 - Pre-Alpha N/A
|
||||||
:pypi:`pytest-codeowners` Pytest plugin for selecting tests by GitHub CODEOWNERS. Mar 30, 2022 4 - Beta pytest (>=6.0.0)
|
:pypi:`pytest-codeowners` Pytest plugin for selecting tests by GitHub CODEOWNERS. Mar 30, 2022 4 - Beta pytest (>=6.0.0)
|
||||||
:pypi:`pytest-codestyle` pytest plugin to run pycodestyle Mar 23, 2020 3 - Alpha N/A
|
:pypi:`pytest-codestyle` pytest plugin to run pycodestyle Mar 23, 2020 3 - Alpha N/A
|
||||||
:pypi:`pytest-codspeed` Pytest plugin to create CodSpeed benchmarks Dec 02, 2022 5 - Production/Stable pytest>=3.8
|
:pypi:`pytest-codspeed` Pytest plugin to create CodSpeed benchmarks Jul 04, 2023 5 - Production/Stable pytest>=3.8
|
||||||
:pypi:`pytest-collect-formatter` Formatter for pytest collect output Mar 29, 2021 5 - Production/Stable N/A
|
:pypi:`pytest-collect-formatter` Formatter for pytest collect output Mar 29, 2021 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-collect-formatter2` Formatter for pytest collect output May 31, 2021 5 - Production/Stable N/A
|
:pypi:`pytest-collect-formatter2` Formatter for pytest collect output May 31, 2021 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-collector` Python package for collecting pytest. Aug 02, 2022 N/A pytest (>=7.0,<8.0)
|
:pypi:`pytest-collector` Python package for collecting pytest. Aug 02, 2022 N/A pytest (>=7.0,<8.0)
|
||||||
|
@ -229,7 +230,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-cov` Pytest plugin for measuring coverage. May 24, 2023 5 - Production/Stable pytest (>=4.6)
|
:pypi:`pytest-cov` Pytest plugin for measuring coverage. May 24, 2023 5 - Production/Stable pytest (>=4.6)
|
||||||
:pypi:`pytest-cover` Pytest plugin for measuring coverage. Forked from \`pytest-cov\`. Aug 01, 2015 5 - Production/Stable N/A
|
:pypi:`pytest-cover` Pytest plugin for measuring coverage. Forked from \`pytest-cov\`. Aug 01, 2015 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-coverage` Jun 17, 2015 N/A N/A
|
:pypi:`pytest-coverage` Jun 17, 2015 N/A N/A
|
||||||
:pypi:`pytest-coverage-context` Coverage dynamic context support for PyTest, including sub-processes Jan 04, 2021 4 - Beta pytest (>=6.1.0)
|
:pypi:`pytest-coverage-context` Coverage dynamic context support for PyTest, including sub-processes Jun 28, 2023 4 - Beta N/A
|
||||||
:pypi:`pytest-coveragemarkers` Using pytest markers to track functional coverage and filtering of tests Nov 29, 2022 N/A pytest (>=7.1.2,<8.0.0)
|
:pypi:`pytest-coveragemarkers` Using pytest markers to track functional coverage and filtering of tests Nov 29, 2022 N/A pytest (>=7.1.2,<8.0.0)
|
||||||
:pypi:`pytest-cov-exclude` Pytest plugin for excluding tests based on coverage data Apr 29, 2016 4 - Beta pytest (>=2.8.0,<2.9.0); extra == 'dev'
|
:pypi:`pytest-cov-exclude` Pytest plugin for excluding tests based on coverage data Apr 29, 2016 4 - Beta pytest (>=2.8.0,<2.9.0); extra == 'dev'
|
||||||
:pypi:`pytest-cpp` Use pytest's runner to discover and execute C++ tests Jan 30, 2023 5 - Production/Stable pytest (>=7.0)
|
:pypi:`pytest-cpp` Use pytest's runner to discover and execute C++ tests Jan 30, 2023 5 - Production/Stable pytest (>=7.0)
|
||||||
|
@ -242,7 +243,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-cricri` A Cricri plugin for pytest. Jan 27, 2018 N/A pytest
|
:pypi:`pytest-cricri` A Cricri plugin for pytest. Jan 27, 2018 N/A pytest
|
||||||
:pypi:`pytest-crontab` add crontab task in crontab Dec 09, 2019 N/A N/A
|
:pypi:`pytest-crontab` add crontab task in crontab Dec 09, 2019 N/A N/A
|
||||||
:pypi:`pytest-csv` CSV output for pytest. Apr 22, 2021 N/A pytest (>=6.0)
|
:pypi:`pytest-csv` CSV output for pytest. Apr 22, 2021 N/A pytest (>=6.0)
|
||||||
:pypi:`pytest-csv-params` Pytest plugin for Test Case Parametrization with CSV files Aug 28, 2022 5 - Production/Stable pytest (>=7.1.2,<8.0.0)
|
:pypi:`pytest-csv-params` Pytest plugin for Test Case Parametrization with CSV files Jul 01, 2023 5 - Production/Stable pytest (>=7.4.0,<8.0.0)
|
||||||
:pypi:`pytest-curio` Pytest support for curio. Oct 07, 2020 N/A N/A
|
:pypi:`pytest-curio` Pytest support for curio. Oct 07, 2020 N/A N/A
|
||||||
:pypi:`pytest-curl-report` pytest plugin to generate curl command line report Dec 11, 2016 4 - Beta N/A
|
:pypi:`pytest-curl-report` pytest plugin to generate curl command line report Dec 11, 2016 4 - Beta N/A
|
||||||
:pypi:`pytest-custom-concurrency` Custom grouping concurrence for pytest Feb 08, 2021 N/A N/A
|
:pypi:`pytest-custom-concurrency` Custom grouping concurrence for pytest Feb 08, 2021 N/A N/A
|
||||||
|
@ -346,6 +347,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-doctest-ellipsis-markers` Setup additional values for ELLIPSIS_MARKER for doctests Jan 12, 2018 4 - Beta N/A
|
:pypi:`pytest-doctest-ellipsis-markers` Setup additional values for ELLIPSIS_MARKER for doctests Jan 12, 2018 4 - Beta N/A
|
||||||
:pypi:`pytest-doctest-import` A simple pytest plugin to import names and add them to the doctest namespace. Nov 13, 2018 4 - Beta pytest (>=3.3.0)
|
:pypi:`pytest-doctest-import` A simple pytest plugin to import names and add them to the doctest namespace. Nov 13, 2018 4 - Beta pytest (>=3.3.0)
|
||||||
:pypi:`pytest-doctestplus` Pytest plugin with advanced doctest features. Jun 08, 2023 3 - Alpha pytest (>=4.6)
|
:pypi:`pytest-doctestplus` Pytest plugin with advanced doctest features. Jun 08, 2023 3 - Alpha pytest (>=4.6)
|
||||||
|
:pypi:`pytest-dogu-report` pytest plugin for dogu report Jul 07, 2023 N/A N/A
|
||||||
:pypi:`pytest-dolphin` Some extra stuff that we use ininternally Nov 30, 2016 4 - Beta pytest (==3.0.4)
|
:pypi:`pytest-dolphin` Some extra stuff that we use ininternally Nov 30, 2016 4 - Beta pytest (==3.0.4)
|
||||||
:pypi:`pytest-doorstop` A pytest plugin for adding test results into doorstop items. Jun 09, 2020 4 - Beta pytest (>=3.5.0)
|
:pypi:`pytest-doorstop` A pytest plugin for adding test results into doorstop items. Jun 09, 2020 4 - Beta pytest (>=3.5.0)
|
||||||
:pypi:`pytest-dotenv` A py.test plugin that parses environment files before running tests Jun 16, 2020 4 - Beta pytest (>=5.0.0)
|
:pypi:`pytest-dotenv` A py.test plugin that parses environment files before running tests Jun 16, 2020 4 - Beta pytest (>=5.0.0)
|
||||||
|
@ -373,17 +375,17 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-eliot` An eliot plugin for pytest. Aug 31, 2022 1 - Planning pytest (>=5.4.0)
|
:pypi:`pytest-eliot` An eliot plugin for pytest. Aug 31, 2022 1 - Planning pytest (>=5.4.0)
|
||||||
:pypi:`pytest-elk-reporter` A simple plugin to use with pytest Jan 24, 2021 4 - Beta pytest (>=3.5.0)
|
:pypi:`pytest-elk-reporter` A simple plugin to use with pytest Jan 24, 2021 4 - Beta pytest (>=3.5.0)
|
||||||
:pypi:`pytest-email` Send execution result email Jul 08, 2020 N/A pytest
|
:pypi:`pytest-email` Send execution result email Jul 08, 2020 N/A pytest
|
||||||
:pypi:`pytest-embedded` A pytest plugin that designed for embedded testing. Jun 14, 2023 5 - Production/Stable pytest>=7.0
|
:pypi:`pytest-embedded` A pytest plugin that designed for embedded testing. Jul 05, 2023 5 - Production/Stable pytest>=7.0
|
||||||
:pypi:`pytest-embedded-arduino` Make pytest-embedded plugin work with Arduino. Jun 14, 2023 5 - Production/Stable N/A
|
:pypi:`pytest-embedded-arduino` Make pytest-embedded plugin work with Arduino. Jul 05, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-embedded-idf` Make pytest-embedded plugin work with ESP-IDF. Jun 14, 2023 5 - Production/Stable N/A
|
:pypi:`pytest-embedded-idf` Make pytest-embedded plugin work with ESP-IDF. Jul 05, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-embedded-jtag` Make pytest-embedded plugin work with JTAG. Jun 14, 2023 5 - Production/Stable N/A
|
:pypi:`pytest-embedded-jtag` Make pytest-embedded plugin work with JTAG. Jul 05, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-embedded-qemu` Make pytest-embedded plugin work with QEMU. Jun 14, 2023 5 - Production/Stable N/A
|
:pypi:`pytest-embedded-qemu` Make pytest-embedded plugin work with QEMU. Jul 05, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-embedded-serial` Make pytest-embedded plugin work with Serial. Jun 14, 2023 5 - Production/Stable N/A
|
:pypi:`pytest-embedded-serial` Make pytest-embedded plugin work with Serial. Jul 05, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-embedded-serial-esp` Make pytest-embedded plugin work with Espressif target boards. Jun 14, 2023 5 - Production/Stable N/A
|
:pypi:`pytest-embedded-serial-esp` Make pytest-embedded plugin work with Espressif target boards. Jul 05, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-embrace` 💝 Dataclasses-as-tests. Describe the runtime once and multiply coverage with no boilerplate. Mar 25, 2023 N/A pytest (>=7.0,<8.0)
|
:pypi:`pytest-embrace` 💝 Dataclasses-as-tests. Describe the runtime once and multiply coverage with no boilerplate. Mar 25, 2023 N/A pytest (>=7.0,<8.0)
|
||||||
:pypi:`pytest-emoji` A pytest plugin that adds emojis to your test result report Feb 19, 2019 4 - Beta pytest (>=4.2.1)
|
:pypi:`pytest-emoji` A pytest plugin that adds emojis to your test result report Feb 19, 2019 4 - Beta pytest (>=4.2.1)
|
||||||
:pypi:`pytest-emoji-output` Pytest plugin to represent test output with emoji support Apr 09, 2023 4 - Beta pytest (==7.0.1)
|
:pypi:`pytest-emoji-output` Pytest plugin to represent test output with emoji support Apr 09, 2023 4 - Beta pytest (==7.0.1)
|
||||||
:pypi:`pytest-enabler` Enable installed pytest plugins May 12, 2023 5 - Production/Stable pytest (>=6) ; extra == 'testing'
|
:pypi:`pytest-enabler` Enable installed pytest plugins Jun 26, 2023 5 - Production/Stable pytest (>=6) ; extra == 'testing'
|
||||||
:pypi:`pytest-encode` set your encoding and logger Nov 06, 2021 N/A N/A
|
:pypi:`pytest-encode` set your encoding and logger Nov 06, 2021 N/A N/A
|
||||||
:pypi:`pytest-encode-kane` set your encoding and logger Nov 16, 2021 N/A pytest
|
:pypi:`pytest-encode-kane` set your encoding and logger Nov 16, 2021 N/A pytest
|
||||||
:pypi:`pytest-enhanced-reports` Enhanced test reports for pytest Dec 15, 2022 N/A N/A
|
:pypi:`pytest-enhanced-reports` Enhanced test reports for pytest Dec 15, 2022 N/A N/A
|
||||||
|
@ -469,7 +471,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-flask-sqlalchemy` A pytest plugin for preserving test isolation in Flask-SQlAlchemy using database transactions. Apr 30, 2022 4 - Beta pytest (>=3.2.1)
|
:pypi:`pytest-flask-sqlalchemy` A pytest plugin for preserving test isolation in Flask-SQlAlchemy using database transactions. Apr 30, 2022 4 - Beta pytest (>=3.2.1)
|
||||||
:pypi:`pytest-flask-sqlalchemy-transactions` Run tests in transactions using pytest, Flask, and SQLalchemy. Aug 02, 2018 4 - Beta pytest (>=3.2.1)
|
:pypi:`pytest-flask-sqlalchemy-transactions` Run tests in transactions using pytest, Flask, and SQLalchemy. Aug 02, 2018 4 - Beta pytest (>=3.2.1)
|
||||||
:pypi:`pytest-flexreport` Apr 15, 2023 4 - Beta pytest
|
:pypi:`pytest-flexreport` Apr 15, 2023 4 - Beta pytest
|
||||||
:pypi:`pytest-fluent` A pytest plugin in order to provide logs via fluentd Jul 12, 2022 4 - Beta pytest
|
:pypi:`pytest-fluent` A pytest plugin in order to provide logs via fluentd Jun 26, 2023 4 - Beta pytest (>=7.0.0)
|
||||||
:pypi:`pytest-fluentbit` A pytest plugin in order to provide logs via fluentbit Jun 16, 2023 4 - Beta pytest (>=7.0.0)
|
:pypi:`pytest-fluentbit` A pytest plugin in order to provide logs via fluentbit Jun 16, 2023 4 - Beta pytest (>=7.0.0)
|
||||||
:pypi:`pytest-flyte` Pytest fixtures for simplifying Flyte integration testing May 03, 2021 N/A pytest
|
:pypi:`pytest-flyte` Pytest fixtures for simplifying Flyte integration testing May 03, 2021 N/A pytest
|
||||||
:pypi:`pytest-focus` A pytest plugin that alerts user of failed test cases with screen notifications May 04, 2019 4 - Beta pytest
|
:pypi:`pytest-focus` A pytest plugin that alerts user of failed test cases with screen notifications May 04, 2019 4 - Beta pytest
|
||||||
|
@ -494,7 +496,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-gherkin` A flexible framework for executing BDD gherkin tests Jul 27, 2019 3 - Alpha pytest (>=5.0.0)
|
:pypi:`pytest-gherkin` A flexible framework for executing BDD gherkin tests Jul 27, 2019 3 - Alpha pytest (>=5.0.0)
|
||||||
:pypi:`pytest-gh-log-group` pytest plugin for gh actions Jan 11, 2022 3 - Alpha pytest
|
:pypi:`pytest-gh-log-group` pytest plugin for gh actions Jan 11, 2022 3 - Alpha pytest
|
||||||
:pypi:`pytest-ghostinspector` For finding/executing Ghost Inspector tests May 17, 2016 3 - Alpha N/A
|
:pypi:`pytest-ghostinspector` For finding/executing Ghost Inspector tests May 17, 2016 3 - Alpha N/A
|
||||||
:pypi:`pytest-girder` A set of pytest fixtures for testing Girder applications. Jun 14, 2023 N/A N/A
|
:pypi:`pytest-girder` A set of pytest fixtures for testing Girder applications. Jun 28, 2023 N/A N/A
|
||||||
:pypi:`pytest-git` Git repository fixture for py.test May 28, 2019 5 - Production/Stable pytest
|
:pypi:`pytest-git` Git repository fixture for py.test May 28, 2019 5 - Production/Stable pytest
|
||||||
:pypi:`pytest-gitconfig` Provide a gitconfig sandbox for testing Jun 22, 2023 4 - Beta pytest>=7.1.2
|
:pypi:`pytest-gitconfig` Provide a gitconfig sandbox for testing Jun 22, 2023 4 - Beta pytest>=7.1.2
|
||||||
:pypi:`pytest-gitcov` Pytest plugin for reporting on coverage of the last git commit. Jan 11, 2020 2 - Pre-Alpha N/A
|
:pypi:`pytest-gitcov` Pytest plugin for reporting on coverage of the last git commit. Jan 11, 2020 2 - Pre-Alpha N/A
|
||||||
|
@ -512,6 +514,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-google-chat` Notify google chat channel for test results Mar 27, 2022 4 - Beta pytest
|
:pypi:`pytest-google-chat` Notify google chat channel for test results Mar 27, 2022 4 - Beta pytest
|
||||||
:pypi:`pytest-graphql-schema` Get graphql schema as fixture for pytest Oct 18, 2019 N/A N/A
|
:pypi:`pytest-graphql-schema` Get graphql schema as fixture for pytest Oct 18, 2019 N/A N/A
|
||||||
:pypi:`pytest-greendots` Green progress dots Feb 08, 2014 3 - Alpha N/A
|
:pypi:`pytest-greendots` Green progress dots Feb 08, 2014 3 - Alpha N/A
|
||||||
|
:pypi:`pytest-group-by-class` A Pytest plugin for running a subset of your tests by splitting them in to groups of classes. Jun 27, 2023 5 - Production/Stable pytest (>=2.5)
|
||||||
:pypi:`pytest-growl` Growl notifications for pytest results. Jan 13, 2014 5 - Production/Stable N/A
|
:pypi:`pytest-growl` Growl notifications for pytest results. Jan 13, 2014 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-grpc` pytest plugin for grpc May 01, 2020 N/A pytest (>=3.6.0)
|
:pypi:`pytest-grpc` pytest plugin for grpc May 01, 2020 N/A pytest (>=3.6.0)
|
||||||
:pypi:`pytest-grunnur` Py.Test plugin for Grunnur-based packages. Feb 05, 2023 N/A N/A
|
:pypi:`pytest-grunnur` Py.Test plugin for Grunnur-based packages. Feb 05, 2023 N/A N/A
|
||||||
|
@ -527,7 +530,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-historic` Custom report to display pytest historical execution records Apr 08, 2020 N/A pytest
|
:pypi:`pytest-historic` Custom report to display pytest historical execution records Apr 08, 2020 N/A pytest
|
||||||
:pypi:`pytest-historic-hook` Custom listener to store execution results into MYSQL DB, which is used for pytest-historic report Apr 08, 2020 N/A pytest
|
:pypi:`pytest-historic-hook` Custom listener to store execution results into MYSQL DB, which is used for pytest-historic report Apr 08, 2020 N/A pytest
|
||||||
:pypi:`pytest-homeassistant` A pytest plugin for use with homeassistant custom components. Aug 12, 2020 4 - Beta N/A
|
:pypi:`pytest-homeassistant` A pytest plugin for use with homeassistant custom components. Aug 12, 2020 4 - Beta N/A
|
||||||
:pypi:`pytest-homeassistant-custom-component` Experimental package to automatically extract test plugins for Home Assistant custom components Jun 24, 2023 3 - Alpha pytest (==7.3.1)
|
:pypi:`pytest-homeassistant-custom-component` Experimental package to automatically extract test plugins for Home Assistant custom components Jul 07, 2023 3 - Alpha pytest (==7.3.1)
|
||||||
:pypi:`pytest-honey` A simple plugin to use with pytest Jan 07, 2022 4 - Beta pytest (>=3.5.0)
|
:pypi:`pytest-honey` A simple plugin to use with pytest Jan 07, 2022 4 - Beta pytest (>=3.5.0)
|
||||||
:pypi:`pytest-honors` Report on tests that honor constraints, and guard against regressions Mar 06, 2020 4 - Beta N/A
|
:pypi:`pytest-honors` Report on tests that honor constraints, and guard against regressions Mar 06, 2020 4 - Beta N/A
|
||||||
:pypi:`pytest-hot-reloading` Jun 23, 2023 N/A N/A
|
:pypi:`pytest-hot-reloading` Jun 23, 2023 N/A N/A
|
||||||
|
@ -570,7 +573,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-ini` Reuse pytest.ini to store env variables Apr 26, 2022 N/A N/A
|
:pypi:`pytest-ini` Reuse pytest.ini to store env variables Apr 26, 2022 N/A N/A
|
||||||
:pypi:`pytest-inline` A pytest plugin for writing inline tests. Feb 08, 2023 4 - Beta pytest (>=7.0.0)
|
:pypi:`pytest-inline` A pytest plugin for writing inline tests. Feb 08, 2023 4 - Beta pytest (>=7.0.0)
|
||||||
:pypi:`pytest-inmanta` A py.test plugin providing fixtures to simplify inmanta modules testing. Feb 23, 2023 5 - Production/Stable N/A
|
:pypi:`pytest-inmanta` A py.test plugin providing fixtures to simplify inmanta modules testing. Feb 23, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-inmanta-extensions` Inmanta tests package Apr 12, 2023 5 - Production/Stable N/A
|
:pypi:`pytest-inmanta-extensions` Inmanta tests package Jul 04, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-inmanta-lsm` Common fixtures for inmanta LSM related modules May 17, 2023 5 - Production/Stable N/A
|
:pypi:`pytest-inmanta-lsm` Common fixtures for inmanta LSM related modules May 17, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-inmanta-yang` Common fixtures used in inmanta yang related modules Jun 16, 2022 4 - Beta N/A
|
:pypi:`pytest-inmanta-yang` Common fixtures used in inmanta yang related modules Jun 16, 2022 4 - Beta N/A
|
||||||
:pypi:`pytest-Inomaly` A simple image diff plugin for pytest Feb 13, 2018 4 - Beta N/A
|
:pypi:`pytest-Inomaly` A simple image diff plugin for pytest Feb 13, 2018 4 - Beta N/A
|
||||||
|
@ -581,7 +584,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-integration-mark` Automatic integration test marking and excluding plugin for pytest May 22, 2023 N/A pytest (>=5.2)
|
:pypi:`pytest-integration-mark` Automatic integration test marking and excluding plugin for pytest May 22, 2023 N/A pytest (>=5.2)
|
||||||
:pypi:`pytest-interactive` A pytest plugin for console based interactive test selection just after the collection phase Nov 30, 2017 3 - Alpha N/A
|
:pypi:`pytest-interactive` A pytest plugin for console based interactive test selection just after the collection phase Nov 30, 2017 3 - Alpha N/A
|
||||||
:pypi:`pytest-intercept-remote` Pytest plugin for intercepting outgoing connection requests during pytest run. May 24, 2021 4 - Beta pytest (>=4.6)
|
:pypi:`pytest-intercept-remote` Pytest plugin for intercepting outgoing connection requests during pytest run. May 24, 2021 4 - Beta pytest (>=4.6)
|
||||||
:pypi:`pytest-interface-tester` Pytest plugin for checking charm relation interface protocol compliance. May 09, 2023 4 - Beta pytest
|
:pypi:`pytest-interface-tester` Pytest plugin for checking charm relation interface protocol compliance. Jun 29, 2023 4 - Beta pytest
|
||||||
:pypi:`pytest-invenio` Pytest fixtures for Invenio. Jun 02, 2023 5 - Production/Stable pytest (<7.2.0,>=6)
|
:pypi:`pytest-invenio` Pytest fixtures for Invenio. Jun 02, 2023 5 - Production/Stable pytest (<7.2.0,>=6)
|
||||||
:pypi:`pytest-involve` Run tests covering a specific file or changeset Feb 02, 2020 4 - Beta pytest (>=3.5.0)
|
:pypi:`pytest-involve` Run tests covering a specific file or changeset Feb 02, 2020 4 - Beta pytest (>=3.5.0)
|
||||||
:pypi:`pytest-ipdb` A py.test plug-in to enable drop to ipdb debugger on test failure. Mar 20, 2013 2 - Pre-Alpha N/A
|
:pypi:`pytest-ipdb` A py.test plug-in to enable drop to ipdb debugger on test failure. Mar 20, 2013 2 - Pre-Alpha N/A
|
||||||
|
@ -680,7 +683,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-maybe-raises` Pytest fixture for optional exception testing. May 27, 2022 N/A pytest ; extra == 'dev'
|
:pypi:`pytest-maybe-raises` Pytest fixture for optional exception testing. May 27, 2022 N/A pytest ; extra == 'dev'
|
||||||
:pypi:`pytest-mccabe` pytest plugin to run the mccabe code complexity checker. Jul 22, 2020 3 - Alpha pytest (>=5.4.0)
|
:pypi:`pytest-mccabe` pytest plugin to run the mccabe code complexity checker. Jul 22, 2020 3 - Alpha pytest (>=5.4.0)
|
||||||
:pypi:`pytest-md` Plugin for generating Markdown reports for pytest results Jul 11, 2019 3 - Alpha pytest (>=4.2.1)
|
:pypi:`pytest-md` Plugin for generating Markdown reports for pytest results Jul 11, 2019 3 - Alpha pytest (>=4.2.1)
|
||||||
:pypi:`pytest-md-report` A pytest plugin to make a test results report with Markdown table format. May 28, 2023 4 - Beta pytest (!=6.0.0,<8,>=3.3.2)
|
:pypi:`pytest-md-report` A pytest plugin to make a test results report with Markdown table format. Jun 25, 2023 4 - Beta pytest (!=6.0.0,<8,>=3.3.2)
|
||||||
:pypi:`pytest-memlog` Log memory usage during tests May 03, 2023 N/A pytest (>=7.3.0,<8.0.0)
|
:pypi:`pytest-memlog` Log memory usage during tests May 03, 2023 N/A pytest (>=7.3.0,<8.0.0)
|
||||||
:pypi:`pytest-memprof` Estimates memory consumption of test functions Mar 29, 2019 4 - Beta N/A
|
:pypi:`pytest-memprof` Estimates memory consumption of test functions Mar 29, 2019 4 - Beta N/A
|
||||||
:pypi:`pytest-memray` A simple plugin to use with pytest Jun 06, 2023 N/A pytest>=7.2
|
:pypi:`pytest-memray` A simple plugin to use with pytest Jun 06, 2023 N/A pytest>=7.2
|
||||||
|
@ -714,7 +717,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-molecule` PyTest Molecule Plugin :: discover and run molecule tests Mar 29, 2022 5 - Production/Stable pytest (>=7.0.0)
|
:pypi:`pytest-molecule` PyTest Molecule Plugin :: discover and run molecule tests Mar 29, 2022 5 - Production/Stable pytest (>=7.0.0)
|
||||||
:pypi:`pytest-mongo` MongoDB process and client fixtures plugin for Pytest. Jun 07, 2021 5 - Production/Stable pytest
|
:pypi:`pytest-mongo` MongoDB process and client fixtures plugin for Pytest. Jun 07, 2021 5 - Production/Stable pytest
|
||||||
:pypi:`pytest-mongodb` pytest plugin for MongoDB fixtures May 16, 2023 5 - Production/Stable N/A
|
:pypi:`pytest-mongodb` pytest plugin for MongoDB fixtures May 16, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-monitor` Pytest plugin for analyzing resource usage. Oct 22, 2022 5 - Production/Stable pytest
|
:pypi:`pytest-monitor` Pytest plugin for analyzing resource usage. Jun 25, 2023 5 - Production/Stable pytest
|
||||||
:pypi:`pytest-monkeyplus` pytest's monkeypatch subclass with extra functionalities Sep 18, 2012 5 - Production/Stable N/A
|
:pypi:`pytest-monkeyplus` pytest's monkeypatch subclass with extra functionalities Sep 18, 2012 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-monkeytype` pytest-monkeytype: Generate Monkeytype annotations from your pytest tests. Jul 29, 2020 4 - Beta N/A
|
:pypi:`pytest-monkeytype` pytest-monkeytype: Generate Monkeytype annotations from your pytest tests. Jul 29, 2020 4 - Beta N/A
|
||||||
:pypi:`pytest-moto` Fixtures for integration tests of AWS services,uses moto mocking library. Aug 28, 2015 1 - Planning N/A
|
:pypi:`pytest-moto` Fixtures for integration tests of AWS services,uses moto mocking library. Aug 28, 2015 1 - Planning N/A
|
||||||
|
@ -732,13 +735,13 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-mutagen` Add the mutation testing feature to pytest Jul 24, 2020 N/A pytest (>=5.4)
|
:pypi:`pytest-mutagen` Add the mutation testing feature to pytest Jul 24, 2020 N/A pytest (>=5.4)
|
||||||
:pypi:`pytest-mypy` Mypy static type checker plugin for Pytest Dec 18, 2022 4 - Beta pytest (>=6.2) ; python_version >= "3.10"
|
:pypi:`pytest-mypy` Mypy static type checker plugin for Pytest Dec 18, 2022 4 - Beta pytest (>=6.2) ; python_version >= "3.10"
|
||||||
:pypi:`pytest-mypyd` Mypy static type checker plugin for Pytest Aug 20, 2019 4 - Beta pytest (<4.7,>=2.8) ; python_version < "3.5"
|
:pypi:`pytest-mypyd` Mypy static type checker plugin for Pytest Aug 20, 2019 4 - Beta pytest (<4.7,>=2.8) ; python_version < "3.5"
|
||||||
:pypi:`pytest-mypy-plugins` pytest plugin for writing tests for mypy plugins May 05, 2023 4 - Beta pytest (>=6.2.0)
|
:pypi:`pytest-mypy-plugins` pytest plugin for writing tests for mypy plugins Jun 29, 2023 4 - Beta pytest (>=7.0.0)
|
||||||
:pypi:`pytest-mypy-plugins-shim` Substitute for "pytest-mypy-plugins" for Python implementations which aren't supported by mypy. Apr 12, 2021 N/A pytest>=6.0.0
|
:pypi:`pytest-mypy-plugins-shim` Substitute for "pytest-mypy-plugins" for Python implementations which aren't supported by mypy. Apr 12, 2021 N/A pytest>=6.0.0
|
||||||
:pypi:`pytest-mypy-testing` Pytest plugin to check mypy output. Feb 25, 2023 N/A pytest>=7,<8
|
:pypi:`pytest-mypy-testing` Pytest plugin to check mypy output. Feb 25, 2023 N/A pytest>=7,<8
|
||||||
:pypi:`pytest-mysql` MySQL process and client fixtures for pytest Mar 27, 2023 5 - Production/Stable pytest (>=6.2)
|
:pypi:`pytest-mysql` MySQL process and client fixtures for pytest Mar 27, 2023 5 - Production/Stable pytest (>=6.2)
|
||||||
:pypi:`pytest-needle` pytest plugin for visual testing websites using selenium Dec 10, 2018 4 - Beta pytest (<5.0.0,>=3.0.0)
|
:pypi:`pytest-needle` pytest plugin for visual testing websites using selenium Dec 10, 2018 4 - Beta pytest (<5.0.0,>=3.0.0)
|
||||||
:pypi:`pytest-neo` pytest-neo is a plugin for pytest that shows tests like screen of Matrix. Jan 08, 2022 3 - Alpha pytest (>=6.2.0)
|
:pypi:`pytest-neo` pytest-neo is a plugin for pytest that shows tests like screen of Matrix. Jan 08, 2022 3 - Alpha pytest (>=6.2.0)
|
||||||
:pypi:`pytest-netdut` "Automated software testing for switches using pytest" Jun 19, 2023 N/A pytest (>=3.5.0)
|
:pypi:`pytest-netdut` "Automated software testing for switches using pytest" Jul 06, 2023 N/A pytest (>=3.5.0)
|
||||||
:pypi:`pytest-network` A simple plugin to disable network on socket level. May 07, 2020 N/A N/A
|
:pypi:`pytest-network` A simple plugin to disable network on socket level. May 07, 2020 N/A N/A
|
||||||
:pypi:`pytest-network-endpoints` Network endpoints plugin for pytest Mar 06, 2022 N/A pytest
|
:pypi:`pytest-network-endpoints` Network endpoints plugin for pytest Mar 06, 2022 N/A pytest
|
||||||
:pypi:`pytest-never-sleep` pytest plugin helps to avoid adding tests without mock \`time.sleep\` May 05, 2021 3 - Alpha pytest (>=3.5.1)
|
:pypi:`pytest-never-sleep` pytest plugin helps to avoid adding tests without mock \`time.sleep\` May 05, 2021 3 - Alpha pytest (>=3.5.1)
|
||||||
|
@ -762,7 +765,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-oar` PyTest plugin for the OAR testing framework May 02, 2023 N/A pytest>=6.0.1
|
:pypi:`pytest-oar` PyTest plugin for the OAR testing framework May 02, 2023 N/A pytest>=6.0.1
|
||||||
:pypi:`pytest-object-getter` Import any object from a 3rd party module while mocking its namespace on demand. Jul 31, 2022 5 - Production/Stable pytest
|
:pypi:`pytest-object-getter` Import any object from a 3rd party module while mocking its namespace on demand. Jul 31, 2022 5 - Production/Stable pytest
|
||||||
:pypi:`pytest-ochrus` pytest results data-base and HTML reporter Feb 21, 2018 4 - Beta N/A
|
:pypi:`pytest-ochrus` pytest results data-base and HTML reporter Feb 21, 2018 4 - Beta N/A
|
||||||
:pypi:`pytest-odoo` py.test plugin to run Odoo tests Nov 17, 2022 4 - Beta pytest (>=7.2.0)
|
:pypi:`pytest-odoo` py.test plugin to run Odoo tests Jul 06, 2023 4 - Beta pytest (>=7.2.0)
|
||||||
:pypi:`pytest-odoo-fixtures` Project description Jun 25, 2019 N/A N/A
|
:pypi:`pytest-odoo-fixtures` Project description Jun 25, 2019 N/A N/A
|
||||||
:pypi:`pytest-oerp` pytest plugin to test OpenERP modules Feb 28, 2012 3 - Alpha N/A
|
:pypi:`pytest-oerp` pytest plugin to test OpenERP modules Feb 28, 2012 3 - Alpha N/A
|
||||||
:pypi:`pytest-offline` Mar 09, 2023 1 - Planning pytest (>=7.0.0,<8.0.0)
|
:pypi:`pytest-offline` Mar 09, 2023 1 - Planning pytest (>=7.0.0,<8.0.0)
|
||||||
|
@ -808,7 +811,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-percent` Change the exit code of pytest test sessions when a required percent of tests pass. May 21, 2020 N/A pytest (>=5.2.0)
|
:pypi:`pytest-percent` Change the exit code of pytest test sessions when a required percent of tests pass. May 21, 2020 N/A pytest (>=5.2.0)
|
||||||
:pypi:`pytest-perf` Run performance tests against the mainline code. Jun 02, 2023 5 - Production/Stable pytest (>=6) ; extra == 'testing'
|
:pypi:`pytest-perf` Run performance tests against the mainline code. Jun 02, 2023 5 - Production/Stable pytest (>=6) ; extra == 'testing'
|
||||||
:pypi:`pytest-performance` A simple plugin to ensure the execution of critical sections of code has not been impacted Sep 11, 2020 5 - Production/Stable pytest (>=3.7.0)
|
:pypi:`pytest-performance` A simple plugin to ensure the execution of critical sections of code has not been impacted Sep 11, 2020 5 - Production/Stable pytest (>=3.7.0)
|
||||||
:pypi:`pytest-persistence` Pytest tool for persistent objects Jun 14, 2023 N/A N/A
|
:pypi:`pytest-persistence` Pytest tool for persistent objects Jul 04, 2023 N/A N/A
|
||||||
:pypi:`pytest-pg` A tiny plugin for pytest which runs PostgreSQL in Docker May 04, 2023 5 - Production/Stable pytest (>=6.0.0)
|
:pypi:`pytest-pg` A tiny plugin for pytest which runs PostgreSQL in Docker May 04, 2023 5 - Production/Stable pytest (>=6.0.0)
|
||||||
:pypi:`pytest-pgsql` Pytest plugins and helpers for tests using a Postgres database. May 13, 2020 5 - Production/Stable pytest (>=3.0.0)
|
:pypi:`pytest-pgsql` Pytest plugins and helpers for tests using a Postgres database. May 13, 2020 5 - Production/Stable pytest (>=3.0.0)
|
||||||
:pypi:`pytest-phmdoctest` pytest plugin to test Python examples in Markdown using phmdoctest. Apr 15, 2022 4 - Beta pytest (>=5.4.3)
|
:pypi:`pytest-phmdoctest` pytest plugin to test Python examples in Markdown using phmdoctest. Apr 15, 2022 4 - Beta pytest (>=5.4.3)
|
||||||
|
@ -825,6 +828,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-play` pytest plugin that let you automate actions and assertions with test metrics reporting executing plain YAML files Jun 12, 2019 5 - Production/Stable N/A
|
:pypi:`pytest-play` pytest plugin that let you automate actions and assertions with test metrics reporting executing plain YAML files Jun 12, 2019 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-playbook` Pytest plugin for reading playbooks. Jan 21, 2021 3 - Alpha pytest (>=6.1.2,<7.0.0)
|
:pypi:`pytest-playbook` Pytest plugin for reading playbooks. Jan 21, 2021 3 - Alpha pytest (>=6.1.2,<7.0.0)
|
||||||
:pypi:`pytest-playwright` A pytest wrapper with fixtures for Playwright to automate web browsers Apr 24, 2023 N/A pytest (<8.0.0,>=6.2.4)
|
:pypi:`pytest-playwright` A pytest wrapper with fixtures for Playwright to automate web browsers Apr 24, 2023 N/A pytest (<8.0.0,>=6.2.4)
|
||||||
|
:pypi:`pytest-playwright-async` ASYNC Pytest plugin for Playwright Jul 03, 2023 N/A N/A
|
||||||
:pypi:`pytest-playwrights` A pytest wrapper with fixtures for Playwright to automate web browsers Dec 02, 2021 N/A N/A
|
:pypi:`pytest-playwrights` A pytest wrapper with fixtures for Playwright to automate web browsers Dec 02, 2021 N/A N/A
|
||||||
:pypi:`pytest-playwright-snapshot` A pytest wrapper for snapshot testing with playwright Aug 19, 2021 N/A N/A
|
:pypi:`pytest-playwright-snapshot` A pytest wrapper for snapshot testing with playwright Aug 19, 2021 N/A N/A
|
||||||
:pypi:`pytest-playwright-visual` A pytest fixture for visual testing with Playwright Apr 28, 2022 N/A N/A
|
:pypi:`pytest-playwright-visual` A pytest fixture for visual testing with Playwright Apr 28, 2022 N/A N/A
|
||||||
|
@ -842,6 +846,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-poo` Visualize your crappy tests Mar 25, 2021 5 - Production/Stable pytest (>=2.3.4)
|
:pypi:`pytest-poo` Visualize your crappy tests Mar 25, 2021 5 - Production/Stable pytest (>=2.3.4)
|
||||||
:pypi:`pytest-poo-fail` Visualize your failed tests with poo Feb 12, 2015 5 - Production/Stable N/A
|
:pypi:`pytest-poo-fail` Visualize your failed tests with poo Feb 12, 2015 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-pop` A pytest plugin to help with testing pop projects May 09, 2023 5 - Production/Stable pytest
|
:pypi:`pytest-pop` A pytest plugin to help with testing pop projects May 09, 2023 5 - Production/Stable pytest
|
||||||
|
:pypi:`pytest-porringer` Jun 24, 2023 N/A pytest>=7.1.2
|
||||||
:pypi:`pytest-portion` Select a portion of the collected tests Jan 28, 2021 4 - Beta pytest (>=3.5.0)
|
:pypi:`pytest-portion` Select a portion of the collected tests Jan 28, 2021 4 - Beta pytest (>=3.5.0)
|
||||||
:pypi:`pytest-postgres` Run PostgreSQL in Docker container in Pytest. Mar 22, 2020 N/A pytest
|
:pypi:`pytest-postgres` Run PostgreSQL in Docker container in Pytest. Mar 22, 2020 N/A pytest
|
||||||
:pypi:`pytest-postgresql` Postgresql fixtures and fixture factories for Pytest. May 20, 2023 5 - Production/Stable pytest (>=6.2)
|
:pypi:`pytest-postgresql` Postgresql fixtures and fixture factories for Pytest. May 20, 2023 5 - Production/Stable pytest (>=6.2)
|
||||||
|
@ -851,7 +856,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-pretty` pytest plugin for printing summary data as I want it Apr 05, 2023 5 - Production/Stable pytest>=7
|
:pypi:`pytest-pretty` pytest plugin for printing summary data as I want it Apr 05, 2023 5 - Production/Stable pytest>=7
|
||||||
:pypi:`pytest-pretty-terminal` pytest plugin for generating prettier terminal output Jan 31, 2022 N/A pytest (>=3.4.1)
|
:pypi:`pytest-pretty-terminal` pytest plugin for generating prettier terminal output Jan 31, 2022 N/A pytest (>=3.4.1)
|
||||||
:pypi:`pytest-pride` Minitest-style test colors Apr 02, 2016 3 - Alpha N/A
|
:pypi:`pytest-pride` Minitest-style test colors Apr 02, 2016 3 - Alpha N/A
|
||||||
:pypi:`pytest-print` pytest-print adds the printer fixture you can use to print messages to the user (directly to the pytest runner, not stdout) Jun 16, 2023 5 - Production/Stable pytest>=7.3.2
|
:pypi:`pytest-print` pytest-print adds the printer fixture you can use to print messages to the user (directly to the pytest runner, not stdout) Jun 28, 2023 5 - Production/Stable pytest>=7.3.2
|
||||||
:pypi:`pytest-profiles` pytest plugin for configuration profiles Dec 09, 2021 4 - Beta pytest (>=3.7.0)
|
:pypi:`pytest-profiles` pytest plugin for configuration profiles Dec 09, 2021 4 - Beta pytest (>=3.7.0)
|
||||||
:pypi:`pytest-profiling` Profiling plugin for py.test May 28, 2019 5 - Production/Stable pytest
|
:pypi:`pytest-profiling` Profiling plugin for py.test May 28, 2019 5 - Production/Stable pytest
|
||||||
:pypi:`pytest-progress` pytest plugin for instant test progress status Jan 31, 2022 5 - Production/Stable N/A
|
:pypi:`pytest-progress` pytest plugin for instant test progress status Jan 31, 2022 5 - Production/Stable N/A
|
||||||
|
@ -879,7 +884,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-pyq` Pytest fixture "q" for pyq Mar 10, 2020 5 - Production/Stable N/A
|
:pypi:`pytest-pyq` Pytest fixture "q" for pyq Mar 10, 2020 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-pyramid` pytest_pyramid - provides fixtures for testing pyramid applications with pytest test suite Dec 13, 2022 5 - Production/Stable pytest
|
:pypi:`pytest-pyramid` pytest_pyramid - provides fixtures for testing pyramid applications with pytest test suite Dec 13, 2022 5 - Production/Stable pytest
|
||||||
:pypi:`pytest-pyramid-server` Pyramid server fixture for py.test May 28, 2019 5 - Production/Stable pytest
|
:pypi:`pytest-pyramid-server` Pyramid server fixture for py.test May 28, 2019 5 - Production/Stable pytest
|
||||||
:pypi:`pytest-pyreport` PyReport is a lightweight reporting plugin for Pytest that provides concise HTML report May 08, 2023 N/A pytest (>=7.3.1)
|
:pypi:`pytest-pyreport` PyReport is a lightweight reporting plugin for Pytest that provides concise HTML report Jul 02, 2023 N/A pytest (>=7.3.1)
|
||||||
:pypi:`pytest-pyright` Pytest plugin for type checking code with Pyright Nov 20, 2022 4 - Beta pytest (>=7.0.0)
|
:pypi:`pytest-pyright` Pytest plugin for type checking code with Pyright Nov 20, 2022 4 - Beta pytest (>=7.0.0)
|
||||||
:pypi:`pytest-pyspec` A plugin that transforms the pytest output into a result similar to the RSpec. It enables the use of docstrings to display results and also enables the use of the prefixes "describe", "with" and "it". Mar 12, 2023 5 - Production/Stable pytest (>=7.2.1,<8.0.0)
|
:pypi:`pytest-pyspec` A plugin that transforms the pytest output into a result similar to the RSpec. It enables the use of docstrings to display results and also enables the use of the prefixes "describe", "with" and "it". Mar 12, 2023 5 - Production/Stable pytest (>=7.2.1,<8.0.0)
|
||||||
:pypi:`pytest-pystack` Plugin to run pystack after a timeout for a test suite. May 07, 2023 N/A pytest (>=3.5.0)
|
:pypi:`pytest-pystack` Plugin to run pystack after a timeout for a test suite. May 07, 2023 N/A pytest (>=3.5.0)
|
||||||
|
@ -890,14 +895,14 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-qaseio` Pytest plugin for Qase.io integration May 11, 2023 4 - Beta pytest (>=7.2.2,<8.0.0)
|
:pypi:`pytest-qaseio` Pytest plugin for Qase.io integration May 11, 2023 4 - Beta pytest (>=7.2.2,<8.0.0)
|
||||||
:pypi:`pytest-qasync` Pytest support for qasync. Jul 12, 2021 4 - Beta pytest (>=5.4.0)
|
:pypi:`pytest-qasync` Pytest support for qasync. Jul 12, 2021 4 - Beta pytest (>=5.4.0)
|
||||||
:pypi:`pytest-qatouch` Pytest plugin for uploading test results to your QA Touch Testrun. Feb 14, 2023 4 - Beta pytest (>=6.2.0)
|
:pypi:`pytest-qatouch` Pytest plugin for uploading test results to your QA Touch Testrun. Feb 14, 2023 4 - Beta pytest (>=6.2.0)
|
||||||
:pypi:`pytest-qgis` A pytest plugin for testing QGIS python plugins Jun 09, 2023 5 - Production/Stable pytest (>=6.2.5)
|
:pypi:`pytest-qgis` A pytest plugin for testing QGIS python plugins Jun 30, 2023 5 - Production/Stable pytest (>=6.2.5)
|
||||||
:pypi:`pytest-qml` Run QML Tests with pytest Dec 02, 2020 4 - Beta pytest (>=6.0.0)
|
:pypi:`pytest-qml` Run QML Tests with pytest Dec 02, 2020 4 - Beta pytest (>=6.0.0)
|
||||||
:pypi:`pytest-qr` pytest plugin to generate test result QR codes Nov 25, 2021 4 - Beta N/A
|
:pypi:`pytest-qr` pytest plugin to generate test result QR codes Nov 25, 2021 4 - Beta N/A
|
||||||
:pypi:`pytest-qt` pytest support for PyQt and PySide applications Oct 25, 2022 5 - Production/Stable pytest (>=3.0.0)
|
:pypi:`pytest-qt` pytest support for PyQt and PySide applications Oct 25, 2022 5 - Production/Stable pytest (>=3.0.0)
|
||||||
:pypi:`pytest-qt-app` QT app fixture for py.test Dec 23, 2015 5 - Production/Stable N/A
|
:pypi:`pytest-qt-app` QT app fixture for py.test Dec 23, 2015 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-quarantine` A plugin for pytest to manage expected test failures Nov 24, 2019 5 - Production/Stable pytest (>=4.6)
|
:pypi:`pytest-quarantine` A plugin for pytest to manage expected test failures Nov 24, 2019 5 - Production/Stable pytest (>=4.6)
|
||||||
:pypi:`pytest-quickcheck` pytest plugin to generate random data inspired by QuickCheck Nov 05, 2022 4 - Beta pytest (>=4.0)
|
:pypi:`pytest-quickcheck` pytest plugin to generate random data inspired by QuickCheck Nov 05, 2022 4 - Beta pytest (>=4.0)
|
||||||
:pypi:`pytest-rabbitmq` RabbitMQ process and client fixtures for pytest Jun 16, 2023 5 - Production/Stable pytest (>=6.2)
|
:pypi:`pytest-rabbitmq` RabbitMQ process and client fixtures for pytest Jul 05, 2023 5 - Production/Stable pytest (>=6.2)
|
||||||
:pypi:`pytest-race` Race conditions tester for pytest Jun 07, 2022 4 - Beta N/A
|
:pypi:`pytest-race` Race conditions tester for pytest Jun 07, 2022 4 - Beta N/A
|
||||||
:pypi:`pytest-rage` pytest plugin to implement PEP712 Oct 21, 2011 3 - Alpha N/A
|
:pypi:`pytest-rage` pytest plugin to implement PEP712 Oct 21, 2011 3 - Alpha N/A
|
||||||
:pypi:`pytest-rail` pytest plugin for creating TestRail runs and adding results May 02, 2022 N/A pytest (>=3.6)
|
:pypi:`pytest-rail` pytest plugin for creating TestRail runs and adding results May 02, 2022 N/A pytest (>=3.6)
|
||||||
|
@ -929,7 +934,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-remfiles` Pytest plugin to create a temporary directory with remote files Jul 01, 2019 5 - Production/Stable N/A
|
:pypi:`pytest-remfiles` Pytest plugin to create a temporary directory with remote files Jul 01, 2019 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-remotedata` Pytest plugin for controlling remote data access. Dec 12, 2022 3 - Alpha pytest (>=4.6)
|
:pypi:`pytest-remotedata` Pytest plugin for controlling remote data access. Dec 12, 2022 3 - Alpha pytest (>=4.6)
|
||||||
:pypi:`pytest-remote-response` Pytest plugin for capturing and mocking connection requests. Apr 26, 2023 5 - Production/Stable pytest (>=4.6)
|
:pypi:`pytest-remote-response` Pytest plugin for capturing and mocking connection requests. Apr 26, 2023 5 - Production/Stable pytest (>=4.6)
|
||||||
:pypi:`pytest-remove-stale-bytecode` py.test plugin to remove stale byte code files. Mar 04, 2020 4 - Beta pytest
|
:pypi:`pytest-remove-stale-bytecode` py.test plugin to remove stale byte code files. Jul 07, 2023 4 - Beta pytest
|
||||||
:pypi:`pytest-reorder` Reorder tests depending on their paths and names. May 31, 2018 4 - Beta pytest
|
:pypi:`pytest-reorder` Reorder tests depending on their paths and names. May 31, 2018 4 - Beta pytest
|
||||||
:pypi:`pytest-repeat` pytest plugin for repeating tests Oct 31, 2020 5 - Production/Stable pytest (>=3.6)
|
:pypi:`pytest-repeat` pytest plugin for repeating tests Oct 31, 2020 5 - Production/Stable pytest (>=3.6)
|
||||||
:pypi:`pytest-replay` Saves previous test runs and allow re-execute previous pytest runs to reproduce crashes or flaky tests Jun 09, 2021 4 - Beta pytest (>=3.0.0)
|
:pypi:`pytest-replay` Saves previous test runs and allow re-execute previous pytest runs to reproduce crashes or flaky tests Jun 09, 2021 4 - Beta pytest (>=3.0.0)
|
||||||
|
@ -943,7 +948,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-reportlog` Replacement for the --resultlog option, focused in simplicity and extensibility May 22, 2023 3 - Alpha pytest
|
:pypi:`pytest-reportlog` Replacement for the --resultlog option, focused in simplicity and extensibility May 22, 2023 3 - Alpha pytest
|
||||||
:pypi:`pytest-report-me` A pytest plugin to generate report. Dec 31, 2020 N/A pytest
|
:pypi:`pytest-report-me` A pytest plugin to generate report. Dec 31, 2020 N/A pytest
|
||||||
:pypi:`pytest-report-parameters` pytest plugin for adding tests' parameters to junit report Jun 18, 2020 3 - Alpha pytest (>=2.4.2)
|
:pypi:`pytest-report-parameters` pytest plugin for adding tests' parameters to junit report Jun 18, 2020 3 - Alpha pytest (>=2.4.2)
|
||||||
:pypi:`pytest-reportportal` Agent for Reporting results of tests to the Report Portal Jun 08, 2023 N/A pytest (>=3.8.0)
|
:pypi:`pytest-reportportal` Agent for Reporting results of tests to the Report Portal Jun 30, 2023 N/A pytest (>=3.8.0)
|
||||||
:pypi:`pytest-reports` An interesting python package Jun 07, 2023 N/A N/A
|
:pypi:`pytest-reports` An interesting python package Jun 07, 2023 N/A N/A
|
||||||
:pypi:`pytest-reqs` pytest plugin to check pinned requirements May 12, 2019 N/A pytest (>=2.4.2)
|
:pypi:`pytest-reqs` pytest plugin to check pinned requirements May 12, 2019 N/A pytest (>=2.4.2)
|
||||||
:pypi:`pytest-requests` A simple plugin to use with pytest Jun 24, 2019 4 - Beta pytest (>=3.5.0)
|
:pypi:`pytest-requests` A simple plugin to use with pytest Jun 24, 2019 4 - Beta pytest (>=3.5.0)
|
||||||
|
@ -952,7 +957,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-requires` A pytest plugin to elegantly skip tests with optional requirements Dec 21, 2021 4 - Beta pytest (>=3.5.0)
|
:pypi:`pytest-requires` A pytest plugin to elegantly skip tests with optional requirements Dec 21, 2021 4 - Beta pytest (>=3.5.0)
|
||||||
:pypi:`pytest-reraise` Make multi-threaded pytest test cases fail when they should Sep 20, 2022 5 - Production/Stable pytest (>=4.6)
|
:pypi:`pytest-reraise` Make multi-threaded pytest test cases fail when they should Sep 20, 2022 5 - Production/Stable pytest (>=4.6)
|
||||||
:pypi:`pytest-rerun` Re-run only changed files in specified branch Jul 08, 2019 N/A pytest (>=3.6)
|
:pypi:`pytest-rerun` Re-run only changed files in specified branch Jul 08, 2019 N/A pytest (>=3.6)
|
||||||
:pypi:`pytest-rerunfailures` pytest plugin to re-run tests to eliminate flaky failures Mar 09, 2023 5 - Production/Stable pytest (>=5.3)
|
:pypi:`pytest-rerunfailures` pytest plugin to re-run tests to eliminate flaky failures Jul 05, 2023 5 - Production/Stable pytest (>=6.2)
|
||||||
:pypi:`pytest-rerunfailures-all-logs` pytest plugin to re-run tests to eliminate flaky failures Mar 07, 2022 5 - Production/Stable N/A
|
:pypi:`pytest-rerunfailures-all-logs` pytest plugin to re-run tests to eliminate flaky failures Mar 07, 2022 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-reserial` Pytest fixture for recording and replaying serial port traffic. Apr 26, 2023 4 - Beta pytest
|
:pypi:`pytest-reserial` Pytest fixture for recording and replaying serial port traffic. Apr 26, 2023 4 - Beta pytest
|
||||||
:pypi:`pytest-resilient-circuits` Resilient Circuits fixtures for PyTest Jun 01, 2023 N/A pytest (~=4.6) ; python_version == "2.7"
|
:pypi:`pytest-resilient-circuits` Resilient Circuits fixtures for PyTest Jun 01, 2023 N/A pytest (~=4.6) ; python_version == "2.7"
|
||||||
|
@ -1002,14 +1007,14 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-sanic` a pytest plugin for Sanic Oct 25, 2021 N/A pytest (>=5.2)
|
:pypi:`pytest-sanic` a pytest plugin for Sanic Oct 25, 2021 N/A pytest (>=5.2)
|
||||||
:pypi:`pytest-sanity` Dec 07, 2020 N/A N/A
|
:pypi:`pytest-sanity` Dec 07, 2020 N/A N/A
|
||||||
:pypi:`pytest-sa-pg` May 14, 2019 N/A N/A
|
:pypi:`pytest-sa-pg` May 14, 2019 N/A N/A
|
||||||
:pypi:`pytest-sbase` A complete web automation framework for end-to-end testing. Jun 24, 2023 5 - Production/Stable N/A
|
:pypi:`pytest-sbase` A complete web automation framework for end-to-end testing. Jul 08, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-scenario` pytest plugin for test scenarios Feb 06, 2017 3 - Alpha N/A
|
:pypi:`pytest-scenario` pytest plugin for test scenarios Feb 06, 2017 3 - Alpha N/A
|
||||||
:pypi:`pytest-schedule` The job of test scheduling for humans. Jan 07, 2023 5 - Production/Stable N/A
|
:pypi:`pytest-schedule` The job of test scheduling for humans. Jan 07, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-schema` 👍 Validate return values against a schema-like object in testing Mar 14, 2022 5 - Production/Stable pytest (>=3.5.0)
|
:pypi:`pytest-schema` 👍 Validate return values against a schema-like object in testing Mar 14, 2022 5 - Production/Stable pytest (>=3.5.0)
|
||||||
:pypi:`pytest-securestore` An encrypted password store for use within pytest cases Nov 08, 2021 4 - Beta N/A
|
:pypi:`pytest-securestore` An encrypted password store for use within pytest cases Nov 08, 2021 4 - Beta N/A
|
||||||
:pypi:`pytest-select` A pytest plugin which allows to (de-)select tests from a file. Jan 18, 2019 3 - Alpha pytest (>=3.0)
|
:pypi:`pytest-select` A pytest plugin which allows to (de-)select tests from a file. Jan 18, 2019 3 - Alpha pytest (>=3.0)
|
||||||
:pypi:`pytest-selenium` pytest plugin for Selenium May 28, 2023 5 - Production/Stable pytest>=6.0.0
|
:pypi:`pytest-selenium` pytest plugin for Selenium May 28, 2023 5 - Production/Stable pytest>=6.0.0
|
||||||
:pypi:`pytest-seleniumbase` A complete web automation framework for end-to-end testing. Jun 24, 2023 5 - Production/Stable N/A
|
:pypi:`pytest-seleniumbase` A complete web automation framework for end-to-end testing. Jul 08, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-selenium-enhancer` pytest plugin for Selenium Apr 29, 2022 5 - Production/Stable N/A
|
:pypi:`pytest-selenium-enhancer` pytest plugin for Selenium Apr 29, 2022 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-selenium-pdiff` A pytest package implementing perceptualdiff for Selenium tests. Apr 06, 2017 2 - Pre-Alpha N/A
|
:pypi:`pytest-selenium-pdiff` A pytest package implementing perceptualdiff for Selenium tests. Apr 06, 2017 2 - Pre-Alpha N/A
|
||||||
:pypi:`pytest-send-email` Send pytest execution result email Dec 04, 2019 N/A N/A
|
:pypi:`pytest-send-email` Send pytest execution result email Dec 04, 2019 N/A N/A
|
||||||
|
@ -1028,7 +1033,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-share-hdf` Plugin to save test data in HDF files and retrieve them for comparison Sep 21, 2022 4 - Beta pytest (>=3.5.0)
|
:pypi:`pytest-share-hdf` Plugin to save test data in HDF files and retrieve them for comparison Sep 21, 2022 4 - Beta pytest (>=3.5.0)
|
||||||
:pypi:`pytest-sharkreport` this is pytest report plugin. Jul 11, 2022 N/A pytest (>=3.5)
|
:pypi:`pytest-sharkreport` this is pytest report plugin. Jul 11, 2022 N/A pytest (>=3.5)
|
||||||
:pypi:`pytest-shell` A pytest plugin to help with testing shell scripts / black box commands Mar 27, 2022 N/A N/A
|
:pypi:`pytest-shell` A pytest plugin to help with testing shell scripts / black box commands Mar 27, 2022 N/A N/A
|
||||||
:pypi:`pytest-shell-utilities` Pytest plugin to simplify running shell commands against the system Sep 23, 2022 4 - Beta pytest (>=6.0.0)
|
:pypi:`pytest-shell-utilities` Pytest plugin to simplify running shell commands against the system Jul 02, 2023 5 - Production/Stable pytest (>=7.1.0)
|
||||||
:pypi:`pytest-sheraf` Versatile ZODB abstraction layer - pytest fixtures Feb 11, 2020 N/A pytest
|
:pypi:`pytest-sheraf` Versatile ZODB abstraction layer - pytest fixtures Feb 11, 2020 N/A pytest
|
||||||
:pypi:`pytest-sherlock` pytest plugin help to find coupled tests Jan 16, 2023 5 - Production/Stable pytest (>=3.5.1)
|
:pypi:`pytest-sherlock` pytest plugin help to find coupled tests Jan 16, 2023 5 - Production/Stable pytest (>=3.5.1)
|
||||||
:pypi:`pytest-shortcuts` Expand command-line shortcuts listed in pytest configuration Oct 29, 2020 4 - Beta pytest (>=3.5.0)
|
:pypi:`pytest-shortcuts` Expand command-line shortcuts listed in pytest configuration Oct 29, 2020 4 - Beta pytest (>=3.5.0)
|
||||||
|
@ -1049,6 +1054,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-smartcov` Smart coverage plugin for pytest. Sep 30, 2017 3 - Alpha N/A
|
:pypi:`pytest-smartcov` Smart coverage plugin for pytest. Sep 30, 2017 3 - Alpha N/A
|
||||||
:pypi:`pytest-smell` Automated bad smell detection tool for Pytest Jun 26, 2022 N/A N/A
|
:pypi:`pytest-smell` Automated bad smell detection tool for Pytest Jun 26, 2022 N/A N/A
|
||||||
:pypi:`pytest-smtp` Send email with pytest execution result Feb 20, 2021 N/A pytest
|
:pypi:`pytest-smtp` Send email with pytest execution result Feb 20, 2021 N/A pytest
|
||||||
|
:pypi:`pytest-smtp4dev` Plugin for smtp4dev API Jun 27, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-smtpd` An SMTP server for testing built on aiosmtpd May 15, 2023 N/A pytest
|
:pypi:`pytest-smtpd` An SMTP server for testing built on aiosmtpd May 15, 2023 N/A pytest
|
||||||
:pypi:`pytest-snail` Plugin for adding a marker to slow running tests. 🐌 Nov 04, 2019 3 - Alpha pytest (>=5.0.1)
|
:pypi:`pytest-snail` Plugin for adding a marker to slow running tests. 🐌 Nov 04, 2019 3 - Alpha pytest (>=5.0.1)
|
||||||
:pypi:`pytest-snapci` py.test plugin for Snap-CI Nov 12, 2015 N/A N/A
|
:pypi:`pytest-snapci` py.test plugin for Snap-CI Nov 12, 2015 N/A N/A
|
||||||
|
@ -1076,7 +1082,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-splitio` Split.io SDK integration for e2e tests Sep 22, 2020 N/A pytest (<7,>=5.0)
|
:pypi:`pytest-splitio` Split.io SDK integration for e2e tests Sep 22, 2020 N/A pytest (<7,>=5.0)
|
||||||
:pypi:`pytest-split-tests` A Pytest plugin for running a subset of your tests by splitting them in to equally sized groups. Forked from Mark Adams' original project pytest-test-groups. Jul 30, 2021 5 - Production/Stable pytest (>=2.5)
|
:pypi:`pytest-split-tests` A Pytest plugin for running a subset of your tests by splitting them in to equally sized groups. Forked from Mark Adams' original project pytest-test-groups. Jul 30, 2021 5 - Production/Stable pytest (>=2.5)
|
||||||
:pypi:`pytest-split-tests-tresorit` Feb 22, 2021 1 - Planning N/A
|
:pypi:`pytest-split-tests-tresorit` Feb 22, 2021 1 - Planning N/A
|
||||||
:pypi:`pytest-splunk-addon` A Dynamic test tool for Splunk Apps and Add-ons Feb 22, 2023 N/A pytest (>5.4.0,<7.3)
|
:pypi:`pytest-splunk-addon` A Dynamic test tool for Splunk Apps and Add-ons Jun 30, 2023 N/A pytest (>5.4.0,<8)
|
||||||
:pypi:`pytest-splunk-addon-ui-smartx` Library to support testing Splunk Add-on UX Mar 07, 2023 N/A N/A
|
:pypi:`pytest-splunk-addon-ui-smartx` Library to support testing Splunk Add-on UX Mar 07, 2023 N/A N/A
|
||||||
:pypi:`pytest-splunk-env` pytest fixtures for interaction with Splunk Enterprise and Splunk Cloud Oct 22, 2020 N/A pytest (>=6.1.1,<7.0.0)
|
:pypi:`pytest-splunk-env` pytest fixtures for interaction with Splunk Enterprise and Splunk Cloud Oct 22, 2020 N/A pytest (>=6.1.1,<7.0.0)
|
||||||
:pypi:`pytest-sqitch` sqitch for pytest Apr 06, 2020 4 - Beta N/A
|
:pypi:`pytest-sqitch` sqitch for pytest Apr 06, 2020 4 - Beta N/A
|
||||||
|
@ -1109,6 +1115,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-subunit` pytest-subunit is a plugin for py.test which outputs testsresult in subunit format. Aug 29, 2017 N/A N/A
|
:pypi:`pytest-subunit` pytest-subunit is a plugin for py.test which outputs testsresult in subunit format. Aug 29, 2017 N/A N/A
|
||||||
:pypi:`pytest-sugar` pytest-sugar is a plugin for pytest that changes the default look and feel of pytest (e.g. progressbar, show tests that fail instantly). Apr 10, 2023 4 - Beta pytest (>=6.2.0)
|
:pypi:`pytest-sugar` pytest-sugar is a plugin for pytest that changes the default look and feel of pytest (e.g. progressbar, show tests that fail instantly). Apr 10, 2023 4 - Beta pytest (>=6.2.0)
|
||||||
:pypi:`pytest-suitemanager` A simple plugin to use with pytest Apr 28, 2023 4 - Beta N/A
|
:pypi:`pytest-suitemanager` A simple plugin to use with pytest Apr 28, 2023 4 - Beta N/A
|
||||||
|
:pypi:`pytest-supercov` Pytest plugin for measuring explicit test-file to source-file coverage Jul 02, 2023 N/A N/A
|
||||||
:pypi:`pytest-svn` SVN repository fixture for py.test May 28, 2019 5 - Production/Stable pytest
|
:pypi:`pytest-svn` SVN repository fixture for py.test May 28, 2019 5 - Production/Stable pytest
|
||||||
:pypi:`pytest-symbols` pytest-symbols is a pytest plugin that adds support for passing test environment symbols into pytest tests. Nov 20, 2017 3 - Alpha N/A
|
:pypi:`pytest-symbols` pytest-symbols is a pytest plugin that adds support for passing test environment symbols into pytest tests. Nov 20, 2017 3 - Alpha N/A
|
||||||
:pypi:`pytest-system-statistics` Pytest plugin to track and report system usage statistics Feb 16, 2022 5 - Production/Stable pytest (>=6.0.0)
|
:pypi:`pytest-system-statistics` Pytest plugin to track and report system usage statistics Feb 16, 2022 5 - Production/Stable pytest (>=6.0.0)
|
||||||
|
@ -1124,7 +1131,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-tcpclient` A pytest plugin for testing TCP clients Nov 16, 2022 N/A pytest (<8,>=7.1.3)
|
:pypi:`pytest-tcpclient` A pytest plugin for testing TCP clients Nov 16, 2022 N/A pytest (<8,>=7.1.3)
|
||||||
:pypi:`pytest-teamcity-logblock` py.test plugin to introduce block structure in teamcity build log, if output is not captured May 15, 2018 4 - Beta N/A
|
:pypi:`pytest-teamcity-logblock` py.test plugin to introduce block structure in teamcity build log, if output is not captured May 15, 2018 4 - Beta N/A
|
||||||
:pypi:`pytest-telegram` Pytest to Telegram reporting plugin Dec 10, 2020 5 - Production/Stable N/A
|
:pypi:`pytest-telegram` Pytest to Telegram reporting plugin Dec 10, 2020 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-telegram-notifier` Telegram notification plugin for Pytest Mar 17, 2023 5 - Production/Stable N/A
|
:pypi:`pytest-telegram-notifier` Telegram notification plugin for Pytest Jun 27, 2023 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-tempdir` Predictable and repeatable tempdir support. Oct 11, 2019 4 - Beta pytest (>=2.8.1)
|
:pypi:`pytest-tempdir` Predictable and repeatable tempdir support. Oct 11, 2019 4 - Beta pytest (>=2.8.1)
|
||||||
:pypi:`pytest-terra-fixt` Terraform and Terragrunt fixtures for pytest Sep 15, 2022 N/A pytest (==6.2.5)
|
:pypi:`pytest-terra-fixt` Terraform and Terragrunt fixtures for pytest Sep 15, 2022 N/A pytest (==6.2.5)
|
||||||
:pypi:`pytest-terraform` A pytest plugin for using terraform fixtures Jun 20, 2023 N/A pytest (>=6.0)
|
:pypi:`pytest-terraform` A pytest plugin for using terraform fixtures Jun 20, 2023 N/A pytest (>=6.0)
|
||||||
|
@ -1159,9 +1166,11 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-test-this` Plugin for py.test to run relevant tests, based on naively checking if a test contains a reference to the symbol you supply Sep 15, 2019 2 - Pre-Alpha pytest (>=2.3)
|
:pypi:`pytest-test-this` Plugin for py.test to run relevant tests, based on naively checking if a test contains a reference to the symbol you supply Sep 15, 2019 2 - Pre-Alpha pytest (>=2.3)
|
||||||
:pypi:`pytest-test-utils` Jul 14, 2022 N/A pytest (>=5)
|
:pypi:`pytest-test-utils` Jul 14, 2022 N/A pytest (>=5)
|
||||||
:pypi:`pytest-tesults` Tesults plugin for pytest Dec 23, 2022 5 - Production/Stable pytest (>=3.5.0)
|
:pypi:`pytest-tesults` Tesults plugin for pytest Dec 23, 2022 5 - Production/Stable pytest (>=3.5.0)
|
||||||
|
:pypi:`pytest-textual-snapshot` Snapshot testing for Textual apps Jun 27, 2023 4 - Beta pytest (>=7.0.0)
|
||||||
:pypi:`pytest-tezos` pytest-ligo Jan 16, 2020 4 - Beta N/A
|
:pypi:`pytest-tezos` pytest-ligo Jan 16, 2020 4 - Beta N/A
|
||||||
:pypi:`pytest-th2-bdd` pytest_th2_bdd May 13, 2022 N/A N/A
|
:pypi:`pytest-th2-bdd` pytest_th2_bdd May 13, 2022 N/A N/A
|
||||||
:pypi:`pytest-thawgun` Pytest plugin for time travel May 26, 2020 3 - Alpha N/A
|
:pypi:`pytest-thawgun` Pytest plugin for time travel May 26, 2020 3 - Alpha N/A
|
||||||
|
:pypi:`pytest-thread` Jul 07, 2023 N/A N/A
|
||||||
:pypi:`pytest-threadleak` Detects thread leaks Jul 03, 2022 4 - Beta pytest (>=3.1.1)
|
:pypi:`pytest-threadleak` Detects thread leaks Jul 03, 2022 4 - Beta pytest (>=3.1.1)
|
||||||
:pypi:`pytest-tick` Ticking on tests Aug 31, 2021 5 - Production/Stable pytest (>=6.2.5,<7.0.0)
|
:pypi:`pytest-tick` Ticking on tests Aug 31, 2021 5 - Production/Stable pytest (>=6.2.5,<7.0.0)
|
||||||
:pypi:`pytest-time` Jun 24, 2023 3 - Alpha pytest
|
:pypi:`pytest-time` Jun 24, 2023 3 - Alpha pytest
|
||||||
|
@ -1171,6 +1180,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-timer` A timer plugin for pytest Jun 02, 2021 N/A N/A
|
:pypi:`pytest-timer` A timer plugin for pytest Jun 02, 2021 N/A N/A
|
||||||
:pypi:`pytest-timestamper` Pytest plugin to add a timestamp prefix to the pytest output Jun 06, 2021 N/A N/A
|
:pypi:`pytest-timestamper` Pytest plugin to add a timestamp prefix to the pytest output Jun 06, 2021 N/A N/A
|
||||||
:pypi:`pytest-timestamps` A simple plugin to view timestamps for each test Apr 01, 2023 N/A pytest (>=5.2)
|
:pypi:`pytest-timestamps` A simple plugin to view timestamps for each test Apr 01, 2023 N/A pytest (>=5.2)
|
||||||
|
:pypi:`pytest-tinybird` A pytest plugin to report test results to tinybird Jun 26, 2023 4 - Beta pytest (>=3.8.0)
|
||||||
:pypi:`pytest-tipsi-django` Nov 17, 2021 4 - Beta pytest (>=6.0.0)
|
:pypi:`pytest-tipsi-django` Nov 17, 2021 4 - Beta pytest (>=6.0.0)
|
||||||
:pypi:`pytest-tipsi-testing` Better fixtures management. Various helpers Nov 04, 2020 4 - Beta pytest (>=3.3.0)
|
:pypi:`pytest-tipsi-testing` Better fixtures management. Various helpers Nov 04, 2020 4 - Beta pytest (>=3.3.0)
|
||||||
:pypi:`pytest-tldr` A pytest plugin that limits the output to just the things you need. Oct 26, 2022 4 - Beta pytest (>=3.5.0)
|
:pypi:`pytest-tldr` A pytest plugin that limits the output to just the things you need. Oct 26, 2022 4 - Beta pytest (>=3.5.0)
|
||||||
|
@ -1219,7 +1229,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-unmarked` Run only unmarked tests Aug 27, 2019 5 - Production/Stable N/A
|
:pypi:`pytest-unmarked` Run only unmarked tests Aug 27, 2019 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-unordered` Test equality of unordered collections in pytest Nov 28, 2022 4 - Beta pytest (>=6.0.0)
|
:pypi:`pytest-unordered` Test equality of unordered collections in pytest Nov 28, 2022 4 - Beta pytest (>=6.0.0)
|
||||||
:pypi:`pytest-unstable` Set a test as unstable to return 0 even if it failed Sep 27, 2022 4 - Beta N/A
|
:pypi:`pytest-unstable` Set a test as unstable to return 0 even if it failed Sep 27, 2022 4 - Beta N/A
|
||||||
:pypi:`pytest-unused-fixtures` A pytest plugin to list unused fixtures after a test run. Jun 15, 2023 4 - Beta pytest (>=7.3.2,<8.0.0)
|
:pypi:`pytest-unused-fixtures` A pytest plugin to list unused fixtures after a test run. Jun 30, 2023 4 - Beta pytest (>=7.3.2,<8.0.0)
|
||||||
:pypi:`pytest-upload-report` pytest-upload-report is a plugin for pytest that upload your test report for test results. Jun 18, 2021 5 - Production/Stable N/A
|
:pypi:`pytest-upload-report` pytest-upload-report is a plugin for pytest that upload your test report for test results. Jun 18, 2021 5 - Production/Stable N/A
|
||||||
:pypi:`pytest-utils` Some helpers for pytest. Feb 02, 2023 4 - Beta pytest (>=7.0.0,<8.0.0)
|
:pypi:`pytest-utils` Some helpers for pytest. Feb 02, 2023 4 - Beta pytest (>=7.0.0,<8.0.0)
|
||||||
:pypi:`pytest-vagrant` A py.test plugin providing access to vagrant. Sep 07, 2021 5 - Production/Stable pytest
|
:pypi:`pytest-vagrant` A py.test plugin providing access to vagrant. Sep 07, 2021 5 - Production/Stable pytest
|
||||||
|
@ -1267,7 +1277,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-xfaillist` Maintain a xfaillist in an additional file to avoid merge-conflicts. Sep 17, 2021 N/A pytest (>=6.2.2,<7.0.0)
|
:pypi:`pytest-xfaillist` Maintain a xfaillist in an additional file to avoid merge-conflicts. Sep 17, 2021 N/A pytest (>=6.2.2,<7.0.0)
|
||||||
:pypi:`pytest-xfiles` Pytest fixtures providing data read from function, module or package related (x)files. Feb 27, 2018 N/A N/A
|
:pypi:`pytest-xfiles` Pytest fixtures providing data read from function, module or package related (x)files. Feb 27, 2018 N/A N/A
|
||||||
:pypi:`pytest-xlog` Extended logging for test and decorators May 31, 2020 4 - Beta N/A
|
:pypi:`pytest-xlog` Extended logging for test and decorators May 31, 2020 4 - Beta N/A
|
||||||
:pypi:`pytest-xlsx` pytest plugin for generating test cases by xlsx(excel) Mar 01, 2023 N/A pytest>=7.2.0
|
:pypi:`pytest-xlsx` pytest plugin for generating test cases by xlsx(excel) Jul 03, 2023 N/A pytest<8,>=7.4.0
|
||||||
:pypi:`pytest-xpara` An extended parametrizing plugin of pytest. Oct 30, 2017 3 - Alpha pytest
|
:pypi:`pytest-xpara` An extended parametrizing plugin of pytest. Oct 30, 2017 3 - Alpha pytest
|
||||||
:pypi:`pytest-xprocess` A pytest plugin for managing processes across test runs. Jan 05, 2023 4 - Beta pytest (>=2.8)
|
:pypi:`pytest-xprocess` A pytest plugin for managing processes across test runs. Jan 05, 2023 4 - Beta pytest (>=2.8)
|
||||||
:pypi:`pytest-xray` May 30, 2019 3 - Alpha N/A
|
:pypi:`pytest-xray` May 30, 2019 3 - Alpha N/A
|
||||||
|
@ -1277,7 +1287,7 @@ This list contains 1272 plugins.
|
||||||
:pypi:`pytest-xvfb` A pytest plugin to run Xvfb (or Xephyr/Xvnc) for tests. May 29, 2023 4 - Beta pytest (>=2.8.1)
|
:pypi:`pytest-xvfb` A pytest plugin to run Xvfb (or Xephyr/Xvnc) for tests. May 29, 2023 4 - Beta pytest (>=2.8.1)
|
||||||
:pypi:`pytest-xvirt` A pytest plugin to virtualize test. For example to transparently running them on a remote box. Jun 18, 2023 4 - Beta pytest (>=7.1.0)
|
:pypi:`pytest-xvirt` A pytest plugin to virtualize test. For example to transparently running them on a remote box. Jun 18, 2023 4 - Beta pytest (>=7.1.0)
|
||||||
:pypi:`pytest-yaml` This plugin is used to load yaml output to your test using pytest framework. Oct 05, 2018 N/A pytest
|
:pypi:`pytest-yaml` This plugin is used to load yaml output to your test using pytest framework. Oct 05, 2018 N/A pytest
|
||||||
:pypi:`pytest-yaml-sanmu` pytest plugin for generating test cases by yaml May 28, 2023 N/A pytest>=7.2.0
|
:pypi:`pytest-yaml-sanmu` pytest plugin for generating test cases by yaml Jul 03, 2023 N/A pytest>=7.4.0
|
||||||
:pypi:`pytest-yamltree` Create or check file/directory trees described by YAML Mar 02, 2020 4 - Beta pytest (>=3.1.1)
|
:pypi:`pytest-yamltree` Create or check file/directory trees described by YAML Mar 02, 2020 4 - Beta pytest (>=3.1.1)
|
||||||
:pypi:`pytest-yamlwsgi` Run tests against wsgi apps defined in yaml May 11, 2010 N/A N/A
|
:pypi:`pytest-yamlwsgi` Run tests against wsgi apps defined in yaml May 11, 2010 N/A N/A
|
||||||
:pypi:`pytest-yaml-yoyo` http/https API run by yaml Jun 19, 2023 N/A pytest (>=7.2.0)
|
:pypi:`pytest-yaml-yoyo` http/https API run by yaml Jun 19, 2023 N/A pytest (>=7.2.0)
|
||||||
|
@ -1445,7 +1455,7 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
|
|
||||||
:pypi:`pytest-alembic`
|
:pypi:`pytest-alembic`
|
||||||
*last release*: May 23, 2023,
|
*last release*: Jul 06, 2023,
|
||||||
*status*: N/A,
|
*status*: N/A,
|
||||||
*requires*: pytest (>=6.0)
|
*requires*: pytest (>=6.0)
|
||||||
|
|
||||||
|
@ -1752,6 +1762,13 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
:pypi:`pytest-async-generators`
|
||||||
|
*last release*: Jul 05, 2023,
|
||||||
|
*status*: N/A,
|
||||||
|
*requires*: N/A
|
||||||
|
|
||||||
|
Pytest fixtures for async generators
|
||||||
|
|
||||||
:pypi:`pytest-asyncio`
|
:pypi:`pytest-asyncio`
|
||||||
*last release*: Mar 19, 2023,
|
*last release*: Mar 19, 2023,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
|
@ -1942,7 +1959,7 @@ This list contains 1272 plugins.
|
||||||
pytest plugin to display BDD info in HTML test report
|
pytest plugin to display BDD info in HTML test report
|
||||||
|
|
||||||
:pypi:`pytest-bdd-ng`
|
:pypi:`pytest-bdd-ng`
|
||||||
*last release*: Oct 06, 2022,
|
*last release*: Jul 01, 2023,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
*requires*: pytest (>=5.0)
|
*requires*: pytest (>=5.0)
|
||||||
|
|
||||||
|
@ -1984,7 +2001,7 @@ This list contains 1272 plugins.
|
||||||
Fixtures for testing Google Appengine (GAE) apps
|
Fixtures for testing Google Appengine (GAE) apps
|
||||||
|
|
||||||
:pypi:`pytest-beeprint`
|
:pypi:`pytest-beeprint`
|
||||||
*last release*: Jun 09, 2023,
|
*last release*: Jul 04, 2023,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
*requires*: N/A
|
*requires*: N/A
|
||||||
|
|
||||||
|
@ -2600,7 +2617,7 @@ This list contains 1272 plugins.
|
||||||
pytest plugin to run pycodestyle
|
pytest plugin to run pycodestyle
|
||||||
|
|
||||||
:pypi:`pytest-codspeed`
|
:pypi:`pytest-codspeed`
|
||||||
*last release*: Dec 02, 2022,
|
*last release*: Jul 04, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: pytest>=3.8
|
*requires*: pytest>=3.8
|
||||||
|
|
||||||
|
@ -2761,9 +2778,9 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
|
|
||||||
:pypi:`pytest-coverage-context`
|
:pypi:`pytest-coverage-context`
|
||||||
*last release*: Jan 04, 2021,
|
*last release*: Jun 28, 2023,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
*requires*: pytest (>=6.1.0)
|
*requires*: N/A
|
||||||
|
|
||||||
Coverage dynamic context support for PyTest, including sub-processes
|
Coverage dynamic context support for PyTest, including sub-processes
|
||||||
|
|
||||||
|
@ -2852,9 +2869,9 @@ This list contains 1272 plugins.
|
||||||
CSV output for pytest.
|
CSV output for pytest.
|
||||||
|
|
||||||
:pypi:`pytest-csv-params`
|
:pypi:`pytest-csv-params`
|
||||||
*last release*: Aug 28, 2022,
|
*last release*: Jul 01, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: pytest (>=7.1.2,<8.0.0)
|
*requires*: pytest (>=7.4.0,<8.0.0)
|
||||||
|
|
||||||
Pytest plugin for Test Case Parametrization with CSV files
|
Pytest plugin for Test Case Parametrization with CSV files
|
||||||
|
|
||||||
|
@ -3579,6 +3596,13 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
Pytest plugin with advanced doctest features.
|
Pytest plugin with advanced doctest features.
|
||||||
|
|
||||||
|
:pypi:`pytest-dogu-report`
|
||||||
|
*last release*: Jul 07, 2023,
|
||||||
|
*status*: N/A,
|
||||||
|
*requires*: N/A
|
||||||
|
|
||||||
|
pytest plugin for dogu report
|
||||||
|
|
||||||
:pypi:`pytest-dolphin`
|
:pypi:`pytest-dolphin`
|
||||||
*last release*: Nov 30, 2016,
|
*last release*: Nov 30, 2016,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
|
@ -3769,49 +3793,49 @@ This list contains 1272 plugins.
|
||||||
Send execution result email
|
Send execution result email
|
||||||
|
|
||||||
:pypi:`pytest-embedded`
|
:pypi:`pytest-embedded`
|
||||||
*last release*: Jun 14, 2023,
|
*last release*: Jul 05, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: pytest>=7.0
|
*requires*: pytest>=7.0
|
||||||
|
|
||||||
A pytest plugin that designed for embedded testing.
|
A pytest plugin that designed for embedded testing.
|
||||||
|
|
||||||
:pypi:`pytest-embedded-arduino`
|
:pypi:`pytest-embedded-arduino`
|
||||||
*last release*: Jun 14, 2023,
|
*last release*: Jul 05, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: N/A
|
*requires*: N/A
|
||||||
|
|
||||||
Make pytest-embedded plugin work with Arduino.
|
Make pytest-embedded plugin work with Arduino.
|
||||||
|
|
||||||
:pypi:`pytest-embedded-idf`
|
:pypi:`pytest-embedded-idf`
|
||||||
*last release*: Jun 14, 2023,
|
*last release*: Jul 05, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: N/A
|
*requires*: N/A
|
||||||
|
|
||||||
Make pytest-embedded plugin work with ESP-IDF.
|
Make pytest-embedded plugin work with ESP-IDF.
|
||||||
|
|
||||||
:pypi:`pytest-embedded-jtag`
|
:pypi:`pytest-embedded-jtag`
|
||||||
*last release*: Jun 14, 2023,
|
*last release*: Jul 05, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: N/A
|
*requires*: N/A
|
||||||
|
|
||||||
Make pytest-embedded plugin work with JTAG.
|
Make pytest-embedded plugin work with JTAG.
|
||||||
|
|
||||||
:pypi:`pytest-embedded-qemu`
|
:pypi:`pytest-embedded-qemu`
|
||||||
*last release*: Jun 14, 2023,
|
*last release*: Jul 05, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: N/A
|
*requires*: N/A
|
||||||
|
|
||||||
Make pytest-embedded plugin work with QEMU.
|
Make pytest-embedded plugin work with QEMU.
|
||||||
|
|
||||||
:pypi:`pytest-embedded-serial`
|
:pypi:`pytest-embedded-serial`
|
||||||
*last release*: Jun 14, 2023,
|
*last release*: Jul 05, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: N/A
|
*requires*: N/A
|
||||||
|
|
||||||
Make pytest-embedded plugin work with Serial.
|
Make pytest-embedded plugin work with Serial.
|
||||||
|
|
||||||
:pypi:`pytest-embedded-serial-esp`
|
:pypi:`pytest-embedded-serial-esp`
|
||||||
*last release*: Jun 14, 2023,
|
*last release*: Jul 05, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: N/A
|
*requires*: N/A
|
||||||
|
|
||||||
|
@ -3839,7 +3863,7 @@ This list contains 1272 plugins.
|
||||||
Pytest plugin to represent test output with emoji support
|
Pytest plugin to represent test output with emoji support
|
||||||
|
|
||||||
:pypi:`pytest-enabler`
|
:pypi:`pytest-enabler`
|
||||||
*last release*: May 12, 2023,
|
*last release*: Jun 26, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: pytest (>=6) ; extra == 'testing'
|
*requires*: pytest (>=6) ; extra == 'testing'
|
||||||
|
|
||||||
|
@ -4441,9 +4465,9 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
|
|
||||||
:pypi:`pytest-fluent`
|
:pypi:`pytest-fluent`
|
||||||
*last release*: Jul 12, 2022,
|
*last release*: Jun 26, 2023,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
*requires*: pytest
|
*requires*: pytest (>=7.0.0)
|
||||||
|
|
||||||
A pytest plugin in order to provide logs via fluentd
|
A pytest plugin in order to provide logs via fluentd
|
||||||
|
|
||||||
|
@ -4616,7 +4640,7 @@ This list contains 1272 plugins.
|
||||||
For finding/executing Ghost Inspector tests
|
For finding/executing Ghost Inspector tests
|
||||||
|
|
||||||
:pypi:`pytest-girder`
|
:pypi:`pytest-girder`
|
||||||
*last release*: Jun 14, 2023,
|
*last release*: Jun 28, 2023,
|
||||||
*status*: N/A,
|
*status*: N/A,
|
||||||
*requires*: N/A
|
*requires*: N/A
|
||||||
|
|
||||||
|
@ -4741,6 +4765,13 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
Green progress dots
|
Green progress dots
|
||||||
|
|
||||||
|
:pypi:`pytest-group-by-class`
|
||||||
|
*last release*: Jun 27, 2023,
|
||||||
|
*status*: 5 - Production/Stable,
|
||||||
|
*requires*: pytest (>=2.5)
|
||||||
|
|
||||||
|
A Pytest plugin for running a subset of your tests by splitting them in to groups of classes.
|
||||||
|
|
||||||
:pypi:`pytest-growl`
|
:pypi:`pytest-growl`
|
||||||
*last release*: Jan 13, 2014,
|
*last release*: Jan 13, 2014,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
|
@ -4847,7 +4878,7 @@ This list contains 1272 plugins.
|
||||||
A pytest plugin for use with homeassistant custom components.
|
A pytest plugin for use with homeassistant custom components.
|
||||||
|
|
||||||
:pypi:`pytest-homeassistant-custom-component`
|
:pypi:`pytest-homeassistant-custom-component`
|
||||||
*last release*: Jun 24, 2023,
|
*last release*: Jul 07, 2023,
|
||||||
*status*: 3 - Alpha,
|
*status*: 3 - Alpha,
|
||||||
*requires*: pytest (==7.3.1)
|
*requires*: pytest (==7.3.1)
|
||||||
|
|
||||||
|
@ -5148,7 +5179,7 @@ This list contains 1272 plugins.
|
||||||
A py.test plugin providing fixtures to simplify inmanta modules testing.
|
A py.test plugin providing fixtures to simplify inmanta modules testing.
|
||||||
|
|
||||||
:pypi:`pytest-inmanta-extensions`
|
:pypi:`pytest-inmanta-extensions`
|
||||||
*last release*: Apr 12, 2023,
|
*last release*: Jul 04, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: N/A
|
*requires*: N/A
|
||||||
|
|
||||||
|
@ -5225,7 +5256,7 @@ This list contains 1272 plugins.
|
||||||
Pytest plugin for intercepting outgoing connection requests during pytest run.
|
Pytest plugin for intercepting outgoing connection requests during pytest run.
|
||||||
|
|
||||||
:pypi:`pytest-interface-tester`
|
:pypi:`pytest-interface-tester`
|
||||||
*last release*: May 09, 2023,
|
*last release*: Jun 29, 2023,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
*requires*: pytest
|
*requires*: pytest
|
||||||
|
|
||||||
|
@ -5918,7 +5949,7 @@ This list contains 1272 plugins.
|
||||||
Plugin for generating Markdown reports for pytest results
|
Plugin for generating Markdown reports for pytest results
|
||||||
|
|
||||||
:pypi:`pytest-md-report`
|
:pypi:`pytest-md-report`
|
||||||
*last release*: May 28, 2023,
|
*last release*: Jun 25, 2023,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
*requires*: pytest (!=6.0.0,<8,>=3.3.2)
|
*requires*: pytest (!=6.0.0,<8,>=3.3.2)
|
||||||
|
|
||||||
|
@ -6156,7 +6187,7 @@ This list contains 1272 plugins.
|
||||||
pytest plugin for MongoDB fixtures
|
pytest plugin for MongoDB fixtures
|
||||||
|
|
||||||
:pypi:`pytest-monitor`
|
:pypi:`pytest-monitor`
|
||||||
*last release*: Oct 22, 2022,
|
*last release*: Jun 25, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: pytest
|
*requires*: pytest
|
||||||
|
|
||||||
|
@ -6282,9 +6313,9 @@ This list contains 1272 plugins.
|
||||||
Mypy static type checker plugin for Pytest
|
Mypy static type checker plugin for Pytest
|
||||||
|
|
||||||
:pypi:`pytest-mypy-plugins`
|
:pypi:`pytest-mypy-plugins`
|
||||||
*last release*: May 05, 2023,
|
*last release*: Jun 29, 2023,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
*requires*: pytest (>=6.2.0)
|
*requires*: pytest (>=7.0.0)
|
||||||
|
|
||||||
pytest plugin for writing tests for mypy plugins
|
pytest plugin for writing tests for mypy plugins
|
||||||
|
|
||||||
|
@ -6324,7 +6355,7 @@ This list contains 1272 plugins.
|
||||||
pytest-neo is a plugin for pytest that shows tests like screen of Matrix.
|
pytest-neo is a plugin for pytest that shows tests like screen of Matrix.
|
||||||
|
|
||||||
:pypi:`pytest-netdut`
|
:pypi:`pytest-netdut`
|
||||||
*last release*: Jun 19, 2023,
|
*last release*: Jul 06, 2023,
|
||||||
*status*: N/A,
|
*status*: N/A,
|
||||||
*requires*: pytest (>=3.5.0)
|
*requires*: pytest (>=3.5.0)
|
||||||
|
|
||||||
|
@ -6492,7 +6523,7 @@ This list contains 1272 plugins.
|
||||||
pytest results data-base and HTML reporter
|
pytest results data-base and HTML reporter
|
||||||
|
|
||||||
:pypi:`pytest-odoo`
|
:pypi:`pytest-odoo`
|
||||||
*last release*: Nov 17, 2022,
|
*last release*: Jul 06, 2023,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
*requires*: pytest (>=7.2.0)
|
*requires*: pytest (>=7.2.0)
|
||||||
|
|
||||||
|
@ -6814,7 +6845,7 @@ This list contains 1272 plugins.
|
||||||
A simple plugin to ensure the execution of critical sections of code has not been impacted
|
A simple plugin to ensure the execution of critical sections of code has not been impacted
|
||||||
|
|
||||||
:pypi:`pytest-persistence`
|
:pypi:`pytest-persistence`
|
||||||
*last release*: Jun 14, 2023,
|
*last release*: Jul 04, 2023,
|
||||||
*status*: N/A,
|
*status*: N/A,
|
||||||
*requires*: N/A
|
*requires*: N/A
|
||||||
|
|
||||||
|
@ -6932,6 +6963,13 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
A pytest wrapper with fixtures for Playwright to automate web browsers
|
A pytest wrapper with fixtures for Playwright to automate web browsers
|
||||||
|
|
||||||
|
:pypi:`pytest-playwright-async`
|
||||||
|
*last release*: Jul 03, 2023,
|
||||||
|
*status*: N/A,
|
||||||
|
*requires*: N/A
|
||||||
|
|
||||||
|
ASYNC Pytest plugin for Playwright
|
||||||
|
|
||||||
:pypi:`pytest-playwrights`
|
:pypi:`pytest-playwrights`
|
||||||
*last release*: Dec 02, 2021,
|
*last release*: Dec 02, 2021,
|
||||||
*status*: N/A,
|
*status*: N/A,
|
||||||
|
@ -7051,6 +7089,13 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
A pytest plugin to help with testing pop projects
|
A pytest plugin to help with testing pop projects
|
||||||
|
|
||||||
|
:pypi:`pytest-porringer`
|
||||||
|
*last release*: Jun 24, 2023,
|
||||||
|
*status*: N/A,
|
||||||
|
*requires*: pytest>=7.1.2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
:pypi:`pytest-portion`
|
:pypi:`pytest-portion`
|
||||||
*last release*: Jan 28, 2021,
|
*last release*: Jan 28, 2021,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
|
@ -7115,7 +7160,7 @@ This list contains 1272 plugins.
|
||||||
Minitest-style test colors
|
Minitest-style test colors
|
||||||
|
|
||||||
:pypi:`pytest-print`
|
:pypi:`pytest-print`
|
||||||
*last release*: Jun 16, 2023,
|
*last release*: Jun 28, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: pytest>=7.3.2
|
*requires*: pytest>=7.3.2
|
||||||
|
|
||||||
|
@ -7311,7 +7356,7 @@ This list contains 1272 plugins.
|
||||||
Pyramid server fixture for py.test
|
Pyramid server fixture for py.test
|
||||||
|
|
||||||
:pypi:`pytest-pyreport`
|
:pypi:`pytest-pyreport`
|
||||||
*last release*: May 08, 2023,
|
*last release*: Jul 02, 2023,
|
||||||
*status*: N/A,
|
*status*: N/A,
|
||||||
*requires*: pytest (>=7.3.1)
|
*requires*: pytest (>=7.3.1)
|
||||||
|
|
||||||
|
@ -7388,7 +7433,7 @@ This list contains 1272 plugins.
|
||||||
Pytest plugin for uploading test results to your QA Touch Testrun.
|
Pytest plugin for uploading test results to your QA Touch Testrun.
|
||||||
|
|
||||||
:pypi:`pytest-qgis`
|
:pypi:`pytest-qgis`
|
||||||
*last release*: Jun 09, 2023,
|
*last release*: Jun 30, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: pytest (>=6.2.5)
|
*requires*: pytest (>=6.2.5)
|
||||||
|
|
||||||
|
@ -7437,7 +7482,7 @@ This list contains 1272 plugins.
|
||||||
pytest plugin to generate random data inspired by QuickCheck
|
pytest plugin to generate random data inspired by QuickCheck
|
||||||
|
|
||||||
:pypi:`pytest-rabbitmq`
|
:pypi:`pytest-rabbitmq`
|
||||||
*last release*: Jun 16, 2023,
|
*last release*: Jul 05, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: pytest (>=6.2)
|
*requires*: pytest (>=6.2)
|
||||||
|
|
||||||
|
@ -7661,7 +7706,7 @@ This list contains 1272 plugins.
|
||||||
Pytest plugin for capturing and mocking connection requests.
|
Pytest plugin for capturing and mocking connection requests.
|
||||||
|
|
||||||
:pypi:`pytest-remove-stale-bytecode`
|
:pypi:`pytest-remove-stale-bytecode`
|
||||||
*last release*: Mar 04, 2020,
|
*last release*: Jul 07, 2023,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
*requires*: pytest
|
*requires*: pytest
|
||||||
|
|
||||||
|
@ -7759,7 +7804,7 @@ This list contains 1272 plugins.
|
||||||
pytest plugin for adding tests' parameters to junit report
|
pytest plugin for adding tests' parameters to junit report
|
||||||
|
|
||||||
:pypi:`pytest-reportportal`
|
:pypi:`pytest-reportportal`
|
||||||
*last release*: Jun 08, 2023,
|
*last release*: Jun 30, 2023,
|
||||||
*status*: N/A,
|
*status*: N/A,
|
||||||
*requires*: pytest (>=3.8.0)
|
*requires*: pytest (>=3.8.0)
|
||||||
|
|
||||||
|
@ -7822,9 +7867,9 @@ This list contains 1272 plugins.
|
||||||
Re-run only changed files in specified branch
|
Re-run only changed files in specified branch
|
||||||
|
|
||||||
:pypi:`pytest-rerunfailures`
|
:pypi:`pytest-rerunfailures`
|
||||||
*last release*: Mar 09, 2023,
|
*last release*: Jul 05, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: pytest (>=5.3)
|
*requires*: pytest (>=6.2)
|
||||||
|
|
||||||
pytest plugin to re-run tests to eliminate flaky failures
|
pytest plugin to re-run tests to eliminate flaky failures
|
||||||
|
|
||||||
|
@ -8172,7 +8217,7 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
|
|
||||||
:pypi:`pytest-sbase`
|
:pypi:`pytest-sbase`
|
||||||
*last release*: Jun 24, 2023,
|
*last release*: Jul 08, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: N/A
|
*requires*: N/A
|
||||||
|
|
||||||
|
@ -8221,7 +8266,7 @@ This list contains 1272 plugins.
|
||||||
pytest plugin for Selenium
|
pytest plugin for Selenium
|
||||||
|
|
||||||
:pypi:`pytest-seleniumbase`
|
:pypi:`pytest-seleniumbase`
|
||||||
*last release*: Jun 24, 2023,
|
*last release*: Jul 08, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: N/A
|
*requires*: N/A
|
||||||
|
|
||||||
|
@ -8354,9 +8399,9 @@ This list contains 1272 plugins.
|
||||||
A pytest plugin to help with testing shell scripts / black box commands
|
A pytest plugin to help with testing shell scripts / black box commands
|
||||||
|
|
||||||
:pypi:`pytest-shell-utilities`
|
:pypi:`pytest-shell-utilities`
|
||||||
*last release*: Sep 23, 2022,
|
*last release*: Jul 02, 2023,
|
||||||
*status*: 4 - Beta,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: pytest (>=6.0.0)
|
*requires*: pytest (>=7.1.0)
|
||||||
|
|
||||||
Pytest plugin to simplify running shell commands against the system
|
Pytest plugin to simplify running shell commands against the system
|
||||||
|
|
||||||
|
@ -8500,6 +8545,13 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
Send email with pytest execution result
|
Send email with pytest execution result
|
||||||
|
|
||||||
|
:pypi:`pytest-smtp4dev`
|
||||||
|
*last release*: Jun 27, 2023,
|
||||||
|
*status*: 5 - Production/Stable,
|
||||||
|
*requires*: N/A
|
||||||
|
|
||||||
|
Plugin for smtp4dev API
|
||||||
|
|
||||||
:pypi:`pytest-smtpd`
|
:pypi:`pytest-smtpd`
|
||||||
*last release*: May 15, 2023,
|
*last release*: May 15, 2023,
|
||||||
*status*: N/A,
|
*status*: N/A,
|
||||||
|
@ -8690,9 +8742,9 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
|
|
||||||
:pypi:`pytest-splunk-addon`
|
:pypi:`pytest-splunk-addon`
|
||||||
*last release*: Feb 22, 2023,
|
*last release*: Jun 30, 2023,
|
||||||
*status*: N/A,
|
*status*: N/A,
|
||||||
*requires*: pytest (>5.4.0,<7.3)
|
*requires*: pytest (>5.4.0,<8)
|
||||||
|
|
||||||
A Dynamic test tool for Splunk Apps and Add-ons
|
A Dynamic test tool for Splunk Apps and Add-ons
|
||||||
|
|
||||||
|
@ -8920,6 +8972,13 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
A simple plugin to use with pytest
|
A simple plugin to use with pytest
|
||||||
|
|
||||||
|
:pypi:`pytest-supercov`
|
||||||
|
*last release*: Jul 02, 2023,
|
||||||
|
*status*: N/A,
|
||||||
|
*requires*: N/A
|
||||||
|
|
||||||
|
Pytest plugin for measuring explicit test-file to source-file coverage
|
||||||
|
|
||||||
:pypi:`pytest-svn`
|
:pypi:`pytest-svn`
|
||||||
*last release*: May 28, 2019,
|
*last release*: May 28, 2019,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
|
@ -9026,7 +9085,7 @@ This list contains 1272 plugins.
|
||||||
Pytest to Telegram reporting plugin
|
Pytest to Telegram reporting plugin
|
||||||
|
|
||||||
:pypi:`pytest-telegram-notifier`
|
:pypi:`pytest-telegram-notifier`
|
||||||
*last release*: Mar 17, 2023,
|
*last release*: Jun 27, 2023,
|
||||||
*status*: 5 - Production/Stable,
|
*status*: 5 - Production/Stable,
|
||||||
*requires*: N/A
|
*requires*: N/A
|
||||||
|
|
||||||
|
@ -9270,6 +9329,13 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
Tesults plugin for pytest
|
Tesults plugin for pytest
|
||||||
|
|
||||||
|
:pypi:`pytest-textual-snapshot`
|
||||||
|
*last release*: Jun 27, 2023,
|
||||||
|
*status*: 4 - Beta,
|
||||||
|
*requires*: pytest (>=7.0.0)
|
||||||
|
|
||||||
|
Snapshot testing for Textual apps
|
||||||
|
|
||||||
:pypi:`pytest-tezos`
|
:pypi:`pytest-tezos`
|
||||||
*last release*: Jan 16, 2020,
|
*last release*: Jan 16, 2020,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
|
@ -9291,6 +9357,13 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
Pytest plugin for time travel
|
Pytest plugin for time travel
|
||||||
|
|
||||||
|
:pypi:`pytest-thread`
|
||||||
|
*last release*: Jul 07, 2023,
|
||||||
|
*status*: N/A,
|
||||||
|
*requires*: N/A
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
:pypi:`pytest-threadleak`
|
:pypi:`pytest-threadleak`
|
||||||
*last release*: Jul 03, 2022,
|
*last release*: Jul 03, 2022,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
|
@ -9354,6 +9427,13 @@ This list contains 1272 plugins.
|
||||||
|
|
||||||
A simple plugin to view timestamps for each test
|
A simple plugin to view timestamps for each test
|
||||||
|
|
||||||
|
:pypi:`pytest-tinybird`
|
||||||
|
*last release*: Jun 26, 2023,
|
||||||
|
*status*: 4 - Beta,
|
||||||
|
*requires*: pytest (>=3.8.0)
|
||||||
|
|
||||||
|
A pytest plugin to report test results to tinybird
|
||||||
|
|
||||||
:pypi:`pytest-tipsi-django`
|
:pypi:`pytest-tipsi-django`
|
||||||
*last release*: Nov 17, 2021,
|
*last release*: Nov 17, 2021,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
|
@ -9691,7 +9771,7 @@ This list contains 1272 plugins.
|
||||||
Set a test as unstable to return 0 even if it failed
|
Set a test as unstable to return 0 even if it failed
|
||||||
|
|
||||||
:pypi:`pytest-unused-fixtures`
|
:pypi:`pytest-unused-fixtures`
|
||||||
*last release*: Jun 15, 2023,
|
*last release*: Jun 30, 2023,
|
||||||
*status*: 4 - Beta,
|
*status*: 4 - Beta,
|
||||||
*requires*: pytest (>=7.3.2,<8.0.0)
|
*requires*: pytest (>=7.3.2,<8.0.0)
|
||||||
|
|
||||||
|
@ -10027,9 +10107,9 @@ This list contains 1272 plugins.
|
||||||
Extended logging for test and decorators
|
Extended logging for test and decorators
|
||||||
|
|
||||||
:pypi:`pytest-xlsx`
|
:pypi:`pytest-xlsx`
|
||||||
*last release*: Mar 01, 2023,
|
*last release*: Jul 03, 2023,
|
||||||
*status*: N/A,
|
*status*: N/A,
|
||||||
*requires*: pytest>=7.2.0
|
*requires*: pytest<8,>=7.4.0
|
||||||
|
|
||||||
pytest plugin for generating test cases by xlsx(excel)
|
pytest plugin for generating test cases by xlsx(excel)
|
||||||
|
|
||||||
|
@ -10097,9 +10177,9 @@ This list contains 1272 plugins.
|
||||||
This plugin is used to load yaml output to your test using pytest framework.
|
This plugin is used to load yaml output to your test using pytest framework.
|
||||||
|
|
||||||
:pypi:`pytest-yaml-sanmu`
|
:pypi:`pytest-yaml-sanmu`
|
||||||
*last release*: May 28, 2023,
|
*last release*: Jul 03, 2023,
|
||||||
*status*: N/A,
|
*status*: N/A,
|
||||||
*requires*: pytest>=7.2.0
|
*requires*: pytest>=7.4.0
|
||||||
|
|
||||||
pytest plugin for generating test cases by yaml
|
pytest plugin for generating test cases by yaml
|
||||||
|
|
||||||
|
|
|
@ -783,18 +783,66 @@ reporting or interaction with exceptions:
|
||||||
.. autofunction:: pytest_leave_pdb
|
.. autofunction:: pytest_leave_pdb
|
||||||
|
|
||||||
|
|
||||||
Objects
|
Collection tree objects
|
||||||
-------
|
-----------------------
|
||||||
|
|
||||||
Full reference to objects accessible from :ref:`fixtures <fixture>` or :ref:`hooks <hook-reference>`.
|
These are the collector and item classes (collectively called "nodes") which
|
||||||
|
make up the collection tree.
|
||||||
|
|
||||||
|
Node
|
||||||
|
~~~~
|
||||||
|
|
||||||
CallInfo
|
.. autoclass:: _pytest.nodes.Node()
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: pytest.CallInfo()
|
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
Collector
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: pytest.Collector()
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
Item
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
.. autoclass:: pytest.Item()
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
File
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
.. autoclass:: pytest.File()
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
FSCollector
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: _pytest.nodes.FSCollector()
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
Session
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: pytest.Session()
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
Package
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: pytest.Package()
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
Module
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: pytest.Module()
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
Class
|
Class
|
||||||
~~~~~
|
~~~~~
|
||||||
|
@ -803,13 +851,34 @@ Class
|
||||||
:members:
|
:members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
Collector
|
Function
|
||||||
~~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
.. autoclass:: pytest.Collector()
|
.. autoclass:: pytest.Function()
|
||||||
:members:
|
:members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
FunctionDefinition
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: _pytest.python.FunctionDefinition()
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
|
Objects
|
||||||
|
-------
|
||||||
|
|
||||||
|
Objects accessible from :ref:`fixtures <fixture>` or :ref:`hooks <hook-reference>`
|
||||||
|
or importable from ``pytest``.
|
||||||
|
|
||||||
|
|
||||||
|
CallInfo
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: pytest.CallInfo()
|
||||||
|
:members:
|
||||||
|
|
||||||
CollectReport
|
CollectReport
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -837,13 +906,6 @@ ExitCode
|
||||||
.. autoclass:: pytest.ExitCode
|
.. autoclass:: pytest.ExitCode
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
File
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
.. autoclass:: pytest.File()
|
|
||||||
:members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
|
|
||||||
FixtureDef
|
FixtureDef
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
@ -852,34 +914,6 @@ FixtureDef
|
||||||
:members:
|
:members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
FSCollector
|
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: _pytest.nodes.FSCollector()
|
|
||||||
:members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
Function
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: pytest.Function()
|
|
||||||
:members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
FunctionDefinition
|
|
||||||
~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: _pytest.python.FunctionDefinition()
|
|
||||||
:members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
Item
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
.. autoclass:: pytest.Item()
|
|
||||||
:members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
MarkDecorator
|
MarkDecorator
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -907,19 +941,6 @@ Metafunc
|
||||||
.. autoclass:: pytest.Metafunc()
|
.. autoclass:: pytest.Metafunc()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
Module
|
|
||||||
~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: pytest.Module()
|
|
||||||
:members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
Node
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
.. autoclass:: _pytest.nodes.Node()
|
|
||||||
:members:
|
|
||||||
|
|
||||||
Parser
|
Parser
|
||||||
~~~~~~
|
~~~~~~
|
||||||
|
|
||||||
|
@ -941,13 +962,6 @@ PytestPluginManager
|
||||||
:inherited-members:
|
:inherited-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
Session
|
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: pytest.Session()
|
|
||||||
:members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
TestReport
|
TestReport
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
pallets-sphinx-themes
|
pallets-sphinx-themes
|
||||||
pluggy>=1.0
|
pluggy>=1.2.0
|
||||||
pygments-pytest>=2.3.0
|
pygments-pytest>=2.3.0
|
||||||
sphinx-removed-in>=0.2.0
|
sphinx-removed-in>=0.2.0
|
||||||
sphinx>=5,<6
|
sphinx>=5,<6
|
||||||
|
|
|
@ -113,7 +113,7 @@ template = "changelog/_template.rst"
|
||||||
showcontent = true
|
showcontent = true
|
||||||
|
|
||||||
[tool.black]
|
[tool.black]
|
||||||
target-version = ['py37']
|
target-version = ['py38']
|
||||||
|
|
||||||
# check-wheel-contents is executed by the build-and-inspect-python-package action.
|
# check-wheel-contents is executed by the build-and-inspect-python-package action.
|
||||||
[tool.check-wheel-contents]
|
[tool.check-wheel-contents]
|
||||||
|
|
|
@ -17,7 +17,6 @@ classifiers =
|
||||||
Operating System :: POSIX
|
Operating System :: POSIX
|
||||||
Programming Language :: Python :: 3
|
Programming Language :: Python :: 3
|
||||||
Programming Language :: Python :: 3 :: Only
|
Programming Language :: Python :: 3 :: Only
|
||||||
Programming Language :: Python :: 3.7
|
|
||||||
Programming Language :: Python :: 3.8
|
Programming Language :: Python :: 3.8
|
||||||
Programming Language :: Python :: 3.9
|
Programming Language :: Python :: 3.9
|
||||||
Programming Language :: Python :: 3.10
|
Programming Language :: Python :: 3.10
|
||||||
|
@ -47,12 +46,11 @@ py_modules = py
|
||||||
install_requires =
|
install_requires =
|
||||||
iniconfig
|
iniconfig
|
||||||
packaging
|
packaging
|
||||||
pluggy>=0.12,<2.0
|
pluggy>=1.2.0,<2.0
|
||||||
colorama;sys_platform=="win32"
|
colorama;sys_platform=="win32"
|
||||||
exceptiongroup>=1.0.0rc8;python_version<"3.11"
|
exceptiongroup>=1.0.0rc8;python_version<"3.11"
|
||||||
importlib-metadata>=0.12;python_version<"3.8"
|
|
||||||
tomli>=1.0.0;python_version<"3.11"
|
tomli>=1.0.0;python_version<"3.11"
|
||||||
python_requires = >=3.7
|
python_requires = >=3.8
|
||||||
package_dir =
|
package_dir =
|
||||||
=src
|
=src
|
||||||
setup_requires =
|
setup_requires =
|
||||||
|
|
|
@ -17,18 +17,21 @@ from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import ClassVar
|
from typing import ClassVar
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import Final
|
||||||
|
from typing import final
|
||||||
from typing import Generic
|
from typing import Generic
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from typing import Literal
|
||||||
from typing import Mapping
|
from typing import Mapping
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import overload
|
from typing import overload
|
||||||
from typing import Pattern
|
from typing import Pattern
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Set
|
from typing import Set
|
||||||
|
from typing import SupportsIndex
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
from typing import Type
|
from typing import Type
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
@ -42,22 +45,16 @@ from _pytest._code.source import Source
|
||||||
from _pytest._io import TerminalWriter
|
from _pytest._io import TerminalWriter
|
||||||
from _pytest._io.saferepr import safeformat
|
from _pytest._io.saferepr import safeformat
|
||||||
from _pytest._io.saferepr import saferepr
|
from _pytest._io.saferepr import saferepr
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.compat import get_real_func
|
from _pytest.compat import get_real_func
|
||||||
from _pytest.deprecated import check_ispytest
|
from _pytest.deprecated import check_ispytest
|
||||||
from _pytest.pathlib import absolutepath
|
from _pytest.pathlib import absolutepath
|
||||||
from _pytest.pathlib import bestrelpath
|
from _pytest.pathlib import bestrelpath
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from typing_extensions import Final
|
|
||||||
from typing_extensions import Literal
|
|
||||||
from typing_extensions import SupportsIndex
|
|
||||||
|
|
||||||
_TracebackStyle = Literal["long", "short", "line", "no", "native", "value", "auto"]
|
|
||||||
|
|
||||||
if sys.version_info[:2] < (3, 11):
|
if sys.version_info[:2] < (3, 11):
|
||||||
from exceptiongroup import BaseExceptionGroup
|
from exceptiongroup import BaseExceptionGroup
|
||||||
|
|
||||||
|
_TracebackStyle = Literal["long", "short", "line", "no", "native", "value", "auto"]
|
||||||
|
|
||||||
|
|
||||||
class Code:
|
class Code:
|
||||||
"""Wrapper around Python code objects."""
|
"""Wrapper around Python code objects."""
|
||||||
|
@ -396,11 +393,11 @@ class Traceback(List[TracebackEntry]):
|
||||||
|
|
||||||
def filter(
|
def filter(
|
||||||
self,
|
self,
|
||||||
# TODO(py38): change to positional only.
|
excinfo_or_fn: Union[
|
||||||
_excinfo_or_fn: Union[
|
|
||||||
"ExceptionInfo[BaseException]",
|
"ExceptionInfo[BaseException]",
|
||||||
Callable[[TracebackEntry], bool],
|
Callable[[TracebackEntry], bool],
|
||||||
],
|
],
|
||||||
|
/,
|
||||||
) -> "Traceback":
|
) -> "Traceback":
|
||||||
"""Return a Traceback instance with certain items removed.
|
"""Return a Traceback instance with certain items removed.
|
||||||
|
|
||||||
|
@ -411,10 +408,10 @@ class Traceback(List[TracebackEntry]):
|
||||||
``TracebackEntry`` instance, and should return True when the item should
|
``TracebackEntry`` instance, and should return True when the item should
|
||||||
be added to the ``Traceback``, False when not.
|
be added to the ``Traceback``, False when not.
|
||||||
"""
|
"""
|
||||||
if isinstance(_excinfo_or_fn, ExceptionInfo):
|
if isinstance(excinfo_or_fn, ExceptionInfo):
|
||||||
fn = lambda x: not x.ishidden(_excinfo_or_fn) # noqa: E731
|
fn = lambda x: not x.ishidden(excinfo_or_fn) # noqa: E731
|
||||||
else:
|
else:
|
||||||
fn = _excinfo_or_fn
|
fn = excinfo_or_fn
|
||||||
return Traceback(filter(fn, self))
|
return Traceback(filter(fn, self))
|
||||||
|
|
||||||
def recursionindex(self) -> Optional[int]:
|
def recursionindex(self) -> Optional[int]:
|
||||||
|
@ -633,7 +630,7 @@ class ExceptionInfo(Generic[E]):
|
||||||
def getrepr(
|
def getrepr(
|
||||||
self,
|
self,
|
||||||
showlocals: bool = False,
|
showlocals: bool = False,
|
||||||
style: "_TracebackStyle" = "long",
|
style: _TracebackStyle = "long",
|
||||||
abspath: bool = False,
|
abspath: bool = False,
|
||||||
tbfilter: Union[
|
tbfilter: Union[
|
||||||
bool, Callable[["ExceptionInfo[BaseException]"], Traceback]
|
bool, Callable[["ExceptionInfo[BaseException]"], Traceback]
|
||||||
|
@ -725,7 +722,7 @@ class FormattedExcinfo:
|
||||||
fail_marker: ClassVar = "E"
|
fail_marker: ClassVar = "E"
|
||||||
|
|
||||||
showlocals: bool = False
|
showlocals: bool = False
|
||||||
style: "_TracebackStyle" = "long"
|
style: _TracebackStyle = "long"
|
||||||
abspath: bool = True
|
abspath: bool = True
|
||||||
tbfilter: Union[bool, Callable[[ExceptionInfo[BaseException]], Traceback]] = True
|
tbfilter: Union[bool, Callable[[ExceptionInfo[BaseException]], Traceback]] = True
|
||||||
funcargs: bool = False
|
funcargs: bool = False
|
||||||
|
@ -1090,7 +1087,7 @@ class ReprExceptionInfo(ExceptionRepr):
|
||||||
class ReprTraceback(TerminalRepr):
|
class ReprTraceback(TerminalRepr):
|
||||||
reprentries: Sequence[Union["ReprEntry", "ReprEntryNative"]]
|
reprentries: Sequence[Union["ReprEntry", "ReprEntryNative"]]
|
||||||
extraline: Optional[str]
|
extraline: Optional[str]
|
||||||
style: "_TracebackStyle"
|
style: _TracebackStyle
|
||||||
|
|
||||||
entrysep: ClassVar = "_ "
|
entrysep: ClassVar = "_ "
|
||||||
|
|
||||||
|
@ -1124,7 +1121,7 @@ class ReprTracebackNative(ReprTraceback):
|
||||||
class ReprEntryNative(TerminalRepr):
|
class ReprEntryNative(TerminalRepr):
|
||||||
lines: Sequence[str]
|
lines: Sequence[str]
|
||||||
|
|
||||||
style: ClassVar["_TracebackStyle"] = "native"
|
style: ClassVar[_TracebackStyle] = "native"
|
||||||
|
|
||||||
def toterminal(self, tw: TerminalWriter) -> None:
|
def toterminal(self, tw: TerminalWriter) -> None:
|
||||||
tw.write("".join(self.lines))
|
tw.write("".join(self.lines))
|
||||||
|
@ -1136,7 +1133,7 @@ class ReprEntry(TerminalRepr):
|
||||||
reprfuncargs: Optional["ReprFuncArgs"]
|
reprfuncargs: Optional["ReprFuncArgs"]
|
||||||
reprlocals: Optional["ReprLocals"]
|
reprlocals: Optional["ReprLocals"]
|
||||||
reprfileloc: Optional["ReprFileLocation"]
|
reprfileloc: Optional["ReprFileLocation"]
|
||||||
style: "_TracebackStyle"
|
style: _TracebackStyle
|
||||||
|
|
||||||
def _write_entry_lines(self, tw: TerminalWriter) -> None:
|
def _write_entry_lines(self, tw: TerminalWriter) -> None:
|
||||||
"""Write the source code portions of a list of traceback entries with syntax highlighting.
|
"""Write the source code portions of a list of traceback entries with syntax highlighting.
|
||||||
|
|
|
@ -149,8 +149,7 @@ def get_statement_startend2(lineno: int, node: ast.AST) -> Tuple[int, Optional[i
|
||||||
values: List[int] = []
|
values: List[int] = []
|
||||||
for x in ast.walk(node):
|
for x in ast.walk(node):
|
||||||
if isinstance(x, (ast.stmt, ast.ExceptHandler)):
|
if isinstance(x, (ast.stmt, ast.ExceptHandler)):
|
||||||
# Before Python 3.8, the lineno of a decorated class or function pointed at the decorator.
|
# The lineno points to the class/def, so need to include the decorators.
|
||||||
# Since Python 3.8, the lineno points to the class/def, so need to include the decorators.
|
|
||||||
if isinstance(x, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)):
|
if isinstance(x, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||||
for d in x.decorator_list:
|
for d in x.decorator_list:
|
||||||
values.append(d.lineno - 1)
|
values.append(d.lineno - 1)
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
|
from typing import final
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import TextIO
|
from typing import TextIO
|
||||||
|
|
||||||
from .wcwidth import wcswidth
|
from .wcwidth import wcswidth
|
||||||
from _pytest.compat import final
|
|
||||||
|
|
||||||
|
|
||||||
# This code was initially copied from py 1.8.1, file _io/terminalwriter.py.
|
# This code was initially copied from py 1.8.1, file _io/terminalwriter.py.
|
||||||
|
|
|
@ -112,8 +112,8 @@ def pytest_collection(session: "Session") -> None:
|
||||||
assertstate.hook.set_session(session)
|
assertstate.hook.set_session(session)
|
||||||
|
|
||||||
|
|
||||||
@hookimpl(tryfirst=True, hookwrapper=True)
|
@hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]:
|
||||||
"""Setup the pytest_assertrepr_compare and pytest_assertion_pass hooks.
|
"""Setup the pytest_assertrepr_compare and pytest_assertion_pass hooks.
|
||||||
|
|
||||||
The rewrite module will use util._reprcompare if it exists to use custom
|
The rewrite module will use util._reprcompare if it exists to use custom
|
||||||
|
@ -162,10 +162,11 @@ def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
||||||
|
|
||||||
util._assertion_pass = call_assertion_pass_hook
|
util._assertion_pass = call_assertion_pass_hook
|
||||||
|
|
||||||
yield
|
try:
|
||||||
|
return (yield)
|
||||||
util._reprcompare, util._assertion_pass = saved_assert_hooks
|
finally:
|
||||||
util._config = None
|
util._reprcompare, util._assertion_pass = saved_assert_hooks
|
||||||
|
util._config = None
|
||||||
|
|
||||||
|
|
||||||
def pytest_sessionfinish(session: "Session") -> None:
|
def pytest_sessionfinish(session: "Session") -> None:
|
||||||
|
|
|
@ -44,17 +44,6 @@ from _pytest.stash import StashKey
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from _pytest.assertion import AssertionState
|
from _pytest.assertion import AssertionState
|
||||||
|
|
||||||
if sys.version_info >= (3, 8):
|
|
||||||
namedExpr = ast.NamedExpr
|
|
||||||
astNameConstant = ast.Constant
|
|
||||||
astStr = ast.Constant
|
|
||||||
astNum = ast.Constant
|
|
||||||
else:
|
|
||||||
namedExpr = ast.Expr
|
|
||||||
astNameConstant = ast.NameConstant
|
|
||||||
astStr = ast.Str
|
|
||||||
astNum = ast.Num
|
|
||||||
|
|
||||||
|
|
||||||
assertstate_key = StashKey["AssertionState"]()
|
assertstate_key = StashKey["AssertionState"]()
|
||||||
|
|
||||||
|
@ -686,12 +675,10 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
if (
|
if (
|
||||||
expect_docstring
|
expect_docstring
|
||||||
and isinstance(item, ast.Expr)
|
and isinstance(item, ast.Expr)
|
||||||
and isinstance(item.value, astStr)
|
and isinstance(item.value, ast.Constant)
|
||||||
|
and isinstance(item.value.value, str)
|
||||||
):
|
):
|
||||||
if sys.version_info >= (3, 8):
|
doc = item.value.value
|
||||||
doc = item.value.value
|
|
||||||
else:
|
|
||||||
doc = item.value.s
|
|
||||||
if self.is_rewrite_disabled(doc):
|
if self.is_rewrite_disabled(doc):
|
||||||
return
|
return
|
||||||
expect_docstring = False
|
expect_docstring = False
|
||||||
|
@ -823,7 +810,7 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
current = self.stack.pop()
|
current = self.stack.pop()
|
||||||
if self.stack:
|
if self.stack:
|
||||||
self.explanation_specifiers = self.stack[-1]
|
self.explanation_specifiers = self.stack[-1]
|
||||||
keys = [astStr(key) for key in current.keys()]
|
keys = [ast.Constant(key) for key in current.keys()]
|
||||||
format_dict = ast.Dict(keys, list(current.values()))
|
format_dict = ast.Dict(keys, list(current.values()))
|
||||||
form = ast.BinOp(expl_expr, ast.Mod(), format_dict)
|
form = ast.BinOp(expl_expr, ast.Mod(), format_dict)
|
||||||
name = "@py_format" + str(next(self.variable_counter))
|
name = "@py_format" + str(next(self.variable_counter))
|
||||||
|
@ -877,16 +864,16 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
negation = ast.UnaryOp(ast.Not(), top_condition)
|
negation = ast.UnaryOp(ast.Not(), top_condition)
|
||||||
|
|
||||||
if self.enable_assertion_pass_hook: # Experimental pytest_assertion_pass hook
|
if self.enable_assertion_pass_hook: # Experimental pytest_assertion_pass hook
|
||||||
msg = self.pop_format_context(astStr(explanation))
|
msg = self.pop_format_context(ast.Constant(explanation))
|
||||||
|
|
||||||
# Failed
|
# Failed
|
||||||
if assert_.msg:
|
if assert_.msg:
|
||||||
assertmsg = self.helper("_format_assertmsg", assert_.msg)
|
assertmsg = self.helper("_format_assertmsg", assert_.msg)
|
||||||
gluestr = "\n>assert "
|
gluestr = "\n>assert "
|
||||||
else:
|
else:
|
||||||
assertmsg = astStr("")
|
assertmsg = ast.Constant("")
|
||||||
gluestr = "assert "
|
gluestr = "assert "
|
||||||
err_explanation = ast.BinOp(astStr(gluestr), ast.Add(), msg)
|
err_explanation = ast.BinOp(ast.Constant(gluestr), ast.Add(), msg)
|
||||||
err_msg = ast.BinOp(assertmsg, ast.Add(), err_explanation)
|
err_msg = ast.BinOp(assertmsg, ast.Add(), err_explanation)
|
||||||
err_name = ast.Name("AssertionError", ast.Load())
|
err_name = ast.Name("AssertionError", ast.Load())
|
||||||
fmt = self.helper("_format_explanation", err_msg)
|
fmt = self.helper("_format_explanation", err_msg)
|
||||||
|
@ -902,8 +889,8 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
hook_call_pass = ast.Expr(
|
hook_call_pass = ast.Expr(
|
||||||
self.helper(
|
self.helper(
|
||||||
"_call_assertion_pass",
|
"_call_assertion_pass",
|
||||||
astNum(assert_.lineno),
|
ast.Constant(assert_.lineno),
|
||||||
astStr(orig),
|
ast.Constant(orig),
|
||||||
fmt_pass,
|
fmt_pass,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -922,7 +909,7 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
variables = [
|
variables = [
|
||||||
ast.Name(name, ast.Store()) for name in self.format_variables
|
ast.Name(name, ast.Store()) for name in self.format_variables
|
||||||
]
|
]
|
||||||
clear_format = ast.Assign(variables, astNameConstant(None))
|
clear_format = ast.Assign(variables, ast.Constant(None))
|
||||||
self.statements.append(clear_format)
|
self.statements.append(clear_format)
|
||||||
|
|
||||||
else: # Original assertion rewriting
|
else: # Original assertion rewriting
|
||||||
|
@ -933,9 +920,9 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
assertmsg = self.helper("_format_assertmsg", assert_.msg)
|
assertmsg = self.helper("_format_assertmsg", assert_.msg)
|
||||||
explanation = "\n>assert " + explanation
|
explanation = "\n>assert " + explanation
|
||||||
else:
|
else:
|
||||||
assertmsg = astStr("")
|
assertmsg = ast.Constant("")
|
||||||
explanation = "assert " + explanation
|
explanation = "assert " + explanation
|
||||||
template = ast.BinOp(assertmsg, ast.Add(), astStr(explanation))
|
template = ast.BinOp(assertmsg, ast.Add(), ast.Constant(explanation))
|
||||||
msg = self.pop_format_context(template)
|
msg = self.pop_format_context(template)
|
||||||
fmt = self.helper("_format_explanation", msg)
|
fmt = self.helper("_format_explanation", msg)
|
||||||
err_name = ast.Name("AssertionError", ast.Load())
|
err_name = ast.Name("AssertionError", ast.Load())
|
||||||
|
@ -947,7 +934,7 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
# Clear temporary variables by setting them to None.
|
# Clear temporary variables by setting them to None.
|
||||||
if self.variables:
|
if self.variables:
|
||||||
variables = [ast.Name(name, ast.Store()) for name in self.variables]
|
variables = [ast.Name(name, ast.Store()) for name in self.variables]
|
||||||
clear = ast.Assign(variables, astNameConstant(None))
|
clear = ast.Assign(variables, ast.Constant(None))
|
||||||
self.statements.append(clear)
|
self.statements.append(clear)
|
||||||
# Fix locations (line numbers/column offsets).
|
# Fix locations (line numbers/column offsets).
|
||||||
for stmt in self.statements:
|
for stmt in self.statements:
|
||||||
|
@ -955,26 +942,26 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
ast.copy_location(node, assert_)
|
ast.copy_location(node, assert_)
|
||||||
return self.statements
|
return self.statements
|
||||||
|
|
||||||
def visit_NamedExpr(self, name: namedExpr) -> Tuple[namedExpr, str]:
|
def visit_NamedExpr(self, name: ast.NamedExpr) -> Tuple[ast.NamedExpr, str]:
|
||||||
# This method handles the 'walrus operator' repr of the target
|
# This method handles the 'walrus operator' repr of the target
|
||||||
# name if it's a local variable or _should_repr_global_name()
|
# name if it's a local variable or _should_repr_global_name()
|
||||||
# thinks it's acceptable.
|
# thinks it's acceptable.
|
||||||
locs = ast.Call(self.builtin("locals"), [], [])
|
locs = ast.Call(self.builtin("locals"), [], [])
|
||||||
target_id = name.target.id # type: ignore[attr-defined]
|
target_id = name.target.id # type: ignore[attr-defined]
|
||||||
inlocs = ast.Compare(astStr(target_id), [ast.In()], [locs])
|
inlocs = ast.Compare(ast.Constant(target_id), [ast.In()], [locs])
|
||||||
dorepr = self.helper("_should_repr_global_name", name)
|
dorepr = self.helper("_should_repr_global_name", name)
|
||||||
test = ast.BoolOp(ast.Or(), [inlocs, dorepr])
|
test = ast.BoolOp(ast.Or(), [inlocs, dorepr])
|
||||||
expr = ast.IfExp(test, self.display(name), astStr(target_id))
|
expr = ast.IfExp(test, self.display(name), ast.Constant(target_id))
|
||||||
return name, self.explanation_param(expr)
|
return name, self.explanation_param(expr)
|
||||||
|
|
||||||
def visit_Name(self, name: ast.Name) -> Tuple[ast.Name, str]:
|
def visit_Name(self, name: ast.Name) -> Tuple[ast.Name, str]:
|
||||||
# Display the repr of the name if it's a local variable or
|
# Display the repr of the name if it's a local variable or
|
||||||
# _should_repr_global_name() thinks it's acceptable.
|
# _should_repr_global_name() thinks it's acceptable.
|
||||||
locs = ast.Call(self.builtin("locals"), [], [])
|
locs = ast.Call(self.builtin("locals"), [], [])
|
||||||
inlocs = ast.Compare(astStr(name.id), [ast.In()], [locs])
|
inlocs = ast.Compare(ast.Constant(name.id), [ast.In()], [locs])
|
||||||
dorepr = self.helper("_should_repr_global_name", name)
|
dorepr = self.helper("_should_repr_global_name", name)
|
||||||
test = ast.BoolOp(ast.Or(), [inlocs, dorepr])
|
test = ast.BoolOp(ast.Or(), [inlocs, dorepr])
|
||||||
expr = ast.IfExp(test, self.display(name), astStr(name.id))
|
expr = ast.IfExp(test, self.display(name), ast.Constant(name.id))
|
||||||
return name, self.explanation_param(expr)
|
return name, self.explanation_param(expr)
|
||||||
|
|
||||||
def visit_BoolOp(self, boolop: ast.BoolOp) -> Tuple[ast.Name, str]:
|
def visit_BoolOp(self, boolop: ast.BoolOp) -> Tuple[ast.Name, str]:
|
||||||
|
@ -993,10 +980,10 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
# cond is set in a prior loop iteration below
|
# cond is set in a prior loop iteration below
|
||||||
self.expl_stmts.append(ast.If(cond, fail_inner, [])) # noqa
|
self.expl_stmts.append(ast.If(cond, fail_inner, [])) # noqa
|
||||||
self.expl_stmts = fail_inner
|
self.expl_stmts = fail_inner
|
||||||
# Check if the left operand is a namedExpr and the value has already been visited
|
# Check if the left operand is a ast.NamedExpr and the value has already been visited
|
||||||
if (
|
if (
|
||||||
isinstance(v, ast.Compare)
|
isinstance(v, ast.Compare)
|
||||||
and isinstance(v.left, namedExpr)
|
and isinstance(v.left, ast.NamedExpr)
|
||||||
and v.left.target.id
|
and v.left.target.id
|
||||||
in [
|
in [
|
||||||
ast_expr.id
|
ast_expr.id
|
||||||
|
@ -1012,7 +999,7 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
self.push_format_context()
|
self.push_format_context()
|
||||||
res, expl = self.visit(v)
|
res, expl = self.visit(v)
|
||||||
body.append(ast.Assign([ast.Name(res_var, ast.Store())], res))
|
body.append(ast.Assign([ast.Name(res_var, ast.Store())], res))
|
||||||
expl_format = self.pop_format_context(astStr(expl))
|
expl_format = self.pop_format_context(ast.Constant(expl))
|
||||||
call = ast.Call(app, [expl_format], [])
|
call = ast.Call(app, [expl_format], [])
|
||||||
self.expl_stmts.append(ast.Expr(call))
|
self.expl_stmts.append(ast.Expr(call))
|
||||||
if i < levels:
|
if i < levels:
|
||||||
|
@ -1024,7 +1011,7 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
self.statements = body = inner
|
self.statements = body = inner
|
||||||
self.statements = save
|
self.statements = save
|
||||||
self.expl_stmts = fail_save
|
self.expl_stmts = fail_save
|
||||||
expl_template = self.helper("_format_boolop", expl_list, astNum(is_or))
|
expl_template = self.helper("_format_boolop", expl_list, ast.Constant(is_or))
|
||||||
expl = self.pop_format_context(expl_template)
|
expl = self.pop_format_context(expl_template)
|
||||||
return ast.Name(res_var, ast.Load()), self.explanation_param(expl)
|
return ast.Name(res_var, ast.Load()), self.explanation_param(expl)
|
||||||
|
|
||||||
|
@ -1098,7 +1085,7 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
comp.left = self.variables_overwrite[
|
comp.left = self.variables_overwrite[
|
||||||
comp.left.id
|
comp.left.id
|
||||||
] # type:ignore[assignment]
|
] # type:ignore[assignment]
|
||||||
if isinstance(comp.left, namedExpr):
|
if isinstance(comp.left, ast.NamedExpr):
|
||||||
self.variables_overwrite[
|
self.variables_overwrite[
|
||||||
comp.left.target.id
|
comp.left.target.id
|
||||||
] = comp.left # type:ignore[assignment]
|
] = comp.left # type:ignore[assignment]
|
||||||
|
@ -1114,7 +1101,7 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
results = [left_res]
|
results = [left_res]
|
||||||
for i, op, next_operand in it:
|
for i, op, next_operand in it:
|
||||||
if (
|
if (
|
||||||
isinstance(next_operand, namedExpr)
|
isinstance(next_operand, ast.NamedExpr)
|
||||||
and isinstance(left_res, ast.Name)
|
and isinstance(left_res, ast.Name)
|
||||||
and next_operand.target.id == left_res.id
|
and next_operand.target.id == left_res.id
|
||||||
):
|
):
|
||||||
|
@ -1127,9 +1114,9 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
next_expl = f"({next_expl})"
|
next_expl = f"({next_expl})"
|
||||||
results.append(next_res)
|
results.append(next_res)
|
||||||
sym = BINOP_MAP[op.__class__]
|
sym = BINOP_MAP[op.__class__]
|
||||||
syms.append(astStr(sym))
|
syms.append(ast.Constant(sym))
|
||||||
expl = f"{left_expl} {sym} {next_expl}"
|
expl = f"{left_expl} {sym} {next_expl}"
|
||||||
expls.append(astStr(expl))
|
expls.append(ast.Constant(expl))
|
||||||
res_expr = ast.Compare(left_res, [op], [next_res])
|
res_expr = ast.Compare(left_res, [op], [next_res])
|
||||||
self.statements.append(ast.Assign([store_names[i]], res_expr))
|
self.statements.append(ast.Assign([store_names[i]], res_expr))
|
||||||
left_res, left_expl = next_res, next_expl
|
left_res, left_expl = next_res, next_expl
|
||||||
|
@ -1173,7 +1160,7 @@ def try_makedirs(cache_dir: Path) -> bool:
|
||||||
|
|
||||||
def get_cache_dir(file_path: Path) -> Path:
|
def get_cache_dir(file_path: Path) -> Path:
|
||||||
"""Return the cache directory to write .pyc files for the given .py file path."""
|
"""Return the cache directory to write .pyc files for the given .py file path."""
|
||||||
if sys.version_info >= (3, 8) and sys.pycache_prefix:
|
if sys.pycache_prefix:
|
||||||
# given:
|
# given:
|
||||||
# prefix = '/tmp/pycs'
|
# prefix = '/tmp/pycs'
|
||||||
# path = '/home/user/proj/test_app.py'
|
# path = '/home/user/proj/test_app.py'
|
||||||
|
|
|
@ -6,6 +6,7 @@ import json
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import final
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from typing import List
|
from typing import List
|
||||||
|
@ -18,7 +19,6 @@ from .pathlib import rm_rf
|
||||||
from .reports import CollectReport
|
from .reports import CollectReport
|
||||||
from _pytest import nodes
|
from _pytest import nodes
|
||||||
from _pytest._io import TerminalWriter
|
from _pytest._io import TerminalWriter
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
from _pytest.config import hookimpl
|
from _pytest.config import hookimpl
|
||||||
|
@ -217,12 +217,12 @@ class LFPluginCollWrapper:
|
||||||
self.lfplugin = lfplugin
|
self.lfplugin = lfplugin
|
||||||
self._collected_at_least_one_failure = False
|
self._collected_at_least_one_failure = False
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_make_collect_report(self, collector: nodes.Collector):
|
def pytest_make_collect_report(
|
||||||
|
self, collector: nodes.Collector
|
||||||
|
) -> Generator[None, CollectReport, CollectReport]:
|
||||||
|
res = yield
|
||||||
if isinstance(collector, (Session, Package)):
|
if isinstance(collector, (Session, Package)):
|
||||||
out = yield
|
|
||||||
res: CollectReport = out.get_result()
|
|
||||||
|
|
||||||
# Sort any lf-paths to the beginning.
|
# Sort any lf-paths to the beginning.
|
||||||
lf_paths = self.lfplugin._last_failed_paths
|
lf_paths = self.lfplugin._last_failed_paths
|
||||||
|
|
||||||
|
@ -240,19 +240,16 @@ class LFPluginCollWrapper:
|
||||||
key=sort_key,
|
key=sort_key,
|
||||||
reverse=True,
|
reverse=True,
|
||||||
)
|
)
|
||||||
return
|
|
||||||
|
|
||||||
elif isinstance(collector, File):
|
elif isinstance(collector, File):
|
||||||
if collector.path in self.lfplugin._last_failed_paths:
|
if collector.path in self.lfplugin._last_failed_paths:
|
||||||
out = yield
|
|
||||||
res = out.get_result()
|
|
||||||
result = res.result
|
result = res.result
|
||||||
lastfailed = self.lfplugin.lastfailed
|
lastfailed = self.lfplugin.lastfailed
|
||||||
|
|
||||||
# Only filter with known failures.
|
# Only filter with known failures.
|
||||||
if not self._collected_at_least_one_failure:
|
if not self._collected_at_least_one_failure:
|
||||||
if not any(x.nodeid in lastfailed for x in result):
|
if not any(x.nodeid in lastfailed for x in result):
|
||||||
return
|
return res
|
||||||
self.lfplugin.config.pluginmanager.register(
|
self.lfplugin.config.pluginmanager.register(
|
||||||
LFPluginCollSkipfiles(self.lfplugin), "lfplugin-collskip"
|
LFPluginCollSkipfiles(self.lfplugin), "lfplugin-collskip"
|
||||||
)
|
)
|
||||||
|
@ -268,8 +265,8 @@ class LFPluginCollWrapper:
|
||||||
# Keep all sub-collectors.
|
# Keep all sub-collectors.
|
||||||
or isinstance(x, nodes.Collector)
|
or isinstance(x, nodes.Collector)
|
||||||
]
|
]
|
||||||
return
|
|
||||||
yield
|
return res
|
||||||
|
|
||||||
|
|
||||||
class LFPluginCollSkipfiles:
|
class LFPluginCollSkipfiles:
|
||||||
|
@ -342,14 +339,14 @@ class LFPlugin:
|
||||||
else:
|
else:
|
||||||
self.lastfailed[report.nodeid] = True
|
self.lastfailed[report.nodeid] = True
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True, tryfirst=True)
|
@hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_collection_modifyitems(
|
def pytest_collection_modifyitems(
|
||||||
self, config: Config, items: List[nodes.Item]
|
self, config: Config, items: List[nodes.Item]
|
||||||
) -> Generator[None, None, None]:
|
) -> Generator[None, None, None]:
|
||||||
yield
|
res = yield
|
||||||
|
|
||||||
if not self.active:
|
if not self.active:
|
||||||
return
|
return res
|
||||||
|
|
||||||
if self.lastfailed:
|
if self.lastfailed:
|
||||||
previously_failed = []
|
previously_failed = []
|
||||||
|
@ -394,6 +391,8 @@ class LFPlugin:
|
||||||
else:
|
else:
|
||||||
self._report_status += "not deselecting items."
|
self._report_status += "not deselecting items."
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
def pytest_sessionfinish(self, session: Session) -> None:
|
def pytest_sessionfinish(self, session: Session) -> None:
|
||||||
config = self.config
|
config = self.config
|
||||||
if config.getoption("cacheshow") or hasattr(config, "workerinput"):
|
if config.getoption("cacheshow") or hasattr(config, "workerinput"):
|
||||||
|
@ -414,11 +413,11 @@ class NFPlugin:
|
||||||
assert config.cache is not None
|
assert config.cache is not None
|
||||||
self.cached_nodeids = set(config.cache.get("cache/nodeids", []))
|
self.cached_nodeids = set(config.cache.get("cache/nodeids", []))
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True, tryfirst=True)
|
@hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_collection_modifyitems(
|
def pytest_collection_modifyitems(
|
||||||
self, items: List[nodes.Item]
|
self, items: List[nodes.Item]
|
||||||
) -> Generator[None, None, None]:
|
) -> Generator[None, None, None]:
|
||||||
yield
|
res = yield
|
||||||
|
|
||||||
if self.active:
|
if self.active:
|
||||||
new_items: Dict[str, nodes.Item] = {}
|
new_items: Dict[str, nodes.Item] = {}
|
||||||
|
@ -436,6 +435,8 @@ class NFPlugin:
|
||||||
else:
|
else:
|
||||||
self.cached_nodeids.update(item.nodeid for item in items)
|
self.cached_nodeids.update(item.nodeid for item in items)
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
def _get_increasing_order(self, items: Iterable[nodes.Item]) -> List[nodes.Item]:
|
def _get_increasing_order(self, items: Iterable[nodes.Item]) -> List[nodes.Item]:
|
||||||
return sorted(items, key=lambda item: item.path.stat().st_mtime, reverse=True) # type: ignore[no-any-return]
|
return sorted(items, key=lambda item: item.path.stat().st_mtime, reverse=True) # type: ignore[no-any-return]
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,14 @@ from types import TracebackType
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import AnyStr
|
from typing import AnyStr
|
||||||
from typing import BinaryIO
|
from typing import BinaryIO
|
||||||
|
from typing import Final
|
||||||
|
from typing import final
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Generic
|
from typing import Generic
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from typing import Literal
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import TextIO
|
from typing import TextIO
|
||||||
|
@ -24,7 +27,6 @@ from typing import Type
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config import hookimpl
|
from _pytest.config import hookimpl
|
||||||
from _pytest.config.argparsing import Parser
|
from _pytest.config.argparsing import Parser
|
||||||
|
@ -34,12 +36,9 @@ from _pytest.fixtures import SubRequest
|
||||||
from _pytest.nodes import Collector
|
from _pytest.nodes import Collector
|
||||||
from _pytest.nodes import File
|
from _pytest.nodes import File
|
||||||
from _pytest.nodes import Item
|
from _pytest.nodes import Item
|
||||||
|
from _pytest.reports import CollectReport
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
_CaptureMethod = Literal["fd", "sys", "no", "tee-sys"]
|
||||||
from typing_extensions import Final
|
|
||||||
from typing_extensions import Literal
|
|
||||||
|
|
||||||
_CaptureMethod = Literal["fd", "sys", "no", "tee-sys"]
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser: Parser) -> None:
|
def pytest_addoption(parser: Parser) -> None:
|
||||||
|
@ -132,8 +131,8 @@ def _windowsconsoleio_workaround(stream: TextIO) -> None:
|
||||||
sys.stderr = _reopen_stdio(sys.stderr, "wb")
|
sys.stderr = _reopen_stdio(sys.stderr, "wb")
|
||||||
|
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_load_initial_conftests(early_config: Config):
|
def pytest_load_initial_conftests(early_config: Config) -> Generator[None, None, None]:
|
||||||
ns = early_config.known_args_namespace
|
ns = early_config.known_args_namespace
|
||||||
if ns.capture == "fd":
|
if ns.capture == "fd":
|
||||||
_windowsconsoleio_workaround(sys.stdout)
|
_windowsconsoleio_workaround(sys.stdout)
|
||||||
|
@ -147,12 +146,16 @@ def pytest_load_initial_conftests(early_config: Config):
|
||||||
|
|
||||||
# Finally trigger conftest loading but while capturing (issue #93).
|
# Finally trigger conftest loading but while capturing (issue #93).
|
||||||
capman.start_global_capturing()
|
capman.start_global_capturing()
|
||||||
outcome = yield
|
try:
|
||||||
capman.suspend_global_capture()
|
try:
|
||||||
if outcome.excinfo is not None:
|
yield
|
||||||
|
finally:
|
||||||
|
capman.suspend_global_capture()
|
||||||
|
except BaseException:
|
||||||
out, err = capman.read_global_capture()
|
out, err = capman.read_global_capture()
|
||||||
sys.stdout.write(out)
|
sys.stdout.write(out)
|
||||||
sys.stderr.write(err)
|
sys.stderr.write(err)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
# IO Helpers.
|
# IO Helpers.
|
||||||
|
@ -687,7 +690,7 @@ class MultiCapture(Generic[AnyStr]):
|
||||||
return CaptureResult(out, err) # type: ignore[arg-type]
|
return CaptureResult(out, err) # type: ignore[arg-type]
|
||||||
|
|
||||||
|
|
||||||
def _get_multicapture(method: "_CaptureMethod") -> MultiCapture[str]:
|
def _get_multicapture(method: _CaptureMethod) -> MultiCapture[str]:
|
||||||
if method == "fd":
|
if method == "fd":
|
||||||
return MultiCapture(in_=FDCapture(0), out=FDCapture(1), err=FDCapture(2))
|
return MultiCapture(in_=FDCapture(0), out=FDCapture(1), err=FDCapture(2))
|
||||||
elif method == "sys":
|
elif method == "sys":
|
||||||
|
@ -723,7 +726,7 @@ class CaptureManager:
|
||||||
needed to ensure the fixtures take precedence over the global capture.
|
needed to ensure the fixtures take precedence over the global capture.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, method: "_CaptureMethod") -> None:
|
def __init__(self, method: _CaptureMethod) -> None:
|
||||||
self._method: Final = method
|
self._method: Final = method
|
||||||
self._global_capturing: Optional[MultiCapture[str]] = None
|
self._global_capturing: Optional[MultiCapture[str]] = None
|
||||||
self._capture_fixture: Optional[CaptureFixture[Any]] = None
|
self._capture_fixture: Optional[CaptureFixture[Any]] = None
|
||||||
|
@ -843,41 +846,45 @@ class CaptureManager:
|
||||||
self.deactivate_fixture()
|
self.deactivate_fixture()
|
||||||
self.suspend_global_capture(in_=False)
|
self.suspend_global_capture(in_=False)
|
||||||
|
|
||||||
out, err = self.read_global_capture()
|
out, err = self.read_global_capture()
|
||||||
item.add_report_section(when, "stdout", out)
|
item.add_report_section(when, "stdout", out)
|
||||||
item.add_report_section(when, "stderr", err)
|
item.add_report_section(when, "stderr", err)
|
||||||
|
|
||||||
# Hooks
|
# Hooks
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_make_collect_report(self, collector: Collector):
|
def pytest_make_collect_report(
|
||||||
|
self, collector: Collector
|
||||||
|
) -> Generator[None, CollectReport, CollectReport]:
|
||||||
if isinstance(collector, File):
|
if isinstance(collector, File):
|
||||||
self.resume_global_capture()
|
self.resume_global_capture()
|
||||||
outcome = yield
|
try:
|
||||||
self.suspend_global_capture()
|
rep = yield
|
||||||
|
finally:
|
||||||
|
self.suspend_global_capture()
|
||||||
out, err = self.read_global_capture()
|
out, err = self.read_global_capture()
|
||||||
rep = outcome.get_result()
|
|
||||||
if out:
|
if out:
|
||||||
rep.sections.append(("Captured stdout", out))
|
rep.sections.append(("Captured stdout", out))
|
||||||
if err:
|
if err:
|
||||||
rep.sections.append(("Captured stderr", err))
|
rep.sections.append(("Captured stderr", err))
|
||||||
else:
|
else:
|
||||||
yield
|
rep = yield
|
||||||
|
return rep
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_runtest_setup(self, item: Item) -> Generator[None, None, None]:
|
def pytest_runtest_setup(self, item: Item) -> Generator[None, None, None]:
|
||||||
with self.item_capture("setup", item):
|
with self.item_capture("setup", item):
|
||||||
yield
|
return (yield)
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_runtest_call(self, item: Item) -> Generator[None, None, None]:
|
def pytest_runtest_call(self, item: Item) -> Generator[None, None, None]:
|
||||||
with self.item_capture("call", item):
|
with self.item_capture("call", item):
|
||||||
yield
|
return (yield)
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_runtest_teardown(self, item: Item) -> Generator[None, None, None]:
|
def pytest_runtest_teardown(self, item: Item) -> Generator[None, None, None]:
|
||||||
with self.item_capture("teardown", item):
|
with self.item_capture("teardown", item):
|
||||||
yield
|
return (yield)
|
||||||
|
|
||||||
@hookimpl(tryfirst=True)
|
@hookimpl(tryfirst=True)
|
||||||
def pytest_keyboard_interrupt(self) -> None:
|
def pytest_keyboard_interrupt(self) -> None:
|
||||||
|
|
|
@ -12,26 +12,12 @@ from inspect import signature
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Generic
|
from typing import Final
|
||||||
from typing import NoReturn
|
from typing import NoReturn
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
|
|
||||||
import py
|
import py
|
||||||
|
|
||||||
# fmt: off
|
|
||||||
# Workaround for https://github.com/sphinx-doc/sphinx/issues/10351.
|
|
||||||
# If `overload` is imported from `compat` instead of from `typing`,
|
|
||||||
# Sphinx doesn't recognize it as `overload` and the API docs for
|
|
||||||
# overloaded functions look good again. But type checkers handle
|
|
||||||
# it fine.
|
|
||||||
# fmt: on
|
|
||||||
if True:
|
|
||||||
from typing import overload as overload
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from typing_extensions import Final
|
|
||||||
|
|
||||||
|
|
||||||
_T = TypeVar("_T")
|
_T = TypeVar("_T")
|
||||||
_S = TypeVar("_S")
|
_S = TypeVar("_S")
|
||||||
|
@ -58,17 +44,6 @@ class NotSetType(enum.Enum):
|
||||||
NOTSET: Final = NotSetType.token # noqa: E305
|
NOTSET: Final = NotSetType.token # noqa: E305
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
if sys.version_info >= (3, 8):
|
|
||||||
import importlib.metadata
|
|
||||||
|
|
||||||
importlib_metadata = importlib.metadata
|
|
||||||
else:
|
|
||||||
import importlib_metadata as importlib_metadata # noqa: F401
|
|
||||||
|
|
||||||
|
|
||||||
def _format_args(func: Callable[..., Any]) -> str:
|
|
||||||
return str(signature(func))
|
|
||||||
|
|
||||||
|
|
||||||
def is_generator(func: object) -> bool:
|
def is_generator(func: object) -> bool:
|
||||||
genfunc = inspect.isgeneratorfunction(func)
|
genfunc = inspect.isgeneratorfunction(func)
|
||||||
|
@ -338,47 +313,6 @@ def safe_isclass(obj: object) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
if sys.version_info >= (3, 8):
|
|
||||||
from typing import final as final
|
|
||||||
else:
|
|
||||||
from typing_extensions import final as final
|
|
||||||
elif sys.version_info >= (3, 8):
|
|
||||||
from typing import final as final
|
|
||||||
else:
|
|
||||||
|
|
||||||
def final(f):
|
|
||||||
return f
|
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info >= (3, 8):
|
|
||||||
from functools import cached_property as cached_property
|
|
||||||
else:
|
|
||||||
|
|
||||||
class cached_property(Generic[_S, _T]):
|
|
||||||
__slots__ = ("func", "__doc__")
|
|
||||||
|
|
||||||
def __init__(self, func: Callable[[_S], _T]) -> None:
|
|
||||||
self.func = func
|
|
||||||
self.__doc__ = func.__doc__
|
|
||||||
|
|
||||||
@overload
|
|
||||||
def __get__(
|
|
||||||
self, instance: None, owner: type[_S] | None = ...
|
|
||||||
) -> cached_property[_S, _T]:
|
|
||||||
...
|
|
||||||
|
|
||||||
@overload
|
|
||||||
def __get__(self, instance: _S, owner: type[_S] | None = ...) -> _T:
|
|
||||||
...
|
|
||||||
|
|
||||||
def __get__(self, instance, owner=None):
|
|
||||||
if instance is None:
|
|
||||||
return self
|
|
||||||
value = instance.__dict__[self.func.__name__] = self.func(instance)
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
def get_user_id() -> int | None:
|
def get_user_id() -> int | None:
|
||||||
"""Return the current user id, or None if we cannot get it reliably on the current platform."""
|
"""Return the current user id, or None if we cannot get it reliably on the current platform."""
|
||||||
# win32 does not have a getuid() function.
|
# win32 does not have a getuid() function.
|
||||||
|
|
|
@ -5,6 +5,7 @@ import copy
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import enum
|
import enum
|
||||||
import glob
|
import glob
|
||||||
|
import importlib.metadata
|
||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
@ -21,6 +22,7 @@ from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import cast
|
from typing import cast
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import final
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import IO
|
from typing import IO
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
@ -48,8 +50,6 @@ from .findpaths import determine_setup
|
||||||
from _pytest._code import ExceptionInfo
|
from _pytest._code import ExceptionInfo
|
||||||
from _pytest._code import filter_traceback
|
from _pytest._code import filter_traceback
|
||||||
from _pytest._io import TerminalWriter
|
from _pytest._io import TerminalWriter
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.compat import importlib_metadata # type: ignore[attr-defined]
|
|
||||||
from _pytest.outcomes import fail
|
from _pytest.outcomes import fail
|
||||||
from _pytest.outcomes import Skipped
|
from _pytest.outcomes import Skipped
|
||||||
from _pytest.pathlib import absolutepath
|
from _pytest.pathlib import absolutepath
|
||||||
|
@ -137,7 +137,9 @@ def main(
|
||||||
) -> Union[int, ExitCode]:
|
) -> Union[int, ExitCode]:
|
||||||
"""Perform an in-process test run.
|
"""Perform an in-process test run.
|
||||||
|
|
||||||
:param args: List of command line arguments.
|
:param args:
|
||||||
|
List of command line arguments. If `None` or not given, defaults to reading
|
||||||
|
arguments directly from the process command line (:data:`sys.argv`).
|
||||||
:param plugins: List of plugin objects to be auto-registered during initialization.
|
:param plugins: List of plugin objects to be auto-registered during initialization.
|
||||||
|
|
||||||
:returns: An exit code.
|
:returns: An exit code.
|
||||||
|
@ -257,7 +259,8 @@ default_plugins = essential_plugins + (
|
||||||
"logging",
|
"logging",
|
||||||
"reports",
|
"reports",
|
||||||
"python_path",
|
"python_path",
|
||||||
*(["unraisableexception", "threadexception"] if sys.version_info >= (3, 8) else []),
|
"unraisableexception",
|
||||||
|
"threadexception",
|
||||||
"faulthandler",
|
"faulthandler",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1216,7 +1219,7 @@ class Config:
|
||||||
|
|
||||||
package_files = (
|
package_files = (
|
||||||
str(file)
|
str(file)
|
||||||
for dist in importlib_metadata.distributions()
|
for dist in importlib.metadata.distributions()
|
||||||
if any(ep.group == "pytest11" for ep in dist.entry_points)
|
if any(ep.group == "pytest11" for ep in dist.entry_points)
|
||||||
for file in dist.files or []
|
for file in dist.files or []
|
||||||
)
|
)
|
||||||
|
@ -1338,12 +1341,14 @@ class Config:
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_collection(self) -> Generator[None, None, None]:
|
def pytest_collection(self) -> Generator[None, object, object]:
|
||||||
# Validate invalid ini keys after collection is done so we take in account
|
# Validate invalid ini keys after collection is done so we take in account
|
||||||
# options added by late-loading conftest files.
|
# options added by late-loading conftest files.
|
||||||
yield
|
try:
|
||||||
self._validate_config_options()
|
return (yield)
|
||||||
|
finally:
|
||||||
|
self._validate_config_options()
|
||||||
|
|
||||||
def _checkversion(self) -> None:
|
def _checkversion(self) -> None:
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -1445,7 +1450,7 @@ class Config:
|
||||||
"""Issue and handle a warning during the "configure" stage.
|
"""Issue and handle a warning during the "configure" stage.
|
||||||
|
|
||||||
During ``pytest_configure`` we can't capture warnings using the ``catch_warnings_for_item``
|
During ``pytest_configure`` we can't capture warnings using the ``catch_warnings_for_item``
|
||||||
function because it is not possible to have hookwrappers around ``pytest_configure``.
|
function because it is not possible to have hook wrappers around ``pytest_configure``.
|
||||||
|
|
||||||
This function is mainly intended for plugins that need to issue warnings during
|
This function is mainly intended for plugins that need to issue warnings during
|
||||||
``pytest_configure`` (or similar stages).
|
``pytest_configure`` (or similar stages).
|
||||||
|
|
|
@ -7,6 +7,7 @@ from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import cast
|
from typing import cast
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import final
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Mapping
|
from typing import Mapping
|
||||||
from typing import NoReturn
|
from typing import NoReturn
|
||||||
|
@ -17,7 +18,6 @@ from typing import TYPE_CHECKING
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
import _pytest._io
|
import _pytest._io
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.config.exceptions import UsageError
|
from _pytest.config.exceptions import UsageError
|
||||||
from _pytest.deprecated import ARGUMENT_PERCENT_DEFAULT
|
from _pytest.deprecated import ARGUMENT_PERCENT_DEFAULT
|
||||||
from _pytest.deprecated import ARGUMENT_TYPE_STR
|
from _pytest.deprecated import ARGUMENT_TYPE_STR
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from _pytest.compat import final
|
from typing import final
|
||||||
|
|
||||||
|
|
||||||
@final
|
@final
|
||||||
|
|
|
@ -304,10 +304,10 @@ class PdbInvoke:
|
||||||
|
|
||||||
|
|
||||||
class PdbTrace:
|
class PdbTrace:
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_pyfunc_call(self, pyfuncitem) -> Generator[None, None, None]:
|
def pytest_pyfunc_call(self, pyfuncitem) -> Generator[None, object, object]:
|
||||||
wrap_pytest_function_for_tracing(pyfuncitem)
|
wrap_pytest_function_for_tracing(pyfuncitem)
|
||||||
yield
|
return (yield)
|
||||||
|
|
||||||
|
|
||||||
def wrap_pytest_function_for_tracing(pyfuncitem):
|
def wrap_pytest_function_for_tracing(pyfuncitem):
|
||||||
|
|
|
@ -62,8 +62,8 @@ def get_timeout_config_value(config: Config) -> float:
|
||||||
return float(config.getini("faulthandler_timeout") or 0.0)
|
return float(config.getini("faulthandler_timeout") or 0.0)
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True, trylast=True)
|
@pytest.hookimpl(wrapper=True, trylast=True)
|
||||||
def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]:
|
||||||
timeout = get_timeout_config_value(item.config)
|
timeout = get_timeout_config_value(item.config)
|
||||||
if timeout > 0:
|
if timeout > 0:
|
||||||
import faulthandler
|
import faulthandler
|
||||||
|
@ -71,11 +71,11 @@ def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
||||||
stderr = item.config.stash[fault_handler_stderr_fd_key]
|
stderr = item.config.stash[fault_handler_stderr_fd_key]
|
||||||
faulthandler.dump_traceback_later(timeout, file=stderr)
|
faulthandler.dump_traceback_later(timeout, file=stderr)
|
||||||
try:
|
try:
|
||||||
yield
|
return (yield)
|
||||||
finally:
|
finally:
|
||||||
faulthandler.cancel_dump_traceback_later()
|
faulthandler.cancel_dump_traceback_later()
|
||||||
else:
|
else:
|
||||||
yield
|
return (yield)
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(tryfirst=True)
|
@pytest.hookimpl(tryfirst=True)
|
||||||
|
|
|
@ -13,6 +13,7 @@ from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import cast
|
from typing import cast
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import final
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Generic
|
from typing import Generic
|
||||||
from typing import Hashable
|
from typing import Hashable
|
||||||
|
@ -22,6 +23,7 @@ from typing import List
|
||||||
from typing import MutableMapping
|
from typing import MutableMapping
|
||||||
from typing import NoReturn
|
from typing import NoReturn
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from typing import overload
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Set
|
from typing import Set
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
@ -36,10 +38,8 @@ from _pytest._code import getfslineno
|
||||||
from _pytest._code.code import FormattedExcinfo
|
from _pytest._code.code import FormattedExcinfo
|
||||||
from _pytest._code.code import TerminalRepr
|
from _pytest._code.code import TerminalRepr
|
||||||
from _pytest._io import TerminalWriter
|
from _pytest._io import TerminalWriter
|
||||||
from _pytest.compat import _format_args
|
|
||||||
from _pytest.compat import _PytestWrapper
|
from _pytest.compat import _PytestWrapper
|
||||||
from _pytest.compat import assert_never
|
from _pytest.compat import assert_never
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.compat import get_real_func
|
from _pytest.compat import get_real_func
|
||||||
from _pytest.compat import get_real_method
|
from _pytest.compat import get_real_method
|
||||||
from _pytest.compat import getfuncargnames
|
from _pytest.compat import getfuncargnames
|
||||||
|
@ -48,7 +48,6 @@ from _pytest.compat import getlocation
|
||||||
from _pytest.compat import is_generator
|
from _pytest.compat import is_generator
|
||||||
from _pytest.compat import NOTSET
|
from _pytest.compat import NOTSET
|
||||||
from _pytest.compat import NotSetType
|
from _pytest.compat import NotSetType
|
||||||
from _pytest.compat import overload
|
|
||||||
from _pytest.compat import safe_getattr
|
from _pytest.compat import safe_getattr
|
||||||
from _pytest.config import _PluggyPlugin
|
from _pytest.config import _PluggyPlugin
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
|
@ -796,8 +795,10 @@ class FixtureRequest:
|
||||||
p = bestrelpath(session.path, fs)
|
p = bestrelpath(session.path, fs)
|
||||||
else:
|
else:
|
||||||
p = fs
|
p = fs
|
||||||
args = _format_args(factory)
|
lines.append(
|
||||||
lines.append("%s:%d: def %s%s" % (p, lineno + 1, factory.__name__, args))
|
"%s:%d: def %s%s"
|
||||||
|
% (p, lineno + 1, factory.__name__, inspect.signature(factory))
|
||||||
|
)
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from argparse import Action
|
from argparse import Action
|
||||||
|
from typing import Generator
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
@ -97,10 +98,9 @@ def pytest_addoption(parser: Parser) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_cmdline_parse():
|
def pytest_cmdline_parse() -> Generator[None, Config, Config]:
|
||||||
outcome = yield
|
config = yield
|
||||||
config: Config = outcome.get_result()
|
|
||||||
|
|
||||||
if config.option.debug:
|
if config.option.debug:
|
||||||
# --debug | --debug <file.log> was provided.
|
# --debug | --debug <file.log> was provided.
|
||||||
|
@ -128,6 +128,8 @@ def pytest_cmdline_parse():
|
||||||
|
|
||||||
config.add_cleanup(unset_tracing)
|
config.add_cleanup(unset_tracing)
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
def showversion(config: Config) -> None:
|
def showversion(config: Config) -> None:
|
||||||
if config.option.version > 1:
|
if config.option.version > 1:
|
||||||
|
|
|
@ -60,7 +60,7 @@ def pytest_addhooks(pluginmanager: "PytestPluginManager") -> None:
|
||||||
:param pytest.PytestPluginManager pluginmanager: The pytest plugin manager.
|
:param pytest.PytestPluginManager pluginmanager: The pytest plugin manager.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
This hook is incompatible with ``hookwrapper=True``.
|
This hook is incompatible with hook wrappers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ def pytest_plugin_registered(
|
||||||
:param pytest.PytestPluginManager manager: pytest plugin manager.
|
:param pytest.PytestPluginManager manager: pytest plugin manager.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
This hook is incompatible with ``hookwrapper=True``.
|
This hook is incompatible with hook wrappers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ def pytest_addoption(parser: "Parser", pluginmanager: "PytestPluginManager") ->
|
||||||
attribute or can be retrieved as the ``pytestconfig`` fixture.
|
attribute or can be retrieved as the ``pytestconfig`` fixture.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
This hook is incompatible with ``hookwrapper=True``.
|
This hook is incompatible with hook wrappers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ def pytest_configure(config: "Config") -> None:
|
||||||
imported.
|
imported.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
This hook is incompatible with ``hookwrapper=True``.
|
This hook is incompatible with hook wrappers.
|
||||||
|
|
||||||
:param pytest.Config config: The pytest config object.
|
:param pytest.Config config: The pytest config object.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -3,6 +3,8 @@ import dataclasses
|
||||||
import shlex
|
import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Final
|
||||||
|
from typing import final
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
@ -11,7 +13,6 @@ from typing import Union
|
||||||
from iniconfig import SectionWrapper
|
from iniconfig import SectionWrapper
|
||||||
|
|
||||||
from _pytest.cacheprovider import Cache
|
from _pytest.cacheprovider import Cache
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.compat import LEGACY_PATH
|
from _pytest.compat import LEGACY_PATH
|
||||||
from _pytest.compat import legacy_path
|
from _pytest.compat import legacy_path
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
|
@ -32,8 +33,6 @@ from _pytest.terminal import TerminalReporter
|
||||||
from _pytest.tmpdir import TempPathFactory
|
from _pytest.tmpdir import TempPathFactory
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing_extensions import Final
|
|
||||||
|
|
||||||
import pexpect
|
import pexpect
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ from logging import LogRecord
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import AbstractSet
|
from typing import AbstractSet
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import final
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Mapping
|
from typing import Mapping
|
||||||
|
@ -25,7 +26,6 @@ from typing import Union
|
||||||
from _pytest import nodes
|
from _pytest import nodes
|
||||||
from _pytest._io import TerminalWriter
|
from _pytest._io import TerminalWriter
|
||||||
from _pytest.capture import CaptureManager
|
from _pytest.capture import CaptureManager
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.config import _strtobool
|
from _pytest.config import _strtobool
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config import create_terminal_writer
|
from _pytest.config import create_terminal_writer
|
||||||
|
@ -738,27 +738,26 @@ class LoggingPlugin:
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True, tryfirst=True)
|
@hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_sessionstart(self) -> Generator[None, None, None]:
|
def pytest_sessionstart(self) -> Generator[None, None, None]:
|
||||||
self.log_cli_handler.set_when("sessionstart")
|
self.log_cli_handler.set_when("sessionstart")
|
||||||
|
|
||||||
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
||||||
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||||
yield
|
return (yield)
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True, tryfirst=True)
|
@hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_collection(self) -> Generator[None, None, None]:
|
def pytest_collection(self) -> Generator[None, None, None]:
|
||||||
self.log_cli_handler.set_when("collection")
|
self.log_cli_handler.set_when("collection")
|
||||||
|
|
||||||
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
||||||
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||||
yield
|
return (yield)
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_runtestloop(self, session: Session) -> Generator[None, None, None]:
|
def pytest_runtestloop(self, session: Session) -> Generator[None, object, object]:
|
||||||
if session.config.option.collectonly:
|
if session.config.option.collectonly:
|
||||||
yield
|
return (yield)
|
||||||
return
|
|
||||||
|
|
||||||
if self._log_cli_enabled() and self._config.getoption("verbose") < 1:
|
if self._log_cli_enabled() and self._config.getoption("verbose") < 1:
|
||||||
# The verbose flag is needed to avoid messy test progress output.
|
# The verbose flag is needed to avoid messy test progress output.
|
||||||
|
@ -766,7 +765,7 @@ class LoggingPlugin:
|
||||||
|
|
||||||
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
||||||
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||||
yield # Run all the tests.
|
return (yield) # Run all the tests.
|
||||||
|
|
||||||
@hookimpl
|
@hookimpl
|
||||||
def pytest_runtest_logstart(self) -> None:
|
def pytest_runtest_logstart(self) -> None:
|
||||||
|
@ -791,12 +790,13 @@ class LoggingPlugin:
|
||||||
item.stash[caplog_records_key][when] = caplog_handler.records
|
item.stash[caplog_records_key][when] = caplog_handler.records
|
||||||
item.stash[caplog_handler_key] = caplog_handler
|
item.stash[caplog_handler_key] = caplog_handler
|
||||||
|
|
||||||
yield
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
log = report_handler.stream.getvalue().strip()
|
||||||
|
item.add_report_section(when, "log", log)
|
||||||
|
|
||||||
log = report_handler.stream.getvalue().strip()
|
@hookimpl(wrapper=True)
|
||||||
item.add_report_section(when, "log", log)
|
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
|
||||||
def pytest_runtest_setup(self, item: nodes.Item) -> Generator[None, None, None]:
|
def pytest_runtest_setup(self, item: nodes.Item) -> Generator[None, None, None]:
|
||||||
self.log_cli_handler.set_when("setup")
|
self.log_cli_handler.set_when("setup")
|
||||||
|
|
||||||
|
@ -804,31 +804,33 @@ class LoggingPlugin:
|
||||||
item.stash[caplog_records_key] = empty
|
item.stash[caplog_records_key] = empty
|
||||||
yield from self._runtest_for(item, "setup")
|
yield from self._runtest_for(item, "setup")
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_runtest_call(self, item: nodes.Item) -> Generator[None, None, None]:
|
def pytest_runtest_call(self, item: nodes.Item) -> Generator[None, None, None]:
|
||||||
self.log_cli_handler.set_when("call")
|
self.log_cli_handler.set_when("call")
|
||||||
|
|
||||||
yield from self._runtest_for(item, "call")
|
yield from self._runtest_for(item, "call")
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_runtest_teardown(self, item: nodes.Item) -> Generator[None, None, None]:
|
def pytest_runtest_teardown(self, item: nodes.Item) -> Generator[None, None, None]:
|
||||||
self.log_cli_handler.set_when("teardown")
|
self.log_cli_handler.set_when("teardown")
|
||||||
|
|
||||||
yield from self._runtest_for(item, "teardown")
|
try:
|
||||||
del item.stash[caplog_records_key]
|
yield from self._runtest_for(item, "teardown")
|
||||||
del item.stash[caplog_handler_key]
|
finally:
|
||||||
|
del item.stash[caplog_records_key]
|
||||||
|
del item.stash[caplog_handler_key]
|
||||||
|
|
||||||
@hookimpl
|
@hookimpl
|
||||||
def pytest_runtest_logfinish(self) -> None:
|
def pytest_runtest_logfinish(self) -> None:
|
||||||
self.log_cli_handler.set_when("finish")
|
self.log_cli_handler.set_when("finish")
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True, tryfirst=True)
|
@hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_sessionfinish(self) -> Generator[None, None, None]:
|
def pytest_sessionfinish(self) -> Generator[None, None, None]:
|
||||||
self.log_cli_handler.set_when("sessionfinish")
|
self.log_cli_handler.set_when("sessionfinish")
|
||||||
|
|
||||||
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
||||||
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||||
yield
|
return (yield)
|
||||||
|
|
||||||
@hookimpl
|
@hookimpl
|
||||||
def pytest_unconfigure(self) -> None:
|
def pytest_unconfigure(self) -> None:
|
||||||
|
|
|
@ -9,10 +9,12 @@ import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import final
|
||||||
from typing import FrozenSet
|
from typing import FrozenSet
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from typing import overload
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Set
|
from typing import Set
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
@ -22,8 +24,6 @@ from typing import Union
|
||||||
|
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
from _pytest import nodes
|
from _pytest import nodes
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.compat import overload
|
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config import directory_arg
|
from _pytest.config import directory_arg
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
|
@ -462,6 +462,11 @@ class _bestrelpath_cache(Dict[Path, str]):
|
||||||
|
|
||||||
@final
|
@final
|
||||||
class Session(nodes.FSCollector):
|
class Session(nodes.FSCollector):
|
||||||
|
"""The root of the collection tree.
|
||||||
|
|
||||||
|
``Session`` collects the initial paths given as arguments to pytest.
|
||||||
|
"""
|
||||||
|
|
||||||
Interrupted = Interrupted
|
Interrupted = Interrupted
|
||||||
Failed = Failed
|
Failed = Failed
|
||||||
# Set on the session by runner.pytest_sessionstart.
|
# Set on the session by runner.pytest_sessionstart.
|
||||||
|
|
|
@ -18,7 +18,6 @@ import ast
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import enum
|
import enum
|
||||||
import re
|
import re
|
||||||
import sys
|
|
||||||
import types
|
import types
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
|
@ -27,12 +26,6 @@ from typing import NoReturn
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
if sys.version_info >= (3, 8):
|
|
||||||
astNameConstant = ast.Constant
|
|
||||||
else:
|
|
||||||
astNameConstant = ast.NameConstant
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"Expression",
|
"Expression",
|
||||||
"ParseError",
|
"ParseError",
|
||||||
|
@ -138,7 +131,7 @@ IDENT_PREFIX = "$"
|
||||||
|
|
||||||
def expression(s: Scanner) -> ast.Expression:
|
def expression(s: Scanner) -> ast.Expression:
|
||||||
if s.accept(TokenType.EOF):
|
if s.accept(TokenType.EOF):
|
||||||
ret: ast.expr = astNameConstant(False)
|
ret: ast.expr = ast.Constant(False)
|
||||||
else:
|
else:
|
||||||
ret = expr(s)
|
ret = expr(s)
|
||||||
s.accept(TokenType.EOF, reject=True)
|
s.accept(TokenType.EOF, reject=True)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import warnings
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Collection
|
from typing import Collection
|
||||||
|
from typing import final
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
from typing import List
|
from typing import List
|
||||||
|
@ -23,7 +24,6 @@ from typing import Union
|
||||||
|
|
||||||
from .._code import getfslineno
|
from .._code import getfslineno
|
||||||
from ..compat import ascii_escaped
|
from ..compat import ascii_escaped
|
||||||
from ..compat import final
|
|
||||||
from ..compat import NOTSET
|
from ..compat import NOTSET
|
||||||
from ..compat import NotSetType
|
from ..compat import NotSetType
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
|
@ -374,7 +374,9 @@ def get_unpacked_marks(
|
||||||
if not consider_mro:
|
if not consider_mro:
|
||||||
mark_lists = [obj.__dict__.get("pytestmark", [])]
|
mark_lists = [obj.__dict__.get("pytestmark", [])]
|
||||||
else:
|
else:
|
||||||
mark_lists = [x.__dict__.get("pytestmark", []) for x in obj.__mro__]
|
mark_lists = [
|
||||||
|
x.__dict__.get("pytestmark", []) for x in reversed(obj.__mro__)
|
||||||
|
]
|
||||||
mark_list = []
|
mark_list = []
|
||||||
for item in mark_lists:
|
for item in mark_lists:
|
||||||
if isinstance(item, list):
|
if isinstance(item, list):
|
||||||
|
|
|
@ -5,6 +5,7 @@ import sys
|
||||||
import warnings
|
import warnings
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
from typing import final
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Mapping
|
from typing import Mapping
|
||||||
|
@ -15,7 +16,6 @@ from typing import Tuple
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.fixtures import fixture
|
from _pytest.fixtures import fixture
|
||||||
from _pytest.warning_types import PytestWarning
|
from _pytest.warning_types import PytestWarning
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import warnings
|
import warnings
|
||||||
|
from functools import cached_property
|
||||||
from inspect import signature
|
from inspect import signature
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
@ -23,7 +24,6 @@ from _pytest._code import getfslineno
|
||||||
from _pytest._code.code import ExceptionInfo
|
from _pytest._code.code import ExceptionInfo
|
||||||
from _pytest._code.code import TerminalRepr
|
from _pytest._code.code import TerminalRepr
|
||||||
from _pytest._code.code import Traceback
|
from _pytest._code.code import Traceback
|
||||||
from _pytest.compat import cached_property
|
|
||||||
from _pytest.compat import LEGACY_PATH
|
from _pytest.compat import LEGACY_PATH
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config import ConftestImportFailure
|
from _pytest.config import ConftestImportFailure
|
||||||
|
@ -157,10 +157,11 @@ class NodeMeta(type):
|
||||||
|
|
||||||
|
|
||||||
class Node(metaclass=NodeMeta):
|
class Node(metaclass=NodeMeta):
|
||||||
"""Base class for Collector and Item, the components of the test
|
r"""Base class of :class:`Collector` and :class:`Item`, the components of
|
||||||
collection tree.
|
the test collection tree.
|
||||||
|
|
||||||
Collector subclasses have children; Items are leaf nodes.
|
``Collector``\'s are the internal nodes of the tree, and ``Item``\'s are the
|
||||||
|
leaf nodes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Implemented in the legacypath plugin.
|
# Implemented in the legacypath plugin.
|
||||||
|
@ -525,15 +526,17 @@ def get_fslocation_from_item(node: "Node") -> Tuple[Union[str, Path], Optional[i
|
||||||
|
|
||||||
|
|
||||||
class Collector(Node):
|
class Collector(Node):
|
||||||
"""Collector instances create children through collect() and thus
|
"""Base class of all collectors.
|
||||||
iteratively build a tree."""
|
|
||||||
|
Collector create children through `collect()` and thus iteratively build
|
||||||
|
the collection tree.
|
||||||
|
"""
|
||||||
|
|
||||||
class CollectError(Exception):
|
class CollectError(Exception):
|
||||||
"""An error during collection, contains a custom message."""
|
"""An error during collection, contains a custom message."""
|
||||||
|
|
||||||
def collect(self) -> Iterable[Union["Item", "Collector"]]:
|
def collect(self) -> Iterable[Union["Item", "Collector"]]:
|
||||||
"""Return a list of children (items and collectors) for this
|
"""Collect children (items and collectors) for this collector."""
|
||||||
collection node."""
|
|
||||||
raise NotImplementedError("abstract")
|
raise NotImplementedError("abstract")
|
||||||
|
|
||||||
# TODO: This omits the style= parameter which breaks Liskov Substitution.
|
# TODO: This omits the style= parameter which breaks Liskov Substitution.
|
||||||
|
@ -577,6 +580,8 @@ def _check_initialpaths_for_relpath(session: "Session", path: Path) -> Optional[
|
||||||
|
|
||||||
|
|
||||||
class FSCollector(Collector):
|
class FSCollector(Collector):
|
||||||
|
"""Base class for filesystem collectors."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
fspath: Optional[LEGACY_PATH] = None,
|
fspath: Optional[LEGACY_PATH] = None,
|
||||||
|
@ -660,7 +665,7 @@ class File(FSCollector):
|
||||||
|
|
||||||
|
|
||||||
class Item(Node):
|
class Item(Node):
|
||||||
"""A basic test invocation item.
|
"""Base class of all test invocation items.
|
||||||
|
|
||||||
Note that for a single function there might be multiple test invocation items.
|
Note that for a single function there might be multiple test invocation items.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -7,23 +7,12 @@ from typing import Callable
|
||||||
from typing import cast
|
from typing import cast
|
||||||
from typing import NoReturn
|
from typing import NoReturn
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from typing import Protocol
|
||||||
from typing import Type
|
from typing import Type
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
|
|
||||||
from _pytest.deprecated import KEYWORD_MSG_ARG
|
from _pytest.deprecated import KEYWORD_MSG_ARG
|
||||||
|
|
||||||
TYPE_CHECKING = False # Avoid circular import through compat.
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from typing_extensions import Protocol
|
|
||||||
else:
|
|
||||||
# typing.Protocol is only available starting from Python 3.8. It is also
|
|
||||||
# available from typing_extensions, but we don't want a runtime dependency
|
|
||||||
# on that. So use a dummy runtime implementation.
|
|
||||||
from typing import Generic
|
|
||||||
|
|
||||||
Protocol = Generic
|
|
||||||
|
|
||||||
|
|
||||||
class OutcomeException(BaseException):
|
class OutcomeException(BaseException):
|
||||||
"""OutcomeException and its subclass instances indicate and contain info
|
"""OutcomeException and its subclass instances indicate and contain info
|
||||||
|
|
|
@ -523,6 +523,8 @@ def import_path(
|
||||||
|
|
||||||
if mode is ImportMode.importlib:
|
if mode is ImportMode.importlib:
|
||||||
module_name = module_name_from_path(path, root)
|
module_name = module_name_from_path(path, root)
|
||||||
|
with contextlib.suppress(KeyError):
|
||||||
|
return sys.modules[module_name]
|
||||||
|
|
||||||
for meta_importer in sys.meta_path:
|
for meta_importer in sys.meta_path:
|
||||||
spec = meta_importer.find_spec(module_name, [str(path.parent)])
|
spec = meta_importer.find_spec(module_name, [str(path.parent)])
|
||||||
|
@ -633,6 +635,9 @@ def insert_missing_modules(modules: Dict[str, ModuleType], module_name: str) ->
|
||||||
otherwise "src.tests.test_foo" is not importable by ``__import__``.
|
otherwise "src.tests.test_foo" is not importable by ``__import__``.
|
||||||
"""
|
"""
|
||||||
module_parts = module_name.split(".")
|
module_parts = module_name.split(".")
|
||||||
|
child_module: Union[ModuleType, None] = None
|
||||||
|
module: Union[ModuleType, None] = None
|
||||||
|
child_name: str = ""
|
||||||
while module_name:
|
while module_name:
|
||||||
if module_name not in modules:
|
if module_name not in modules:
|
||||||
try:
|
try:
|
||||||
|
@ -642,13 +647,22 @@ def insert_missing_modules(modules: Dict[str, ModuleType], module_name: str) ->
|
||||||
# ourselves to fall back to creating a dummy module.
|
# ourselves to fall back to creating a dummy module.
|
||||||
if not sys.meta_path:
|
if not sys.meta_path:
|
||||||
raise ModuleNotFoundError
|
raise ModuleNotFoundError
|
||||||
importlib.import_module(module_name)
|
module = importlib.import_module(module_name)
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
module = ModuleType(
|
module = ModuleType(
|
||||||
module_name,
|
module_name,
|
||||||
doc="Empty module created by pytest's importmode=importlib.",
|
doc="Empty module created by pytest's importmode=importlib.",
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
module = modules[module_name]
|
||||||
|
if child_module:
|
||||||
|
# Add child attribute to the parent that can reference the child
|
||||||
|
# modules.
|
||||||
|
if not hasattr(module, child_name):
|
||||||
|
setattr(module, child_name, child_module)
|
||||||
modules[module_name] = module
|
modules[module_name] = module
|
||||||
|
# Keep track of the child module while moving up the tree.
|
||||||
|
child_module, child_name = module, module_name.rpartition(".")[-1]
|
||||||
module_parts.pop(-1)
|
module_parts.pop(-1)
|
||||||
module_name = ".".join(module_parts)
|
module_name = ".".join(module_parts)
|
||||||
|
|
||||||
|
@ -755,21 +769,3 @@ def bestrelpath(directory: Path, dest: Path) -> str:
|
||||||
# Forward from base to dest.
|
# Forward from base to dest.
|
||||||
*reldest.parts,
|
*reldest.parts,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Originates from py. path.local.copy(), with siginficant trims and adjustments.
|
|
||||||
# TODO(py38): Replace with shutil.copytree(..., symlinks=True, dirs_exist_ok=True)
|
|
||||||
def copytree(source: Path, target: Path) -> None:
|
|
||||||
"""Recursively copy a source directory to target."""
|
|
||||||
assert source.is_dir()
|
|
||||||
for entry in visit(source, recurse=lambda entry: not entry.is_symlink()):
|
|
||||||
x = Path(entry)
|
|
||||||
relpath = x.relative_to(source)
|
|
||||||
newx = target / relpath
|
|
||||||
newx.parent.mkdir(exist_ok=True)
|
|
||||||
if x.is_symlink():
|
|
||||||
newx.symlink_to(os.readlink(x))
|
|
||||||
elif x.is_file():
|
|
||||||
shutil.copyfile(x, newx)
|
|
||||||
elif x.is_dir():
|
|
||||||
newx.mkdir(exist_ok=True)
|
|
||||||
|
|
|
@ -20,10 +20,13 @@ from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import Final
|
||||||
|
from typing import final
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import IO
|
from typing import IO
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from typing import Literal
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import overload
|
from typing import overload
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
@ -40,7 +43,6 @@ from iniconfig import SectionWrapper
|
||||||
from _pytest import timing
|
from _pytest import timing
|
||||||
from _pytest._code import Source
|
from _pytest._code import Source
|
||||||
from _pytest.capture import _get_multicapture
|
from _pytest.capture import _get_multicapture
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.compat import NOTSET
|
from _pytest.compat import NOTSET
|
||||||
from _pytest.compat import NotSetType
|
from _pytest.compat import NotSetType
|
||||||
from _pytest.config import _PluggyPlugin
|
from _pytest.config import _PluggyPlugin
|
||||||
|
@ -61,18 +63,13 @@ from _pytest.outcomes import fail
|
||||||
from _pytest.outcomes import importorskip
|
from _pytest.outcomes import importorskip
|
||||||
from _pytest.outcomes import skip
|
from _pytest.outcomes import skip
|
||||||
from _pytest.pathlib import bestrelpath
|
from _pytest.pathlib import bestrelpath
|
||||||
from _pytest.pathlib import copytree
|
|
||||||
from _pytest.pathlib import make_numbered_dir
|
from _pytest.pathlib import make_numbered_dir
|
||||||
from _pytest.reports import CollectReport
|
from _pytest.reports import CollectReport
|
||||||
from _pytest.reports import TestReport
|
from _pytest.reports import TestReport
|
||||||
from _pytest.tmpdir import TempPathFactory
|
from _pytest.tmpdir import TempPathFactory
|
||||||
from _pytest.warning_types import PytestWarning
|
from _pytest.warning_types import PytestWarning
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing_extensions import Final
|
|
||||||
from typing_extensions import Literal
|
|
||||||
|
|
||||||
import pexpect
|
import pexpect
|
||||||
|
|
||||||
|
|
||||||
|
@ -163,29 +160,31 @@ class LsofFdLeakChecker:
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True, tryfirst=True)
|
@hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_runtest_protocol(self, item: Item) -> Generator[None, None, None]:
|
def pytest_runtest_protocol(self, item: Item) -> Generator[None, object, object]:
|
||||||
lines1 = self.get_open_files()
|
lines1 = self.get_open_files()
|
||||||
yield
|
try:
|
||||||
if hasattr(sys, "pypy_version_info"):
|
return (yield)
|
||||||
gc.collect()
|
finally:
|
||||||
lines2 = self.get_open_files()
|
if hasattr(sys, "pypy_version_info"):
|
||||||
|
gc.collect()
|
||||||
|
lines2 = self.get_open_files()
|
||||||
|
|
||||||
new_fds = {t[0] for t in lines2} - {t[0] for t in lines1}
|
new_fds = {t[0] for t in lines2} - {t[0] for t in lines1}
|
||||||
leaked_files = [t for t in lines2 if t[0] in new_fds]
|
leaked_files = [t for t in lines2 if t[0] in new_fds]
|
||||||
if leaked_files:
|
if leaked_files:
|
||||||
error = [
|
error = [
|
||||||
"***** %s FD leakage detected" % len(leaked_files),
|
"***** %s FD leakage detected" % len(leaked_files),
|
||||||
*(str(f) for f in leaked_files),
|
*(str(f) for f in leaked_files),
|
||||||
"*** Before:",
|
"*** Before:",
|
||||||
*(str(f) for f in lines1),
|
*(str(f) for f in lines1),
|
||||||
"*** After:",
|
"*** After:",
|
||||||
*(str(f) for f in lines2),
|
*(str(f) for f in lines2),
|
||||||
"***** %s FD leakage detected" % len(leaked_files),
|
"***** %s FD leakage detected" % len(leaked_files),
|
||||||
"*** function %s:%s: %s " % item.location,
|
"*** function %s:%s: %s " % item.location,
|
||||||
"See issue #2366",
|
"See issue #2366",
|
||||||
]
|
]
|
||||||
item.warn(PytestWarning("\n".join(error)))
|
item.warn(PytestWarning("\n".join(error)))
|
||||||
|
|
||||||
|
|
||||||
# used at least by pytest-xdist plugin
|
# used at least by pytest-xdist plugin
|
||||||
|
@ -973,7 +972,7 @@ class Pytester:
|
||||||
example_path = example_dir.joinpath(name)
|
example_path = example_dir.joinpath(name)
|
||||||
|
|
||||||
if example_path.is_dir() and not example_path.joinpath("__init__.py").is_file():
|
if example_path.is_dir() and not example_path.joinpath("__init__.py").is_file():
|
||||||
copytree(example_path, self.path)
|
shutil.copytree(example_path, self.path, symlinks=True, dirs_exist_ok=True)
|
||||||
return self.path
|
return self.path
|
||||||
elif example_path.is_file():
|
elif example_path.is_file():
|
||||||
result = self.path.joinpath(example_path.name)
|
result = self.path.joinpath(example_path.name)
|
||||||
|
|
|
@ -15,6 +15,7 @@ from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import final
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
|
@ -39,7 +40,7 @@ from _pytest._code.code import Traceback
|
||||||
from _pytest._io import TerminalWriter
|
from _pytest._io import TerminalWriter
|
||||||
from _pytest._io.saferepr import saferepr
|
from _pytest._io.saferepr import saferepr
|
||||||
from _pytest.compat import ascii_escaped
|
from _pytest.compat import ascii_escaped
|
||||||
from _pytest.compat import final
|
from _pytest.compat import assert_never
|
||||||
from _pytest.compat import get_default_arg_names
|
from _pytest.compat import get_default_arg_names
|
||||||
from _pytest.compat import get_real_func
|
from _pytest.compat import get_real_func
|
||||||
from _pytest.compat import getimfunc
|
from _pytest.compat import getimfunc
|
||||||
|
@ -550,7 +551,7 @@ class PyCollector(PyobjMixin, nodes.Collector):
|
||||||
|
|
||||||
|
|
||||||
class Module(nodes.File, PyCollector):
|
class Module(nodes.File, PyCollector):
|
||||||
"""Collector for test classes and functions."""
|
"""Collector for test classes and functions in a Python module."""
|
||||||
|
|
||||||
def _getobj(self):
|
def _getobj(self):
|
||||||
return self._importtestmodule()
|
return self._importtestmodule()
|
||||||
|
@ -687,6 +688,9 @@ class Module(nodes.File, PyCollector):
|
||||||
|
|
||||||
|
|
||||||
class Package(Module):
|
class Package(Module):
|
||||||
|
"""Collector for files and directories in a Python packages -- directories
|
||||||
|
with an `__init__.py` file."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
fspath: Optional[LEGACY_PATH],
|
fspath: Optional[LEGACY_PATH],
|
||||||
|
@ -818,7 +822,7 @@ def _get_first_non_fixture_func(obj: object, names: Iterable[str]) -> Optional[o
|
||||||
|
|
||||||
|
|
||||||
class Class(PyCollector):
|
class Class(PyCollector):
|
||||||
"""Collector for test methods."""
|
"""Collector for test methods (and nested classes) in a Python class."""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_parent(cls, parent, *, name, obj=None, **kw):
|
def from_parent(cls, parent, *, name, obj=None, **kw):
|
||||||
|
@ -1743,7 +1747,7 @@ def write_docstring(tw: TerminalWriter, doc: str, indent: str = " ") -> None:
|
||||||
|
|
||||||
|
|
||||||
class Function(PyobjMixin, nodes.Item):
|
class Function(PyobjMixin, nodes.Item):
|
||||||
"""An Item responsible for setting up and executing a Python test function.
|
"""Item responsible for setting up and executing a Python test function.
|
||||||
|
|
||||||
:param name:
|
:param name:
|
||||||
The full function name, including any decorations like those
|
The full function name, including any decorations like those
|
||||||
|
@ -1900,10 +1904,8 @@ class Function(PyobjMixin, nodes.Item):
|
||||||
|
|
||||||
|
|
||||||
class FunctionDefinition(Function):
|
class FunctionDefinition(Function):
|
||||||
"""
|
"""This class is a stop gap solution until we evolve to have actual function
|
||||||
This class is a step gap solution until we evolve to have actual function definition nodes
|
definition nodes and manage to get rid of ``metafunc``."""
|
||||||
and manage to get rid of ``metafunc``.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def runtest(self) -> None:
|
def runtest(self) -> None:
|
||||||
raise RuntimeError("function definitions are not supposed to be run as tests")
|
raise RuntimeError("function definitions are not supposed to be run as tests")
|
||||||
|
|
|
@ -9,9 +9,11 @@ from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import cast
|
from typing import cast
|
||||||
from typing import ContextManager
|
from typing import ContextManager
|
||||||
|
from typing import final
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Mapping
|
from typing import Mapping
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from typing import overload
|
||||||
from typing import Pattern
|
from typing import Pattern
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
@ -20,17 +22,14 @@ from typing import TYPE_CHECKING
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
import _pytest._code
|
||||||
|
from _pytest.compat import STRING_TYPES
|
||||||
|
from _pytest.outcomes import fail
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from numpy import ndarray
|
from numpy import ndarray
|
||||||
|
|
||||||
|
|
||||||
import _pytest._code
|
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.compat import STRING_TYPES
|
|
||||||
from _pytest.compat import overload
|
|
||||||
from _pytest.outcomes import fail
|
|
||||||
|
|
||||||
|
|
||||||
def _non_numeric_type_error(value, at: Optional[str]) -> TypeError:
|
def _non_numeric_type_error(value, at: Optional[str]) -> TypeError:
|
||||||
at_str = f" at {at}" if at else ""
|
at_str = f" at {at}" if at else ""
|
||||||
return TypeError(
|
return TypeError(
|
||||||
|
@ -266,19 +265,20 @@ class ApproxMapping(ApproxBase):
|
||||||
approx_side_as_map.items(), other_side.values()
|
approx_side_as_map.items(), other_side.values()
|
||||||
):
|
):
|
||||||
if approx_value != other_value:
|
if approx_value != other_value:
|
||||||
max_abs_diff = max(
|
if approx_value.expected is not None and other_value is not None:
|
||||||
max_abs_diff, abs(approx_value.expected - other_value)
|
max_abs_diff = max(
|
||||||
)
|
max_abs_diff, abs(approx_value.expected - other_value)
|
||||||
if approx_value.expected == 0.0:
|
|
||||||
max_rel_diff = math.inf
|
|
||||||
else:
|
|
||||||
max_rel_diff = max(
|
|
||||||
max_rel_diff,
|
|
||||||
abs(
|
|
||||||
(approx_value.expected - other_value)
|
|
||||||
/ approx_value.expected
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
if approx_value.expected == 0.0:
|
||||||
|
max_rel_diff = math.inf
|
||||||
|
else:
|
||||||
|
max_rel_diff = max(
|
||||||
|
max_rel_diff,
|
||||||
|
abs(
|
||||||
|
(approx_value.expected - other_value)
|
||||||
|
/ approx_value.expected
|
||||||
|
),
|
||||||
|
)
|
||||||
different_ids.append(approx_key)
|
different_ids.append(approx_key)
|
||||||
|
|
||||||
message_data = [
|
message_data = [
|
||||||
|
|
|
@ -5,18 +5,18 @@ from pprint import pformat
|
||||||
from types import TracebackType
|
from types import TracebackType
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
from typing import final
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from typing import overload
|
||||||
from typing import Pattern
|
from typing import Pattern
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
from typing import Type
|
from typing import Type
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.compat import overload
|
|
||||||
from _pytest.deprecated import check_ispytest
|
from _pytest.deprecated import check_ispytest
|
||||||
from _pytest.deprecated import WARNS_NONE_ARG
|
from _pytest.deprecated import WARNS_NONE_ARG
|
||||||
from _pytest.fixtures import fixture
|
from _pytest.fixtures import fixture
|
||||||
|
@ -117,10 +117,10 @@ def warns( # noqa: F811
|
||||||
warning of that class or classes.
|
warning of that class or classes.
|
||||||
|
|
||||||
This helper produces a list of :class:`warnings.WarningMessage` objects, one for
|
This helper produces a list of :class:`warnings.WarningMessage` objects, one for
|
||||||
each warning raised (regardless of whether it is an ``expected_warning`` or not).
|
each warning emitted (regardless of whether it is an ``expected_warning`` or not).
|
||||||
|
Since pytest 8.0, unmatched warnings are also re-emitted when the context closes.
|
||||||
|
|
||||||
This function can be used as a context manager, which will capture all the raised
|
This function can be used as a context manager::
|
||||||
warnings inside it::
|
|
||||||
|
|
||||||
>>> import pytest
|
>>> import pytest
|
||||||
>>> with pytest.warns(RuntimeWarning):
|
>>> with pytest.warns(RuntimeWarning):
|
||||||
|
@ -135,8 +135,9 @@ def warns( # noqa: F811
|
||||||
>>> with pytest.warns(UserWarning, match=r'must be \d+$'):
|
>>> with pytest.warns(UserWarning, match=r'must be \d+$'):
|
||||||
... warnings.warn("value must be 42", UserWarning)
|
... warnings.warn("value must be 42", UserWarning)
|
||||||
|
|
||||||
>>> with pytest.warns(UserWarning, match=r'must be \d+$'):
|
>>> with pytest.warns(UserWarning): # catch re-emitted warning
|
||||||
... warnings.warn("this is not here", UserWarning)
|
... with pytest.warns(UserWarning, match=r'must be \d+$'):
|
||||||
|
... warnings.warn("this is not here", UserWarning)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
Failed: DID NOT WARN. No warnings of type ...UserWarning... were emitted...
|
Failed: DID NOT WARN. No warnings of type ...UserWarning... were emitted...
|
||||||
|
@ -205,10 +206,21 @@ class WarningsRecorder(warnings.catch_warnings): # type:ignore[type-arg]
|
||||||
return len(self._list)
|
return len(self._list)
|
||||||
|
|
||||||
def pop(self, cls: Type[Warning] = Warning) -> "warnings.WarningMessage":
|
def pop(self, cls: Type[Warning] = Warning) -> "warnings.WarningMessage":
|
||||||
"""Pop the first recorded warning, raise exception if not exists."""
|
"""Pop the first recorded warning which is an instance of ``cls``,
|
||||||
|
but not an instance of a child class of any other match.
|
||||||
|
Raises ``AssertionError`` if there is no match.
|
||||||
|
"""
|
||||||
|
best_idx: Optional[int] = None
|
||||||
for i, w in enumerate(self._list):
|
for i, w in enumerate(self._list):
|
||||||
if issubclass(w.category, cls):
|
if w.category == cls:
|
||||||
return self._list.pop(i)
|
return self._list.pop(i) # exact match, stop looking
|
||||||
|
if issubclass(w.category, cls) and (
|
||||||
|
best_idx is None
|
||||||
|
or not issubclass(w.category, self._list[best_idx].category)
|
||||||
|
):
|
||||||
|
best_idx = i
|
||||||
|
if best_idx is not None:
|
||||||
|
return self._list.pop(best_idx)
|
||||||
__tracebackhide__ = True
|
__tracebackhide__ = True
|
||||||
raise AssertionError(f"{cls!r} not found in warning list")
|
raise AssertionError(f"{cls!r} not found in warning list")
|
||||||
|
|
||||||
|
@ -277,6 +289,12 @@ class WarningsChecker(WarningsRecorder):
|
||||||
self.expected_warning = expected_warning_tup
|
self.expected_warning = expected_warning_tup
|
||||||
self.match_expr = match_expr
|
self.match_expr = match_expr
|
||||||
|
|
||||||
|
def matches(self, warning: warnings.WarningMessage) -> bool:
|
||||||
|
assert self.expected_warning is not None
|
||||||
|
return issubclass(warning.category, self.expected_warning) and bool(
|
||||||
|
self.match_expr is None or re.search(self.match_expr, str(warning.message))
|
||||||
|
)
|
||||||
|
|
||||||
def __exit__(
|
def __exit__(
|
||||||
self,
|
self,
|
||||||
exc_type: Optional[Type[BaseException]],
|
exc_type: Optional[Type[BaseException]],
|
||||||
|
@ -287,27 +305,34 @@ class WarningsChecker(WarningsRecorder):
|
||||||
|
|
||||||
__tracebackhide__ = True
|
__tracebackhide__ = True
|
||||||
|
|
||||||
|
if self.expected_warning is None:
|
||||||
|
# nothing to do in this deprecated case, see WARNS_NONE_ARG above
|
||||||
|
return
|
||||||
|
|
||||||
def found_str():
|
def found_str():
|
||||||
return pformat([record.message for record in self], indent=2)
|
return pformat([record.message for record in self], indent=2)
|
||||||
|
|
||||||
# only check if we're not currently handling an exception
|
try:
|
||||||
if exc_type is None and exc_val is None and exc_tb is None:
|
if not any(issubclass(w.category, self.expected_warning) for w in self):
|
||||||
if self.expected_warning is not None:
|
fail(
|
||||||
if not any(issubclass(r.category, self.expected_warning) for r in self):
|
f"DID NOT WARN. No warnings of type {self.expected_warning} were emitted.\n"
|
||||||
__tracebackhide__ = True
|
f" Emitted warnings: {found_str()}."
|
||||||
fail(
|
)
|
||||||
f"DID NOT WARN. No warnings of type {self.expected_warning} were emitted.\n"
|
elif not any(self.matches(w) for w in self):
|
||||||
f"The list of emitted warnings is: {found_str()}."
|
fail(
|
||||||
|
f"DID NOT WARN. No warnings of type {self.expected_warning} matching the regex were emitted.\n"
|
||||||
|
f" Regex: {self.match_expr}\n"
|
||||||
|
f" Emitted warnings: {found_str()}."
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
# Whether or not any warnings matched, we want to re-emit all unmatched warnings.
|
||||||
|
for w in self:
|
||||||
|
if not self.matches(w):
|
||||||
|
warnings.warn_explicit(
|
||||||
|
str(w.message),
|
||||||
|
w.message.__class__, # type: ignore[arg-type]
|
||||||
|
w.filename,
|
||||||
|
w.lineno,
|
||||||
|
module=w.__module__,
|
||||||
|
source=w.source,
|
||||||
)
|
)
|
||||||
elif self.match_expr is not None:
|
|
||||||
for r in self:
|
|
||||||
if issubclass(r.category, self.expected_warning):
|
|
||||||
if re.compile(self.match_expr).search(str(r.message)):
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
fail(
|
|
||||||
f"""\
|
|
||||||
DID NOT WARN. No warnings of type {self.expected_warning} matching the regex were emitted.
|
|
||||||
Regex: {self.match_expr}
|
|
||||||
Emitted warnings: {found_str()}"""
|
|
||||||
)
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ from pprint import pprint
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import cast
|
from typing import cast
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import final
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
from typing import List
|
from typing import List
|
||||||
|
@ -29,7 +30,6 @@ from _pytest._code.code import ReprLocals
|
||||||
from _pytest._code.code import ReprTraceback
|
from _pytest._code.code import ReprTraceback
|
||||||
from _pytest._code.code import TerminalRepr
|
from _pytest._code.code import TerminalRepr
|
||||||
from _pytest._io import TerminalWriter
|
from _pytest._io import TerminalWriter
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.nodes import Collector
|
from _pytest.nodes import Collector
|
||||||
from _pytest.nodes import Item
|
from _pytest.nodes import Item
|
||||||
|
@ -249,6 +249,9 @@ class TestReport(BaseReport):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__test__ = False
|
__test__ = False
|
||||||
|
# Defined by skipping plugin.
|
||||||
|
# xfail reason if xfailed, otherwise not defined. Use hasattr to distinguish.
|
||||||
|
wasxfail: str
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -6,6 +6,7 @@ import sys
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import cast
|
from typing import cast
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import final
|
||||||
from typing import Generic
|
from typing import Generic
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
@ -23,7 +24,6 @@ from _pytest import timing
|
||||||
from _pytest._code.code import ExceptionChainRepr
|
from _pytest._code.code import ExceptionChainRepr
|
||||||
from _pytest._code.code import ExceptionInfo
|
from _pytest._code.code import ExceptionInfo
|
||||||
from _pytest._code.code import TerminalRepr
|
from _pytest._code.code import TerminalRepr
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.config.argparsing import Parser
|
from _pytest.config.argparsing import Parser
|
||||||
from _pytest.deprecated import check_ispytest
|
from _pytest.deprecated import check_ispytest
|
||||||
from _pytest.nodes import Collector
|
from _pytest.nodes import Collector
|
||||||
|
|
|
@ -28,24 +28,26 @@ def pytest_addoption(parser: Parser) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_fixture_setup(
|
def pytest_fixture_setup(
|
||||||
fixturedef: FixtureDef[object], request: SubRequest
|
fixturedef: FixtureDef[object], request: SubRequest
|
||||||
) -> Generator[None, None, None]:
|
) -> Generator[None, object, object]:
|
||||||
yield
|
try:
|
||||||
if request.config.option.setupshow:
|
return (yield)
|
||||||
if hasattr(request, "param"):
|
finally:
|
||||||
# Save the fixture parameter so ._show_fixture_action() can
|
if request.config.option.setupshow:
|
||||||
# display it now and during the teardown (in .finish()).
|
if hasattr(request, "param"):
|
||||||
if fixturedef.ids:
|
# Save the fixture parameter so ._show_fixture_action() can
|
||||||
if callable(fixturedef.ids):
|
# display it now and during the teardown (in .finish()).
|
||||||
param = fixturedef.ids(request.param)
|
if fixturedef.ids:
|
||||||
|
if callable(fixturedef.ids):
|
||||||
|
param = fixturedef.ids(request.param)
|
||||||
|
else:
|
||||||
|
param = fixturedef.ids[request.param_index]
|
||||||
else:
|
else:
|
||||||
param = fixturedef.ids[request.param_index]
|
param = request.param
|
||||||
else:
|
fixturedef.cached_param = param # type: ignore[attr-defined]
|
||||||
param = request.param
|
_show_fixture_action(fixturedef, "SETUP")
|
||||||
fixturedef.cached_param = param # type: ignore[attr-defined]
|
|
||||||
_show_fixture_action(fixturedef, "SETUP")
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_fixture_post_finalizer(fixturedef: FixtureDef[object]) -> None:
|
def pytest_fixture_post_finalizer(fixturedef: FixtureDef[object]) -> None:
|
||||||
|
|
|
@ -19,6 +19,7 @@ from _pytest.outcomes import fail
|
||||||
from _pytest.outcomes import skip
|
from _pytest.outcomes import skip
|
||||||
from _pytest.outcomes import xfail
|
from _pytest.outcomes import xfail
|
||||||
from _pytest.reports import BaseReport
|
from _pytest.reports import BaseReport
|
||||||
|
from _pytest.reports import TestReport
|
||||||
from _pytest.runner import CallInfo
|
from _pytest.runner import CallInfo
|
||||||
from _pytest.stash import StashKey
|
from _pytest.stash import StashKey
|
||||||
|
|
||||||
|
@ -243,7 +244,7 @@ def pytest_runtest_setup(item: Item) -> None:
|
||||||
xfail("[NOTRUN] " + xfailed.reason)
|
xfail("[NOTRUN] " + xfailed.reason)
|
||||||
|
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_runtest_call(item: Item) -> Generator[None, None, None]:
|
def pytest_runtest_call(item: Item) -> Generator[None, None, None]:
|
||||||
xfailed = item.stash.get(xfailed_key, None)
|
xfailed = item.stash.get(xfailed_key, None)
|
||||||
if xfailed is None:
|
if xfailed is None:
|
||||||
|
@ -252,18 +253,20 @@ def pytest_runtest_call(item: Item) -> Generator[None, None, None]:
|
||||||
if xfailed and not item.config.option.runxfail and not xfailed.run:
|
if xfailed and not item.config.option.runxfail and not xfailed.run:
|
||||||
xfail("[NOTRUN] " + xfailed.reason)
|
xfail("[NOTRUN] " + xfailed.reason)
|
||||||
|
|
||||||
yield
|
try:
|
||||||
|
return (yield)
|
||||||
# The test run may have added an xfail mark dynamically.
|
finally:
|
||||||
xfailed = item.stash.get(xfailed_key, None)
|
# The test run may have added an xfail mark dynamically.
|
||||||
if xfailed is None:
|
xfailed = item.stash.get(xfailed_key, None)
|
||||||
item.stash[xfailed_key] = xfailed = evaluate_xfail_marks(item)
|
if xfailed is None:
|
||||||
|
item.stash[xfailed_key] = xfailed = evaluate_xfail_marks(item)
|
||||||
|
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_runtest_makereport(item: Item, call: CallInfo[None]):
|
def pytest_runtest_makereport(
|
||||||
outcome = yield
|
item: Item, call: CallInfo[None]
|
||||||
rep = outcome.get_result()
|
) -> Generator[None, TestReport, TestReport]:
|
||||||
|
rep = yield
|
||||||
xfailed = item.stash.get(xfailed_key, None)
|
xfailed = item.stash.get(xfailed_key, None)
|
||||||
if item.config.option.runxfail:
|
if item.config.option.runxfail:
|
||||||
pass # don't interfere
|
pass # don't interfere
|
||||||
|
@ -286,6 +289,7 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]):
|
||||||
else:
|
else:
|
||||||
rep.outcome = "passed"
|
rep.outcome = "passed"
|
||||||
rep.wasxfail = xfailed.reason
|
rep.wasxfail = xfailed.reason
|
||||||
|
return rep
|
||||||
|
|
||||||
|
|
||||||
def pytest_report_teststatus(report: BaseReport) -> Optional[Tuple[str, str, str]]:
|
def pytest_report_teststatus(report: BaseReport) -> Optional[Tuple[str, str, str]]:
|
||||||
|
|
|
@ -15,9 +15,9 @@ from functools import partial
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import cast
|
|
||||||
from typing import ClassVar
|
from typing import ClassVar
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import final
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Mapping
|
from typing import Mapping
|
||||||
|
@ -40,7 +40,6 @@ from _pytest._code.code import ExceptionRepr
|
||||||
from _pytest._io import TerminalWriter
|
from _pytest._io import TerminalWriter
|
||||||
from _pytest._io.wcwidth import wcswidth
|
from _pytest._io.wcwidth import wcswidth
|
||||||
from _pytest.assertion.util import running_on_ci
|
from _pytest.assertion.util import running_on_ci
|
||||||
from _pytest.compat import final
|
|
||||||
from _pytest.config import _PluggyPlugin
|
from _pytest.config import _PluggyPlugin
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
|
@ -849,12 +848,11 @@ class TerminalReporter:
|
||||||
for line in doc.splitlines():
|
for line in doc.splitlines():
|
||||||
self._tw.line("{}{}".format(indent + " ", line))
|
self._tw.line("{}{}".format(indent + " ", line))
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_sessionfinish(
|
def pytest_sessionfinish(
|
||||||
self, session: "Session", exitstatus: Union[int, ExitCode]
|
self, session: "Session", exitstatus: Union[int, ExitCode]
|
||||||
):
|
) -> Generator[None, None, None]:
|
||||||
outcome = yield
|
result = yield
|
||||||
outcome.get_result()
|
|
||||||
self._tw.line("")
|
self._tw.line("")
|
||||||
summary_exit_codes = (
|
summary_exit_codes = (
|
||||||
ExitCode.OK,
|
ExitCode.OK,
|
||||||
|
@ -875,17 +873,20 @@ class TerminalReporter:
|
||||||
elif session.shouldstop:
|
elif session.shouldstop:
|
||||||
self.write_sep("!", str(session.shouldstop), red=True)
|
self.write_sep("!", str(session.shouldstop), red=True)
|
||||||
self.summary_stats()
|
self.summary_stats()
|
||||||
|
return result
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_terminal_summary(self) -> Generator[None, None, None]:
|
def pytest_terminal_summary(self) -> Generator[None, None, None]:
|
||||||
self.summary_errors()
|
self.summary_errors()
|
||||||
self.summary_failures()
|
self.summary_failures()
|
||||||
self.summary_warnings()
|
self.summary_warnings()
|
||||||
self.summary_passes()
|
self.summary_passes()
|
||||||
yield
|
try:
|
||||||
self.short_test_summary()
|
return (yield)
|
||||||
# Display any extra warnings from teardown here (if any).
|
finally:
|
||||||
self.summary_warnings()
|
self.short_test_summary()
|
||||||
|
# Display any extra warnings from teardown here (if any).
|
||||||
|
self.summary_warnings()
|
||||||
|
|
||||||
def pytest_keyboard_interrupt(self, excinfo: ExceptionInfo[BaseException]) -> None:
|
def pytest_keyboard_interrupt(self, excinfo: ExceptionInfo[BaseException]) -> None:
|
||||||
self._keyboardinterrupt_memo = excinfo.getrepr(funcargs=True)
|
self._keyboardinterrupt_memo = excinfo.getrepr(funcargs=True)
|
||||||
|
@ -1466,7 +1467,7 @@ def _get_raw_skip_reason(report: TestReport) -> str:
|
||||||
The string is just the part given by the user.
|
The string is just the part given by the user.
|
||||||
"""
|
"""
|
||||||
if hasattr(report, "wasxfail"):
|
if hasattr(report, "wasxfail"):
|
||||||
reason = cast(str, report.wasxfail)
|
reason = report.wasxfail
|
||||||
if reason.startswith("reason: "):
|
if reason.startswith("reason: "):
|
||||||
reason = reason[len("reason: ") :]
|
reason = reason[len("reason: ") :]
|
||||||
return reason
|
return reason
|
||||||
|
|
|
@ -59,30 +59,34 @@ class catch_threading_exception:
|
||||||
|
|
||||||
def thread_exception_runtest_hook() -> Generator[None, None, None]:
|
def thread_exception_runtest_hook() -> Generator[None, None, None]:
|
||||||
with catch_threading_exception() as cm:
|
with catch_threading_exception() as cm:
|
||||||
yield
|
try:
|
||||||
if cm.args:
|
yield
|
||||||
thread_name = "<unknown>" if cm.args.thread is None else cm.args.thread.name
|
finally:
|
||||||
msg = f"Exception in thread {thread_name}\n\n"
|
if cm.args:
|
||||||
msg += "".join(
|
thread_name = (
|
||||||
traceback.format_exception(
|
"<unknown>" if cm.args.thread is None else cm.args.thread.name
|
||||||
cm.args.exc_type,
|
|
||||||
cm.args.exc_value,
|
|
||||||
cm.args.exc_traceback,
|
|
||||||
)
|
)
|
||||||
)
|
msg = f"Exception in thread {thread_name}\n\n"
|
||||||
warnings.warn(pytest.PytestUnhandledThreadExceptionWarning(msg))
|
msg += "".join(
|
||||||
|
traceback.format_exception(
|
||||||
|
cm.args.exc_type,
|
||||||
|
cm.args.exc_value,
|
||||||
|
cm.args.exc_traceback,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
warnings.warn(pytest.PytestUnhandledThreadExceptionWarning(msg))
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True, trylast=True)
|
@pytest.hookimpl(wrapper=True, trylast=True)
|
||||||
def pytest_runtest_setup() -> Generator[None, None, None]:
|
def pytest_runtest_setup() -> Generator[None, None, None]:
|
||||||
yield from thread_exception_runtest_hook()
|
yield from thread_exception_runtest_hook()
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_runtest_call() -> Generator[None, None, None]:
|
def pytest_runtest_call() -> Generator[None, None, None]:
|
||||||
yield from thread_exception_runtest_hook()
|
yield from thread_exception_runtest_hook()
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_runtest_teardown() -> Generator[None, None, None]:
|
def pytest_runtest_teardown() -> Generator[None, None, None]:
|
||||||
yield from thread_exception_runtest_hook()
|
yield from thread_exception_runtest_hook()
|
||||||
|
|
|
@ -7,38 +7,32 @@ from pathlib import Path
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import final
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
|
from typing import Literal
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from _pytest.nodes import Item
|
from .pathlib import cleanup_dead_symlinks
|
||||||
from _pytest.reports import CollectReport
|
|
||||||
from _pytest.stash import StashKey
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from typing_extensions import Literal
|
|
||||||
|
|
||||||
RetentionType = Literal["all", "failed", "none"]
|
|
||||||
|
|
||||||
|
|
||||||
from _pytest.config.argparsing import Parser
|
|
||||||
|
|
||||||
from .pathlib import LOCK_TIMEOUT
|
from .pathlib import LOCK_TIMEOUT
|
||||||
from .pathlib import make_numbered_dir
|
from .pathlib import make_numbered_dir
|
||||||
from .pathlib import make_numbered_dir_with_cleanup
|
from .pathlib import make_numbered_dir_with_cleanup
|
||||||
from .pathlib import rm_rf
|
from .pathlib import rm_rf
|
||||||
from .pathlib import cleanup_dead_symlinks
|
from _pytest.compat import get_user_id
|
||||||
from _pytest.compat import final, get_user_id
|
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
from _pytest.config import hookimpl
|
from _pytest.config import hookimpl
|
||||||
|
from _pytest.config.argparsing import Parser
|
||||||
from _pytest.deprecated import check_ispytest
|
from _pytest.deprecated import check_ispytest
|
||||||
from _pytest.fixtures import fixture
|
from _pytest.fixtures import fixture
|
||||||
from _pytest.fixtures import FixtureRequest
|
from _pytest.fixtures import FixtureRequest
|
||||||
from _pytest.monkeypatch import MonkeyPatch
|
from _pytest.monkeypatch import MonkeyPatch
|
||||||
|
from _pytest.nodes import Item
|
||||||
|
from _pytest.reports import TestReport
|
||||||
|
from _pytest.stash import StashKey
|
||||||
|
|
||||||
tmppath_result_key = StashKey[Dict[str, bool]]()
|
tmppath_result_key = StashKey[Dict[str, bool]]()
|
||||||
|
RetentionType = Literal["all", "failed", "none"]
|
||||||
|
|
||||||
|
|
||||||
@final
|
@final
|
||||||
|
@ -315,10 +309,12 @@ def pytest_sessionfinish(session, exitstatus: Union[int, ExitCode]):
|
||||||
cleanup_dead_symlinks(basetemp)
|
cleanup_dead_symlinks(basetemp)
|
||||||
|
|
||||||
|
|
||||||
@hookimpl(tryfirst=True, hookwrapper=True)
|
@hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_runtest_makereport(item: Item, call):
|
def pytest_runtest_makereport(
|
||||||
outcome = yield
|
item: Item, call
|
||||||
result: CollectReport = outcome.get_result()
|
) -> Generator[None, TestReport, TestReport]:
|
||||||
|
rep = yield
|
||||||
|
assert rep.when is not None
|
||||||
empty: Dict[str, bool] = {}
|
empty: Dict[str, bool] = {}
|
||||||
item.stash.setdefault(tmppath_result_key, empty)[result.when] = result.passed
|
item.stash.setdefault(tmppath_result_key, empty)[rep.when] = rep.passed
|
||||||
|
return rep
|
||||||
|
|
|
@ -376,8 +376,8 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> None:
|
||||||
# Twisted trial support.
|
# Twisted trial support.
|
||||||
|
|
||||||
|
|
||||||
@hookimpl(hookwrapper=True)
|
@hookimpl(wrapper=True)
|
||||||
def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]:
|
||||||
if isinstance(item, TestCaseFunction) and "twisted.trial.unittest" in sys.modules:
|
if isinstance(item, TestCaseFunction) and "twisted.trial.unittest" in sys.modules:
|
||||||
ut: Any = sys.modules["twisted.python.failure"]
|
ut: Any = sys.modules["twisted.python.failure"]
|
||||||
Failure__init__ = ut.Failure.__init__
|
Failure__init__ = ut.Failure.__init__
|
||||||
|
@ -400,10 +400,13 @@ def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
||||||
Failure__init__(self, exc_value, exc_type, exc_tb)
|
Failure__init__(self, exc_value, exc_type, exc_tb)
|
||||||
|
|
||||||
ut.Failure.__init__ = excstore
|
ut.Failure.__init__ = excstore
|
||||||
yield
|
try:
|
||||||
ut.Failure.__init__ = Failure__init__
|
res = yield
|
||||||
|
finally:
|
||||||
|
ut.Failure.__init__ = Failure__init__
|
||||||
else:
|
else:
|
||||||
yield
|
res = yield
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
def check_testcase_implements_trial_reporter(done: List[int] = []) -> None:
|
def check_testcase_implements_trial_reporter(done: List[int] = []) -> None:
|
||||||
|
|
|
@ -61,33 +61,35 @@ class catch_unraisable_exception:
|
||||||
|
|
||||||
def unraisable_exception_runtest_hook() -> Generator[None, None, None]:
|
def unraisable_exception_runtest_hook() -> Generator[None, None, None]:
|
||||||
with catch_unraisable_exception() as cm:
|
with catch_unraisable_exception() as cm:
|
||||||
yield
|
try:
|
||||||
if cm.unraisable:
|
yield
|
||||||
if cm.unraisable.err_msg is not None:
|
finally:
|
||||||
err_msg = cm.unraisable.err_msg
|
if cm.unraisable:
|
||||||
else:
|
if cm.unraisable.err_msg is not None:
|
||||||
err_msg = "Exception ignored in"
|
err_msg = cm.unraisable.err_msg
|
||||||
msg = f"{err_msg}: {cm.unraisable.object!r}\n\n"
|
else:
|
||||||
msg += "".join(
|
err_msg = "Exception ignored in"
|
||||||
traceback.format_exception(
|
msg = f"{err_msg}: {cm.unraisable.object!r}\n\n"
|
||||||
cm.unraisable.exc_type,
|
msg += "".join(
|
||||||
cm.unraisable.exc_value,
|
traceback.format_exception(
|
||||||
cm.unraisable.exc_traceback,
|
cm.unraisable.exc_type,
|
||||||
|
cm.unraisable.exc_value,
|
||||||
|
cm.unraisable.exc_traceback,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
|
||||||
warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_runtest_setup() -> Generator[None, None, None]:
|
def pytest_runtest_setup() -> Generator[None, None, None]:
|
||||||
yield from unraisable_exception_runtest_hook()
|
yield from unraisable_exception_runtest_hook()
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_runtest_call() -> Generator[None, None, None]:
|
def pytest_runtest_call() -> Generator[None, None, None]:
|
||||||
yield from unraisable_exception_runtest_hook()
|
yield from unraisable_exception_runtest_hook()
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_runtest_teardown() -> Generator[None, None, None]:
|
def pytest_runtest_teardown() -> Generator[None, None, None]:
|
||||||
yield from unraisable_exception_runtest_hook()
|
yield from unraisable_exception_runtest_hook()
|
||||||
|
|
|
@ -3,12 +3,11 @@ import inspect
|
||||||
import warnings
|
import warnings
|
||||||
from types import FunctionType
|
from types import FunctionType
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
from typing import final
|
||||||
from typing import Generic
|
from typing import Generic
|
||||||
from typing import Type
|
from typing import Type
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
|
|
||||||
from _pytest.compat import final
|
|
||||||
|
|
||||||
|
|
||||||
class PytestWarning(UserWarning):
|
class PytestWarning(UserWarning):
|
||||||
"""Base class for all warnings emitted by pytest."""
|
"""Base class for all warnings emitted by pytest."""
|
||||||
|
|
|
@ -60,17 +60,18 @@ def catch_warnings_for_item(
|
||||||
for arg in mark.args:
|
for arg in mark.args:
|
||||||
warnings.filterwarnings(*parse_warning_filter(arg, escape=False))
|
warnings.filterwarnings(*parse_warning_filter(arg, escape=False))
|
||||||
|
|
||||||
yield
|
try:
|
||||||
|
yield
|
||||||
for warning_message in log:
|
finally:
|
||||||
ihook.pytest_warning_recorded.call_historic(
|
for warning_message in log:
|
||||||
kwargs=dict(
|
ihook.pytest_warning_recorded.call_historic(
|
||||||
warning_message=warning_message,
|
kwargs=dict(
|
||||||
nodeid=nodeid,
|
warning_message=warning_message,
|
||||||
when=when,
|
nodeid=nodeid,
|
||||||
location=None,
|
when=when,
|
||||||
|
location=None,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def warning_record_to_str(warning_message: warnings.WarningMessage) -> str:
|
def warning_record_to_str(warning_message: warnings.WarningMessage) -> str:
|
||||||
|
@ -103,24 +104,24 @@ def warning_record_to_str(warning_message: warnings.WarningMessage) -> str:
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
|
def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]:
|
||||||
with catch_warnings_for_item(
|
with catch_warnings_for_item(
|
||||||
config=item.config, ihook=item.ihook, when="runtest", item=item
|
config=item.config, ihook=item.ihook, when="runtest", item=item
|
||||||
):
|
):
|
||||||
yield
|
return (yield)
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_collection(session: Session) -> Generator[None, None, None]:
|
def pytest_collection(session: Session) -> Generator[None, object, object]:
|
||||||
config = session.config
|
config = session.config
|
||||||
with catch_warnings_for_item(
|
with catch_warnings_for_item(
|
||||||
config=config, ihook=config.hook, when="collect", item=None
|
config=config, ihook=config.hook, when="collect", item=None
|
||||||
):
|
):
|
||||||
yield
|
return (yield)
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_terminal_summary(
|
def pytest_terminal_summary(
|
||||||
terminalreporter: TerminalReporter,
|
terminalreporter: TerminalReporter,
|
||||||
) -> Generator[None, None, None]:
|
) -> Generator[None, None, None]:
|
||||||
|
@ -128,23 +129,23 @@ def pytest_terminal_summary(
|
||||||
with catch_warnings_for_item(
|
with catch_warnings_for_item(
|
||||||
config=config, ihook=config.hook, when="config", item=None
|
config=config, ihook=config.hook, when="config", item=None
|
||||||
):
|
):
|
||||||
yield
|
return (yield)
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_sessionfinish(session: Session) -> Generator[None, None, None]:
|
def pytest_sessionfinish(session: Session) -> Generator[None, None, None]:
|
||||||
config = session.config
|
config = session.config
|
||||||
with catch_warnings_for_item(
|
with catch_warnings_for_item(
|
||||||
config=config, ihook=config.hook, when="config", item=None
|
config=config, ihook=config.hook, when="config", item=None
|
||||||
):
|
):
|
||||||
yield
|
return (yield)
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_load_initial_conftests(
|
def pytest_load_initial_conftests(
|
||||||
early_config: "Config",
|
early_config: "Config",
|
||||||
) -> Generator[None, None, None]:
|
) -> Generator[None, None, None]:
|
||||||
with catch_warnings_for_item(
|
with catch_warnings_for_item(
|
||||||
config=early_config, ihook=early_config.hook, when="config", item=None
|
config=early_config, ihook=early_config.hook, when="config", item=None
|
||||||
):
|
):
|
||||||
yield
|
return (yield)
|
||||||
|
|
|
@ -1519,9 +1519,9 @@ class TestPOSIXLocalPath:
|
||||||
path1.chown(owner, group)
|
path1.chown(owner, group)
|
||||||
|
|
||||||
|
|
||||||
class TestUnicodePy2Py3:
|
class TestUnicode:
|
||||||
def test_join_ensure(self, tmpdir, monkeypatch):
|
def test_join_ensure(self, tmpdir, monkeypatch):
|
||||||
if sys.version_info >= (3, 0) and "LANG" not in os.environ:
|
if "LANG" not in os.environ:
|
||||||
pytest.skip("cannot run test without locale")
|
pytest.skip("cannot run test without locale")
|
||||||
x = local(tmpdir.strpath)
|
x = local(tmpdir.strpath)
|
||||||
part = "hällo"
|
part = "hällo"
|
||||||
|
@ -1529,7 +1529,7 @@ class TestUnicodePy2Py3:
|
||||||
assert x.join(part) == y
|
assert x.join(part) == y
|
||||||
|
|
||||||
def test_listdir(self, tmpdir):
|
def test_listdir(self, tmpdir):
|
||||||
if sys.version_info >= (3, 0) and "LANG" not in os.environ:
|
if "LANG" not in os.environ:
|
||||||
pytest.skip("cannot run test without locale")
|
pytest.skip("cannot run test without locale")
|
||||||
x = local(tmpdir.strpath)
|
x = local(tmpdir.strpath)
|
||||||
part = "hällo"
|
part = "hällo"
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import dataclasses
|
import dataclasses
|
||||||
|
import importlib.metadata
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.compat import importlib_metadata
|
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
from _pytest.pathlib import symlink_or_skip
|
from _pytest.pathlib import symlink_or_skip
|
||||||
from _pytest.pytester import Pytester
|
from _pytest.pytester import Pytester
|
||||||
|
@ -139,7 +139,7 @@ class TestGeneralUsage:
|
||||||
def my_dists():
|
def my_dists():
|
||||||
return (DummyDist(entry_points),)
|
return (DummyDist(entry_points),)
|
||||||
|
|
||||||
monkeypatch.setattr(importlib_metadata, "distributions", my_dists)
|
monkeypatch.setattr(importlib.metadata, "distributions", my_dists)
|
||||||
params = ("-p", "mycov") if load_cov_early else ()
|
params = ("-p", "mycov") if load_cov_early else ()
|
||||||
pytester.runpytest_inprocess(*params)
|
pytester.runpytest_inprocess(*params)
|
||||||
if load_cov_early:
|
if load_cov_early:
|
||||||
|
@ -1315,3 +1315,38 @@ def test_function_return_non_none_warning(pytester: Pytester) -> None:
|
||||||
)
|
)
|
||||||
res = pytester.runpytest()
|
res = pytester.runpytest()
|
||||||
res.stdout.fnmatch_lines(["*Did you mean to use `assert` instead of `return`?*"])
|
res.stdout.fnmatch_lines(["*Did you mean to use `assert` instead of `return`?*"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_doctest_and_normal_imports_with_importlib(pytester: Pytester) -> None:
|
||||||
|
"""
|
||||||
|
Regression test for #10811: previously import_path with ImportMode.importlib would
|
||||||
|
not return a module if already in sys.modules, resulting in modules being imported
|
||||||
|
multiple times, which causes problems with modules that have import side effects.
|
||||||
|
"""
|
||||||
|
# Uses the exact reproducer form #10811, given it is very minimal
|
||||||
|
# and illustrates the problem well.
|
||||||
|
pytester.makepyfile(
|
||||||
|
**{
|
||||||
|
"pmxbot/commands.py": "from . import logging",
|
||||||
|
"pmxbot/logging.py": "",
|
||||||
|
"tests/__init__.py": "",
|
||||||
|
"tests/test_commands.py": """
|
||||||
|
import importlib
|
||||||
|
from pmxbot import logging
|
||||||
|
|
||||||
|
class TestCommands:
|
||||||
|
def test_boo(self):
|
||||||
|
assert importlib.import_module('pmxbot.logging') is logging
|
||||||
|
""",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
pytester.makeini(
|
||||||
|
"""
|
||||||
|
[pytest]
|
||||||
|
addopts=
|
||||||
|
--doctest-modules
|
||||||
|
--import-mode importlib
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = pytester.runpytest_subprocess()
|
||||||
|
result.stdout.fnmatch_lines("*1 passed*")
|
||||||
|
|
|
@ -439,14 +439,9 @@ comment 4
|
||||||
'''
|
'''
|
||||||
for line in range(2, 6):
|
for line in range(2, 6):
|
||||||
assert str(getstatement(line, source)) == " x = 1"
|
assert str(getstatement(line, source)) == " x = 1"
|
||||||
if sys.version_info >= (3, 8) or hasattr(sys, "pypy_version_info"):
|
for line in range(6, 8):
|
||||||
tqs_start = 8
|
|
||||||
else:
|
|
||||||
tqs_start = 10
|
|
||||||
assert str(getstatement(10, source)) == '"""'
|
|
||||||
for line in range(6, tqs_start):
|
|
||||||
assert str(getstatement(line, source)) == " assert False"
|
assert str(getstatement(line, source)) == " assert False"
|
||||||
for line in range(tqs_start, 10):
|
for line in range(8, 10):
|
||||||
assert str(getstatement(line, source)) == '"""\ncomment 4\n"""'
|
assert str(getstatement(line, source)) == '"""\ncomment 4\n"""'
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
from typing import Generator
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -21,11 +22,11 @@ if sys.gettrace():
|
||||||
sys.settrace(orig_trace)
|
sys.settrace(orig_trace)
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_collection_modifyitems(items):
|
def pytest_collection_modifyitems(items) -> Generator[None, None, None]:
|
||||||
"""Prefer faster tests.
|
"""Prefer faster tests.
|
||||||
|
|
||||||
Use a hookwrapper to do this in the beginning, so e.g. --ff still works
|
Use a hook wrapper to do this in the beginning, so e.g. --ff still works
|
||||||
correctly.
|
correctly.
|
||||||
"""
|
"""
|
||||||
fast_items = []
|
fast_items = []
|
||||||
|
@ -62,7 +63,7 @@ def pytest_collection_modifyitems(items):
|
||||||
|
|
||||||
items[:] = fast_items + neutral_items + slow_items + slowest_items
|
items[:] = fast_items + neutral_items + slow_items + slowest_items
|
||||||
|
|
||||||
yield
|
return (yield)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|
|
@ -1040,13 +1040,13 @@ def test_log_set_path(pytester: Pytester) -> None:
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import pytest
|
import pytest
|
||||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_runtest_setup(item):
|
def pytest_runtest_setup(item):
|
||||||
config = item.config
|
config = item.config
|
||||||
logging_plugin = config.pluginmanager.get_plugin("logging-plugin")
|
logging_plugin = config.pluginmanager.get_plugin("logging-plugin")
|
||||||
report_file = os.path.join({}, item._request.node.name)
|
report_file = os.path.join({}, item._request.node.name)
|
||||||
logging_plugin.set_log_path(report_file)
|
logging_plugin.set_log_path(report_file)
|
||||||
yield
|
return (yield)
|
||||||
""".format(
|
""".format(
|
||||||
repr(report_dir_base)
|
repr(report_dir_base)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
anyio[curio,trio]==3.7.0
|
anyio[curio,trio]==3.7.1
|
||||||
django==4.2.2
|
django==4.2.3
|
||||||
pytest-asyncio==0.21.0
|
pytest-asyncio==0.21.0
|
||||||
pytest-bdd==6.1.1
|
pytest-bdd==6.1.1
|
||||||
pytest-cov==4.1.0
|
pytest-cov==4.1.0
|
||||||
|
@ -7,7 +7,7 @@ pytest-django==4.5.2
|
||||||
pytest-flakes==4.0.5
|
pytest-flakes==4.0.5
|
||||||
pytest-html==3.2.0
|
pytest-html==3.2.0
|
||||||
pytest-mock==3.11.1
|
pytest-mock==3.11.1
|
||||||
pytest-rerunfailures==11.1.2
|
pytest-rerunfailures==12.0
|
||||||
pytest-sugar==0.9.7
|
pytest-sugar==0.9.7
|
||||||
pytest-trio==0.7.0
|
pytest-trio==0.7.0
|
||||||
pytest-twisted==1.14.0
|
pytest-twisted==1.14.0
|
||||||
|
|
|
@ -122,6 +122,23 @@ class TestApprox:
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assert_approx_raises_regex(
|
||||||
|
{"a": 1.0, "b": None, "c": None},
|
||||||
|
{
|
||||||
|
"a": None,
|
||||||
|
"b": 1000.0,
|
||||||
|
"c": None,
|
||||||
|
},
|
||||||
|
[
|
||||||
|
r" comparison failed. Mismatched elements: 2 / 3:",
|
||||||
|
r" Max absolute difference: -inf",
|
||||||
|
r" Max relative difference: -inf",
|
||||||
|
r" Index \| Obtained\s+\| Expected\s+",
|
||||||
|
rf" a \| {SOME_FLOAT} \| None",
|
||||||
|
rf" b \| None\s+\| {SOME_FLOAT} ± {SOME_FLOAT}",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
assert_approx_raises_regex(
|
assert_approx_raises_regex(
|
||||||
[1.0, 2.0, 3.0, 4.0],
|
[1.0, 2.0, 3.0, 4.0],
|
||||||
[1.0, 3.0, 3.0, 5.0],
|
[1.0, 3.0, 3.0, 5.0],
|
||||||
|
|
|
@ -827,11 +827,11 @@ class TestConftestCustomization:
|
||||||
textwrap.dedent(
|
textwrap.dedent(
|
||||||
"""\
|
"""\
|
||||||
import pytest
|
import pytest
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_pycollect_makemodule():
|
def pytest_pycollect_makemodule():
|
||||||
outcome = yield
|
mod = yield
|
||||||
mod = outcome.get_result()
|
|
||||||
mod.obj.hello = "world"
|
mod.obj.hello = "world"
|
||||||
|
return mod
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
|
@ -855,14 +855,13 @@ class TestConftestCustomization:
|
||||||
textwrap.dedent(
|
textwrap.dedent(
|
||||||
"""\
|
"""\
|
||||||
import pytest
|
import pytest
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_pycollect_makeitem():
|
def pytest_pycollect_makeitem():
|
||||||
outcome = yield
|
result = yield
|
||||||
if outcome.excinfo is None:
|
if result:
|
||||||
result = outcome.get_result()
|
for func in result:
|
||||||
if result:
|
func._some123 = "world"
|
||||||
for func in result:
|
return result
|
||||||
func._some123 = "world"
|
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
|
|
|
@ -19,7 +19,6 @@ from hypothesis import strategies
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest import fixtures
|
from _pytest import fixtures
|
||||||
from _pytest import python
|
from _pytest import python
|
||||||
from _pytest.compat import _format_args
|
|
||||||
from _pytest.compat import getfuncargnames
|
from _pytest.compat import getfuncargnames
|
||||||
from _pytest.compat import NOTSET
|
from _pytest.compat import NOTSET
|
||||||
from _pytest.outcomes import fail
|
from _pytest.outcomes import fail
|
||||||
|
@ -1065,27 +1064,6 @@ class TestMetafunc:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_format_args(self) -> None:
|
|
||||||
def function1():
|
|
||||||
pass
|
|
||||||
|
|
||||||
assert _format_args(function1) == "()"
|
|
||||||
|
|
||||||
def function2(arg1):
|
|
||||||
pass
|
|
||||||
|
|
||||||
assert _format_args(function2) == "(arg1)"
|
|
||||||
|
|
||||||
def function3(arg1, arg2="qwe"):
|
|
||||||
pass
|
|
||||||
|
|
||||||
assert _format_args(function3) == "(arg1, arg2='qwe')"
|
|
||||||
|
|
||||||
def function4(arg1, *args, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
assert _format_args(function4) == "(arg1, *args, **kwargs)"
|
|
||||||
|
|
||||||
|
|
||||||
class TestMetafuncFunctional:
|
class TestMetafuncFunctional:
|
||||||
def test_attributes(self, pytester: Pytester) -> None:
|
def test_attributes(self, pytester: Pytester) -> None:
|
||||||
|
|
|
@ -199,8 +199,8 @@ class TestImportHookInstallation:
|
||||||
return check
|
return check
|
||||||
""",
|
""",
|
||||||
"mainwrapper.py": """\
|
"mainwrapper.py": """\
|
||||||
|
import importlib.metadata
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.compat import importlib_metadata
|
|
||||||
|
|
||||||
class DummyEntryPoint(object):
|
class DummyEntryPoint(object):
|
||||||
name = 'spam'
|
name = 'spam'
|
||||||
|
@ -220,7 +220,7 @@ class TestImportHookInstallation:
|
||||||
def distributions():
|
def distributions():
|
||||||
return (DummyDistInfo(),)
|
return (DummyDistInfo(),)
|
||||||
|
|
||||||
importlib_metadata.distributions = distributions
|
importlib.metadata.distributions = distributions
|
||||||
pytest.main()
|
pytest.main()
|
||||||
""",
|
""",
|
||||||
"test_foo.py": """\
|
"test_foo.py": """\
|
||||||
|
|
|
@ -131,9 +131,8 @@ class TestAssertionRewrite:
|
||||||
for n in [node, *ast.iter_child_nodes(node)]:
|
for n in [node, *ast.iter_child_nodes(node)]:
|
||||||
assert n.lineno == 3
|
assert n.lineno == 3
|
||||||
assert n.col_offset == 0
|
assert n.col_offset == 0
|
||||||
if sys.version_info >= (3, 8):
|
assert n.end_lineno == 6
|
||||||
assert n.end_lineno == 6
|
assert n.end_col_offset == 3
|
||||||
assert n.end_col_offset == 3
|
|
||||||
|
|
||||||
def test_dont_rewrite(self) -> None:
|
def test_dont_rewrite(self) -> None:
|
||||||
s = """'PYTEST_DONT_REWRITE'\nassert 14"""
|
s = """'PYTEST_DONT_REWRITE'\nassert 14"""
|
||||||
|
@ -1270,9 +1269,6 @@ class TestIssue2121:
|
||||||
result.stdout.fnmatch_lines(["*E*assert (1 + 1) == 3"])
|
result.stdout.fnmatch_lines(["*E*assert (1 + 1) == 3"])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info < (3, 8), reason="walrus operator not available in py<38"
|
|
||||||
)
|
|
||||||
class TestIssue10743:
|
class TestIssue10743:
|
||||||
def test_assertion_walrus_operator(self, pytester: Pytester) -> None:
|
def test_assertion_walrus_operator(self, pytester: Pytester) -> None:
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
|
@ -1441,9 +1437,6 @@ class TestIssue10743:
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info < (3, 8), reason="walrus operator not available in py<38"
|
|
||||||
)
|
|
||||||
class TestIssue11028:
|
class TestIssue11028:
|
||||||
def test_assertion_walrus_operator_in_operand(self, pytester: Pytester) -> None:
|
def test_assertion_walrus_operator_in_operand(self, pytester: Pytester) -> None:
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
|
@ -1957,16 +1950,10 @@ class TestPyCacheDir:
|
||||||
)
|
)
|
||||||
def test_get_cache_dir(self, monkeypatch, prefix, source, expected) -> None:
|
def test_get_cache_dir(self, monkeypatch, prefix, source, expected) -> None:
|
||||||
monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False)
|
monkeypatch.delenv("PYTHONPYCACHEPREFIX", raising=False)
|
||||||
|
|
||||||
if prefix is not None and sys.version_info < (3, 8):
|
|
||||||
pytest.skip("pycache_prefix not available in py<38")
|
|
||||||
monkeypatch.setattr(sys, "pycache_prefix", prefix, raising=False)
|
monkeypatch.setattr(sys, "pycache_prefix", prefix, raising=False)
|
||||||
|
|
||||||
assert get_cache_dir(Path(source)) == Path(expected)
|
assert get_cache_dir(Path(source)) == Path(expected)
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info < (3, 8), reason="pycache_prefix not available in py<38"
|
|
||||||
)
|
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
sys.version_info[:2] == (3, 9) and sys.platform.startswith("win"),
|
sys.version_info[:2] == (3, 9) and sys.platform.startswith("win"),
|
||||||
reason="#9298",
|
reason="#9298",
|
||||||
|
@ -2055,3 +2042,17 @@ class TestReprSizeVerbosity:
|
||||||
self.create_test_file(pytester, DEFAULT_REPR_MAX_SIZE * 10)
|
self.create_test_file(pytester, DEFAULT_REPR_MAX_SIZE * 10)
|
||||||
result = pytester.runpytest("-vv")
|
result = pytester.runpytest("-vv")
|
||||||
result.stdout.no_fnmatch_line("*xxx...xxx*")
|
result.stdout.no_fnmatch_line("*xxx...xxx*")
|
||||||
|
|
||||||
|
|
||||||
|
class TestIssue11140:
|
||||||
|
def test_constant_not_picked_as_module_docstring(self, pytester: Pytester) -> None:
|
||||||
|
pytester.makepyfile(
|
||||||
|
"""\
|
||||||
|
0
|
||||||
|
|
||||||
|
def test_foo():
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = pytester.runpytest()
|
||||||
|
assert result.ret == 0
|
||||||
|
|
|
@ -334,12 +334,11 @@ class TestPrunetraceback:
|
||||||
pytester.makeconftest(
|
pytester.makeconftest(
|
||||||
"""
|
"""
|
||||||
import pytest
|
import pytest
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_make_collect_report():
|
def pytest_make_collect_report():
|
||||||
outcome = yield
|
rep = yield
|
||||||
rep = outcome.get_result()
|
|
||||||
rep.headerlines += ["header1"]
|
rep.headerlines += ["header1"]
|
||||||
outcome.force_result(rep)
|
return rep
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
result = pytester.runpytest(p)
|
result = pytester.runpytest(p)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import enum
|
import enum
|
||||||
import sys
|
import sys
|
||||||
|
from functools import cached_property
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
@ -8,7 +9,6 @@ from typing import Union
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.compat import _PytestWrapper
|
from _pytest.compat import _PytestWrapper
|
||||||
from _pytest.compat import assert_never
|
from _pytest.compat import assert_never
|
||||||
from _pytest.compat import cached_property
|
|
||||||
from _pytest.compat import get_real_func
|
from _pytest.compat import get_real_func
|
||||||
from _pytest.compat import is_generator
|
from _pytest.compat import is_generator
|
||||||
from _pytest.compat import safe_getattr
|
from _pytest.compat import safe_getattr
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import dataclasses
|
import dataclasses
|
||||||
|
import importlib.metadata
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
@ -13,7 +14,6 @@ from typing import Union
|
||||||
|
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.compat import importlib_metadata
|
|
||||||
from _pytest.config import _get_plugin_specs_as_list
|
from _pytest.config import _get_plugin_specs_as_list
|
||||||
from _pytest.config import _iter_rewritable_modules
|
from _pytest.config import _iter_rewritable_modules
|
||||||
from _pytest.config import _strtobool
|
from _pytest.config import _strtobool
|
||||||
|
@ -475,7 +475,7 @@ class TestParseIni:
|
||||||
pytester.makepyfile(myplugin1_module="# my plugin module")
|
pytester.makepyfile(myplugin1_module="# my plugin module")
|
||||||
pytester.syspathinsert()
|
pytester.syspathinsert()
|
||||||
|
|
||||||
monkeypatch.setattr(importlib_metadata, "distributions", my_dists)
|
monkeypatch.setattr(importlib.metadata, "distributions", my_dists)
|
||||||
monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False)
|
monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False)
|
||||||
|
|
||||||
pytester.makeini(ini_file_text)
|
pytester.makeini(ini_file_text)
|
||||||
|
@ -1003,7 +1003,7 @@ def test_preparse_ordering_with_setuptools(
|
||||||
def my_dists():
|
def my_dists():
|
||||||
return (Dist,)
|
return (Dist,)
|
||||||
|
|
||||||
monkeypatch.setattr(importlib_metadata, "distributions", my_dists)
|
monkeypatch.setattr(importlib.metadata, "distributions", my_dists)
|
||||||
pytester.makeconftest(
|
pytester.makeconftest(
|
||||||
"""
|
"""
|
||||||
pytest_plugins = "mytestplugin",
|
pytest_plugins = "mytestplugin",
|
||||||
|
@ -1036,7 +1036,7 @@ def test_setuptools_importerror_issue1479(
|
||||||
def distributions():
|
def distributions():
|
||||||
return (Distribution(),)
|
return (Distribution(),)
|
||||||
|
|
||||||
monkeypatch.setattr(importlib_metadata, "distributions", distributions)
|
monkeypatch.setattr(importlib.metadata, "distributions", distributions)
|
||||||
with pytest.raises(ImportError):
|
with pytest.raises(ImportError):
|
||||||
pytester.parseconfig()
|
pytester.parseconfig()
|
||||||
|
|
||||||
|
@ -1063,7 +1063,7 @@ def test_importlib_metadata_broken_distribution(
|
||||||
def distributions():
|
def distributions():
|
||||||
return (Distribution(),)
|
return (Distribution(),)
|
||||||
|
|
||||||
monkeypatch.setattr(importlib_metadata, "distributions", distributions)
|
monkeypatch.setattr(importlib.metadata, "distributions", distributions)
|
||||||
pytester.parseconfig()
|
pytester.parseconfig()
|
||||||
|
|
||||||
|
|
||||||
|
@ -1091,7 +1091,7 @@ def test_plugin_preparse_prevents_setuptools_loading(
|
||||||
def distributions():
|
def distributions():
|
||||||
return (Distribution(),)
|
return (Distribution(),)
|
||||||
|
|
||||||
monkeypatch.setattr(importlib_metadata, "distributions", distributions)
|
monkeypatch.setattr(importlib.metadata, "distributions", distributions)
|
||||||
args = ("-p", "no:mytestplugin") if block_it else ()
|
args = ("-p", "no:mytestplugin") if block_it else ()
|
||||||
config = pytester.parseconfig(*args)
|
config = pytester.parseconfig(*args)
|
||||||
config.pluginmanager.import_plugin("mytestplugin")
|
config.pluginmanager.import_plugin("mytestplugin")
|
||||||
|
@ -1140,7 +1140,7 @@ def test_disable_plugin_autoload(
|
||||||
return (Distribution(),)
|
return (Distribution(),)
|
||||||
|
|
||||||
monkeypatch.setenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", "1")
|
monkeypatch.setenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", "1")
|
||||||
monkeypatch.setattr(importlib_metadata, "distributions", distributions)
|
monkeypatch.setattr(importlib.metadata, "distributions", distributions)
|
||||||
monkeypatch.setitem(sys.modules, "mytestplugin", PseudoPlugin()) # type: ignore[misc]
|
monkeypatch.setitem(sys.modules, "mytestplugin", PseudoPlugin()) # type: ignore[misc]
|
||||||
config = pytester.parseconfig(*parse_args)
|
config = pytester.parseconfig(*parse_args)
|
||||||
has_loaded = config.pluginmanager.get_plugin("mytestplugin") is not None
|
has_loaded = config.pluginmanager.get_plugin("mytestplugin") is not None
|
||||||
|
@ -1317,7 +1317,7 @@ def test_load_initial_conftest_last_ordering(_config_for_test):
|
||||||
hookimpls = [
|
hookimpls = [
|
||||||
(
|
(
|
||||||
hookimpl.function.__module__,
|
hookimpl.function.__module__,
|
||||||
"wrapper" if hookimpl.hookwrapper else "nonwrapper",
|
"wrapper" if (hookimpl.wrapper or hookimpl.hookwrapper) else "nonwrapper",
|
||||||
)
|
)
|
||||||
for hookimpl in hc.get_hookimpls()
|
for hookimpl in hc.get_hookimpls()
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from _pytest.compat import importlib_metadata
|
import importlib.metadata
|
||||||
|
|
||||||
|
|
||||||
def test_pytest_entry_points_are_identical():
|
def test_pytest_entry_points_are_identical():
|
||||||
dist = importlib_metadata.distribution("pytest")
|
dist = importlib.metadata.distribution("pytest")
|
||||||
entry_map = {ep.name: ep for ep in dist.entry_points}
|
entry_map = {ep.name: ep for ep in dist.entry_points}
|
||||||
assert entry_map["pytest"].value == entry_map["py.test"].value
|
assert entry_map["pytest"].value == entry_map["py.test"].value
|
||||||
|
|
|
@ -806,12 +806,12 @@ class TestKeywordSelection:
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
conftest="""
|
conftest="""
|
||||||
import pytest
|
import pytest
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_pycollect_makeitem(name):
|
def pytest_pycollect_makeitem(name):
|
||||||
outcome = yield
|
item = yield
|
||||||
if name == "TestClass":
|
if name == "TestClass":
|
||||||
item = outcome.get_result()
|
|
||||||
item.extra_keyword_matches.add("xxx")
|
item.extra_keyword_matches.add("xxx")
|
||||||
|
return item
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
reprec = pytester.inline_run(p.parent, "-s", "-k", keyword)
|
reprec = pytester.inline_run(p.parent, "-s", "-k", keyword)
|
||||||
|
@ -1130,6 +1130,41 @@ def test_mark_mro() -> None:
|
||||||
|
|
||||||
all_marks = get_unpacked_marks(C)
|
all_marks = get_unpacked_marks(C)
|
||||||
|
|
||||||
assert all_marks == [xfail("c").mark, xfail("a").mark, xfail("b").mark]
|
assert all_marks == [xfail("b").mark, xfail("a").mark, xfail("c").mark]
|
||||||
|
|
||||||
assert get_unpacked_marks(C, consider_mro=False) == [xfail("c").mark]
|
assert get_unpacked_marks(C, consider_mro=False) == [xfail("c").mark]
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.mark.issue("https://github.com/pytest-dev/pytest/issues/10447")
|
||||||
|
def test_mark_fixture_order_mro(pytester: Pytester):
|
||||||
|
"""This ensures we walk marks of the mro starting with the base classes
|
||||||
|
the action at a distance fixtures are taken as minimal example from a real project
|
||||||
|
|
||||||
|
"""
|
||||||
|
foo = pytester.makepyfile(
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def add_attr1(request):
|
||||||
|
request.instance.attr1 = object()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def add_attr2(request):
|
||||||
|
request.instance.attr2 = request.instance.attr1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('add_attr1')
|
||||||
|
class Parent:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('add_attr2')
|
||||||
|
class TestThings(Parent):
|
||||||
|
def test_attrs(self):
|
||||||
|
assert self.attr1 == self.attr2
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = pytester.runpytest(foo)
|
||||||
|
result.assert_outcomes(passed=1)
|
||||||
|
|
|
@ -7,6 +7,7 @@ from textwrap import dedent
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
|
from typing import Iterator
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.monkeypatch import MonkeyPatch
|
from _pytest.monkeypatch import MonkeyPatch
|
||||||
|
@ -282,29 +283,36 @@ class TestImportPath:
|
||||||
import_path(tmp_path / "invalid.py", root=tmp_path)
|
import_path(tmp_path / "invalid.py", root=tmp_path)
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def simple_module(self, tmp_path: Path) -> Path:
|
def simple_module(
|
||||||
fn = tmp_path / "_src/tests/mymod.py"
|
self, tmp_path: Path, request: pytest.FixtureRequest
|
||||||
|
) -> Iterator[Path]:
|
||||||
|
name = f"mymod_{request.node.name}"
|
||||||
|
fn = tmp_path / f"_src/tests/{name}.py"
|
||||||
fn.parent.mkdir(parents=True)
|
fn.parent.mkdir(parents=True)
|
||||||
fn.write_text("def foo(x): return 40 + x", encoding="utf-8")
|
fn.write_text("def foo(x): return 40 + x", encoding="utf-8")
|
||||||
return fn
|
module_name = module_name_from_path(fn, root=tmp_path)
|
||||||
|
yield fn
|
||||||
|
sys.modules.pop(module_name, None)
|
||||||
|
|
||||||
def test_importmode_importlib(self, simple_module: Path, tmp_path: Path) -> None:
|
def test_importmode_importlib(
|
||||||
|
self, simple_module: Path, tmp_path: Path, request: pytest.FixtureRequest
|
||||||
|
) -> None:
|
||||||
"""`importlib` mode does not change sys.path."""
|
"""`importlib` mode does not change sys.path."""
|
||||||
module = import_path(simple_module, mode="importlib", root=tmp_path)
|
module = import_path(simple_module, mode="importlib", root=tmp_path)
|
||||||
assert module.foo(2) == 42 # type: ignore[attr-defined]
|
assert module.foo(2) == 42 # type: ignore[attr-defined]
|
||||||
assert str(simple_module.parent) not in sys.path
|
assert str(simple_module.parent) not in sys.path
|
||||||
assert module.__name__ in sys.modules
|
assert module.__name__ in sys.modules
|
||||||
assert module.__name__ == "_src.tests.mymod"
|
assert module.__name__ == f"_src.tests.mymod_{request.node.name}"
|
||||||
assert "_src" in sys.modules
|
assert "_src" in sys.modules
|
||||||
assert "_src.tests" in sys.modules
|
assert "_src.tests" in sys.modules
|
||||||
|
|
||||||
def test_importmode_twice_is_different_module(
|
def test_remembers_previous_imports(
|
||||||
self, simple_module: Path, tmp_path: Path
|
self, simple_module: Path, tmp_path: Path
|
||||||
) -> None:
|
) -> None:
|
||||||
"""`importlib` mode always returns a new module."""
|
"""`importlib` mode called remembers previous module (#10341, #10811)."""
|
||||||
module1 = import_path(simple_module, mode="importlib", root=tmp_path)
|
module1 = import_path(simple_module, mode="importlib", root=tmp_path)
|
||||||
module2 = import_path(simple_module, mode="importlib", root=tmp_path)
|
module2 = import_path(simple_module, mode="importlib", root=tmp_path)
|
||||||
assert module1 is not module2
|
assert module1 is module2
|
||||||
|
|
||||||
def test_no_meta_path_found(
|
def test_no_meta_path_found(
|
||||||
self, simple_module: Path, monkeypatch: MonkeyPatch, tmp_path: Path
|
self, simple_module: Path, monkeypatch: MonkeyPatch, tmp_path: Path
|
||||||
|
@ -317,6 +325,9 @@ class TestImportPath:
|
||||||
# mode='importlib' fails if no spec is found to load the module
|
# mode='importlib' fails if no spec is found to load the module
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
|
||||||
|
# Force module to be re-imported.
|
||||||
|
del sys.modules[module.__name__]
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
importlib.util, "spec_from_file_location", lambda *args: None
|
importlib.util, "spec_from_file_location", lambda *args: None
|
||||||
)
|
)
|
||||||
|
@ -592,3 +603,15 @@ class TestImportLibMode:
|
||||||
modules = {}
|
modules = {}
|
||||||
insert_missing_modules(modules, "")
|
insert_missing_modules(modules, "")
|
||||||
assert modules == {}
|
assert modules == {}
|
||||||
|
|
||||||
|
def test_parent_contains_child_module_attribute(
|
||||||
|
self, monkeypatch: MonkeyPatch, tmp_path: Path
|
||||||
|
):
|
||||||
|
monkeypatch.chdir(tmp_path)
|
||||||
|
# Use 'xxx' and 'xxy' as parent names as they are unlikely to exist and
|
||||||
|
# don't end up being imported.
|
||||||
|
modules = {"xxx.tests.foo": ModuleType("xxx.tests.foo")}
|
||||||
|
insert_missing_modules(modules, "xxx.tests.foo")
|
||||||
|
assert sorted(modules) == ["xxx", "xxx.tests", "xxx.tests.foo"]
|
||||||
|
assert modules["xxx"].tests is modules["xxx.tests"]
|
||||||
|
assert modules["xxx.tests"].foo is modules["xxx.tests.foo"]
|
||||||
|
|
|
@ -85,8 +85,8 @@ def test_clean_up(pytester: Pytester) -> None:
|
||||||
# This is tough to test behaviorally because the cleanup really runs last.
|
# This is tough to test behaviorally because the cleanup really runs last.
|
||||||
# So the test make several implementation assumptions:
|
# So the test make several implementation assumptions:
|
||||||
# - Cleanup is done in pytest_unconfigure().
|
# - Cleanup is done in pytest_unconfigure().
|
||||||
# - Not a hookwrapper.
|
# - Not a hook wrapper.
|
||||||
# So we can add a hookwrapper ourselves to test what it does.
|
# So we can add a hook wrapper ourselves to test what it does.
|
||||||
pytester.makefile(".ini", pytest="[pytest]\npythonpath=I_SHALL_BE_REMOVED\n")
|
pytester.makefile(".ini", pytest="[pytest]\npythonpath=I_SHALL_BE_REMOVED\n")
|
||||||
pytester.makepyfile(test_foo="""def test_foo(): pass""")
|
pytester.makepyfile(test_foo="""def test_foo(): pass""")
|
||||||
|
|
||||||
|
@ -94,12 +94,14 @@ def test_clean_up(pytester: Pytester) -> None:
|
||||||
after: Optional[List[str]] = None
|
after: Optional[List[str]] = None
|
||||||
|
|
||||||
class Plugin:
|
class Plugin:
|
||||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
@pytest.hookimpl(wrapper=True, tryfirst=True)
|
||||||
def pytest_unconfigure(self) -> Generator[None, None, None]:
|
def pytest_unconfigure(self) -> Generator[None, None, None]:
|
||||||
nonlocal before, after
|
nonlocal before, after
|
||||||
before = sys.path.copy()
|
before = sys.path.copy()
|
||||||
yield
|
try:
|
||||||
after = sys.path.copy()
|
return (yield)
|
||||||
|
finally:
|
||||||
|
after = sys.path.copy()
|
||||||
|
|
||||||
result = pytester.runpytest_inprocess(plugins=[Plugin()])
|
result = pytester.runpytest_inprocess(plugins=[Plugin()])
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import warnings
|
import warnings
|
||||||
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from typing import Type
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.pytester import Pytester
|
from _pytest.pytester import Pytester
|
||||||
|
@ -37,6 +39,47 @@ def test_recwarn_captures_deprecation_warning(recwarn: WarningsRecorder) -> None
|
||||||
assert recwarn.pop(DeprecationWarning)
|
assert recwarn.pop(DeprecationWarning)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSubclassWarningPop:
|
||||||
|
class ParentWarning(Warning):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ChildWarning(ParentWarning):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ChildOfChildWarning(ChildWarning):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def raise_warnings_from_list(_warnings: List[Type[Warning]]):
|
||||||
|
for warn in _warnings:
|
||||||
|
warnings.warn(f"Warning {warn().__repr__()}", warn)
|
||||||
|
|
||||||
|
def test_pop_finds_exact_match(self):
|
||||||
|
with pytest.warns((self.ParentWarning, self.ChildWarning)) as record:
|
||||||
|
self.raise_warnings_from_list(
|
||||||
|
[self.ChildWarning, self.ParentWarning, self.ChildOfChildWarning]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(record) == 3
|
||||||
|
_warn = record.pop(self.ParentWarning)
|
||||||
|
assert _warn.category is self.ParentWarning
|
||||||
|
|
||||||
|
def test_pop_raises_if_no_match(self):
|
||||||
|
with pytest.raises(AssertionError):
|
||||||
|
with pytest.warns(self.ParentWarning) as record:
|
||||||
|
self.raise_warnings_from_list([self.ParentWarning])
|
||||||
|
record.pop(self.ChildOfChildWarning)
|
||||||
|
|
||||||
|
def test_pop_finds_best_inexact_match(self):
|
||||||
|
with pytest.warns(self.ParentWarning) as record:
|
||||||
|
self.raise_warnings_from_list(
|
||||||
|
[self.ChildOfChildWarning, self.ChildWarning, self.ChildOfChildWarning]
|
||||||
|
)
|
||||||
|
|
||||||
|
_warn = record.pop(self.ParentWarning)
|
||||||
|
assert _warn.category is self.ChildWarning
|
||||||
|
|
||||||
|
|
||||||
class TestWarningsRecorderChecker:
|
class TestWarningsRecorderChecker:
|
||||||
def test_recording(self) -> None:
|
def test_recording(self) -> None:
|
||||||
rec = WarningsRecorder(_ispytest=True)
|
rec = WarningsRecorder(_ispytest=True)
|
||||||
|
@ -172,22 +215,6 @@ class TestDeprecatedCall:
|
||||||
with pytest.deprecated_call():
|
with pytest.deprecated_call():
|
||||||
assert f() == 10
|
assert f() == 10
|
||||||
|
|
||||||
@pytest.mark.parametrize("mode", ["context_manager", "call"])
|
|
||||||
def test_deprecated_call_exception_is_raised(self, mode) -> None:
|
|
||||||
"""If the block of the code being tested by deprecated_call() raises an exception,
|
|
||||||
it must raise the exception undisturbed.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def f():
|
|
||||||
raise ValueError("some exception")
|
|
||||||
|
|
||||||
with pytest.raises(ValueError, match="some exception"):
|
|
||||||
if mode == "call":
|
|
||||||
pytest.deprecated_call(f)
|
|
||||||
else:
|
|
||||||
with pytest.deprecated_call():
|
|
||||||
f()
|
|
||||||
|
|
||||||
def test_deprecated_call_specificity(self) -> None:
|
def test_deprecated_call_specificity(self) -> None:
|
||||||
other_warnings = [
|
other_warnings = [
|
||||||
Warning,
|
Warning,
|
||||||
|
@ -203,19 +230,21 @@ class TestDeprecatedCall:
|
||||||
def f():
|
def f():
|
||||||
warnings.warn(warning("hi"))
|
warnings.warn(warning("hi"))
|
||||||
|
|
||||||
with pytest.raises(pytest.fail.Exception):
|
with pytest.warns(warning):
|
||||||
pytest.deprecated_call(f)
|
with pytest.raises(pytest.fail.Exception):
|
||||||
with pytest.raises(pytest.fail.Exception):
|
pytest.deprecated_call(f)
|
||||||
with pytest.deprecated_call():
|
with pytest.raises(pytest.fail.Exception):
|
||||||
f()
|
with pytest.deprecated_call():
|
||||||
|
f()
|
||||||
|
|
||||||
def test_deprecated_call_supports_match(self) -> None:
|
def test_deprecated_call_supports_match(self) -> None:
|
||||||
with pytest.deprecated_call(match=r"must be \d+$"):
|
with pytest.deprecated_call(match=r"must be \d+$"):
|
||||||
warnings.warn("value must be 42", DeprecationWarning)
|
warnings.warn("value must be 42", DeprecationWarning)
|
||||||
|
|
||||||
with pytest.raises(pytest.fail.Exception):
|
with pytest.deprecated_call():
|
||||||
with pytest.deprecated_call(match=r"must be \d+$"):
|
with pytest.raises(pytest.fail.Exception, match="DID NOT WARN"):
|
||||||
warnings.warn("this is not here", DeprecationWarning)
|
with pytest.deprecated_call(match=r"must be \d+$"):
|
||||||
|
warnings.warn("this is not here", DeprecationWarning)
|
||||||
|
|
||||||
|
|
||||||
class TestWarns:
|
class TestWarns:
|
||||||
|
@ -227,8 +256,9 @@ class TestWarns:
|
||||||
def test_several_messages(self) -> None:
|
def test_several_messages(self) -> None:
|
||||||
# different messages, b/c Python suppresses multiple identical warnings
|
# different messages, b/c Python suppresses multiple identical warnings
|
||||||
pytest.warns(RuntimeWarning, lambda: warnings.warn("w1", RuntimeWarning))
|
pytest.warns(RuntimeWarning, lambda: warnings.warn("w1", RuntimeWarning))
|
||||||
with pytest.raises(pytest.fail.Exception):
|
with pytest.warns(RuntimeWarning):
|
||||||
pytest.warns(UserWarning, lambda: warnings.warn("w2", RuntimeWarning))
|
with pytest.raises(pytest.fail.Exception):
|
||||||
|
pytest.warns(UserWarning, lambda: warnings.warn("w2", RuntimeWarning))
|
||||||
pytest.warns(RuntimeWarning, lambda: warnings.warn("w3", RuntimeWarning))
|
pytest.warns(RuntimeWarning, lambda: warnings.warn("w3", RuntimeWarning))
|
||||||
|
|
||||||
def test_function(self) -> None:
|
def test_function(self) -> None:
|
||||||
|
@ -243,13 +273,14 @@ class TestWarns:
|
||||||
pytest.warns(
|
pytest.warns(
|
||||||
(RuntimeWarning, SyntaxWarning), lambda: warnings.warn("w2", SyntaxWarning)
|
(RuntimeWarning, SyntaxWarning), lambda: warnings.warn("w2", SyntaxWarning)
|
||||||
)
|
)
|
||||||
pytest.raises(
|
with pytest.warns():
|
||||||
pytest.fail.Exception,
|
pytest.raises(
|
||||||
lambda: pytest.warns(
|
pytest.fail.Exception,
|
||||||
(RuntimeWarning, SyntaxWarning),
|
lambda: pytest.warns(
|
||||||
lambda: warnings.warn("w3", UserWarning),
|
(RuntimeWarning, SyntaxWarning),
|
||||||
),
|
lambda: warnings.warn("w3", UserWarning),
|
||||||
)
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def test_as_contextmanager(self) -> None:
|
def test_as_contextmanager(self) -> None:
|
||||||
with pytest.warns(RuntimeWarning):
|
with pytest.warns(RuntimeWarning):
|
||||||
|
@ -258,20 +289,22 @@ class TestWarns:
|
||||||
with pytest.warns(UserWarning):
|
with pytest.warns(UserWarning):
|
||||||
warnings.warn("user", UserWarning)
|
warnings.warn("user", UserWarning)
|
||||||
|
|
||||||
with pytest.raises(pytest.fail.Exception) as excinfo:
|
with pytest.warns():
|
||||||
with pytest.warns(RuntimeWarning):
|
with pytest.raises(pytest.fail.Exception) as excinfo:
|
||||||
warnings.warn("user", UserWarning)
|
with pytest.warns(RuntimeWarning):
|
||||||
|
warnings.warn("user", UserWarning)
|
||||||
excinfo.match(
|
excinfo.match(
|
||||||
r"DID NOT WARN. No warnings of type \(.+RuntimeWarning.+,\) were emitted.\n"
|
r"DID NOT WARN. No warnings of type \(.+RuntimeWarning.+,\) were emitted.\n"
|
||||||
r"The list of emitted warnings is: \[UserWarning\('user',?\)\]."
|
r" Emitted warnings: \[UserWarning\('user',?\)\]."
|
||||||
)
|
)
|
||||||
|
|
||||||
with pytest.raises(pytest.fail.Exception) as excinfo:
|
with pytest.warns():
|
||||||
with pytest.warns(UserWarning):
|
with pytest.raises(pytest.fail.Exception) as excinfo:
|
||||||
warnings.warn("runtime", RuntimeWarning)
|
with pytest.warns(UserWarning):
|
||||||
|
warnings.warn("runtime", RuntimeWarning)
|
||||||
excinfo.match(
|
excinfo.match(
|
||||||
r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) were emitted.\n"
|
r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) were emitted.\n"
|
||||||
r"The list of emitted warnings is: \[RuntimeWarning\('runtime',?\)]."
|
r" Emitted warnings: \[RuntimeWarning\('runtime',?\)]."
|
||||||
)
|
)
|
||||||
|
|
||||||
with pytest.raises(pytest.fail.Exception) as excinfo:
|
with pytest.raises(pytest.fail.Exception) as excinfo:
|
||||||
|
@ -279,19 +312,20 @@ class TestWarns:
|
||||||
pass
|
pass
|
||||||
excinfo.match(
|
excinfo.match(
|
||||||
r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) were emitted.\n"
|
r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) were emitted.\n"
|
||||||
r"The list of emitted warnings is: \[\]."
|
r" Emitted warnings: \[\]."
|
||||||
)
|
)
|
||||||
|
|
||||||
warning_classes = (UserWarning, FutureWarning)
|
warning_classes = (UserWarning, FutureWarning)
|
||||||
with pytest.raises(pytest.fail.Exception) as excinfo:
|
with pytest.warns():
|
||||||
with pytest.warns(warning_classes) as warninfo:
|
with pytest.raises(pytest.fail.Exception) as excinfo:
|
||||||
warnings.warn("runtime", RuntimeWarning)
|
with pytest.warns(warning_classes) as warninfo:
|
||||||
warnings.warn("import", ImportWarning)
|
warnings.warn("runtime", RuntimeWarning)
|
||||||
|
warnings.warn("import", ImportWarning)
|
||||||
|
|
||||||
messages = [each.message for each in warninfo]
|
messages = [each.message for each in warninfo]
|
||||||
expected_str = (
|
expected_str = (
|
||||||
f"DID NOT WARN. No warnings of type {warning_classes} were emitted.\n"
|
f"DID NOT WARN. No warnings of type {warning_classes} were emitted.\n"
|
||||||
f"The list of emitted warnings is: {messages}."
|
f" Emitted warnings: {messages}."
|
||||||
)
|
)
|
||||||
|
|
||||||
assert str(excinfo.value) == expected_str
|
assert str(excinfo.value) == expected_str
|
||||||
|
@ -367,25 +401,31 @@ class TestWarns:
|
||||||
with pytest.warns(UserWarning, match=r"must be \d+$"):
|
with pytest.warns(UserWarning, match=r"must be \d+$"):
|
||||||
warnings.warn("value must be 42", UserWarning)
|
warnings.warn("value must be 42", UserWarning)
|
||||||
|
|
||||||
with pytest.raises(pytest.fail.Exception):
|
with pytest.warns():
|
||||||
with pytest.warns(UserWarning, match=r"must be \d+$"):
|
with pytest.raises(pytest.fail.Exception):
|
||||||
warnings.warn("this is not here", UserWarning)
|
with pytest.warns(UserWarning, match=r"must be \d+$"):
|
||||||
|
warnings.warn("this is not here", UserWarning)
|
||||||
|
|
||||||
with pytest.raises(pytest.fail.Exception):
|
with pytest.warns():
|
||||||
with pytest.warns(FutureWarning, match=r"must be \d+$"):
|
with pytest.raises(pytest.fail.Exception):
|
||||||
warnings.warn("value must be 42", UserWarning)
|
with pytest.warns(FutureWarning, match=r"must be \d+$"):
|
||||||
|
warnings.warn("value must be 42", UserWarning)
|
||||||
|
|
||||||
def test_one_from_multiple_warns(self) -> None:
|
def test_one_from_multiple_warns(self) -> None:
|
||||||
with pytest.warns(UserWarning, match=r"aaa"):
|
with pytest.warns():
|
||||||
warnings.warn("cccccccccc", UserWarning)
|
with pytest.raises(pytest.fail.Exception, match="DID NOT WARN"):
|
||||||
warnings.warn("bbbbbbbbbb", UserWarning)
|
with pytest.warns(UserWarning, match=r"aaa"):
|
||||||
warnings.warn("aaaaaaaaaa", UserWarning)
|
with pytest.warns(UserWarning, match=r"aaa"):
|
||||||
|
warnings.warn("cccccccccc", UserWarning)
|
||||||
|
warnings.warn("bbbbbbbbbb", UserWarning)
|
||||||
|
warnings.warn("aaaaaaaaaa", UserWarning)
|
||||||
|
|
||||||
def test_none_of_multiple_warns(self) -> None:
|
def test_none_of_multiple_warns(self) -> None:
|
||||||
with pytest.raises(pytest.fail.Exception):
|
with pytest.warns():
|
||||||
with pytest.warns(UserWarning, match=r"aaa"):
|
with pytest.raises(pytest.fail.Exception, match="DID NOT WARN"):
|
||||||
warnings.warn("bbbbbbbbbb", UserWarning)
|
with pytest.warns(UserWarning, match=r"aaa"):
|
||||||
warnings.warn("cccccccccc", UserWarning)
|
warnings.warn("bbbbbbbbbb", UserWarning)
|
||||||
|
warnings.warn("cccccccccc", UserWarning)
|
||||||
|
|
||||||
@pytest.mark.filterwarnings("ignore")
|
@pytest.mark.filterwarnings("ignore")
|
||||||
def test_can_capture_previously_warned(self) -> None:
|
def test_can_capture_previously_warned(self) -> None:
|
||||||
|
@ -403,3 +443,45 @@ class TestWarns:
|
||||||
with pytest.warns(UserWarning, foo="bar"): # type: ignore
|
with pytest.warns(UserWarning, foo="bar"): # type: ignore
|
||||||
pass
|
pass
|
||||||
assert "Unexpected keyword arguments" in str(excinfo.value)
|
assert "Unexpected keyword arguments" in str(excinfo.value)
|
||||||
|
|
||||||
|
def test_re_emit_single(self) -> None:
|
||||||
|
with pytest.warns(DeprecationWarning):
|
||||||
|
with pytest.warns(UserWarning):
|
||||||
|
warnings.warn("user warning", UserWarning)
|
||||||
|
warnings.warn("some deprecation warning", DeprecationWarning)
|
||||||
|
|
||||||
|
def test_re_emit_multiple(self) -> None:
|
||||||
|
with pytest.warns(UserWarning):
|
||||||
|
warnings.warn("first warning", UserWarning)
|
||||||
|
warnings.warn("second warning", UserWarning)
|
||||||
|
|
||||||
|
def test_re_emit_match_single(self) -> None:
|
||||||
|
with pytest.warns(DeprecationWarning):
|
||||||
|
with pytest.warns(UserWarning, match="user warning"):
|
||||||
|
warnings.warn("user warning", UserWarning)
|
||||||
|
warnings.warn("some deprecation warning", DeprecationWarning)
|
||||||
|
|
||||||
|
def test_re_emit_match_multiple(self) -> None:
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter("error") # if anything is re-emitted
|
||||||
|
with pytest.warns(UserWarning, match="user warning"):
|
||||||
|
warnings.warn("first user warning", UserWarning)
|
||||||
|
warnings.warn("second user warning", UserWarning)
|
||||||
|
|
||||||
|
def test_re_emit_non_match_single(self) -> None:
|
||||||
|
with pytest.warns(UserWarning, match="v2 warning"):
|
||||||
|
with pytest.warns(UserWarning, match="v1 warning"):
|
||||||
|
warnings.warn("v1 warning", UserWarning)
|
||||||
|
warnings.warn("non-matching v2 warning", UserWarning)
|
||||||
|
|
||||||
|
def test_catch_warning_within_raise(self) -> None:
|
||||||
|
# warns-in-raises works since https://github.com/pytest-dev/pytest/pull/11129
|
||||||
|
with pytest.raises(ValueError, match="some exception"):
|
||||||
|
with pytest.warns(FutureWarning, match="some warning"):
|
||||||
|
warnings.warn("some warning", category=FutureWarning)
|
||||||
|
raise ValueError("some exception")
|
||||||
|
# and raises-in-warns has always worked but we'll check for symmetry.
|
||||||
|
with pytest.warns(FutureWarning, match="some warning"):
|
||||||
|
with pytest.raises(ValueError, match="some exception"):
|
||||||
|
warnings.warn("some warning", category=FutureWarning)
|
||||||
|
raise ValueError("some exception")
|
||||||
|
|
|
@ -542,10 +542,10 @@ def test_runtest_in_module_ordering(pytester: Pytester) -> None:
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mylist(self, request):
|
def mylist(self, request):
|
||||||
return request.function.mylist
|
return request.function.mylist
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_runtest_call(self, item):
|
def pytest_runtest_call(self, item):
|
||||||
try:
|
try:
|
||||||
(yield).get_result()
|
yield
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
def test_hello1(self, mylist):
|
def test_hello1(self, mylist):
|
||||||
|
@ -826,12 +826,12 @@ def test_unicode_in_longrepr(pytester: Pytester) -> None:
|
||||||
pytester.makeconftest(
|
pytester.makeconftest(
|
||||||
"""\
|
"""\
|
||||||
import pytest
|
import pytest
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_runtest_makereport():
|
def pytest_runtest_makereport():
|
||||||
outcome = yield
|
rep = yield
|
||||||
rep = outcome.get_result()
|
|
||||||
if rep.when == "call":
|
if rep.when == "call":
|
||||||
rep.longrepr = 'ä'
|
rep.longrepr = 'ä'
|
||||||
|
return rep
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
|
|
|
@ -1142,12 +1142,10 @@ def test_errors_in_xfail_skip_expressions(pytester: Pytester) -> None:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
result = pytester.runpytest()
|
result = pytester.runpytest()
|
||||||
markline = " ^"
|
markline = " ^"
|
||||||
pypy_version_info = getattr(sys, "pypy_version_info", None)
|
pypy_version_info = getattr(sys, "pypy_version_info", None)
|
||||||
if pypy_version_info is not None and pypy_version_info < (6,):
|
if pypy_version_info is not None and pypy_version_info < (6,):
|
||||||
markline = markline[5:]
|
markline = markline[1:]
|
||||||
elif sys.version_info >= (3, 8) or hasattr(sys, "pypy_version_info"):
|
|
||||||
markline = markline[4:]
|
|
||||||
|
|
||||||
if sys.version_info[:2] >= (3, 10):
|
if sys.version_info[:2] >= (3, 10):
|
||||||
expected = [
|
expected = [
|
||||||
|
|
|
@ -725,12 +725,12 @@ class TestTerminalFunctional:
|
||||||
)
|
)
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
|
|
||||||
def test_deselected_with_hookwrapper(self, pytester: Pytester) -> None:
|
def test_deselected_with_hook_wrapper(self, pytester: Pytester) -> None:
|
||||||
pytester.makeconftest(
|
pytester.makeconftest(
|
||||||
"""
|
"""
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_collection_modifyitems(config, items):
|
def pytest_collection_modifyitems(config, items):
|
||||||
yield
|
yield
|
||||||
deselected = items.pop()
|
deselected = items.pop()
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
import sys
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.pytester import Pytester
|
from _pytest.pytester import Pytester
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info < (3, 8):
|
|
||||||
pytest.skip("threadexception plugin needs Python>=3.8", allow_module_level=True)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.filterwarnings("default::pytest.PytestUnhandledThreadExceptionWarning")
|
@pytest.mark.filterwarnings("default::pytest.PytestUnhandledThreadExceptionWarning")
|
||||||
def test_unhandled_thread_exception(pytester: Pytester) -> None:
|
def test_unhandled_thread_exception(pytester: Pytester) -> None:
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
|
|
|
@ -952,7 +952,7 @@ def test_issue333_result_clearing(pytester: Pytester) -> None:
|
||||||
pytester.makeconftest(
|
pytester.makeconftest(
|
||||||
"""
|
"""
|
||||||
import pytest
|
import pytest
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(wrapper=True)
|
||||||
def pytest_runtest_call(item):
|
def pytest_runtest_call(item):
|
||||||
yield
|
yield
|
||||||
assert 0
|
assert 0
|
||||||
|
@ -1354,9 +1354,6 @@ def test_plain_unittest_does_not_support_async(pytester: Pytester) -> None:
|
||||||
result.stdout.fnmatch_lines(expected_lines)
|
result.stdout.fnmatch_lines(expected_lines)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info < (3, 8), reason="Feature introduced in Python 3.8"
|
|
||||||
)
|
|
||||||
def test_do_class_cleanups_on_success(pytester: Pytester) -> None:
|
def test_do_class_cleanups_on_success(pytester: Pytester) -> None:
|
||||||
testpath = pytester.makepyfile(
|
testpath = pytester.makepyfile(
|
||||||
"""
|
"""
|
||||||
|
@ -1382,9 +1379,6 @@ def test_do_class_cleanups_on_success(pytester: Pytester) -> None:
|
||||||
assert passed == 3
|
assert passed == 3
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info < (3, 8), reason="Feature introduced in Python 3.8"
|
|
||||||
)
|
|
||||||
def test_do_class_cleanups_on_setupclass_failure(pytester: Pytester) -> None:
|
def test_do_class_cleanups_on_setupclass_failure(pytester: Pytester) -> None:
|
||||||
testpath = pytester.makepyfile(
|
testpath = pytester.makepyfile(
|
||||||
"""
|
"""
|
||||||
|
@ -1409,9 +1403,6 @@ def test_do_class_cleanups_on_setupclass_failure(pytester: Pytester) -> None:
|
||||||
assert passed == 1
|
assert passed == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info < (3, 8), reason="Feature introduced in Python 3.8"
|
|
||||||
)
|
|
||||||
def test_do_class_cleanups_on_teardownclass_failure(pytester: Pytester) -> None:
|
def test_do_class_cleanups_on_teardownclass_failure(pytester: Pytester) -> None:
|
||||||
testpath = pytester.makepyfile(
|
testpath = pytester.makepyfile(
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -3,11 +3,10 @@ import sys
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.pytester import Pytester
|
from _pytest.pytester import Pytester
|
||||||
|
|
||||||
|
PYPY = hasattr(sys, "pypy_version_info")
|
||||||
if sys.version_info < (3, 8):
|
|
||||||
pytest.skip("unraisableexception plugin needs Python>=3.8", allow_module_level=True)
|
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(PYPY, reason="garbage-collection differences make this flaky")
|
||||||
@pytest.mark.filterwarnings("default::pytest.PytestUnraisableExceptionWarning")
|
@pytest.mark.filterwarnings("default::pytest.PytestUnraisableExceptionWarning")
|
||||||
def test_unraisable(pytester: Pytester) -> None:
|
def test_unraisable(pytester: Pytester) -> None:
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
|
@ -40,6 +39,7 @@ def test_unraisable(pytester: Pytester) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(PYPY, reason="garbage-collection differences make this flaky")
|
||||||
@pytest.mark.filterwarnings("default::pytest.PytestUnraisableExceptionWarning")
|
@pytest.mark.filterwarnings("default::pytest.PytestUnraisableExceptionWarning")
|
||||||
def test_unraisable_in_setup(pytester: Pytester) -> None:
|
def test_unraisable_in_setup(pytester: Pytester) -> None:
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
|
@ -76,6 +76,7 @@ def test_unraisable_in_setup(pytester: Pytester) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(PYPY, reason="garbage-collection differences make this flaky")
|
||||||
@pytest.mark.filterwarnings("default::pytest.PytestUnraisableExceptionWarning")
|
@pytest.mark.filterwarnings("default::pytest.PytestUnraisableExceptionWarning")
|
||||||
def test_unraisable_in_teardown(pytester: Pytester) -> None:
|
def test_unraisable_in_teardown(pytester: Pytester) -> None:
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
|
@ -116,7 +117,7 @@ def test_unraisable_in_teardown(pytester: Pytester) -> None:
|
||||||
@pytest.mark.filterwarnings("error::pytest.PytestUnraisableExceptionWarning")
|
@pytest.mark.filterwarnings("error::pytest.PytestUnraisableExceptionWarning")
|
||||||
def test_unraisable_warning_error(pytester: Pytester) -> None:
|
def test_unraisable_warning_error(pytester: Pytester) -> None:
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
test_it="""
|
test_it=f"""
|
||||||
class BrokenDel:
|
class BrokenDel:
|
||||||
def __del__(self) -> None:
|
def __del__(self) -> None:
|
||||||
raise ValueError("del is broken")
|
raise ValueError("del is broken")
|
||||||
|
@ -124,6 +125,7 @@ def test_unraisable_warning_error(pytester: Pytester) -> None:
|
||||||
def test_it() -> None:
|
def test_it() -> None:
|
||||||
obj = BrokenDel()
|
obj = BrokenDel()
|
||||||
del obj
|
del obj
|
||||||
|
{"import gc; gc.collect()" * PYPY}
|
||||||
|
|
||||||
def test_2(): pass
|
def test_2(): pass
|
||||||
"""
|
"""
|
||||||
|
|
21
tox.ini
21
tox.ini
|
@ -4,17 +4,16 @@ minversion = 3.20.0
|
||||||
distshare = {homedir}/.tox/distshare
|
distshare = {homedir}/.tox/distshare
|
||||||
envlist =
|
envlist =
|
||||||
linting
|
linting
|
||||||
py37
|
|
||||||
py38
|
py38
|
||||||
py39
|
py39
|
||||||
py310
|
py310
|
||||||
py311
|
py311
|
||||||
py312
|
py312
|
||||||
pypy3
|
pypy3
|
||||||
py37-{pexpect,xdist,unittestextras,numpy,pluggymain,pylib}
|
py38-{pexpect,xdist,unittestextras,numpy,pluggymain,pylib}
|
||||||
doctesting
|
doctesting
|
||||||
plugins
|
plugins
|
||||||
py37-freeze
|
py38-freeze
|
||||||
docs
|
docs
|
||||||
docs-checklinks
|
docs-checklinks
|
||||||
|
|
||||||
|
@ -43,7 +42,7 @@ setenv =
|
||||||
PYTHONWARNDEFAULTENCODING=1
|
PYTHONWARNDEFAULTENCODING=1
|
||||||
|
|
||||||
# Configuration to run with coverage similar to CI, e.g.
|
# Configuration to run with coverage similar to CI, e.g.
|
||||||
# "tox -e py37-coverage".
|
# "tox -e py38-coverage".
|
||||||
coverage: _PYTEST_TOX_COVERAGE_RUN=coverage run -m
|
coverage: _PYTEST_TOX_COVERAGE_RUN=coverage run -m
|
||||||
coverage: _PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess
|
coverage: _PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess
|
||||||
coverage: COVERAGE_FILE={toxinidir}/.coverage
|
coverage: COVERAGE_FILE={toxinidir}/.coverage
|
||||||
|
@ -75,6 +74,9 @@ skip_install = True
|
||||||
basepython = python3
|
basepython = python3
|
||||||
deps = pre-commit>=2.9.3
|
deps = pre-commit>=2.9.3
|
||||||
commands = pre-commit run --all-files --show-diff-on-failure {posargs:}
|
commands = pre-commit run --all-files --show-diff-on-failure {posargs:}
|
||||||
|
setenv =
|
||||||
|
# pre-commit and tools it launches are not clean of this warning.
|
||||||
|
PYTHONWARNDEFAULTENCODING=
|
||||||
|
|
||||||
[testenv:docs]
|
[testenv:docs]
|
||||||
basepython = python3
|
basepython = python3
|
||||||
|
@ -89,6 +91,9 @@ commands =
|
||||||
# changelog in the docs; this does not happen on ReadTheDocs because it uses
|
# changelog in the docs; this does not happen on ReadTheDocs because it uses
|
||||||
# the standard sphinx command so the 'changelog_towncrier_draft' is never set there
|
# the standard sphinx command so the 'changelog_towncrier_draft' is never set there
|
||||||
sphinx-build -W --keep-going -b html doc/en doc/en/_build/html -t changelog_towncrier_draft {posargs:}
|
sphinx-build -W --keep-going -b html doc/en doc/en/_build/html -t changelog_towncrier_draft {posargs:}
|
||||||
|
setenv =
|
||||||
|
# Sphinx is not clean of this warning.
|
||||||
|
PYTHONWARNDEFAULTENCODING=
|
||||||
|
|
||||||
[testenv:docs-checklinks]
|
[testenv:docs-checklinks]
|
||||||
basepython = python3
|
basepython = python3
|
||||||
|
@ -97,6 +102,9 @@ changedir = doc/en
|
||||||
deps = -r{toxinidir}/doc/en/requirements.txt
|
deps = -r{toxinidir}/doc/en/requirements.txt
|
||||||
commands =
|
commands =
|
||||||
sphinx-build -W -q --keep-going -b linkcheck . _build
|
sphinx-build -W -q --keep-going -b linkcheck . _build
|
||||||
|
setenv =
|
||||||
|
# Sphinx is not clean of this warning.
|
||||||
|
PYTHONWARNDEFAULTENCODING=
|
||||||
|
|
||||||
[testenv:regen]
|
[testenv:regen]
|
||||||
changedir = doc/en
|
changedir = doc/en
|
||||||
|
@ -111,6 +119,9 @@ allowlist_externals =
|
||||||
make
|
make
|
||||||
commands =
|
commands =
|
||||||
make regen
|
make regen
|
||||||
|
setenv =
|
||||||
|
# We don't want this warning to reach regen output.
|
||||||
|
PYTHONWARNDEFAULTENCODING=
|
||||||
|
|
||||||
[testenv:plugins]
|
[testenv:plugins]
|
||||||
# use latest versions of all plugins, including pre-releases
|
# use latest versions of all plugins, including pre-releases
|
||||||
|
@ -136,7 +147,7 @@ commands =
|
||||||
pytest pytest_twisted_integration.py
|
pytest pytest_twisted_integration.py
|
||||||
pytest simple_integration.py --force-sugar --flakes
|
pytest simple_integration.py --force-sugar --flakes
|
||||||
|
|
||||||
[testenv:py37-freeze]
|
[testenv:py38-freeze]
|
||||||
changedir = testing/freeze
|
changedir = testing/freeze
|
||||||
deps =
|
deps =
|
||||||
pyinstaller
|
pyinstaller
|
||||||
|
|
Loading…
Reference in New Issue