Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bf3bcb2bf1 |
@@ -1,23 +1,26 @@
|
||||
name: deploy
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Release version'
|
||||
required: true
|
||||
default: '1.2.3'
|
||||
push:
|
||||
tags:
|
||||
# These tags are protected, see:
|
||||
# https://github.com/pytest-dev/pytest/settings/tag_protection
|
||||
- "[0-9]+.[0-9]+.[0-9]+"
|
||||
- "[0-9]+.[0-9]+.[0-9]+rc[0-9]+"
|
||||
|
||||
|
||||
# Set permissions at the job level.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
package:
|
||||
|
||||
deploy:
|
||||
if: github.repository == 'pytest-dev/pytest'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SETUPTOOLS_SCM_PRETEND_VERSION: ${{ github.event.inputs.version }}
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -28,16 +31,6 @@ jobs:
|
||||
- name: Build and Check Package
|
||||
uses: hynek/build-and-inspect-python-package@v1.5
|
||||
|
||||
deploy:
|
||||
if: github.repository == 'pytest-dev/pytest'
|
||||
needs: [package]
|
||||
runs-on: ubuntu-latest
|
||||
environment: deploy
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Download Package
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
@@ -45,35 +38,14 @@ jobs:
|
||||
path: dist
|
||||
|
||||
- name: Publish package to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@v1.8.5
|
||||
|
||||
- name: Push tag
|
||||
run: |
|
||||
git config user.name "pytest bot"
|
||||
git config user.email "pytestbot@gmail.com"
|
||||
git tag --annotate --message=v${{ github.event.inputs.version }} v${{ github.event.inputs.version }} ${{ github.sha }}
|
||||
git push origin v${{ github.event.inputs.version }}
|
||||
|
||||
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
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
password: ${{ secrets.pypi_token }}
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.10"
|
||||
python-version: "3.7"
|
||||
|
||||
- name: Install tox
|
||||
run: |
|
||||
|
||||
+24
-32
@@ -27,19 +27,7 @@ concurrency:
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
package:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- name: Build and Check Package
|
||||
uses: hynek/build-and-inspect-python-package@v1.5
|
||||
|
||||
build:
|
||||
needs: [package]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
@@ -50,17 +38,17 @@ jobs:
|
||||
matrix:
|
||||
name: [
|
||||
"windows-py37",
|
||||
"windows-py37-pluggy",
|
||||
"windows-py38",
|
||||
"windows-py38-pluggy",
|
||||
"windows-py39",
|
||||
"windows-py310",
|
||||
"windows-py311",
|
||||
"windows-py312",
|
||||
|
||||
"ubuntu-py37",
|
||||
"ubuntu-py37-pluggy",
|
||||
"ubuntu-py37-freeze",
|
||||
"ubuntu-py38",
|
||||
"ubuntu-py38-pluggy",
|
||||
"ubuntu-py39",
|
||||
"ubuntu-py310",
|
||||
"ubuntu-py311",
|
||||
@@ -72,6 +60,7 @@ jobs:
|
||||
"macos-py310",
|
||||
"macos-py312",
|
||||
|
||||
"docs",
|
||||
"doctesting",
|
||||
"plugins",
|
||||
]
|
||||
@@ -81,15 +70,15 @@ jobs:
|
||||
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"
|
||||
python: "3.8"
|
||||
os: windows-latest
|
||||
tox_env: "py38-unittestextras"
|
||||
use_coverage: true
|
||||
- name: "windows-py38-pluggy"
|
||||
python: "3.8"
|
||||
os: windows-latest
|
||||
tox_env: "py38-pluggymain-pylib-xdist"
|
||||
- name: "windows-py39"
|
||||
python: "3.9"
|
||||
os: windows-latest
|
||||
@@ -112,6 +101,10 @@ jobs:
|
||||
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
|
||||
@@ -120,10 +113,6 @@ jobs:
|
||||
python: "3.8"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py38-xdist"
|
||||
- name: "ubuntu-py38-pluggy"
|
||||
python: "3.8"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py38-pluggymain-pylib-xdist"
|
||||
- name: "ubuntu-py39"
|
||||
python: "3.9"
|
||||
os: ubuntu-latest
|
||||
@@ -170,6 +159,10 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
tox_env: "plugins"
|
||||
|
||||
- name: "docs"
|
||||
python: "3.7"
|
||||
os: ubuntu-latest
|
||||
tox_env: "docs"
|
||||
- name: "doctesting"
|
||||
python: "3.7"
|
||||
os: ubuntu-latest
|
||||
@@ -182,12 +175,6 @@ jobs:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Download Package
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: Packages
|
||||
path: dist
|
||||
|
||||
- name: Set up Python ${{ matrix.python }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
@@ -201,13 +188,11 @@ jobs:
|
||||
|
||||
- name: Test without coverage
|
||||
if: "! matrix.use_coverage"
|
||||
shell: bash
|
||||
run: tox run -e ${{ matrix.tox_env }} --installpkg `find dist/*.tar.gz`
|
||||
run: "tox -e ${{ matrix.tox_env }}"
|
||||
|
||||
- name: Test with coverage
|
||||
if: "matrix.use_coverage"
|
||||
shell: bash
|
||||
run: tox run -e ${{ matrix.tox_env }}-coverage --installpkg `find dist/*.tar.gz`
|
||||
run: "tox -e ${{ matrix.tox_env }}-coverage"
|
||||
|
||||
- name: Generate coverage report
|
||||
if: "matrix.use_coverage"
|
||||
@@ -221,3 +206,10 @@ jobs:
|
||||
fail_ci_if_error: true
|
||||
files: ./coverage.xml
|
||||
verbose: true
|
||||
|
||||
check-package:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build and Check Package
|
||||
uses: hynek/build-and-inspect-python-package@v1.5
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
run: python scripts/update-plugin-list.py
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38
|
||||
uses: peter-evans/create-pull-request@5b4a9f6a9e2af26e5f02351490b90d01eb8ec1e5
|
||||
with:
|
||||
commit-message: '[automated] Update plugin list'
|
||||
author: 'pytest bot <pytestbot@users.noreply.github.com>'
|
||||
|
||||
@@ -5,7 +5,7 @@ repos:
|
||||
- id: black
|
||||
args: [--safe, --quiet]
|
||||
- repo: https://github.com/asottile/blacken-docs
|
||||
rev: 1.14.0
|
||||
rev: 1.13.0
|
||||
hooks:
|
||||
- id: blacken-docs
|
||||
additional_dependencies: [black==23.1.0]
|
||||
@@ -37,12 +37,12 @@ repos:
|
||||
- flake8-typing-imports==1.12.0
|
||||
- flake8-docstrings==1.5.0
|
||||
- repo: https://github.com/asottile/reorder-python-imports
|
||||
rev: v3.10.0
|
||||
rev: v3.9.0
|
||||
hooks:
|
||||
- id: reorder-python-imports
|
||||
args: ['--application-directories=.:src', --py37-plus]
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.7.0
|
||||
rev: v3.4.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py37-plus]
|
||||
|
||||
@@ -166,8 +166,6 @@ Ian Bicking
|
||||
Ian Lesperance
|
||||
Ilya Konstantinov
|
||||
Ionuț Turturică
|
||||
Isaac Virshup
|
||||
Israel Fruchter
|
||||
Itxaso Aizpurua
|
||||
Iwan Briquemont
|
||||
Jaap Broekhuizen
|
||||
@@ -341,7 +339,6 @@ Simon Holesch
|
||||
Simon Kerr
|
||||
Skylar Downes
|
||||
Srinivas Reddy Thatiparthy
|
||||
Stefaan Lippens
|
||||
Stefan Farmbauer
|
||||
Stefan Scherfke
|
||||
Stefan Zimmermann
|
||||
@@ -374,14 +371,12 @@ Tony Narlock
|
||||
Tor Colvin
|
||||
Trevor Bekolay
|
||||
Tyler Goodlet
|
||||
Tyler Smart
|
||||
Tzu-ping Chung
|
||||
Vasily Kuznetsov
|
||||
Victor Maryama
|
||||
Victor Rodriguez
|
||||
Victor Uriarte
|
||||
Vidar T. Fauske
|
||||
Vijay Arora
|
||||
Virgil Dupras
|
||||
Vitaly Lashmanov
|
||||
Vivaan Verma
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ Fix bugs
|
||||
--------
|
||||
|
||||
Look through the `GitHub issues for bugs <https://github.com/pytest-dev/pytest/labels/type:%20bug>`_.
|
||||
See also the `"good first issue" issues <https://github.com/pytest-dev/pytest/labels/good%20first%20issue>`_
|
||||
See also the `"status: easy" issues <https://github.com/pytest-dev/pytest/labels/status%3A%20easy>`_
|
||||
that are friendly to new contributors.
|
||||
|
||||
:ref:`Talk <contact>` to developers to find out how you can fix specific bugs. To indicate that you are going
|
||||
|
||||
+7
-4
@@ -133,11 +133,14 @@ Releasing
|
||||
|
||||
Both automatic and manual processes described above follow the same steps from this point onward.
|
||||
|
||||
#. After all tests pass and the PR has been approved, trigger the ``deploy`` job
|
||||
in https://github.com/pytest-dev/pytest/actions/workflows/deploy.yml.
|
||||
#. After all tests pass and the PR has been approved, tag the release commit
|
||||
in the ``release-MAJOR.MINOR.PATCH`` branch and push it. This will publish to PyPI::
|
||||
|
||||
This job will require approval from ``pytest-dev/core``, after which it will publish to PyPI
|
||||
and tag the repository.
|
||||
git fetch upstream
|
||||
git tag MAJOR.MINOR.PATCH upstream/release-MAJOR.MINOR.PATCH
|
||||
git push upstream MAJOR.MINOR.PATCH
|
||||
|
||||
Wait for the deploy to complete, then make sure it is `available on PyPI <https://pypi.org/project/pytest>`_.
|
||||
|
||||
#. Merge the PR. **Make sure it's not squash-merged**, so that the tagged commit ends up in the main branch.
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Terminal Reporting: Fixed bug when running in ``--tb=line`` mode where ``pytest.fail(pytrace=False)`` tests report ``None``.
|
||||
@@ -0,0 +1 @@
|
||||
Update test log report annotation to named tuple and fixed inconsistency in docs for :hook:`pytest_report_teststatus` hook.
|
||||
@@ -0,0 +1,2 @@
|
||||
Added :func:`ExceptionInfo.from_exception() <pytest.ExceptionInfo.from_exception>`, a simpler way to create an :class:`~pytest.ExceptionInfo` from an exception.
|
||||
This can replace :func:`ExceptionInfo.from_exc_info() <pytest.ExceptionInfo.from_exc_info()>` for most uses.
|
||||
@@ -0,0 +1,5 @@
|
||||
When an exception traceback to be displayed is completely filtered out (by mechanisms such as ``__tracebackhide__``, internal frames, and similar), now only the exception string and the following message are shown:
|
||||
|
||||
"All traceback entries are hidden. Pass `--full-trace` to see hidden and internal frames.".
|
||||
|
||||
Previously, the last frame of the traceback was shown, even though it was hidden.
|
||||
@@ -0,0 +1,3 @@
|
||||
Improved verbose output (``-vv``) of ``skip`` and ``xfail`` reasons by performing text wrapping while leaving a clear margin for progress output.
|
||||
|
||||
Added :func:`TerminalReporter.wrap_write() <pytest.TerminalReporter.wrap_write>` as a helper for that.
|
||||
@@ -0,0 +1 @@
|
||||
Added handling of ``%f`` directive to print microseconds in log format options, such as ``log-date-format``.
|
||||
@@ -0,0 +1 @@
|
||||
Added underlying exception to cache provider path creation and write warning messages.
|
||||
@@ -0,0 +1 @@
|
||||
Added warning when :confval:`testpaths` is set, but paths are not found by glob. In this case, pytest will fall back to searching from the current directory.
|
||||
@@ -0,0 +1 @@
|
||||
Enhanced the CLI flag for ``-c`` to now include ``--config-file`` to make it clear that this flag applies to the usage of a custom config file.
|
||||
@@ -0,0 +1,3 @@
|
||||
When `--confcutdir` is not specified, and there is no config file present, the conftest cutoff directory (`--confcutdir`) is now set to the :ref:`rootdir`.
|
||||
Previously in such cases, `conftest.py` files would be probed all the way to the root directory of the filesystem.
|
||||
If you are badly affected by this change, consider adding an empty config file to your desired cutoff directory, or explicitly set `--confcutdir`.
|
||||
@@ -0,0 +1 @@
|
||||
Fixed the ``--last-failed`` whole-file skipping functionality ("skipped N files") for :ref:`non-python test files <non-python tests>`.
|
||||
@@ -0,0 +1,7 @@
|
||||
The :confval:`norecursedir` check is now performed in a :hook:`pytest_ignore_collect` implementation, so plugins can affect it.
|
||||
|
||||
If after updating to this version you see that your `norecursedir` setting is not being respected,
|
||||
it means that a conftest or a plugin you use has a bad `pytest_ignore_collect` implementation.
|
||||
Most likely, your hook returns `False` for paths it does not want to ignore,
|
||||
which ends the processing and doesn't allow other plugins, including pytest itself, to ignore the path.
|
||||
The fix is to return `None` instead of `False` for paths your hook doesn't want to ignore.
|
||||
@@ -0,0 +1 @@
|
||||
Fixed traceback entries hidden with ``__tracebackhide__ = True`` still being shown for chained exceptions (parts after "... the above exception ..." message).
|
||||
@@ -0,0 +1,3 @@
|
||||
:func:`_pytest.logging.LogCaptureFixture.set_level` and :func:`_pytest.logging.LogCaptureFixture.at_level`
|
||||
will temporarily enable the requested ``level`` if ``level`` was disabled globally via
|
||||
``logging.disable(LEVEL)``.
|
||||
@@ -6,9 +6,6 @@ Release announcements
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
release-7.4.2
|
||||
release-7.4.1
|
||||
release-7.4.0
|
||||
release-7.3.2
|
||||
release-7.3.1
|
||||
release-7.3.0
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
pytest-7.4.0
|
||||
=======================================
|
||||
|
||||
The pytest team is proud to announce the 7.4.0 release!
|
||||
|
||||
This release contains new features, improvements, and bug fixes,
|
||||
the full list of changes is available in the changelog:
|
||||
|
||||
https://docs.pytest.org/en/stable/changelog.html
|
||||
|
||||
For complete documentation, please visit:
|
||||
|
||||
https://docs.pytest.org/en/stable/
|
||||
|
||||
As usual, you can upgrade from PyPI via:
|
||||
|
||||
pip install -U pytest
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Adam J. Stewart
|
||||
* Alessio Izzo
|
||||
* Alex
|
||||
* Alex Lambson
|
||||
* Brian Larsen
|
||||
* Bruno Oliveira
|
||||
* Bryan Ricker
|
||||
* Chris Mahoney
|
||||
* Facundo Batista
|
||||
* Florian Bruhin
|
||||
* Jarrett Keifer
|
||||
* Kenny Y
|
||||
* Miro Hrončok
|
||||
* Ran Benita
|
||||
* Roberto Aldera
|
||||
* Ronny Pfannschmidt
|
||||
* Sergey Kim
|
||||
* Stefanie Molin
|
||||
* Vijay Arora
|
||||
* Ville Skyttä
|
||||
* Zac Hatfield-Dodds
|
||||
* bzoracler
|
||||
* leeyueh
|
||||
* nondescryptid
|
||||
* theirix
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -1,20 +0,0 @@
|
||||
pytest-7.4.1
|
||||
=======================================
|
||||
|
||||
pytest 7.4.1 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Bruno Oliveira
|
||||
* Florian Bruhin
|
||||
* Ran Benita
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -1,18 +0,0 @@
|
||||
pytest-7.4.2
|
||||
=======================================
|
||||
|
||||
pytest 7.4.2 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Bruno Oliveira
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
+4
-4
@@ -22,7 +22,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
cachedir: .pytest_cache
|
||||
rootdir: /home/sweet/project
|
||||
collected 0 items
|
||||
cache -- .../_pytest/cacheprovider.py:532
|
||||
cache -- .../_pytest/cacheprovider.py:510
|
||||
Return a cache object that can persist state between testing sessions.
|
||||
|
||||
cache.get(key, default)
|
||||
@@ -105,7 +105,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == "hello\n"
|
||||
|
||||
doctest_namespace [session scope] -- .../_pytest/doctest.py:757
|
||||
doctest_namespace [session scope] -- .../_pytest/doctest.py:737
|
||||
Fixture that returns a :py:class:`dict` that will be injected into the
|
||||
namespace of doctests.
|
||||
|
||||
@@ -119,7 +119,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
|
||||
For more details: :ref:`doctest_namespace`.
|
||||
|
||||
pytestconfig [session scope] -- .../_pytest/fixtures.py:1353
|
||||
pytestconfig [session scope] -- .../_pytest/fixtures.py:1360
|
||||
Session-scoped fixture that returns the session's :class:`pytest.Config`
|
||||
object.
|
||||
|
||||
@@ -196,7 +196,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||
|
||||
.. _legacy_path: https://py.readthedocs.io/en/latest/path.html
|
||||
|
||||
caplog -- .../_pytest/logging.py:570
|
||||
caplog -- .../_pytest/logging.py:498
|
||||
Access and control log capturing.
|
||||
|
||||
Captured logs are available through the following properties/methods::
|
||||
|
||||
@@ -28,140 +28,6 @@ with advance notice in the **Deprecations** section of releases.
|
||||
|
||||
.. towncrier release notes start
|
||||
|
||||
pytest 7.4.2 (2023-09-07)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#11237 <https://github.com/pytest-dev/pytest/issues/11237>`_: Fix doctest collection of `functools.cached_property` objects.
|
||||
|
||||
|
||||
- `#11306 <https://github.com/pytest-dev/pytest/issues/11306>`_: Fixed bug using ``--importmode=importlib`` which would cause package ``__init__.py`` files to be imported more than once in some cases.
|
||||
|
||||
|
||||
- `#11367 <https://github.com/pytest-dev/pytest/issues/11367>`_: Fixed bug where `user_properties` where not being saved in the JUnit XML file if a fixture failed during teardown.
|
||||
|
||||
|
||||
- `#11394 <https://github.com/pytest-dev/pytest/issues/11394>`_: Fixed crash when parsing long command line arguments that might be interpreted as files.
|
||||
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- `#11391 <https://github.com/pytest-dev/pytest/issues/11391>`_: Improved disclaimer on pytest plugin reference page to better indicate this is an automated, non-curated listing.
|
||||
|
||||
|
||||
pytest 7.4.1 (2023-09-02)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#10337 <https://github.com/pytest-dev/pytest/issues/10337>`_: Fixed bug where fake intermediate modules generated by ``--import-mode=importlib`` would not include the
|
||||
child modules as attributes of the parent modules.
|
||||
|
||||
|
||||
- `#10702 <https://github.com/pytest-dev/pytest/issues/10702>`_: Fixed error assertion handling in :func:`pytest.approx` when ``None`` is an expected or received value when comparing dictionaries.
|
||||
|
||||
|
||||
- `#10811 <https://github.com/pytest-dev/pytest/issues/10811>`_: 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.
|
||||
|
||||
|
||||
pytest 7.4.0 (2023-06-23)
|
||||
=========================
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- `#10901 <https://github.com/pytest-dev/pytest/issues/10901>`_: Added :func:`ExceptionInfo.from_exception() <pytest.ExceptionInfo.from_exception>`, a simpler way to create an :class:`~pytest.ExceptionInfo` from an exception.
|
||||
This can replace :func:`ExceptionInfo.from_exc_info() <pytest.ExceptionInfo.from_exc_info()>` for most uses.
|
||||
|
||||
|
||||
|
||||
Improvements
|
||||
------------
|
||||
|
||||
- `#10872 <https://github.com/pytest-dev/pytest/issues/10872>`_: Update test log report annotation to named tuple and fixed inconsistency in docs for :hook:`pytest_report_teststatus` hook.
|
||||
|
||||
|
||||
- `#10907 <https://github.com/pytest-dev/pytest/issues/10907>`_: When an exception traceback to be displayed is completely filtered out (by mechanisms such as ``__tracebackhide__``, internal frames, and similar), now only the exception string and the following message are shown:
|
||||
|
||||
"All traceback entries are hidden. Pass `--full-trace` to see hidden and internal frames.".
|
||||
|
||||
Previously, the last frame of the traceback was shown, even though it was hidden.
|
||||
|
||||
|
||||
- `#10940 <https://github.com/pytest-dev/pytest/issues/10940>`_: Improved verbose output (``-vv``) of ``skip`` and ``xfail`` reasons by performing text wrapping while leaving a clear margin for progress output.
|
||||
|
||||
Added ``TerminalReporter.wrap_write()`` as a helper for that.
|
||||
|
||||
|
||||
- `#10991 <https://github.com/pytest-dev/pytest/issues/10991>`_: Added handling of ``%f`` directive to print microseconds in log format options, such as ``log-date-format``.
|
||||
|
||||
|
||||
- `#11005 <https://github.com/pytest-dev/pytest/issues/11005>`_: Added the underlying exception to the cache provider's path creation and write warning messages.
|
||||
|
||||
|
||||
- `#11013 <https://github.com/pytest-dev/pytest/issues/11013>`_: Added warning when :confval:`testpaths` is set, but paths are not found by glob. In this case, pytest will fall back to searching from the current directory.
|
||||
|
||||
|
||||
- `#11043 <https://github.com/pytest-dev/pytest/issues/11043>`_: When `--confcutdir` is not specified, and there is no config file present, the conftest cutoff directory (`--confcutdir`) is now set to the :ref:`rootdir <rootdir>`.
|
||||
Previously in such cases, `conftest.py` files would be probed all the way to the root directory of the filesystem.
|
||||
If you are badly affected by this change, consider adding an empty config file to your desired cutoff directory, or explicitly set `--confcutdir`.
|
||||
|
||||
|
||||
- `#11081 <https://github.com/pytest-dev/pytest/issues/11081>`_: The :confval:`norecursedirs` check is now performed in a :hook:`pytest_ignore_collect` implementation, so plugins can affect it.
|
||||
|
||||
If after updating to this version you see that your `norecursedirs` setting is not being respected,
|
||||
it means that a conftest or a plugin you use has a bad `pytest_ignore_collect` implementation.
|
||||
Most likely, your hook returns `False` for paths it does not want to ignore,
|
||||
which ends the processing and doesn't allow other plugins, including pytest itself, to ignore the path.
|
||||
The fix is to return `None` instead of `False` for paths your hook doesn't want to ignore.
|
||||
|
||||
|
||||
- `#8711 <https://github.com/pytest-dev/pytest/issues/8711>`_: :func:`caplog.set_level() <pytest.LogCaptureFixture.set_level>` and :func:`caplog.at_level() <pytest.LogCaptureFixture.at_level>`
|
||||
will temporarily enable the requested ``level`` if ``level`` was disabled globally via
|
||||
``logging.disable(LEVEL)``.
|
||||
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#10831 <https://github.com/pytest-dev/pytest/issues/10831>`_: Terminal Reporting: Fixed bug when running in ``--tb=line`` mode where ``pytest.fail(pytrace=False)`` tests report ``None``.
|
||||
|
||||
|
||||
- `#11068 <https://github.com/pytest-dev/pytest/issues/11068>`_: Fixed the ``--last-failed`` whole-file skipping functionality ("skipped N files") for :ref:`non-python test files <non-python tests>`.
|
||||
|
||||
|
||||
- `#11104 <https://github.com/pytest-dev/pytest/issues/11104>`_: Fixed a regression in pytest 7.3.2 which caused to :confval:`testpaths` to be considered for loading initial conftests,
|
||||
even when it was not utilized (e.g. when explicit paths were given on the command line).
|
||||
Now the ``testpaths`` are only considered when they are in use.
|
||||
|
||||
|
||||
- `#1904 <https://github.com/pytest-dev/pytest/issues/1904>`_: Fixed traceback entries hidden with ``__tracebackhide__ = True`` still being shown for chained exceptions (parts after "... the above exception ..." message).
|
||||
|
||||
|
||||
- `#7781 <https://github.com/pytest-dev/pytest/issues/7781>`_: Fix writing non-encodable text to log file when using ``--debug``.
|
||||
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- `#9146 <https://github.com/pytest-dev/pytest/issues/9146>`_: Improved documentation for :func:`caplog.set_level() <pytest.LogCaptureFixture.set_level>`.
|
||||
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- `#11031 <https://github.com/pytest-dev/pytest/issues/11031>`_: Enhanced the CLI flag for ``-c`` to now include ``--config-file`` to make it clear that this flag applies to the usage of a custom config file.
|
||||
|
||||
|
||||
pytest 7.3.2 (2023-06-10)
|
||||
=========================
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ class YamlFile(pytest.File):
|
||||
# We need a yaml parser, e.g. PyYAML.
|
||||
import yaml
|
||||
|
||||
raw = yaml.safe_load(self.path.open(encoding="utf-8"))
|
||||
raw = yaml.safe_load(self.path.open())
|
||||
for name, spec in sorted(raw.items()):
|
||||
yield YamlItem.from_parent(self, name=name, spec=spec)
|
||||
|
||||
|
||||
@@ -817,7 +817,7 @@ case we just write some information out to a ``failures`` file:
|
||||
# we only look at actual failing test calls, not setup/teardown
|
||||
if rep.when == "call" and rep.failed:
|
||||
mode = "a" if os.path.exists("failures") else "w"
|
||||
with open("failures", mode, encoding="utf-8") as f:
|
||||
with open("failures", mode) as f:
|
||||
# let's also access a fixture for the fun of it
|
||||
if "tmp_path" in item.fixturenames:
|
||||
extra = " ({})".format(item.funcargs["tmp_path"])
|
||||
|
||||
@@ -22,7 +22,7 @@ Install ``pytest``
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest --version
|
||||
pytest 7.4.2
|
||||
pytest 7.3.2
|
||||
|
||||
.. _`simpletest`:
|
||||
|
||||
|
||||
@@ -54,13 +54,14 @@ operators. (See :ref:`tbreportdemo`). This allows you to use the
|
||||
idiomatic python constructs without boilerplate code while not losing
|
||||
introspection information.
|
||||
|
||||
If a message is specified with the assertion like this:
|
||||
However, if you specify a message with the assertion like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
assert a % 2 == 0, "value was odd, should be even"
|
||||
|
||||
it is printed alongside the assertion introspection in the traceback.
|
||||
then no assertion introspection takes places at all and the message
|
||||
will be simply shown in the traceback.
|
||||
|
||||
See :ref:`assert-details` for more information on assertion introspection.
|
||||
|
||||
|
||||
+5
-12
@@ -176,21 +176,14 @@ with more recent files coming first.
|
||||
Behavior when no tests failed in the last run
|
||||
---------------------------------------------
|
||||
|
||||
The ``--lfnf/--last-failed-no-failures`` option governs the behavior of ``--last-failed``.
|
||||
Determines whether to execute tests when there are no previously (known)
|
||||
failures or when no cached ``lastfailed`` data was found.
|
||||
|
||||
There are two options:
|
||||
|
||||
* ``all``: when there are no known test failures, runs all tests (the full test suite). This is the default.
|
||||
* ``none``: when there are no known test failures, just emits a message stating this and exit successfully.
|
||||
|
||||
Example:
|
||||
When no tests failed in the last run, or when no cached ``lastfailed`` data was
|
||||
found, ``pytest`` can be configured either to run all of the tests or no tests,
|
||||
using the ``--last-failed-no-failures`` option, which takes one of the following values:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pytest --last-failed --last-failed-no-failures all # runs the full test suite (default behavior)
|
||||
pytest --last-failed --last-failed-no-failures none # runs no tests and exits successfully
|
||||
pytest --last-failed --last-failed-no-failures all # run all tests (default behavior)
|
||||
pytest --last-failed --last-failed-no-failures none # run no tests and exit
|
||||
|
||||
The new config.cache object
|
||||
--------------------------------
|
||||
|
||||
@@ -1698,7 +1698,7 @@ and declare its use in a test module via a ``usefixtures`` marker:
|
||||
class TestDirectoryInit:
|
||||
def test_cwd_starts_empty(self):
|
||||
assert os.listdir(os.getcwd()) == []
|
||||
with open("myfile", "w", encoding="utf-8") as f:
|
||||
with open("myfile", "w") as f:
|
||||
f.write("hello")
|
||||
|
||||
def test_cwd_again_starts_empty(self):
|
||||
|
||||
@@ -24,8 +24,8 @@ created in the `base temporary directory`_.
|
||||
d = tmp_path / "sub"
|
||||
d.mkdir()
|
||||
p = d / "hello.txt"
|
||||
p.write_text(CONTENT, encoding="utf-8")
|
||||
assert p.read_text(encoding="utf-8") == CONTENT
|
||||
p.write_text(CONTENT)
|
||||
assert p.read_text() == CONTENT
|
||||
assert len(list(tmp_path.iterdir())) == 1
|
||||
assert 0
|
||||
|
||||
@@ -51,8 +51,8 @@ Running this would result in a passed test except for the last
|
||||
d = tmp_path / "sub"
|
||||
d.mkdir()
|
||||
p = d / "hello.txt"
|
||||
p.write_text(CONTENT, encoding="utf-8")
|
||||
assert p.read_text(encoding="utf-8") == CONTENT
|
||||
p.write_text(CONTENT)
|
||||
assert p.read_text() == CONTENT
|
||||
assert len(list(tmp_path.iterdir())) == 1
|
||||
> assert 0
|
||||
E assert 0
|
||||
|
||||
@@ -207,10 +207,10 @@ creation of a per-test temporary directory:
|
||||
@pytest.fixture(autouse=True)
|
||||
def initdir(self, tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path) # change to pytest-provided temporary directory
|
||||
tmp_path.joinpath("samplefile.ini").write_text("# testdata", encoding="utf-8")
|
||||
tmp_path.joinpath("samplefile.ini").write_text("# testdata")
|
||||
|
||||
def test_method(self):
|
||||
with open("samplefile.ini", encoding="utf-8") as f:
|
||||
with open("samplefile.ini") as f:
|
||||
s = f.read()
|
||||
assert "testdata" in s
|
||||
|
||||
|
||||
@@ -173,8 +173,7 @@ You can invoke ``pytest`` from Python code directly:
|
||||
|
||||
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.
|
||||
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:
|
||||
You can pass in options and arguments:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
.. sidebar:: Next Open Trainings
|
||||
|
||||
- `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**
|
||||
- `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
|
||||
|
||||
Also see :doc:`previous talks and blogposts <talks>`.
|
||||
|
||||
|
||||
@@ -1,31 +1,19 @@
|
||||
|
||||
.. _plugin-list:
|
||||
|
||||
Pytest Plugin List
|
||||
==================
|
||||
Plugin List
|
||||
===========
|
||||
|
||||
Below is an automated compilation of ``pytest``` plugins available on `PyPI <https://pypi.org>`_.
|
||||
It includes PyPI projects whose names begin with "pytest-" and a handful of manually selected projects.
|
||||
PyPI projects that match "pytest-\*" are considered plugins and are listed
|
||||
automatically together with a manually-maintained list in `the source
|
||||
code <https://github.com/pytest-dev/pytest/blob/main/scripts/update-plugin-list.py>`_.
|
||||
Packages classified as inactive are excluded.
|
||||
|
||||
For detailed insights into how this list is generated,
|
||||
please refer to `the update script <https://github.com/pytest-dev/pytest/blob/main/scripts/update-plugin-list.py>`_.
|
||||
|
||||
.. warning::
|
||||
|
||||
Please be aware that this list is not a curated collection of projects
|
||||
and does not undergo a systematic review process.
|
||||
It serves purely as an informational resource to aid in the discovery of ``pytest`` plugins.
|
||||
|
||||
Do not presume any endorsement from the ``pytest`` project or its developers,
|
||||
and always conduct your own quality assessment before incorporating any of these plugins into your own projects.
|
||||
|
||||
|
||||
.. The following conditional uses a different format for this list when
|
||||
creating a PDF, because otherwise the table gets far too wide for the
|
||||
page.
|
||||
|
||||
This list contains 1267 plugins.
|
||||
This list contains 1263 plugins.
|
||||
|
||||
.. only:: not latex
|
||||
|
||||
@@ -244,7 +232,7 @@ This list contains 1267 plugins.
|
||||
: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-cpp` Use pytest's runner to discover and execute C++ tests Jan 30, 2023 5 - Production/Stable pytest (>=7.0)
|
||||
:pypi:`pytest-cppython` A pytest plugin that imports CPPython testing types Jun 14, 2023 N/A N/A
|
||||
:pypi:`pytest-cppython` A pytest plugin that imports CPPython testing types Jun 02, 2023 N/A N/A
|
||||
:pypi:`pytest-cqase` Custom qase pytest plugin Aug 22, 2022 N/A pytest (>=7.1.2,<8.0.0)
|
||||
:pypi:`pytest-cram` Run cram tests with pytest. Aug 08, 2020 N/A N/A
|
||||
:pypi:`pytest-crate` Manages CrateDB instances during your integration tests May 28, 2019 3 - Alpha pytest (>=4.0)
|
||||
@@ -368,7 +356,7 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-duration-insights` Jun 25, 2021 N/A N/A
|
||||
:pypi:`pytest-durations` Pytest plugin reporting fixtures and test functions execution time. Apr 22, 2022 5 - Production/Stable pytest (>=4.6)
|
||||
:pypi:`pytest-dynamicrerun` A pytest plugin to rerun tests dynamically based off of test outcome and output. Aug 15, 2020 4 - Beta N/A
|
||||
:pypi:`pytest-dynamodb` DynamoDB fixtures for pytest Jun 12, 2023 5 - Production/Stable pytest
|
||||
:pypi:`pytest-dynamodb` DynamoDB fixtures for pytest Mar 27, 2023 5 - Production/Stable pytest
|
||||
:pypi:`pytest-easy-addoption` pytest-easy-addoption: Easy way to work with pytest addoption Jan 22, 2020 N/A N/A
|
||||
:pypi:`pytest-easy-api` Simple API testing with pytest Mar 26, 2018 N/A N/A
|
||||
:pypi:`pytest-easyMPI` Package that supports mpi tests in pytest Oct 21, 2020 N/A N/A
|
||||
@@ -383,13 +371,13 @@ This list contains 1267 plugins.
|
||||
: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-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-arduino` Make pytest-embedded plugin work with Arduino. Jun 14, 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-jtag` Make pytest-embedded plugin work with JTAG. Jun 14, 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-serial` Make pytest-embedded plugin work with Serial. Jun 14, 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` pytest embedded plugin Jun 06, 2023 N/A pytest (>=7.0)
|
||||
:pypi:`pytest-embedded-arduino` pytest embedded plugin for Arduino projects Jun 06, 2023 5 - Production/Stable N/A
|
||||
:pypi:`pytest-embedded-idf` pytest embedded plugin for esp-idf project Jun 06, 2023 5 - Production/Stable N/A
|
||||
:pypi:`pytest-embedded-jtag` pytest embedded plugin for testing with jtag Jun 06, 2023 N/A N/A
|
||||
:pypi:`pytest-embedded-qemu` pytest embedded plugin for qemu, not target chip Jun 06, 2023 5 - Production/Stable N/A
|
||||
:pypi:`pytest-embedded-serial` pytest embedded plugin for testing serial ports Jun 06, 2023 N/A N/A
|
||||
:pypi:`pytest-embedded-serial-esp` pytest embedded plugin for testing espressif boards via serial ports Jun 06, 2023 N/A 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-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)
|
||||
@@ -398,7 +386,7 @@ This list contains 1267 plugins.
|
||||
: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-enhancements` Improvements for pytest (rejected upstream) Oct 30, 2019 4 - Beta N/A
|
||||
:pypi:`pytest-env` py.test plugin that allows you to add environment variables. Jun 15, 2023 5 - Production/Stable pytest>=7.3.1
|
||||
:pypi:`pytest-env` py.test plugin that allows you to add environment variables. Oct 23, 2022 5 - Production/Stable pytest>=7.1.3
|
||||
:pypi:`pytest-envfiles` A py.test plugin that parses environment files before running tests Oct 08, 2015 3 - Alpha N/A
|
||||
:pypi:`pytest-env-info` Push information about the running pytest into envvars Nov 25, 2017 4 - Beta pytest (>=3.1.1)
|
||||
:pypi:`pytest-envraw` py.test plugin that allows you to add environment variables. Aug 27, 2020 4 - Beta pytest (>=2.6.0)
|
||||
@@ -444,7 +432,7 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-fantasy` Pytest plugin for Flask Fantasy Framework Mar 14, 2019 N/A N/A
|
||||
:pypi:`pytest-fastapi` Dec 27, 2020 N/A N/A
|
||||
:pypi:`pytest-fastapi-deps` A fixture which allows easy replacement of fastapi dependencies for testing Jul 20, 2022 5 - Production/Stable pytest
|
||||
:pypi:`pytest-fastest` Use SCM and coverage to run only needed tests Jun 15, 2023 4 - Beta pytest (>=4.4)
|
||||
:pypi:`pytest-fastest` Use SCM and coverage to run only needed tests Mar 05, 2020 N/A N/A
|
||||
:pypi:`pytest-fast-first` Pytest plugin that runs fast tests first Jan 19, 2023 3 - Alpha pytest
|
||||
:pypi:`pytest-faulthandler` py.test plugin that activates the fault handler module for tests (dummy package) Jul 04, 2019 6 - Mature pytest (>=5.0)
|
||||
:pypi:`pytest-fauxfactory` Integration of fauxfactory into pytest. Dec 06, 2017 5 - Production/Stable pytest (>=3.2)
|
||||
@@ -469,7 +457,7 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-fixture-tools` Plugin for pytest which provides tools for fixtures Aug 18, 2020 6 - Mature pytest
|
||||
:pypi:`pytest-fixture-typecheck` A pytest plugin to assert type annotations at runtime. Aug 24, 2021 N/A pytest
|
||||
:pypi:`pytest-flake8` pytest plugin to check FLAKE8 requirements Mar 18, 2022 4 - Beta pytest (>=7.0)
|
||||
:pypi:`pytest-flake8-path` A pytest fixture for testing flake8 plugins. Jun 16, 2023 5 - Production/Stable pytest
|
||||
:pypi:`pytest-flake8-path` A pytest fixture for testing flake8 plugins. May 11, 2022 5 - Production/Stable pytest
|
||||
:pypi:`pytest-flake8-v2` pytest plugin to check FLAKE8 requirements Mar 01, 2022 5 - Production/Stable pytest (>=7.0)
|
||||
:pypi:`pytest-flakefinder` Runs tests multiple times to expose flakiness. Oct 26, 2022 4 - Beta pytest (>=2.7.1)
|
||||
:pypi:`pytest-flakes` pytest plugin to check source code with pyflakes Dec 02, 2021 5 - Production/Stable pytest (>=5)
|
||||
@@ -488,7 +476,7 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-forward-compatibility` A pytest plugin to shim pytest commandline options for fowards compatibility Sep 29, 2020 N/A N/A
|
||||
:pypi:`pytest-frappe` Pytest Frappe Plugin - A set of pytest fixtures to test Frappe applications May 03, 2023 4 - Beta pytest>=7.0.0
|
||||
:pypi:`pytest-freezegun` Wrap tests with fixtures in freeze_time Jul 19, 2020 4 - Beta pytest (>=3.0.0)
|
||||
:pypi:`pytest-freezer` Pytest plugin providing a fixture interface for spulec/freezegun Jun 17, 2023 N/A pytest>=3.6
|
||||
:pypi:`pytest-freezer` Pytest plugin providing a fixture interface for spulec/freezegun Oct 20, 2022 N/A pytest>=3.6
|
||||
:pypi:`pytest-freeze-reqs` Check if requirement files are frozen Apr 29, 2021 N/A N/A
|
||||
:pypi:`pytest-frozen-uuids` Deterministically frozen UUID's for your tests Apr 17, 2022 N/A pytest (>=3.0)
|
||||
:pypi:`pytest-func-cov` Pytest plugin for measuring function coverage Apr 15, 2021 3 - Alpha pytest (>=5)
|
||||
@@ -503,7 +491,7 @@ This list contains 1267 plugins.
|
||||
: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-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 08, 2023 N/A N/A
|
||||
:pypi:`pytest-git` Git repository fixture for py.test May 28, 2019 5 - Production/Stable pytest
|
||||
:pypi:`pytest-gitcov` Pytest plugin for reporting on coverage of the last git commit. Jan 11, 2020 2 - Pre-Alpha N/A
|
||||
:pypi:`pytest-git-fixtures` Pytest fixtures for testing with git. Mar 11, 2021 4 - Beta pytest
|
||||
@@ -535,10 +523,10 @@ This list contains 1267 plugins.
|
||||
: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-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 16, 2023 3 - Alpha pytest (==7.3.1)
|
||||
:pypi:`pytest-homeassistant-custom-component` Experimental package to automatically extract test plugins for Home Assistant custom components Jun 09, 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-honors` Report on tests that honor constraints, and guard against regressions Mar 06, 2020 4 - Beta N/A
|
||||
:pypi:`pytest-hot-reloading` Jun 16, 2023 N/A N/A
|
||||
:pypi:`pytest-hot-reloading` May 18, 2023 N/A N/A
|
||||
:pypi:`pytest-hot-test` A plugin that tracks test changes Dec 10, 2022 4 - Beta pytest (>=3.5.0)
|
||||
:pypi:`pytest-hoverfly` Simplify working with Hoverfly from pytest Jan 30, 2023 N/A pytest (>=5.0)
|
||||
:pypi:`pytest-hoverfly-wrapper` Integrates the Hoverfly HTTP proxy into Pytest Feb 27, 2023 5 - Production/Stable pytest (>=3.7.0)
|
||||
@@ -596,7 +584,7 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-ipynb` THIS PROJECT IS ABANDONED Jan 29, 2019 3 - Alpha N/A
|
||||
:pypi:`pytest-isolate` Feb 20, 2023 4 - Beta pytest
|
||||
:pypi:`pytest-isort` py.test plugin to check import ordering using isort Oct 31, 2022 5 - Production/Stable pytest (>=5.0)
|
||||
:pypi:`pytest-is-running` pytest plugin providing a function to check if pytest is running. Jun 16, 2023 5 - Production/Stable N/A
|
||||
:pypi:`pytest-is-running` pytest plugin providing a function to check if pytest is running. Aug 19, 2022 5 - Production/Stable N/A
|
||||
:pypi:`pytest-it` Pytest plugin to display test reports as a plaintext spec, inspired by Rspec: https://github.com/mattduck/pytest-it. Jan 22, 2020 4 - Beta N/A
|
||||
:pypi:`pytest-iterassert` Nicer list and iterable assertion messages for pytest May 11, 2020 3 - Alpha N/A
|
||||
:pypi:`pytest-iters` A contextmanager pytest fixture for handling multiple mock iters May 24, 2022 N/A N/A
|
||||
@@ -604,8 +592,8 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-jelastic` Pytest plugin defining the necessary command-line options to pass to pytests testing a Jelastic environment. Nov 16, 2022 N/A pytest (>=7.2.0,<8.0.0)
|
||||
:pypi:`pytest-jest` A custom jest-pytest oriented Pytest reporter May 22, 2018 4 - Beta pytest (>=3.3.2)
|
||||
:pypi:`pytest-jinja` A plugin to generate customizable jinja-based HTML reports in pytest Oct 04, 2022 3 - Alpha pytest (>=6.2.5,<7.0.0)
|
||||
:pypi:`pytest-jira` py.test JIRA integration plugin, using markers Jun 12, 2023 3 - Alpha N/A
|
||||
:pypi:`pytest-jira-xfail` Plugin skips (xfail) tests if unresolved Jira issue(s) linked Jun 14, 2023 N/A pytest (>=7.2.0)
|
||||
:pypi:`pytest-jira` py.test JIRA integration plugin, using markers Apr 07, 2022 3 - Alpha N/A
|
||||
:pypi:`pytest-jira-xfail` Plugin skips (xfail) tests if unresolved Jira issue(s) linked Dec 01, 2022 N/A pytest (~=7.2.0)
|
||||
:pypi:`pytest-jira-xray` pytest plugin to integrate tests with JIRA XRAY Jun 06, 2023 4 - Beta pytest
|
||||
:pypi:`pytest-job-selection` A pytest plugin for load balancing test suites Jan 30, 2023 4 - Beta pytest (>=3.5.0)
|
||||
:pypi:`pytest-jobserver` Limit parallel tests with posix jobserver. May 15, 2019 5 - Production/Stable pytest
|
||||
@@ -617,7 +605,7 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-jtr` pytest plugin supporting json test report output Nov 29, 2022 N/A pytest (>=7.1.2,<8.0.0)
|
||||
:pypi:`pytest-jupyter` A pytest plugin for testing Jupyter libraries and extensions. Mar 30, 2023 4 - Beta pytest
|
||||
:pypi:`pytest-jupyterhub` A reusable JupyterHub pytest plugin Apr 25, 2023 5 - Production/Stable pytest
|
||||
:pypi:`pytest-kafka` Zookeeper, Kafka server, and Kafka consumer fixtures for Pytest Jun 14, 2023 N/A pytest
|
||||
:pypi:`pytest-kafka` Zookeeper, Kafka server, and Kafka consumer fixtures for Pytest Oct 01, 2022 N/A pytest
|
||||
:pypi:`pytest-kafkavents` A plugin to send pytest events to Kafka Sep 08, 2021 4 - Beta pytest
|
||||
:pypi:`pytest-kasima` Display horizontal lines above and below the captured standard output for easy viewing. Jan 26, 2023 5 - Production/Stable pytest (>=7.2.1,<8.0.0)
|
||||
:pypi:`pytest-keep-together` Pytest plugin to customize test ordering by running all 'related' tests together Dec 07, 2022 5 - Production/Stable pytest
|
||||
@@ -706,7 +694,7 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-missing-fixtures` Pytest plugin that creates missing fixtures Oct 14, 2020 4 - Beta pytest (>=3.5.0)
|
||||
:pypi:`pytest-ml` Test your machine learning! May 04, 2019 4 - Beta N/A
|
||||
:pypi:`pytest-mocha` pytest plugin to display test execution output like a mochajs Apr 02, 2020 4 - Beta pytest (>=5.4.0)
|
||||
:pypi:`pytest-mock` Thin-wrapper around the mock package for easier use with pytest Jun 15, 2023 5 - Production/Stable pytest (>=5.0)
|
||||
:pypi:`pytest-mock` Thin-wrapper around the mock package for easier use with pytest Oct 05, 2022 5 - Production/Stable pytest (>=5.0)
|
||||
:pypi:`pytest-mock-api` A mock API server with configurable routes and responses available as a fixture. Feb 13, 2019 1 - Planning pytest (>=4.0.0)
|
||||
:pypi:`pytest-mock-generator` A pytest fixture wrapper for https://pypi.org/project/mock-generator May 16, 2022 5 - Production/Stable N/A
|
||||
:pypi:`pytest-mock-helper` Help you mock HTTP call and generate mock code Jan 24, 2018 N/A pytest
|
||||
@@ -816,7 +804,7 @@ This list contains 1267 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-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-persistence` Pytest tool for persistent objects Jun 14, 2023 N/A N/A
|
||||
:pypi:`pytest-persistence` Pytest tool for persistent objects May 16, 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-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)
|
||||
@@ -859,7 +847,7 @@ This list contains 1267 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-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-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) Dec 28, 2021 5 - Production/Stable pytest (>=6)
|
||||
: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-progress` pytest plugin for instant test progress status Jan 31, 2022 5 - Production/Stable N/A
|
||||
@@ -880,7 +868,7 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-pydocstyle` pytest plugin to run pydocstyle Jan 05, 2023 3 - Alpha N/A
|
||||
:pypi:`pytest-pylint` pytest plugin to check source code with pylint Sep 10, 2022 5 - Production/Stable pytest (>=5.4)
|
||||
:pypi:`pytest-pymysql-autorecord` Record PyMySQL queries and mock with the stored data. Sep 02, 2022 N/A N/A
|
||||
:pypi:`pytest-pyodide` "Pytest plugin for testing applications that use Pyodide" Jun 11, 2023 N/A pytest
|
||||
:pypi:`pytest-pyodide` "Pytest plugin for testing applications that use Pyodide" Jun 02, 2023 N/A pytest
|
||||
:pypi:`pytest-pypi` Easily test your HTTP library against a local copy of pypi Mar 04, 2018 3 - Alpha N/A
|
||||
:pypi:`pytest-pypom-navigation` Core engine for cookiecutter-qa and pytest-play packages Feb 18, 2019 4 - Beta pytest (>=3.0.7)
|
||||
:pypi:`pytest-pyppeteer` A plugin to run pyppeteer in pytest Apr 28, 2022 N/A pytest (>=6.2.5,<7.0.0)
|
||||
@@ -905,7 +893,7 @@ This list contains 1267 plugins.
|
||||
: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-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 Feb 11, 2022 5 - Production/Stable pytest (>=3.0.0)
|
||||
: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-rail` pytest plugin for creating TestRail runs and adding results May 02, 2022 N/A pytest (>=3.6)
|
||||
@@ -970,7 +958,7 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-responsemock` Simplified requests calls mocking for pytest Mar 10, 2022 5 - Production/Stable N/A
|
||||
:pypi:`pytest-responses` py.test integration for responses Oct 11, 2022 N/A pytest (>=2.5)
|
||||
:pypi:`pytest-rest-api` Aug 08, 2022 N/A pytest (>=7.1.2,<8.0.0)
|
||||
:pypi:`pytest-restrict` Pytest plugin to restrict the test types allowed Jun 16, 2023 5 - Production/Stable pytest
|
||||
:pypi:`pytest-restrict` Pytest plugin to restrict the test types allowed May 11, 2022 5 - Production/Stable pytest
|
||||
:pypi:`pytest-result-log` Write the execution result of the case to the log Apr 17, 2023 N/A pytest>=7.2.0
|
||||
:pypi:`pytest-result-sender` Apr 20, 2023 N/A pytest>=7.3.1
|
||||
:pypi:`pytest-resume` A Pytest plugin to resuming from the last run test Apr 22, 2023 4 - Beta pytest (>=7.0)
|
||||
@@ -978,7 +966,7 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-retry` Adds the ability to retry flaky tests in CI environments Aug 16, 2022 N/A pytest (>=7.0.0)
|
||||
:pypi:`pytest-retry-class` A pytest plugin to rerun entire class on failure Mar 25, 2023 N/A pytest (>=5.3)
|
||||
:pypi:`pytest-reusable-testcases` Apr 28, 2023 N/A N/A
|
||||
:pypi:`pytest-reverse` Pytest plugin to reverse test order. Jun 16, 2023 5 - Production/Stable pytest
|
||||
:pypi:`pytest-reverse` Pytest plugin to reverse test order. May 11, 2022 5 - Production/Stable pytest
|
||||
:pypi:`pytest-rich` Leverage rich for richer test session output Mar 03, 2022 4 - Beta pytest (>=7.0)
|
||||
:pypi:`pytest-rich-reporter` A pytest plugin using Rich for beautiful test result formatting. Feb 17, 2022 1 - Planning pytest (>=5.0.0)
|
||||
:pypi:`pytest-richtrace` Nov 05, 2022 N/A pytest (>=7.2.0,<8.0.0)
|
||||
@@ -999,7 +987,6 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-run-subprocess` Pytest Plugin for running and testing subprocesses. Nov 12, 2022 5 - Production/Stable pytest
|
||||
:pypi:`pytest-runtime-types` Checks type annotations on runtime while running tests. Feb 09, 2023 N/A pytest
|
||||
:pypi:`pytest-runtime-xfail` Call runtime_xfail() to mark running test as xfail. Aug 26, 2021 N/A pytest>=5.0.0
|
||||
:pypi:`pytest-runtime-yoyo` run case mark timeout Jun 12, 2023 N/A pytest (>=7.2.0)
|
||||
:pypi:`pytest-ry-demo1` 测试 Mar 26, 2023 N/A N/A
|
||||
:pypi:`pytest-saccharin` pytest-saccharin is a updated fork of pytest-sugar, a plugin for pytest that changes the default look and feel of pytest (e.g. progressbar, show tests that fail instantly). Oct 31, 2022 3 - Alpha N/A
|
||||
:pypi:`pytest-salt` Pytest Salt Plugin Jan 27, 2020 4 - Beta N/A
|
||||
@@ -1010,14 +997,14 @@ This list contains 1267 plugins.
|
||||
: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-sa-pg` May 14, 2019 N/A N/A
|
||||
:pypi:`pytest-sbase` A complete web automation framework for end-to-end testing. Jun 13, 2023 5 - Production/Stable N/A
|
||||
:pypi:`pytest-sbase` A complete web automation framework for end-to-end testing. Jun 09, 2023 5 - Production/Stable 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-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-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-seleniumbase` A complete web automation framework for end-to-end testing. Jun 13, 2023 5 - Production/Stable N/A
|
||||
:pypi:`pytest-seleniumbase` A complete web automation framework for end-to-end testing. Jun 09, 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-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
|
||||
@@ -1145,7 +1132,7 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-test-groups` A Pytest plugin for running a subset of your tests by splitting them in to equally sized groups. Oct 25, 2016 5 - Production/Stable N/A
|
||||
:pypi:`pytest-testinfra` Test infrastructures May 21, 2023 5 - Production/Stable pytest (!=3.0.2)
|
||||
:pypi:`pytest-testlink-adaptor` pytest reporting plugin for testlink Dec 20, 2018 4 - Beta pytest (>=2.6)
|
||||
:pypi:`pytest-testmon` selects tests affected by changed files and methods Jun 16, 2023 4 - Beta N/A
|
||||
:pypi:`pytest-testmon` selects tests affected by changed files and methods Jun 09, 2023 4 - Beta N/A
|
||||
:pypi:`pytest-testmon-dev` selects tests affected by changed files and methods Mar 30, 2023 4 - Beta pytest (<8,>=5)
|
||||
:pypi:`pytest-testmon-oc` nOly selects tests affected by changed files and methods Jun 01, 2022 4 - Beta pytest (<8,>=5)
|
||||
:pypi:`pytest-testmon-skip-libraries` selects tests affected by changed files and methods Mar 03, 2023 4 - Beta pytest (<8,>=5)
|
||||
@@ -1172,7 +1159,6 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-thawgun` Pytest plugin for time travel May 26, 2020 3 - Alpha N/A
|
||||
: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-time` Jun 16, 2023 3 - Alpha pytest
|
||||
:pypi:`pytest-timeit` A pytest plugin to time test function runs Oct 13, 2016 4 - Beta N/A
|
||||
:pypi:`pytest-timeout` pytest plugin to abort hanging tests Jan 18, 2022 5 - Production/Stable pytest (>=5.0.0)
|
||||
:pypi:`pytest-timeouts` Linux-only Pytest plugin to control durations of various test case execution phases Sep 21, 2019 5 - Production/Stable N/A
|
||||
@@ -1209,7 +1195,7 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-tspwplib` A simple plugin to use with tspwplib Jan 08, 2021 4 - Beta pytest (>=3.5.0)
|
||||
:pypi:`pytest-tst` Customize pytest options, output and exit code to make it compatible with tst Apr 27, 2022 N/A pytest (>=5.0.0)
|
||||
:pypi:`pytest-tstcls` Test Class Base Mar 23, 2020 5 - Production/Stable N/A
|
||||
:pypi:`pytest-tui` Text User Interface (TUI) and HTML report for Pytest test runs Jun 12, 2023 4 - Beta N/A
|
||||
:pypi:`pytest-tui` Text User Interface (TUI) and HTML report for Pytest test runs Apr 06, 2023 4 - Beta N/A
|
||||
:pypi:`pytest-tutorials` Mar 11, 2023 N/A N/A
|
||||
:pypi:`pytest-twilio-conversations-client-mock` Aug 02, 2022 N/A N/A
|
||||
:pypi:`pytest-twisted` A twisted plugin for pytest. Oct 16, 2022 5 - Production/Stable pytest (>=2.3)
|
||||
@@ -1227,7 +1213,6 @@ This list contains 1267 plugins.
|
||||
: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-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-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-vagrant` A py.test plugin providing access to vagrant. Sep 07, 2021 5 - Production/Stable pytest
|
||||
@@ -1254,7 +1239,7 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-wa-e2e-plugin` Pytest plugin for testing whatsapp bots with end to end tests Feb 18, 2020 4 - Beta pytest (>=3.5.0)
|
||||
:pypi:`pytest-wake` May 11, 2023 N/A pytest
|
||||
:pypi:`pytest-watch` Local continuous test runner with pytest and watchdog. May 20, 2018 N/A N/A
|
||||
:pypi:`pytest-watcher` Automatically rerun your tests on file modifications Jun 11, 2023 4 - Beta N/A
|
||||
:pypi:`pytest-watcher` Automatically rerun your tests on file modifications Jun 07, 2023 4 - Beta N/A
|
||||
:pypi:`pytest-wdl` Pytest plugin for testing WDL workflows. Nov 17, 2020 5 - Production/Stable N/A
|
||||
:pypi:`pytest-web3-data` Sep 15, 2022 4 - Beta pytest
|
||||
:pypi:`pytest-webdriver` Selenium webdriver fixture for py.test May 28, 2019 5 - Production/Stable pytest
|
||||
@@ -1271,7 +1256,6 @@ This list contains 1267 plugins.
|
||||
:pypi:`pytest-xdist-debug-for-graingert` pytest xdist plugin for distributed testing and loop-on-failing modes Jul 24, 2019 5 - Production/Stable pytest (>=4.4.0)
|
||||
:pypi:`pytest-xdist-forked` forked from pytest-xdist Feb 10, 2020 5 - Production/Stable pytest (>=4.4.0)
|
||||
:pypi:`pytest-xdist-tracker` pytest plugin helps to reproduce failures for particular xdist node Nov 18, 2021 3 - Alpha pytest (>=3.5.1)
|
||||
:pypi:`pytest-xdist-worker-stats` A pytest plugin to list worker statistics after a xdist run. Jun 15, 2023 4 - Beta pytest (>=7.3.2,<8.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-xlog` Extended logging for test and decorators May 31, 2020 4 - Beta N/A
|
||||
@@ -2789,7 +2773,7 @@ This list contains 1267 plugins.
|
||||
Use pytest's runner to discover and execute C++ tests
|
||||
|
||||
:pypi:`pytest-cppython`
|
||||
*last release*: Jun 14, 2023,
|
||||
*last release*: Jun 02, 2023,
|
||||
*status*: N/A,
|
||||
*requires*: N/A
|
||||
|
||||
@@ -3657,7 +3641,7 @@ This list contains 1267 plugins.
|
||||
A pytest plugin to rerun tests dynamically based off of test outcome and output.
|
||||
|
||||
:pypi:`pytest-dynamodb`
|
||||
*last release*: Jun 12, 2023,
|
||||
*last release*: Mar 27, 2023,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: pytest
|
||||
|
||||
@@ -3762,53 +3746,53 @@ This list contains 1267 plugins.
|
||||
Send execution result email
|
||||
|
||||
:pypi:`pytest-embedded`
|
||||
*last release*: Jun 14, 2023,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: pytest>=7.0
|
||||
*last release*: Jun 06, 2023,
|
||||
*status*: N/A,
|
||||
*requires*: pytest (>=7.0)
|
||||
|
||||
A pytest plugin that designed for embedded testing.
|
||||
pytest embedded plugin
|
||||
|
||||
:pypi:`pytest-embedded-arduino`
|
||||
*last release*: Jun 14, 2023,
|
||||
*last release*: Jun 06, 2023,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: N/A
|
||||
|
||||
Make pytest-embedded plugin work with Arduino.
|
||||
pytest embedded plugin for Arduino projects
|
||||
|
||||
:pypi:`pytest-embedded-idf`
|
||||
*last release*: Jun 14, 2023,
|
||||
*last release*: Jun 06, 2023,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: N/A
|
||||
|
||||
Make pytest-embedded plugin work with ESP-IDF.
|
||||
pytest embedded plugin for esp-idf project
|
||||
|
||||
:pypi:`pytest-embedded-jtag`
|
||||
*last release*: Jun 14, 2023,
|
||||
*status*: 5 - Production/Stable,
|
||||
*last release*: Jun 06, 2023,
|
||||
*status*: N/A,
|
||||
*requires*: N/A
|
||||
|
||||
Make pytest-embedded plugin work with JTAG.
|
||||
pytest embedded plugin for testing with jtag
|
||||
|
||||
:pypi:`pytest-embedded-qemu`
|
||||
*last release*: Jun 14, 2023,
|
||||
*last release*: Jun 06, 2023,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: N/A
|
||||
|
||||
Make pytest-embedded plugin work with QEMU.
|
||||
pytest embedded plugin for qemu, not target chip
|
||||
|
||||
:pypi:`pytest-embedded-serial`
|
||||
*last release*: Jun 14, 2023,
|
||||
*status*: 5 - Production/Stable,
|
||||
*last release*: Jun 06, 2023,
|
||||
*status*: N/A,
|
||||
*requires*: N/A
|
||||
|
||||
Make pytest-embedded plugin work with Serial.
|
||||
pytest embedded plugin for testing serial ports
|
||||
|
||||
:pypi:`pytest-embedded-serial-esp`
|
||||
*last release*: Jun 14, 2023,
|
||||
*status*: 5 - Production/Stable,
|
||||
*last release*: Jun 06, 2023,
|
||||
*status*: N/A,
|
||||
*requires*: N/A
|
||||
|
||||
Make pytest-embedded plugin work with Espressif target boards.
|
||||
pytest embedded plugin for testing espressif boards via serial ports
|
||||
|
||||
:pypi:`pytest-embrace`
|
||||
*last release*: Mar 25, 2023,
|
||||
@@ -3867,9 +3851,9 @@ This list contains 1267 plugins.
|
||||
Improvements for pytest (rejected upstream)
|
||||
|
||||
:pypi:`pytest-env`
|
||||
*last release*: Jun 15, 2023,
|
||||
*last release*: Oct 23, 2022,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: pytest>=7.3.1
|
||||
*requires*: pytest>=7.1.3
|
||||
|
||||
py.test plugin that allows you to add environment variables.
|
||||
|
||||
@@ -4189,9 +4173,9 @@ This list contains 1267 plugins.
|
||||
A fixture which allows easy replacement of fastapi dependencies for testing
|
||||
|
||||
:pypi:`pytest-fastest`
|
||||
*last release*: Jun 15, 2023,
|
||||
*status*: 4 - Beta,
|
||||
*requires*: pytest (>=4.4)
|
||||
*last release*: Mar 05, 2020,
|
||||
*status*: N/A,
|
||||
*requires*: N/A
|
||||
|
||||
Use SCM and coverage to run only needed tests
|
||||
|
||||
@@ -4364,7 +4348,7 @@ This list contains 1267 plugins.
|
||||
pytest plugin to check FLAKE8 requirements
|
||||
|
||||
:pypi:`pytest-flake8-path`
|
||||
*last release*: Jun 16, 2023,
|
||||
*last release*: May 11, 2022,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: pytest
|
||||
|
||||
@@ -4497,7 +4481,7 @@ This list contains 1267 plugins.
|
||||
Wrap tests with fixtures in freeze_time
|
||||
|
||||
:pypi:`pytest-freezer`
|
||||
*last release*: Jun 17, 2023,
|
||||
*last release*: Oct 20, 2022,
|
||||
*status*: N/A,
|
||||
*requires*: pytest>=3.6
|
||||
|
||||
@@ -4602,7 +4586,7 @@ This list contains 1267 plugins.
|
||||
For finding/executing Ghost Inspector tests
|
||||
|
||||
:pypi:`pytest-girder`
|
||||
*last release*: Jun 14, 2023,
|
||||
*last release*: Jun 08, 2023,
|
||||
*status*: N/A,
|
||||
*requires*: N/A
|
||||
|
||||
@@ -4826,7 +4810,7 @@ This list contains 1267 plugins.
|
||||
A pytest plugin for use with homeassistant custom components.
|
||||
|
||||
:pypi:`pytest-homeassistant-custom-component`
|
||||
*last release*: Jun 16, 2023,
|
||||
*last release*: Jun 09, 2023,
|
||||
*status*: 3 - Alpha,
|
||||
*requires*: pytest (==7.3.1)
|
||||
|
||||
@@ -4847,7 +4831,7 @@ This list contains 1267 plugins.
|
||||
Report on tests that honor constraints, and guard against regressions
|
||||
|
||||
:pypi:`pytest-hot-reloading`
|
||||
*last release*: Jun 16, 2023,
|
||||
*last release*: May 18, 2023,
|
||||
*status*: N/A,
|
||||
*requires*: N/A
|
||||
|
||||
@@ -5253,7 +5237,7 @@ This list contains 1267 plugins.
|
||||
py.test plugin to check import ordering using isort
|
||||
|
||||
:pypi:`pytest-is-running`
|
||||
*last release*: Jun 16, 2023,
|
||||
*last release*: Aug 19, 2022,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: N/A
|
||||
|
||||
@@ -5309,16 +5293,16 @@ This list contains 1267 plugins.
|
||||
A plugin to generate customizable jinja-based HTML reports in pytest
|
||||
|
||||
:pypi:`pytest-jira`
|
||||
*last release*: Jun 12, 2023,
|
||||
*last release*: Apr 07, 2022,
|
||||
*status*: 3 - Alpha,
|
||||
*requires*: N/A
|
||||
|
||||
py.test JIRA integration plugin, using markers
|
||||
|
||||
:pypi:`pytest-jira-xfail`
|
||||
*last release*: Jun 14, 2023,
|
||||
*last release*: Dec 01, 2022,
|
||||
*status*: N/A,
|
||||
*requires*: pytest (>=7.2.0)
|
||||
*requires*: pytest (~=7.2.0)
|
||||
|
||||
Plugin skips (xfail) tests if unresolved Jira issue(s) linked
|
||||
|
||||
@@ -5400,7 +5384,7 @@ This list contains 1267 plugins.
|
||||
A reusable JupyterHub pytest plugin
|
||||
|
||||
:pypi:`pytest-kafka`
|
||||
*last release*: Jun 14, 2023,
|
||||
*last release*: Oct 01, 2022,
|
||||
*status*: N/A,
|
||||
*requires*: pytest
|
||||
|
||||
@@ -6023,7 +6007,7 @@ This list contains 1267 plugins.
|
||||
pytest plugin to display test execution output like a mochajs
|
||||
|
||||
:pypi:`pytest-mock`
|
||||
*last release*: Jun 15, 2023,
|
||||
*last release*: Oct 05, 2022,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: pytest (>=5.0)
|
||||
|
||||
@@ -6793,7 +6777,7 @@ This list contains 1267 plugins.
|
||||
A simple plugin to ensure the execution of critical sections of code has not been impacted
|
||||
|
||||
:pypi:`pytest-persistence`
|
||||
*last release*: Jun 14, 2023,
|
||||
*last release*: May 16, 2023,
|
||||
*status*: N/A,
|
||||
*requires*: N/A
|
||||
|
||||
@@ -7094,9 +7078,9 @@ This list contains 1267 plugins.
|
||||
Minitest-style test colors
|
||||
|
||||
:pypi:`pytest-print`
|
||||
*last release*: Jun 16, 2023,
|
||||
*last release*: Dec 28, 2021,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: pytest>=7.3.2
|
||||
*requires*: pytest (>=6)
|
||||
|
||||
pytest-print adds the printer fixture you can use to print messages to the user (directly to the pytest runner, not stdout)
|
||||
|
||||
@@ -7241,7 +7225,7 @@ This list contains 1267 plugins.
|
||||
Record PyMySQL queries and mock with the stored data.
|
||||
|
||||
:pypi:`pytest-pyodide`
|
||||
*last release*: Jun 11, 2023,
|
||||
*last release*: Jun 02, 2023,
|
||||
*status*: N/A,
|
||||
*requires*: pytest
|
||||
|
||||
@@ -7416,9 +7400,9 @@ This list contains 1267 plugins.
|
||||
pytest plugin to generate random data inspired by QuickCheck
|
||||
|
||||
:pypi:`pytest-rabbitmq`
|
||||
*last release*: Jun 16, 2023,
|
||||
*last release*: Feb 11, 2022,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: pytest (>=6.2)
|
||||
*requires*: pytest (>=3.0.0)
|
||||
|
||||
RabbitMQ process and client fixtures for pytest
|
||||
|
||||
@@ -7871,7 +7855,7 @@ This list contains 1267 plugins.
|
||||
|
||||
|
||||
:pypi:`pytest-restrict`
|
||||
*last release*: Jun 16, 2023,
|
||||
*last release*: May 11, 2022,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: pytest
|
||||
|
||||
@@ -7927,7 +7911,7 @@ This list contains 1267 plugins.
|
||||
|
||||
|
||||
:pypi:`pytest-reverse`
|
||||
*last release*: Jun 16, 2023,
|
||||
*last release*: May 11, 2022,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: pytest
|
||||
|
||||
@@ -8073,13 +8057,6 @@ This list contains 1267 plugins.
|
||||
|
||||
Call runtime_xfail() to mark running test as xfail.
|
||||
|
||||
:pypi:`pytest-runtime-yoyo`
|
||||
*last release*: Jun 12, 2023,
|
||||
*status*: N/A,
|
||||
*requires*: pytest (>=7.2.0)
|
||||
|
||||
run case mark timeout
|
||||
|
||||
:pypi:`pytest-ry-demo1`
|
||||
*last release*: Mar 26, 2023,
|
||||
*status*: N/A,
|
||||
@@ -8151,7 +8128,7 @@ This list contains 1267 plugins.
|
||||
|
||||
|
||||
:pypi:`pytest-sbase`
|
||||
*last release*: Jun 13, 2023,
|
||||
*last release*: Jun 09, 2023,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: N/A
|
||||
|
||||
@@ -8200,7 +8177,7 @@ This list contains 1267 plugins.
|
||||
pytest plugin for Selenium
|
||||
|
||||
:pypi:`pytest-seleniumbase`
|
||||
*last release*: Jun 13, 2023,
|
||||
*last release*: Jun 09, 2023,
|
||||
*status*: 5 - Production/Stable,
|
||||
*requires*: N/A
|
||||
|
||||
@@ -9096,7 +9073,7 @@ This list contains 1267 plugins.
|
||||
pytest reporting plugin for testlink
|
||||
|
||||
:pypi:`pytest-testmon`
|
||||
*last release*: Jun 16, 2023,
|
||||
*last release*: Jun 09, 2023,
|
||||
*status*: 4 - Beta,
|
||||
*requires*: N/A
|
||||
|
||||
@@ -9284,13 +9261,6 @@ This list contains 1267 plugins.
|
||||
|
||||
Ticking on tests
|
||||
|
||||
:pypi:`pytest-time`
|
||||
*last release*: Jun 16, 2023,
|
||||
*status*: 3 - Alpha,
|
||||
*requires*: pytest
|
||||
|
||||
|
||||
|
||||
:pypi:`pytest-timeit`
|
||||
*last release*: Oct 13, 2016,
|
||||
*status*: 4 - Beta,
|
||||
@@ -9544,7 +9514,7 @@ This list contains 1267 plugins.
|
||||
Test Class Base
|
||||
|
||||
:pypi:`pytest-tui`
|
||||
*last release*: Jun 12, 2023,
|
||||
*last release*: Apr 06, 2023,
|
||||
*status*: 4 - Beta,
|
||||
*requires*: N/A
|
||||
|
||||
@@ -9669,13 +9639,6 @@ This list contains 1267 plugins.
|
||||
|
||||
Set a test as unstable to return 0 even if it failed
|
||||
|
||||
:pypi:`pytest-unused-fixtures`
|
||||
*last release*: Jun 15, 2023,
|
||||
*status*: 4 - Beta,
|
||||
*requires*: pytest (>=7.3.2,<8.0.0)
|
||||
|
||||
A pytest plugin to list unused fixtures after a test run.
|
||||
|
||||
:pypi:`pytest-upload-report`
|
||||
*last release*: Jun 18, 2021,
|
||||
*status*: 5 - Production/Stable,
|
||||
@@ -9859,7 +9822,7 @@ This list contains 1267 plugins.
|
||||
Local continuous test runner with pytest and watchdog.
|
||||
|
||||
:pypi:`pytest-watcher`
|
||||
*last release*: Jun 11, 2023,
|
||||
*last release*: Jun 07, 2023,
|
||||
*status*: 4 - Beta,
|
||||
*requires*: N/A
|
||||
|
||||
@@ -9977,13 +9940,6 @@ This list contains 1267 plugins.
|
||||
|
||||
pytest plugin helps to reproduce failures for particular xdist node
|
||||
|
||||
:pypi:`pytest-xdist-worker-stats`
|
||||
*last release*: Jun 15, 2023,
|
||||
*status*: 4 - Beta,
|
||||
*requires*: pytest (>=7.3.2,<8.0.0)
|
||||
|
||||
A pytest plugin to list worker statistics after a xdist run.
|
||||
|
||||
:pypi:`pytest-xfaillist`
|
||||
*last release*: Sep 17, 2021,
|
||||
*status*: N/A,
|
||||
|
||||
@@ -82,8 +82,6 @@ pytest.exit
|
||||
pytest.main
|
||||
~~~~~~~~~~~
|
||||
|
||||
**Tutorial**: :ref:`pytest.main-usage`
|
||||
|
||||
.. autofunction:: pytest.main
|
||||
|
||||
pytest.param
|
||||
@@ -785,66 +783,18 @@ reporting or interaction with exceptions:
|
||||
.. autofunction:: pytest_leave_pdb
|
||||
|
||||
|
||||
Collection tree objects
|
||||
-----------------------
|
||||
Objects
|
||||
-------
|
||||
|
||||
These are the collector and item classes (collectively called "nodes") which
|
||||
make up the collection tree.
|
||||
Full reference to objects accessible from :ref:`fixtures <fixture>` or :ref:`hooks <hook-reference>`.
|
||||
|
||||
Node
|
||||
~~~~
|
||||
|
||||
.. autoclass:: _pytest.nodes.Node()
|
||||
CallInfo
|
||||
~~~~~~~~
|
||||
|
||||
.. autoclass:: pytest.CallInfo()
|
||||
: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
|
||||
~~~~~
|
||||
@@ -853,34 +803,13 @@ Class
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Function
|
||||
~~~~~~~~
|
||||
Collector
|
||||
~~~~~~~~~
|
||||
|
||||
.. autoclass:: pytest.Function()
|
||||
.. autoclass:: pytest.Collector()
|
||||
:members:
|
||||
: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
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
@@ -908,6 +837,13 @@ ExitCode
|
||||
.. autoclass:: pytest.ExitCode
|
||||
:members:
|
||||
|
||||
File
|
||||
~~~~
|
||||
|
||||
.. autoclass:: pytest.File()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
FixtureDef
|
||||
~~~~~~~~~~
|
||||
@@ -916,6 +852,34 @@ FixtureDef
|
||||
:members:
|
||||
: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
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
@@ -943,6 +907,19 @@ Metafunc
|
||||
.. autoclass:: pytest.Metafunc()
|
||||
:members:
|
||||
|
||||
Module
|
||||
~~~~~~
|
||||
|
||||
.. autoclass:: pytest.Module()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Node
|
||||
~~~~
|
||||
|
||||
.. autoclass:: _pytest.nodes.Node()
|
||||
:members:
|
||||
|
||||
Parser
|
||||
~~~~~~
|
||||
|
||||
@@ -964,6 +941,13 @@ PytestPluginManager
|
||||
:inherited-members:
|
||||
:show-inheritance:
|
||||
|
||||
Session
|
||||
~~~~~~~
|
||||
|
||||
.. autoclass:: pytest.Session()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
TestReport
|
||||
~~~~~~~~~~
|
||||
|
||||
@@ -978,10 +962,10 @@ TestShortLogReport
|
||||
.. autoclass:: pytest.TestShortLogReport()
|
||||
:members:
|
||||
|
||||
Result
|
||||
_Result
|
||||
~~~~~~~
|
||||
|
||||
Result object used within :ref:`hook wrappers <hookwrapper>`, see :py:class:`Result in the pluggy documentation <pluggy.Result>` for more information.
|
||||
Result object used within :ref:`hook wrappers <hookwrapper>`, see :py:class:`_Result in the pluggy documentation <pluggy._callers._Result>` for more information.
|
||||
|
||||
Stash
|
||||
~~~~~
|
||||
@@ -1719,11 +1703,6 @@ passed multiple times. The expected format is ``name=value``. For example::
|
||||
[pytest]
|
||||
pythonpath = src1 src2
|
||||
|
||||
.. note::
|
||||
|
||||
``pythonpath`` does not affect some imports that happen very early,
|
||||
most notably plugins loaded using the ``-p`` command line option.
|
||||
|
||||
|
||||
.. confval:: required_plugins
|
||||
|
||||
@@ -1887,12 +1866,8 @@ All the command-line flags can be obtained by running ``pytest --help``::
|
||||
tests. Optional argument: glob (default: '*').
|
||||
--cache-clear Remove all cache contents at start of test run
|
||||
--lfnf={all,none}, --last-failed-no-failures={all,none}
|
||||
With ``--lf``, determines whether to execute tests
|
||||
when there are no previously (known) failures or
|
||||
when no cached ``lastfailed`` data was found.
|
||||
``all`` (the default) runs the full test suite
|
||||
again. ``none`` just emits a message about no known
|
||||
failures and exits successfully.
|
||||
Which tests to run with no previously (known)
|
||||
failures
|
||||
--sw, --stepwise Exit on test failure and continue from last failing
|
||||
test next time
|
||||
--sw-skip, --stepwise-skip
|
||||
@@ -1943,9 +1918,9 @@ All the command-line flags can be obtained by running ``pytest --help``::
|
||||
--strict-markers Markers not registered in the `markers` section of
|
||||
the configuration file raise errors
|
||||
--strict (Deprecated) alias to --strict-markers
|
||||
-c FILE, --config-file=FILE
|
||||
-c, --config-file FILE
|
||||
Load configuration from `FILE` instead of trying to
|
||||
locate one of the implicit configuration files.
|
||||
locate one of the implicit configuration files
|
||||
--continue-on-collection-errors
|
||||
Force test execution even if collection errors occur
|
||||
--rootdir=ROOTDIR Define root directory for tests. Can be relative
|
||||
|
||||
@@ -7,9 +7,7 @@ def main():
|
||||
Platform agnostic wrapper script for towncrier.
|
||||
Fixes the issue (#7251) where windows users are unable to natively run tox -e docs to build pytest docs.
|
||||
"""
|
||||
with open(
|
||||
"doc/en/_changelog_towncrier_draft.rst", "w", encoding="utf-8"
|
||||
) as draft_file:
|
||||
with open("doc/en/_changelog_towncrier_draft.rst", "w") as draft_file:
|
||||
return call(("towncrier", "--draft"), stdout=draft_file)
|
||||
|
||||
|
||||
|
||||
@@ -13,26 +13,14 @@ from tqdm import tqdm
|
||||
FILE_HEAD = r"""
|
||||
.. _plugin-list:
|
||||
|
||||
Pytest Plugin List
|
||||
==================
|
||||
Plugin List
|
||||
===========
|
||||
|
||||
Below is an automated compilation of ``pytest``` plugins available on `PyPI <https://pypi.org>`_.
|
||||
It includes PyPI projects whose names begin with "pytest-" and a handful of manually selected projects.
|
||||
PyPI projects that match "pytest-\*" are considered plugins and are listed
|
||||
automatically together with a manually-maintained list in `the source
|
||||
code <https://github.com/pytest-dev/pytest/blob/main/scripts/update-plugin-list.py>`_.
|
||||
Packages classified as inactive are excluded.
|
||||
|
||||
For detailed insights into how this list is generated,
|
||||
please refer to `the update script <https://github.com/pytest-dev/pytest/blob/main/scripts/update-plugin-list.py>`_.
|
||||
|
||||
.. warning::
|
||||
|
||||
Please be aware that this list is not a curated collection of projects
|
||||
and does not undergo a systematic review process.
|
||||
It serves purely as an informational resource to aid in the discovery of ``pytest`` plugins.
|
||||
|
||||
Do not presume any endorsement from the ``pytest`` project or its developers,
|
||||
and always conduct your own quality assessment before incorporating any of these plugins into your own projects.
|
||||
|
||||
|
||||
.. The following conditional uses a different format for this list when
|
||||
creating a PDF, because otherwise the table gets far too wide for the
|
||||
page.
|
||||
|
||||
@@ -505,11 +505,7 @@ def pytest_addoption(parser: Parser) -> None:
|
||||
dest="last_failed_no_failures",
|
||||
choices=("all", "none"),
|
||||
default="all",
|
||||
help="With ``--lf``, determines whether to execute tests when there "
|
||||
"are no previously (known) failures or when no "
|
||||
"cached ``lastfailed`` data was found. "
|
||||
"``all`` (the default) runs the full test suite again. "
|
||||
"``none`` just emits a message about no known failures and exits successfully.",
|
||||
help="Which tests to run with no previously (known) failures",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -57,7 +57,6 @@ from _pytest.pathlib import bestrelpath
|
||||
from _pytest.pathlib import import_path
|
||||
from _pytest.pathlib import ImportMode
|
||||
from _pytest.pathlib import resolve_package_path
|
||||
from _pytest.pathlib import safe_exists
|
||||
from _pytest.stash import Stash
|
||||
from _pytest.warning_types import PytestConfigWarning
|
||||
from _pytest.warning_types import warn_explicit_for
|
||||
@@ -138,9 +137,7 @@ def main(
|
||||
) -> Union[int, ExitCode]:
|
||||
"""Perform an in-process test run.
|
||||
|
||||
: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 args: List of command line arguments.
|
||||
:param plugins: List of plugin objects to be auto-registered during initialization.
|
||||
|
||||
:returns: An exit code.
|
||||
@@ -445,10 +442,10 @@ class PytestPluginManager(PluginManager):
|
||||
# so we avoid accessing possibly non-readable attributes
|
||||
# (see issue #1073).
|
||||
if not name.startswith("pytest_"):
|
||||
return None
|
||||
return
|
||||
# Ignore names which can not be hooks.
|
||||
if name == "pytest_plugins":
|
||||
return None
|
||||
return
|
||||
|
||||
opts = super().parse_hookimpl_opts(plugin, name)
|
||||
if opts is not None:
|
||||
@@ -457,9 +454,9 @@ class PytestPluginManager(PluginManager):
|
||||
method = getattr(plugin, name)
|
||||
# Consider only actual functions for hooks (#3775).
|
||||
if not inspect.isroutine(method):
|
||||
return None
|
||||
return
|
||||
# Collect unmarked hooks as long as they have the `pytest_' prefix.
|
||||
return _get_legacy_hook_marks( # type: ignore[return-value]
|
||||
return _get_legacy_hook_marks(
|
||||
method, "impl", ("tryfirst", "trylast", "optionalhook", "hookwrapper")
|
||||
)
|
||||
|
||||
@@ -468,7 +465,7 @@ class PytestPluginManager(PluginManager):
|
||||
if opts is None:
|
||||
method = getattr(module_or_class, name)
|
||||
if name.startswith("pytest_"):
|
||||
opts = _get_legacy_hook_marks( # type: ignore[assignment]
|
||||
opts = _get_legacy_hook_marks(
|
||||
method,
|
||||
"spec",
|
||||
("firstresult", "historic"),
|
||||
@@ -530,12 +527,9 @@ class PytestPluginManager(PluginManager):
|
||||
#
|
||||
def _set_initial_conftests(
|
||||
self,
|
||||
args: Sequence[Union[str, Path]],
|
||||
pyargs: bool,
|
||||
noconftest: bool,
|
||||
namespace: argparse.Namespace,
|
||||
rootpath: Path,
|
||||
confcutdir: Optional[Path],
|
||||
importmode: Union[ImportMode, str],
|
||||
testpaths_ini: Sequence[str],
|
||||
) -> None:
|
||||
"""Load initial conftest files given a preparsed "namespace".
|
||||
|
||||
@@ -545,12 +539,17 @@ class PytestPluginManager(PluginManager):
|
||||
common options will not confuse our logic here.
|
||||
"""
|
||||
current = Path.cwd()
|
||||
self._confcutdir = absolutepath(current / confcutdir) if confcutdir else None
|
||||
self._noconftest = noconftest
|
||||
self._using_pyargs = pyargs
|
||||
self._confcutdir = (
|
||||
absolutepath(current / namespace.confcutdir)
|
||||
if namespace.confcutdir
|
||||
else None
|
||||
)
|
||||
self._noconftest = namespace.noconftest
|
||||
self._using_pyargs = namespace.pyargs
|
||||
testpaths = namespace.file_or_dir + testpaths_ini
|
||||
foundanchor = False
|
||||
for intitial_path in args:
|
||||
path = str(intitial_path)
|
||||
for testpath in testpaths:
|
||||
path = str(testpath)
|
||||
# remove node-id syntax
|
||||
i = path.find("::")
|
||||
if i != -1:
|
||||
@@ -558,12 +557,16 @@ class PytestPluginManager(PluginManager):
|
||||
anchor = absolutepath(current / path)
|
||||
|
||||
# Ensure we do not break if what appears to be an anchor
|
||||
# is in fact a very long option (#10169, #11394).
|
||||
if safe_exists(anchor):
|
||||
self._try_load_conftest(anchor, importmode, rootpath)
|
||||
# is in fact a very long option (#10169).
|
||||
try:
|
||||
anchor_exists = anchor.exists()
|
||||
except OSError: # pragma: no cover
|
||||
anchor_exists = False
|
||||
if anchor_exists:
|
||||
self._try_load_conftest(anchor, namespace.importmode, rootpath)
|
||||
foundanchor = True
|
||||
if not foundanchor:
|
||||
self._try_load_conftest(current, importmode, rootpath)
|
||||
self._try_load_conftest(current, namespace.importmode, rootpath)
|
||||
|
||||
def _is_in_confcutdir(self, path: Path) -> bool:
|
||||
"""Whether a path is within the confcutdir.
|
||||
@@ -1062,10 +1065,9 @@ class Config:
|
||||
fin()
|
||||
|
||||
def get_terminal_writer(self) -> TerminalWriter:
|
||||
terminalreporter: Optional[TerminalReporter] = self.pluginmanager.get_plugin(
|
||||
terminalreporter: TerminalReporter = self.pluginmanager.get_plugin(
|
||||
"terminalreporter"
|
||||
)
|
||||
assert terminalreporter is not None
|
||||
return terminalreporter._tw
|
||||
|
||||
def pytest_cmdline_parse(
|
||||
@@ -1138,25 +1140,10 @@ class Config:
|
||||
|
||||
@hookimpl(trylast=True)
|
||||
def pytest_load_initial_conftests(self, early_config: "Config") -> None:
|
||||
# We haven't fully parsed the command line arguments yet, so
|
||||
# early_config.args it not set yet. But we need it for
|
||||
# discovering the initial conftests. So "pre-run" the logic here.
|
||||
# It will be done for real in `parse()`.
|
||||
args, args_source = early_config._decide_args(
|
||||
args=early_config.known_args_namespace.file_or_dir,
|
||||
pyargs=early_config.known_args_namespace.pyargs,
|
||||
testpaths=early_config.getini("testpaths"),
|
||||
invocation_dir=early_config.invocation_params.dir,
|
||||
rootpath=early_config.rootpath,
|
||||
warn=False,
|
||||
)
|
||||
self.pluginmanager._set_initial_conftests(
|
||||
args=args,
|
||||
pyargs=early_config.known_args_namespace.pyargs,
|
||||
noconftest=early_config.known_args_namespace.noconftest,
|
||||
early_config.known_args_namespace,
|
||||
rootpath=early_config.rootpath,
|
||||
confcutdir=early_config.known_args_namespace.confcutdir,
|
||||
importmode=early_config.known_args_namespace.importmode,
|
||||
testpaths_ini=self.getini("testpaths"),
|
||||
)
|
||||
|
||||
def _initini(self, args: Sequence[str]) -> None:
|
||||
@@ -1236,49 +1223,6 @@ class Config:
|
||||
|
||||
return args
|
||||
|
||||
def _decide_args(
|
||||
self,
|
||||
*,
|
||||
args: List[str],
|
||||
pyargs: List[str],
|
||||
testpaths: List[str],
|
||||
invocation_dir: Path,
|
||||
rootpath: Path,
|
||||
warn: bool,
|
||||
) -> Tuple[List[str], ArgsSource]:
|
||||
"""Decide the args (initial paths/nodeids) to use given the relevant inputs.
|
||||
|
||||
:param warn: Whether can issue warnings.
|
||||
"""
|
||||
if args:
|
||||
source = Config.ArgsSource.ARGS
|
||||
result = args
|
||||
else:
|
||||
if invocation_dir == rootpath:
|
||||
source = Config.ArgsSource.TESTPATHS
|
||||
if pyargs:
|
||||
result = testpaths
|
||||
else:
|
||||
result = []
|
||||
for path in testpaths:
|
||||
result.extend(sorted(glob.iglob(path, recursive=True)))
|
||||
if testpaths and not result:
|
||||
if warn:
|
||||
warning_text = (
|
||||
"No files were found in testpaths; "
|
||||
"consider removing or adjusting your testpaths configuration. "
|
||||
"Searching recursively from the current directory instead."
|
||||
)
|
||||
self.issue_config_time_warning(
|
||||
PytestConfigWarning(warning_text), stacklevel=3
|
||||
)
|
||||
else:
|
||||
result = []
|
||||
if not result:
|
||||
source = Config.ArgsSource.INCOVATION_DIR
|
||||
result = [str(invocation_dir)]
|
||||
return result, source
|
||||
|
||||
def _preparse(self, args: List[str], addopts: bool = True) -> None:
|
||||
if addopts:
|
||||
env_addopts = os.environ.get("PYTEST_ADDOPTS", "")
|
||||
@@ -1427,17 +1371,34 @@ class Config:
|
||||
self.hook.pytest_cmdline_preparse(config=self, args=args)
|
||||
self._parser.after_preparse = True # type: ignore
|
||||
try:
|
||||
source = Config.ArgsSource.ARGS
|
||||
args = self._parser.parse_setoption(
|
||||
args, self.option, namespace=self.option
|
||||
)
|
||||
self.args, self.args_source = self._decide_args(
|
||||
args=args,
|
||||
pyargs=self.known_args_namespace.pyargs,
|
||||
testpaths=self.getini("testpaths"),
|
||||
invocation_dir=self.invocation_params.dir,
|
||||
rootpath=self.rootpath,
|
||||
warn=True,
|
||||
)
|
||||
if not args:
|
||||
if self.invocation_params.dir == self.rootpath:
|
||||
source = Config.ArgsSource.TESTPATHS
|
||||
testpaths: List[str] = self.getini("testpaths")
|
||||
if self.known_args_namespace.pyargs:
|
||||
args = testpaths
|
||||
else:
|
||||
args = []
|
||||
for path in testpaths:
|
||||
args.extend(sorted(glob.iglob(path, recursive=True)))
|
||||
if testpaths and not args:
|
||||
warning_text = (
|
||||
"No files were found in testpaths; "
|
||||
"consider removing or adjusting your testpaths configuration. "
|
||||
"Searching recursively from the current directory instead."
|
||||
)
|
||||
self.issue_config_time_warning(
|
||||
PytestConfigWarning(warning_text), stacklevel=3
|
||||
)
|
||||
if not args:
|
||||
source = Config.ArgsSource.INCOVATION_DIR
|
||||
args = [str(self.invocation_params.dir)]
|
||||
self.args = args
|
||||
self.args_source = source
|
||||
except PrintHelp:
|
||||
pass
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ from .exceptions import UsageError
|
||||
from _pytest.outcomes import fail
|
||||
from _pytest.pathlib import absolutepath
|
||||
from _pytest.pathlib import commonpath
|
||||
from _pytest.pathlib import safe_exists
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import Config
|
||||
@@ -152,6 +151,14 @@ def get_dirs_from_args(args: Iterable[str]) -> List[Path]:
|
||||
return path
|
||||
return path.parent
|
||||
|
||||
def safe_exists(path: Path) -> bool:
|
||||
# This can throw on paths that contain characters unrepresentable at the OS level,
|
||||
# or with invalid syntax on Windows (https://bugs.python.org/issue35306)
|
||||
try:
|
||||
return path.exists()
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
# These look like paths but may not exist
|
||||
possible_paths = (
|
||||
absolutepath(get_file_part_from_node_id(arg))
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""Discover and run doctests in modules and test files."""
|
||||
import bdb
|
||||
import functools
|
||||
import inspect
|
||||
import os
|
||||
import platform
|
||||
@@ -537,25 +536,6 @@ class DoctestModule(Module):
|
||||
tests, obj, name, module, source_lines, globs, seen
|
||||
)
|
||||
|
||||
if sys.version_info < (3, 13):
|
||||
|
||||
def _from_module(self, module, object):
|
||||
"""`cached_property` objects are never considered a part
|
||||
of the 'current module'. As such they are skipped by doctest.
|
||||
Here we override `_from_module` to check the underlying
|
||||
function instead. https://github.com/python/cpython/issues/107995
|
||||
"""
|
||||
if hasattr(functools, "cached_property") and isinstance(
|
||||
object, functools.cached_property
|
||||
):
|
||||
object = object.func
|
||||
|
||||
# Type ignored because this is a private function.
|
||||
return super()._from_module(module, object) # type: ignore[misc]
|
||||
|
||||
else: # pragma: no cover
|
||||
pass
|
||||
|
||||
if self.path.name == "conftest.py":
|
||||
module = self.config.pluginmanager._importconftest(
|
||||
self.path,
|
||||
|
||||
@@ -11,7 +11,6 @@ from _pytest.config import Config
|
||||
from _pytest.config import ExitCode
|
||||
from _pytest.config import PrintHelp
|
||||
from _pytest.config.argparsing import Parser
|
||||
from _pytest.terminal import TerminalReporter
|
||||
|
||||
|
||||
class HelpAction(Action):
|
||||
@@ -106,7 +105,7 @@ def pytest_cmdline_parse():
|
||||
if config.option.debug:
|
||||
# --debug | --debug <file.log> was provided.
|
||||
path = config.option.debug
|
||||
debugfile = open(path, "w", encoding="utf-8")
|
||||
debugfile = open(path, "w")
|
||||
debugfile.write(
|
||||
"versions pytest-%s, "
|
||||
"python-%s\ncwd=%s\nargs=%s\n\n"
|
||||
@@ -160,10 +159,7 @@ def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]:
|
||||
def showhelp(config: Config) -> None:
|
||||
import textwrap
|
||||
|
||||
reporter: Optional[TerminalReporter] = config.pluginmanager.get_plugin(
|
||||
"terminalreporter"
|
||||
)
|
||||
assert reporter is not None
|
||||
reporter = config.pluginmanager.get_plugin("terminalreporter")
|
||||
tw = reporter._tw
|
||||
tw.write(config._parser.optparser.format_help())
|
||||
tw.line()
|
||||
|
||||
@@ -502,10 +502,6 @@ class LogXML:
|
||||
# Local hack to handle xdist report order.
|
||||
workernode = getattr(report, "node", None)
|
||||
reporter = self.node_reporters.pop((nodeid, workernode))
|
||||
|
||||
for propname, propvalue in report.user_properties:
|
||||
reporter.add_property(propname, str(propvalue))
|
||||
|
||||
if reporter is not None:
|
||||
reporter.finalize()
|
||||
|
||||
@@ -603,6 +599,9 @@ class LogXML:
|
||||
reporter = self._opentestcase(report)
|
||||
reporter.write_captured_output(report)
|
||||
|
||||
for propname, propvalue in report.user_properties:
|
||||
reporter.add_property(propname, str(propvalue))
|
||||
|
||||
self.finalize(report)
|
||||
report_wid = getattr(report, "worker_id", None)
|
||||
report_ii = getattr(report, "item_index", None)
|
||||
|
||||
@@ -515,9 +515,7 @@ class LogCaptureFixture:
|
||||
return original_disable_level
|
||||
|
||||
def set_level(self, level: Union[int, str], logger: Optional[str] = None) -> None:
|
||||
"""Set the threshold level of a logger for the duration of a test.
|
||||
|
||||
Logging messages which are less severe than this level will not be captured.
|
||||
"""Set the level of a logger for the duration of a test.
|
||||
|
||||
.. versionchanged:: 3.4
|
||||
The levels of the loggers changed by this function will be
|
||||
@@ -660,8 +658,6 @@ class LoggingPlugin:
|
||||
)
|
||||
if self._log_cli_enabled():
|
||||
terminal_reporter = config.pluginmanager.get_plugin("terminalreporter")
|
||||
# Guaranteed by `_log_cli_enabled()`.
|
||||
assert terminal_reporter is not None
|
||||
capture_manager = config.pluginmanager.get_plugin("capturemanager")
|
||||
# if capturemanager plugin is disabled, live logging still works.
|
||||
self.log_cli_handler: Union[
|
||||
|
||||
+1
-7
@@ -36,7 +36,6 @@ from _pytest.outcomes import exit
|
||||
from _pytest.pathlib import absolutepath
|
||||
from _pytest.pathlib import bestrelpath
|
||||
from _pytest.pathlib import fnmatch_ex
|
||||
from _pytest.pathlib import safe_exists
|
||||
from _pytest.pathlib import visit
|
||||
from _pytest.reports import CollectReport
|
||||
from _pytest.reports import TestReport
|
||||
@@ -463,11 +462,6 @@ class _bestrelpath_cache(Dict[Path, str]):
|
||||
|
||||
@final
|
||||
class Session(nodes.FSCollector):
|
||||
"""The root of the collection tree.
|
||||
|
||||
``Session`` collects the initial paths given as arguments to pytest.
|
||||
"""
|
||||
|
||||
Interrupted = Interrupted
|
||||
Failed = Failed
|
||||
# Set on the session by runner.pytest_sessionstart.
|
||||
@@ -896,7 +890,7 @@ def resolve_collection_argument(
|
||||
strpath = search_pypath(strpath)
|
||||
fspath = invocation_path / strpath
|
||||
fspath = absolutepath(fspath)
|
||||
if not safe_exists(fspath):
|
||||
if not fspath.exists():
|
||||
msg = (
|
||||
"module or package not found: {arg} (missing __init__.py?)"
|
||||
if as_pypath
|
||||
|
||||
+8
-13
@@ -157,11 +157,10 @@ class NodeMeta(type):
|
||||
|
||||
|
||||
class Node(metaclass=NodeMeta):
|
||||
r"""Base class of :class:`Collector` and :class:`Item`, the components of
|
||||
the test collection tree.
|
||||
"""Base class for Collector and Item, the components of the test
|
||||
collection tree.
|
||||
|
||||
``Collector``\'s are the internal nodes of the tree, and ``Item``\'s are the
|
||||
leaf nodes.
|
||||
Collector subclasses have children; Items are leaf nodes.
|
||||
"""
|
||||
|
||||
# Implemented in the legacypath plugin.
|
||||
@@ -526,17 +525,15 @@ def get_fslocation_from_item(node: "Node") -> Tuple[Union[str, Path], Optional[i
|
||||
|
||||
|
||||
class Collector(Node):
|
||||
"""Base class of all collectors.
|
||||
|
||||
Collector create children through `collect()` and thus iteratively build
|
||||
the collection tree.
|
||||
"""
|
||||
"""Collector instances create children through collect() and thus
|
||||
iteratively build a tree."""
|
||||
|
||||
class CollectError(Exception):
|
||||
"""An error during collection, contains a custom message."""
|
||||
|
||||
def collect(self) -> Iterable[Union["Item", "Collector"]]:
|
||||
"""Collect children (items and collectors) for this collector."""
|
||||
"""Return a list of children (items and collectors) for this
|
||||
collection node."""
|
||||
raise NotImplementedError("abstract")
|
||||
|
||||
# TODO: This omits the style= parameter which breaks Liskov Substitution.
|
||||
@@ -580,8 +577,6 @@ def _check_initialpaths_for_relpath(session: "Session", path: Path) -> Optional[
|
||||
|
||||
|
||||
class FSCollector(Collector):
|
||||
"""Base class for filesystem collectors."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
fspath: Optional[LEGACY_PATH] = None,
|
||||
@@ -665,7 +660,7 @@ class File(FSCollector):
|
||||
|
||||
|
||||
class Item(Node):
|
||||
"""Base class of all test invocation items.
|
||||
"""A basic test invocation item.
|
||||
|
||||
Note that for a single function there might be multiple test invocation items.
|
||||
"""
|
||||
|
||||
+1
-29
@@ -523,8 +523,6 @@ def import_path(
|
||||
|
||||
if mode is ImportMode.importlib:
|
||||
module_name = module_name_from_path(path, root)
|
||||
with contextlib.suppress(KeyError):
|
||||
return sys.modules[module_name]
|
||||
|
||||
for meta_importer in sys.meta_path:
|
||||
spec = meta_importer.find_spec(module_name, [str(path.parent)])
|
||||
@@ -623,10 +621,6 @@ def module_name_from_path(path: Path, root: Path) -> str:
|
||||
# Use the parts for the relative path to the root path.
|
||||
path_parts = relative_path.parts
|
||||
|
||||
# Module name for packages do not contain the __init__ file.
|
||||
if path_parts[-1] == "__init__":
|
||||
path_parts = path_parts[:-1]
|
||||
|
||||
return ".".join(path_parts)
|
||||
|
||||
|
||||
@@ -639,9 +633,6 @@ def insert_missing_modules(modules: Dict[str, ModuleType], module_name: str) ->
|
||||
otherwise "src.tests.test_foo" is not importable by ``__import__``.
|
||||
"""
|
||||
module_parts = module_name.split(".")
|
||||
child_module: Union[ModuleType, None] = None
|
||||
module: Union[ModuleType, None] = None
|
||||
child_name: str = ""
|
||||
while module_name:
|
||||
if module_name not in modules:
|
||||
try:
|
||||
@@ -651,22 +642,13 @@ def insert_missing_modules(modules: Dict[str, ModuleType], module_name: str) ->
|
||||
# ourselves to fall back to creating a dummy module.
|
||||
if not sys.meta_path:
|
||||
raise ModuleNotFoundError
|
||||
module = importlib.import_module(module_name)
|
||||
importlib.import_module(module_name)
|
||||
except ModuleNotFoundError:
|
||||
module = ModuleType(
|
||||
module_name,
|
||||
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
|
||||
# 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_name = ".".join(module_parts)
|
||||
|
||||
@@ -791,13 +773,3 @@ def copytree(source: Path, target: Path) -> None:
|
||||
shutil.copyfile(x, newx)
|
||||
elif x.is_dir():
|
||||
newx.mkdir(exist_ok=True)
|
||||
|
||||
|
||||
def safe_exists(p: Path) -> bool:
|
||||
"""Like Path.exists(), but account for input arguments that might be too long (#11394)."""
|
||||
try:
|
||||
return p.exists()
|
||||
except (ValueError, OSError):
|
||||
# ValueError: stat: path too long for Windows
|
||||
# OSError: [WinError 123] The filename, directory name, or volume label syntax is incorrect
|
||||
return False
|
||||
|
||||
@@ -6,7 +6,6 @@ import collections.abc
|
||||
import contextlib
|
||||
import gc
|
||||
import importlib
|
||||
import locale
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
@@ -130,7 +129,6 @@ class LsofFdLeakChecker:
|
||||
stderr=subprocess.DEVNULL,
|
||||
check=True,
|
||||
text=True,
|
||||
encoding=locale.getpreferredencoding(False),
|
||||
).stdout
|
||||
|
||||
def isopen(line: str) -> bool:
|
||||
@@ -752,7 +750,7 @@ class Pytester:
|
||||
|
||||
def make_hook_recorder(self, pluginmanager: PytestPluginManager) -> HookRecorder:
|
||||
"""Create a new :class:`HookRecorder` for a :class:`PytestPluginManager`."""
|
||||
pluginmanager.reprec = reprec = HookRecorder(pluginmanager, _ispytest=True) # type: ignore[attr-defined]
|
||||
pluginmanager.reprec = reprec = HookRecorder(pluginmanager, _ispytest=True)
|
||||
self._request.addfinalizer(reprec.finish_recording)
|
||||
return reprec
|
||||
|
||||
|
||||
+10
-12
@@ -522,7 +522,7 @@ class PyCollector(PyobjMixin, nodes.Collector):
|
||||
|
||||
|
||||
class Module(nodes.File, PyCollector):
|
||||
"""Collector for test classes and functions in a Python module."""
|
||||
"""Collector for test classes and functions."""
|
||||
|
||||
def _getobj(self):
|
||||
return self._importtestmodule()
|
||||
@@ -659,9 +659,6 @@ class Module(nodes.File, PyCollector):
|
||||
|
||||
|
||||
class Package(Module):
|
||||
"""Collector for files and directories in a Python packages -- directories
|
||||
with an `__init__.py` file."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
fspath: Optional[LEGACY_PATH],
|
||||
@@ -791,7 +788,7 @@ def _get_first_non_fixture_func(obj: object, names: Iterable[str]) -> Optional[o
|
||||
|
||||
|
||||
class Class(PyCollector):
|
||||
"""Collector for test methods (and nested classes) in a Python class."""
|
||||
"""Collector for test methods."""
|
||||
|
||||
@classmethod
|
||||
def from_parent(cls, parent, *, name, obj=None, **kw):
|
||||
@@ -1152,7 +1149,7 @@ class CallSpec2:
|
||||
arg2scope = self._arg2scope.copy()
|
||||
for arg, val in zip(argnames, valset):
|
||||
if arg in params or arg in funcargs:
|
||||
raise ValueError(f"duplicate parametrization of {arg!r}")
|
||||
raise ValueError(f"duplicate {arg!r}")
|
||||
valtype_for_arg = valtypes[arg]
|
||||
if valtype_for_arg == "params":
|
||||
params[arg] = val
|
||||
@@ -1243,9 +1240,8 @@ class Metafunc:
|
||||
during the collection phase. If you need to setup expensive resources
|
||||
see about setting indirect to do it rather than at test setup time.
|
||||
|
||||
Can be called multiple times per test function (but only on different
|
||||
argument names), in which case each call parametrizes all previous
|
||||
parametrizations, e.g.
|
||||
Can be called multiple times, in which case each call parametrizes all
|
||||
previous parametrizations, e.g.
|
||||
|
||||
::
|
||||
|
||||
@@ -1677,7 +1673,7 @@ def write_docstring(tw: TerminalWriter, doc: str, indent: str = " ") -> None:
|
||||
|
||||
|
||||
class Function(PyobjMixin, nodes.Item):
|
||||
"""Item responsible for setting up and executing a Python test function.
|
||||
"""An Item responsible for setting up and executing a Python test function.
|
||||
|
||||
:param name:
|
||||
The full function name, including any decorations like those
|
||||
@@ -1834,8 +1830,10 @@ class Function(PyobjMixin, nodes.Item):
|
||||
|
||||
|
||||
class FunctionDefinition(Function):
|
||||
"""This class is a stop gap solution until we evolve to have actual function
|
||||
definition nodes and manage to get rid of ``metafunc``."""
|
||||
"""
|
||||
This class is a step gap solution until we evolve to have actual function definition nodes
|
||||
and manage to get rid of ``metafunc``.
|
||||
"""
|
||||
|
||||
def runtest(self) -> None:
|
||||
raise RuntimeError("function definitions are not supposed to be run as tests")
|
||||
|
||||
+12
-13
@@ -266,20 +266,19 @@ class ApproxMapping(ApproxBase):
|
||||
approx_side_as_map.items(), other_side.values()
|
||||
):
|
||||
if approx_value != other_value:
|
||||
if approx_value.expected is not None and other_value is not None:
|
||||
max_abs_diff = max(
|
||||
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)
|
||||
|
||||
message_data = [
|
||||
|
||||
+39
-59
@@ -1,9 +1,7 @@
|
||||
import contextlib
|
||||
import multiprocessing
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import warnings
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
@@ -11,14 +9,6 @@ from py import error
|
||||
from py.path import local
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def ignore_encoding_warning():
|
||||
with warnings.catch_warnings():
|
||||
with contextlib.suppress(NameError): # new in 3.10
|
||||
warnings.simplefilter("ignore", EncodingWarning)
|
||||
yield
|
||||
|
||||
|
||||
class CommonFSTests:
|
||||
def test_constructor_equality(self, path1):
|
||||
p = path1.__class__(path1)
|
||||
@@ -233,8 +223,7 @@ class CommonFSTests:
|
||||
assert not (path1 < path1)
|
||||
|
||||
def test_simple_read(self, path1):
|
||||
with ignore_encoding_warning():
|
||||
x = path1.join("samplefile").read("r")
|
||||
x = path1.join("samplefile").read("r")
|
||||
assert x == "samplefile\n"
|
||||
|
||||
def test_join_div_operator(self, path1):
|
||||
@@ -276,14 +265,12 @@ class CommonFSTests:
|
||||
|
||||
def test_readlines(self, path1):
|
||||
fn = path1.join("samplefile")
|
||||
with ignore_encoding_warning():
|
||||
contents = fn.readlines()
|
||||
contents = fn.readlines()
|
||||
assert contents == ["samplefile\n"]
|
||||
|
||||
def test_readlines_nocr(self, path1):
|
||||
fn = path1.join("samplefile")
|
||||
with ignore_encoding_warning():
|
||||
contents = fn.readlines(cr=0)
|
||||
contents = fn.readlines(cr=0)
|
||||
assert contents == ["samplefile", ""]
|
||||
|
||||
def test_file(self, path1):
|
||||
@@ -375,8 +362,8 @@ class CommonFSTests:
|
||||
initpy.copy(copied)
|
||||
try:
|
||||
assert copied.check()
|
||||
s1 = initpy.read_text(encoding="utf-8")
|
||||
s2 = copied.read_text(encoding="utf-8")
|
||||
s1 = initpy.read()
|
||||
s2 = copied.read()
|
||||
assert s1 == s2
|
||||
finally:
|
||||
if copied.check():
|
||||
@@ -389,8 +376,8 @@ class CommonFSTests:
|
||||
otherdir.copy(copied)
|
||||
assert copied.check(dir=1)
|
||||
assert copied.join("__init__.py").check(file=1)
|
||||
s1 = otherdir.join("__init__.py").read_text(encoding="utf-8")
|
||||
s2 = copied.join("__init__.py").read_text(encoding="utf-8")
|
||||
s1 = otherdir.join("__init__.py").read()
|
||||
s2 = copied.join("__init__.py").read()
|
||||
assert s1 == s2
|
||||
finally:
|
||||
if copied.check(dir=1):
|
||||
@@ -476,13 +463,13 @@ def setuptestfs(path):
|
||||
return
|
||||
# print "setting up test fs for", repr(path)
|
||||
samplefile = path.ensure("samplefile")
|
||||
samplefile.write_text("samplefile\n", encoding="utf-8")
|
||||
samplefile.write("samplefile\n")
|
||||
|
||||
execfile = path.ensure("execfile")
|
||||
execfile.write_text("x=42", encoding="utf-8")
|
||||
execfile.write("x=42")
|
||||
|
||||
execfilepy = path.ensure("execfile.py")
|
||||
execfilepy.write_text("x=42", encoding="utf-8")
|
||||
execfilepy.write("x=42")
|
||||
|
||||
d = {1: 2, "hello": "world", "answer": 42}
|
||||
path.ensure("samplepickle").dump(d)
|
||||
@@ -494,24 +481,22 @@ def setuptestfs(path):
|
||||
otherdir.ensure("__init__.py")
|
||||
|
||||
module_a = otherdir.ensure("a.py")
|
||||
module_a.write_text("from .b import stuff as result\n", encoding="utf-8")
|
||||
module_a.write("from .b import stuff as result\n")
|
||||
module_b = otherdir.ensure("b.py")
|
||||
module_b.write_text('stuff="got it"\n', encoding="utf-8")
|
||||
module_b.write('stuff="got it"\n')
|
||||
module_c = otherdir.ensure("c.py")
|
||||
module_c.write_text(
|
||||
module_c.write(
|
||||
"""import py;
|
||||
import otherdir.a
|
||||
value = otherdir.a.result
|
||||
""",
|
||||
encoding="utf-8",
|
||||
"""
|
||||
)
|
||||
module_d = otherdir.ensure("d.py")
|
||||
module_d.write_text(
|
||||
module_d.write(
|
||||
"""import py;
|
||||
from otherdir import a
|
||||
value2 = a.result
|
||||
""",
|
||||
encoding="utf-8",
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
@@ -549,11 +534,9 @@ def batch_make_numbered_dirs(rootdir, repeats):
|
||||
for i in range(repeats):
|
||||
dir_ = local.make_numbered_dir(prefix="repro-", rootdir=rootdir)
|
||||
file_ = dir_.join("foo")
|
||||
file_.write_text("%s" % i, encoding="utf-8")
|
||||
actual = int(file_.read_text(encoding="utf-8"))
|
||||
assert (
|
||||
actual == i
|
||||
), f"int(file_.read_text(encoding='utf-8')) is {actual} instead of {i}"
|
||||
file_.write("%s" % i)
|
||||
actual = int(file_.read())
|
||||
assert actual == i, f"int(file_.read()) is {actual} instead of {i}"
|
||||
dir_.join(".lock").remove(ignore_errors=True)
|
||||
return True
|
||||
|
||||
@@ -709,14 +692,14 @@ class TestLocalPath(CommonFSTests):
|
||||
|
||||
def test_open_and_ensure(self, path1):
|
||||
p = path1.join("sub1", "sub2", "file")
|
||||
with p.open("w", ensure=1, encoding="utf-8") as f:
|
||||
with p.open("w", ensure=1) as f:
|
||||
f.write("hello")
|
||||
assert p.read_text(encoding="utf-8") == "hello"
|
||||
assert p.read() == "hello"
|
||||
|
||||
def test_write_and_ensure(self, path1):
|
||||
p = path1.join("sub1", "sub2", "file")
|
||||
p.write_text("hello", ensure=1, encoding="utf-8")
|
||||
assert p.read_text(encoding="utf-8") == "hello"
|
||||
p.write("hello", ensure=1)
|
||||
assert p.read() == "hello"
|
||||
|
||||
@pytest.mark.parametrize("bin", (False, True))
|
||||
def test_dump(self, tmpdir, bin):
|
||||
@@ -787,9 +770,9 @@ class TestLocalPath(CommonFSTests):
|
||||
newfile = tmpdir.join("test1", "test")
|
||||
newfile.ensure()
|
||||
assert newfile.check(file=1)
|
||||
newfile.write_text("42", encoding="utf-8")
|
||||
newfile.write("42")
|
||||
newfile.ensure()
|
||||
s = newfile.read_text(encoding="utf-8")
|
||||
s = newfile.read()
|
||||
assert s == "42"
|
||||
|
||||
def test_ensure_filepath_withoutdir(self, tmpdir):
|
||||
@@ -823,9 +806,9 @@ class TestLocalPath(CommonFSTests):
|
||||
newfilename = "/test" * 60 # type:ignore[unreachable]
|
||||
l1 = tmpdir.join(newfilename)
|
||||
l1.ensure(file=True)
|
||||
l1.write_text("foo", encoding="utf-8")
|
||||
l1.write("foo")
|
||||
l2 = tmpdir.join(newfilename)
|
||||
assert l2.read_text(encoding="utf-8") == "foo"
|
||||
assert l2.read() == "foo"
|
||||
|
||||
def test_visit_depth_first(self, tmpdir):
|
||||
tmpdir.ensure("a", "1")
|
||||
@@ -1295,14 +1278,14 @@ class TestPOSIXLocalPath:
|
||||
def test_hardlink(self, tmpdir):
|
||||
linkpath = tmpdir.join("test")
|
||||
filepath = tmpdir.join("file")
|
||||
filepath.write_text("Hello", encoding="utf-8")
|
||||
filepath.write("Hello")
|
||||
nlink = filepath.stat().nlink
|
||||
linkpath.mklinkto(filepath)
|
||||
assert filepath.stat().nlink == nlink + 1
|
||||
|
||||
def test_symlink_are_identical(self, tmpdir):
|
||||
filepath = tmpdir.join("file")
|
||||
filepath.write_text("Hello", encoding="utf-8")
|
||||
filepath.write("Hello")
|
||||
linkpath = tmpdir.join("test")
|
||||
linkpath.mksymlinkto(filepath)
|
||||
assert linkpath.readlink() == str(filepath)
|
||||
@@ -1310,7 +1293,7 @@ class TestPOSIXLocalPath:
|
||||
def test_symlink_isfile(self, tmpdir):
|
||||
linkpath = tmpdir.join("test")
|
||||
filepath = tmpdir.join("file")
|
||||
filepath.write_text("", encoding="utf-8")
|
||||
filepath.write("")
|
||||
linkpath.mksymlinkto(filepath)
|
||||
assert linkpath.check(file=1)
|
||||
assert not linkpath.check(link=0, file=1)
|
||||
@@ -1319,12 +1302,10 @@ class TestPOSIXLocalPath:
|
||||
def test_symlink_relative(self, tmpdir):
|
||||
linkpath = tmpdir.join("test")
|
||||
filepath = tmpdir.join("file")
|
||||
filepath.write_text("Hello", encoding="utf-8")
|
||||
filepath.write("Hello")
|
||||
linkpath.mksymlinkto(filepath, absolute=False)
|
||||
assert linkpath.readlink() == "file"
|
||||
assert filepath.read_text(encoding="utf-8") == linkpath.read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
assert filepath.read() == linkpath.read()
|
||||
|
||||
def test_symlink_not_existing(self, tmpdir):
|
||||
linkpath = tmpdir.join("testnotexisting")
|
||||
@@ -1357,7 +1338,7 @@ class TestPOSIXLocalPath:
|
||||
def test_realpath_file(self, tmpdir):
|
||||
linkpath = tmpdir.join("test")
|
||||
filepath = tmpdir.join("file")
|
||||
filepath.write_text("", encoding="utf-8")
|
||||
filepath.write("")
|
||||
linkpath.mksymlinkto(filepath)
|
||||
realpath = linkpath.realpath()
|
||||
assert realpath.basename == "file"
|
||||
@@ -1402,7 +1383,7 @@ class TestPOSIXLocalPath:
|
||||
atime1 = path.atime()
|
||||
# we could wait here but timer resolution is very
|
||||
# system dependent
|
||||
path.read_binary()
|
||||
path.read()
|
||||
time.sleep(ATIME_RESOLUTION)
|
||||
atime2 = path.atime()
|
||||
time.sleep(ATIME_RESOLUTION)
|
||||
@@ -1486,7 +1467,7 @@ class TestPOSIXLocalPath:
|
||||
test_files = ["a", "b", "c"]
|
||||
src = tmpdir.join("src")
|
||||
for f in test_files:
|
||||
src.join(f).write_text(f, ensure=True, encoding="utf-8")
|
||||
src.join(f).write(f, ensure=True)
|
||||
dst = tmpdir.join("dst")
|
||||
# a small delay before the copy
|
||||
time.sleep(ATIME_RESOLUTION)
|
||||
@@ -1540,11 +1521,10 @@ class TestUnicodePy2Py3:
|
||||
def test_read_write(self, tmpdir):
|
||||
x = tmpdir.join("hello")
|
||||
part = "hällo"
|
||||
with ignore_encoding_warning():
|
||||
x.write(part)
|
||||
assert x.read() == part
|
||||
x.write(part.encode(sys.getdefaultencoding()))
|
||||
assert x.read() == part.encode(sys.getdefaultencoding())
|
||||
x.write(part)
|
||||
assert x.read() == part
|
||||
x.write(part.encode(sys.getdefaultencoding()))
|
||||
assert x.read() == part.encode(sys.getdefaultencoding())
|
||||
|
||||
|
||||
class TestBinaryAndTextMethods:
|
||||
|
||||
+14
-54
@@ -267,7 +267,7 @@ class TestGeneralUsage:
|
||||
def test_issue109_sibling_conftests_not_loaded(self, pytester: Pytester) -> None:
|
||||
sub1 = pytester.mkdir("sub1")
|
||||
sub2 = pytester.mkdir("sub2")
|
||||
sub1.joinpath("conftest.py").write_text("assert 0", encoding="utf-8")
|
||||
sub1.joinpath("conftest.py").write_text("assert 0")
|
||||
result = pytester.runpytest(sub2)
|
||||
assert result.ret == ExitCode.NO_TESTS_COLLECTED
|
||||
sub2.joinpath("__init__.py").touch()
|
||||
@@ -467,7 +467,7 @@ class TestGeneralUsage:
|
||||
assert "invalid" in str(excinfo.value)
|
||||
|
||||
p = pytester.path.joinpath("test_test_plugins_given_as_strings.py")
|
||||
p.write_text("def test_foo(): pass", encoding="utf-8")
|
||||
p.write_text("def test_foo(): pass")
|
||||
mod = types.ModuleType("myplugin")
|
||||
monkeypatch.setitem(sys.modules, "myplugin", mod)
|
||||
assert pytest.main(args=[str(pytester.path)], plugins=["myplugin"]) == 0
|
||||
@@ -587,7 +587,7 @@ class TestInvocationVariants:
|
||||
def test_pyargs_importerror(self, pytester: Pytester, monkeypatch) -> None:
|
||||
monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", False)
|
||||
path = pytester.mkpydir("tpkg")
|
||||
path.joinpath("test_hello.py").write_text("raise ImportError", encoding="utf-8")
|
||||
path.joinpath("test_hello.py").write_text("raise ImportError")
|
||||
|
||||
result = pytester.runpytest("--pyargs", "tpkg.test_hello", syspathinsert=True)
|
||||
assert result.ret != 0
|
||||
@@ -597,10 +597,10 @@ class TestInvocationVariants:
|
||||
def test_pyargs_only_imported_once(self, pytester: Pytester) -> None:
|
||||
pkg = pytester.mkpydir("foo")
|
||||
pkg.joinpath("test_foo.py").write_text(
|
||||
"print('hello from test_foo')\ndef test(): pass", encoding="utf-8"
|
||||
"print('hello from test_foo')\ndef test(): pass"
|
||||
)
|
||||
pkg.joinpath("conftest.py").write_text(
|
||||
"def pytest_configure(config): print('configuring')", encoding="utf-8"
|
||||
"def pytest_configure(config): print('configuring')"
|
||||
)
|
||||
|
||||
result = pytester.runpytest(
|
||||
@@ -613,7 +613,7 @@ class TestInvocationVariants:
|
||||
|
||||
def test_pyargs_filename_looks_like_module(self, pytester: Pytester) -> None:
|
||||
pytester.path.joinpath("conftest.py").touch()
|
||||
pytester.path.joinpath("t.py").write_text("def test(): pass", encoding="utf-8")
|
||||
pytester.path.joinpath("t.py").write_text("def test(): pass")
|
||||
result = pytester.runpytest("--pyargs", "t.py")
|
||||
assert result.ret == ExitCode.OK
|
||||
|
||||
@@ -622,12 +622,8 @@ class TestInvocationVariants:
|
||||
|
||||
monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", False)
|
||||
path = pytester.mkpydir("tpkg")
|
||||
path.joinpath("test_hello.py").write_text(
|
||||
"def test_hello(): pass", encoding="utf-8"
|
||||
)
|
||||
path.joinpath("test_world.py").write_text(
|
||||
"def test_world(): pass", encoding="utf-8"
|
||||
)
|
||||
path.joinpath("test_hello.py").write_text("def test_hello(): pass")
|
||||
path.joinpath("test_world.py").write_text("def test_world(): pass")
|
||||
result = pytester.runpytest("--pyargs", "tpkg")
|
||||
assert result.ret == 0
|
||||
result.stdout.fnmatch_lines(["*2 passed*"])
|
||||
@@ -666,15 +662,13 @@ class TestInvocationVariants:
|
||||
ns = d.joinpath("ns_pkg")
|
||||
ns.mkdir()
|
||||
ns.joinpath("__init__.py").write_text(
|
||||
"__import__('pkg_resources').declare_namespace(__name__)",
|
||||
encoding="utf-8",
|
||||
"__import__('pkg_resources').declare_namespace(__name__)"
|
||||
)
|
||||
lib = ns.joinpath(dirname)
|
||||
lib.mkdir()
|
||||
lib.joinpath("__init__.py").touch()
|
||||
lib.joinpath(f"test_{dirname}.py").write_text(
|
||||
f"def test_{dirname}(): pass\ndef test_other():pass",
|
||||
encoding="utf-8",
|
||||
f"def test_{dirname}(): pass\ndef test_other():pass"
|
||||
)
|
||||
|
||||
# The structure of the test directory is now:
|
||||
@@ -760,10 +754,10 @@ class TestInvocationVariants:
|
||||
lib.mkdir()
|
||||
lib.joinpath("__init__.py").touch()
|
||||
lib.joinpath("test_bar.py").write_text(
|
||||
"def test_bar(): pass\ndef test_other(a_fixture):pass", encoding="utf-8"
|
||||
"def test_bar(): pass\ndef test_other(a_fixture):pass"
|
||||
)
|
||||
lib.joinpath("conftest.py").write_text(
|
||||
"import pytest\n@pytest.fixture\ndef a_fixture():pass", encoding="utf-8"
|
||||
"import pytest\n@pytest.fixture\ndef a_fixture():pass"
|
||||
)
|
||||
|
||||
d_local = pytester.mkdir("symlink_root")
|
||||
@@ -1282,7 +1276,8 @@ def test_tee_stdio_captures_and_live_prints(pytester: Pytester) -> None:
|
||||
result.stderr.fnmatch_lines(["*@this is stderr@*"])
|
||||
|
||||
# now ensure the output is in the junitxml
|
||||
fullXml = pytester.path.joinpath("output.xml").read_text(encoding="utf-8")
|
||||
with open(pytester.path.joinpath("output.xml")) as f:
|
||||
fullXml = f.read()
|
||||
assert "@this is stdout@\n" in fullXml
|
||||
assert "@this is stderr@\n" in fullXml
|
||||
|
||||
@@ -1317,38 +1312,3 @@ def test_function_return_non_none_warning(pytester: Pytester) -> None:
|
||||
)
|
||||
res = pytester.runpytest()
|
||||
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*")
|
||||
|
||||
@@ -374,7 +374,7 @@ def test_excinfo_no_sourcecode():
|
||||
|
||||
def test_excinfo_no_python_sourcecode(tmp_path: Path) -> None:
|
||||
# XXX: simplified locally testable version
|
||||
tmp_path.joinpath("test.txt").write_text("{{ h()}}:", encoding="utf-8")
|
||||
tmp_path.joinpath("test.txt").write_text("{{ h()}}:")
|
||||
|
||||
jinja2 = pytest.importorskip("jinja2")
|
||||
loader = jinja2.FileSystemLoader(str(tmp_path))
|
||||
@@ -451,7 +451,7 @@ class TestFormattedExcinfo:
|
||||
source = textwrap.dedent(source)
|
||||
modpath = tmp_path.joinpath("mod.py")
|
||||
tmp_path.joinpath("__init__.py").touch()
|
||||
modpath.write_text(source, encoding="utf-8")
|
||||
modpath.write_text(source)
|
||||
importlib.invalidate_caches()
|
||||
return import_path(modpath, root=tmp_path)
|
||||
|
||||
@@ -1023,7 +1023,7 @@ raise ValueError()
|
||||
"""
|
||||
)
|
||||
excinfo = pytest.raises(ValueError, mod.f)
|
||||
tmp_path.joinpath("mod.py").write_text("asdf", encoding="utf-8")
|
||||
tmp_path.joinpath("mod.py").write_text("asdf")
|
||||
excinfo.traceback = excinfo.traceback.filter(excinfo)
|
||||
repr = excinfo.getrepr()
|
||||
repr.toterminal(tw_mock)
|
||||
|
||||
@@ -294,7 +294,7 @@ def test_source_of_class_at_eof_without_newline(_sys_snapshot, tmp_path: Path) -
|
||||
"""
|
||||
)
|
||||
path = tmp_path.joinpath("a.py")
|
||||
path.write_text(str(source), encoding="utf-8")
|
||||
path.write_text(str(source))
|
||||
mod: Any = import_path(path, root=tmp_path)
|
||||
s2 = Source(mod.A)
|
||||
assert str(source).strip() == str(s2).strip()
|
||||
|
||||
@@ -81,7 +81,7 @@ def test_root_logger_affected(pytester: Pytester) -> None:
|
||||
# not the info one, because the default level of the root logger is
|
||||
# WARNING.
|
||||
assert os.path.isfile(log_file)
|
||||
with open(log_file, encoding="utf-8") as rfh:
|
||||
with open(log_file) as rfh:
|
||||
contents = rfh.read()
|
||||
assert "info text going to logger" not in contents
|
||||
assert "warning text going to logger" in contents
|
||||
@@ -656,7 +656,7 @@ def test_log_file_cli(pytester: Pytester) -> None:
|
||||
# make sure that we get a '0' exit code for the testsuite
|
||||
assert result.ret == 0
|
||||
assert os.path.isfile(log_file)
|
||||
with open(log_file, encoding="utf-8") as rfh:
|
||||
with open(log_file) as rfh:
|
||||
contents = rfh.read()
|
||||
assert "This log message will be shown" in contents
|
||||
assert "This log message won't be shown" not in contents
|
||||
@@ -687,7 +687,7 @@ def test_log_file_cli_level(pytester: Pytester) -> None:
|
||||
# make sure that we get a '0' exit code for the testsuite
|
||||
assert result.ret == 0
|
||||
assert os.path.isfile(log_file)
|
||||
with open(log_file, encoding="utf-8") as rfh:
|
||||
with open(log_file) as rfh:
|
||||
contents = rfh.read()
|
||||
assert "This log message will be shown" in contents
|
||||
assert "This log message won't be shown" not in contents
|
||||
@@ -738,7 +738,7 @@ def test_log_file_ini(pytester: Pytester) -> None:
|
||||
# make sure that we get a '0' exit code for the testsuite
|
||||
assert result.ret == 0
|
||||
assert os.path.isfile(log_file)
|
||||
with open(log_file, encoding="utf-8") as rfh:
|
||||
with open(log_file) as rfh:
|
||||
contents = rfh.read()
|
||||
assert "This log message will be shown" in contents
|
||||
assert "This log message won't be shown" not in contents
|
||||
@@ -777,7 +777,7 @@ def test_log_file_ini_level(pytester: Pytester) -> None:
|
||||
# make sure that we get a '0' exit code for the testsuite
|
||||
assert result.ret == 0
|
||||
assert os.path.isfile(log_file)
|
||||
with open(log_file, encoding="utf-8") as rfh:
|
||||
with open(log_file) as rfh:
|
||||
contents = rfh.read()
|
||||
assert "This log message will be shown" in contents
|
||||
assert "This log message won't be shown" not in contents
|
||||
@@ -985,7 +985,7 @@ def test_log_in_hooks(pytester: Pytester) -> None:
|
||||
)
|
||||
result = pytester.runpytest()
|
||||
result.stdout.fnmatch_lines(["*sessionstart*", "*runtestloop*", "*sessionfinish*"])
|
||||
with open(log_file, encoding="utf-8") as rfh:
|
||||
with open(log_file) as rfh:
|
||||
contents = rfh.read()
|
||||
assert "sessionstart" in contents
|
||||
assert "runtestloop" in contents
|
||||
@@ -1021,7 +1021,7 @@ def test_log_in_runtest_logreport(pytester: Pytester) -> None:
|
||||
"""
|
||||
)
|
||||
pytester.runpytest()
|
||||
with open(log_file, encoding="utf-8") as rfh:
|
||||
with open(log_file) as rfh:
|
||||
contents = rfh.read()
|
||||
assert contents.count("logreport") == 3
|
||||
|
||||
@@ -1065,11 +1065,11 @@ def test_log_set_path(pytester: Pytester) -> None:
|
||||
"""
|
||||
)
|
||||
pytester.runpytest()
|
||||
with open(os.path.join(report_dir_base, "test_first"), encoding="utf-8") as rfh:
|
||||
with open(os.path.join(report_dir_base, "test_first")) as rfh:
|
||||
content = rfh.read()
|
||||
assert "message from test 1" in content
|
||||
|
||||
with open(os.path.join(report_dir_base, "test_second"), encoding="utf-8") as rfh:
|
||||
with open(os.path.join(report_dir_base, "test_second")) as rfh:
|
||||
content = rfh.read()
|
||||
assert "message from test 2" in content
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
anyio[curio,trio]==3.7.0
|
||||
django==4.2.2
|
||||
django==4.2.1
|
||||
pytest-asyncio==0.21.0
|
||||
pytest-bdd==6.1.1
|
||||
pytest-cov==4.1.0
|
||||
pytest-django==4.5.2
|
||||
pytest-flakes==4.0.5
|
||||
pytest-html==3.2.0
|
||||
pytest-mock==3.11.1
|
||||
pytest-mock==3.10.0
|
||||
pytest-rerunfailures==11.1.2
|
||||
pytest-sugar==0.9.7
|
||||
pytest-trio==0.7.0
|
||||
|
||||
@@ -122,23 +122,6 @@ 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(
|
||||
[1.0, 2.0, 3.0, 4.0],
|
||||
[1.0, 3.0, 3.0, 5.0],
|
||||
|
||||
+16
-31
@@ -60,8 +60,7 @@ class TestModule:
|
||||
""".format(
|
||||
str(root2)
|
||||
)
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
with monkeypatch.context() as mp:
|
||||
mp.chdir(root2)
|
||||
@@ -833,8 +832,7 @@ class TestConftestCustomization:
|
||||
mod = outcome.get_result()
|
||||
mod.obj.hello = "world"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
b.joinpath("test_module.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -842,8 +840,7 @@ class TestConftestCustomization:
|
||||
def test_hello():
|
||||
assert hello == "world"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
reprec = pytester.inline_run()
|
||||
reprec.assertoutcome(passed=1)
|
||||
@@ -864,8 +861,7 @@ class TestConftestCustomization:
|
||||
for func in result:
|
||||
func._some123 = "world"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
b.joinpath("test_module.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -878,8 +874,7 @@ class TestConftestCustomization:
|
||||
def test_hello(obj):
|
||||
assert obj == "world"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
reprec = pytester.inline_run()
|
||||
reprec.assertoutcome(passed=1)
|
||||
@@ -979,8 +974,7 @@ def test_setup_only_available_in_subdir(pytester: Pytester) -> None:
|
||||
def pytest_runtest_teardown(item):
|
||||
assert item.path.stem == "test_in_sub1"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
sub2.joinpath("conftest.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -993,11 +987,10 @@ def test_setup_only_available_in_subdir(pytester: Pytester) -> None:
|
||||
def pytest_runtest_teardown(item):
|
||||
assert item.path.stem == "test_in_sub2"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
sub1.joinpath("test_in_sub1.py").write_text("def test_1(): pass", encoding="utf-8")
|
||||
sub2.joinpath("test_in_sub2.py").write_text("def test_2(): pass", encoding="utf-8")
|
||||
sub1.joinpath("test_in_sub1.py").write_text("def test_1(): pass")
|
||||
sub2.joinpath("test_in_sub2.py").write_text("def test_2(): pass")
|
||||
result = pytester.runpytest("-v", "-s")
|
||||
result.assert_outcomes(passed=2)
|
||||
|
||||
@@ -1385,8 +1378,7 @@ def test_skip_duplicates_by_default(pytester: Pytester) -> None:
|
||||
def test_real():
|
||||
pass
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
result = pytester.runpytest(str(a), str(a))
|
||||
result.stdout.fnmatch_lines(["*collected 1 item*"])
|
||||
@@ -1406,8 +1398,7 @@ def test_keep_duplicates(pytester: Pytester) -> None:
|
||||
def test_real():
|
||||
pass
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
result = pytester.runpytest("--keep-duplicates", str(a), str(a))
|
||||
result.stdout.fnmatch_lines(["*collected 2 item*"])
|
||||
@@ -1452,12 +1443,8 @@ def test_package_with_modules(pytester: Pytester) -> None:
|
||||
sub2_test = sub2.joinpath("test")
|
||||
sub2_test.mkdir(parents=True)
|
||||
|
||||
sub1_test.joinpath("test_in_sub1.py").write_text(
|
||||
"def test_1(): pass", encoding="utf-8"
|
||||
)
|
||||
sub2_test.joinpath("test_in_sub2.py").write_text(
|
||||
"def test_2(): pass", encoding="utf-8"
|
||||
)
|
||||
sub1_test.joinpath("test_in_sub1.py").write_text("def test_1(): pass")
|
||||
sub2_test.joinpath("test_in_sub2.py").write_text("def test_2(): pass")
|
||||
|
||||
# Execute from .
|
||||
result = pytester.runpytest("-v", "-s")
|
||||
@@ -1501,11 +1488,9 @@ def test_package_ordering(pytester: Pytester) -> None:
|
||||
sub2_test = sub2.joinpath("test")
|
||||
sub2_test.mkdir(parents=True)
|
||||
|
||||
root.joinpath("Test_root.py").write_text("def test_1(): pass", encoding="utf-8")
|
||||
sub1.joinpath("Test_sub1.py").write_text("def test_2(): pass", encoding="utf-8")
|
||||
sub2_test.joinpath("test_sub2.py").write_text(
|
||||
"def test_3(): pass", encoding="utf-8"
|
||||
)
|
||||
root.joinpath("Test_root.py").write_text("def test_1(): pass")
|
||||
sub1.joinpath("Test_sub1.py").write_text("def test_2(): pass")
|
||||
sub2_test.joinpath("test_sub2.py").write_text("def test_3(): pass")
|
||||
|
||||
# Execute from .
|
||||
result = pytester.runpytest("-v", "-s")
|
||||
|
||||
+32
-62
@@ -287,8 +287,7 @@ class TestFillFixtures:
|
||||
def spam():
|
||||
return 'spam'
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
testfile = subdir.joinpath("test_spam.py")
|
||||
testfile.write_text(
|
||||
@@ -297,8 +296,7 @@ class TestFillFixtures:
|
||||
def test_spam(spam):
|
||||
assert spam == "spam"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
result = pytester.runpytest()
|
||||
result.stdout.fnmatch_lines(["*1 passed*"])
|
||||
@@ -361,8 +359,7 @@ class TestFillFixtures:
|
||||
def spam(request):
|
||||
return request.param
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
testfile = subdir.joinpath("test_spam.py")
|
||||
testfile.write_text(
|
||||
@@ -374,8 +371,7 @@ class TestFillFixtures:
|
||||
assert spam == params['spam']
|
||||
params['spam'] += 1
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
result = pytester.runpytest()
|
||||
result.stdout.fnmatch_lines(["*3 passed*"])
|
||||
@@ -407,8 +403,7 @@ class TestFillFixtures:
|
||||
def spam(request):
|
||||
return request.param
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
testfile = subdir.joinpath("test_spam.py")
|
||||
testfile.write_text(
|
||||
@@ -420,8 +415,7 @@ class TestFillFixtures:
|
||||
assert spam == params['spam']
|
||||
params['spam'] += 1
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
result = pytester.runpytest()
|
||||
result.stdout.fnmatch_lines(["*3 passed*"])
|
||||
@@ -1043,11 +1037,10 @@ class TestRequestBasic:
|
||||
def arg1():
|
||||
pass
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
p = b.joinpath("test_module.py")
|
||||
p.write_text("def test_func(arg1): pass", encoding="utf-8")
|
||||
p.write_text("def test_func(arg1): pass")
|
||||
result = pytester.runpytest(p, "--fixtures")
|
||||
assert result.ret == 0
|
||||
result.stdout.fnmatch_lines(
|
||||
@@ -1624,8 +1617,7 @@ class TestFixtureManagerParseFactories:
|
||||
def one():
|
||||
return 1
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
package.joinpath("test_x.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -1633,8 +1625,7 @@ class TestFixtureManagerParseFactories:
|
||||
def test_x(one):
|
||||
assert one == 1
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
sub = package.joinpath("sub")
|
||||
sub.mkdir()
|
||||
@@ -1647,8 +1638,7 @@ class TestFixtureManagerParseFactories:
|
||||
def one():
|
||||
return 2
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
sub.joinpath("test_y.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -1656,8 +1646,7 @@ class TestFixtureManagerParseFactories:
|
||||
def test_x(one):
|
||||
assert one == 2
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
reprec = pytester.inline_run()
|
||||
reprec.assertoutcome(passed=2)
|
||||
@@ -1682,8 +1671,7 @@ class TestFixtureManagerParseFactories:
|
||||
def teardown_module():
|
||||
values[:] = []
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
package.joinpath("test_x.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -1692,8 +1680,7 @@ class TestFixtureManagerParseFactories:
|
||||
def test_x():
|
||||
assert values == ["package"]
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
package = pytester.mkdir("package2")
|
||||
package.joinpath("__init__.py").write_text(
|
||||
@@ -1705,8 +1692,7 @@ class TestFixtureManagerParseFactories:
|
||||
def teardown_module():
|
||||
values[:] = []
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
package.joinpath("test_x.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -1715,8 +1701,7 @@ class TestFixtureManagerParseFactories:
|
||||
def test_x():
|
||||
assert values == ["package2"]
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
reprec = pytester.inline_run()
|
||||
reprec.assertoutcome(passed=2)
|
||||
@@ -1729,7 +1714,7 @@ class TestFixtureManagerParseFactories:
|
||||
)
|
||||
pytester.syspathinsert(pytester.path.name)
|
||||
package = pytester.mkdir("package")
|
||||
package.joinpath("__init__.py").write_text("", encoding="utf-8")
|
||||
package.joinpath("__init__.py").write_text("")
|
||||
package.joinpath("conftest.py").write_text(
|
||||
textwrap.dedent(
|
||||
"""\
|
||||
@@ -1746,8 +1731,7 @@ class TestFixtureManagerParseFactories:
|
||||
yield values
|
||||
values.pop()
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
package.joinpath("test_x.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -1758,8 +1742,7 @@ class TestFixtureManagerParseFactories:
|
||||
def test_package(one):
|
||||
assert values == ["package-auto", "package"]
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
reprec = pytester.inline_run()
|
||||
reprec.assertoutcome(passed=2)
|
||||
@@ -1909,12 +1892,8 @@ class TestAutouseDiscovery:
|
||||
"""
|
||||
)
|
||||
conftest.rename(a.joinpath(conftest.name))
|
||||
a.joinpath("test_something.py").write_text(
|
||||
"def test_func(): pass", encoding="utf-8"
|
||||
)
|
||||
b.joinpath("test_otherthing.py").write_text(
|
||||
"def test_func(): pass", encoding="utf-8"
|
||||
)
|
||||
a.joinpath("test_something.py").write_text("def test_func(): pass")
|
||||
b.joinpath("test_otherthing.py").write_text("def test_func(): pass")
|
||||
result = pytester.runpytest()
|
||||
result.stdout.fnmatch_lines(
|
||||
"""
|
||||
@@ -1960,8 +1939,7 @@ class TestAutouseManagement:
|
||||
import sys
|
||||
sys._myapp = "hello"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
sub = pkgdir.joinpath("tests")
|
||||
sub.mkdir()
|
||||
@@ -1974,8 +1952,7 @@ class TestAutouseManagement:
|
||||
def test_app():
|
||||
assert sys._myapp == "hello"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
reprec = pytester.inline_run("-s")
|
||||
reprec.assertoutcome(passed=1)
|
||||
@@ -2905,7 +2882,7 @@ class TestFixtureMarker:
|
||||
def browser(request):
|
||||
|
||||
def finalize():
|
||||
sys.stdout.write_text('Finalized', encoding='utf-8')
|
||||
sys.stdout.write_text('Finalized')
|
||||
request.addfinalizer(finalize)
|
||||
return {}
|
||||
"""
|
||||
@@ -2923,8 +2900,7 @@ class TestFixtureMarker:
|
||||
def test_browser(browser):
|
||||
assert browser['visited'] is True
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
reprec = pytester.runpytest("-s")
|
||||
for test in ["test_browser"]:
|
||||
@@ -3879,8 +3855,7 @@ class TestParameterizedSubRequest:
|
||||
def fix_with_param(request):
|
||||
return request.param
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
|
||||
testfile = tests_dir.joinpath("test_foos.py")
|
||||
@@ -3892,8 +3867,7 @@ class TestParameterizedSubRequest:
|
||||
def test_foo(request):
|
||||
request.getfixturevalue('fix_with_param')
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
|
||||
os.chdir(tests_dir)
|
||||
@@ -4222,7 +4196,7 @@ class TestScopeOrdering:
|
||||
└── test_2.py
|
||||
"""
|
||||
root = pytester.mkdir("root")
|
||||
root.joinpath("__init__.py").write_text("values = []", encoding="utf-8")
|
||||
root.joinpath("__init__.py").write_text("values = []")
|
||||
sub1 = root.joinpath("sub1")
|
||||
sub1.mkdir()
|
||||
sub1.joinpath("__init__.py").touch()
|
||||
@@ -4237,8 +4211,7 @@ class TestScopeOrdering:
|
||||
yield values
|
||||
assert values.pop() == "pre-sub1"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
sub1.joinpath("test_1.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -4247,8 +4220,7 @@ class TestScopeOrdering:
|
||||
def test_1(fix):
|
||||
assert values == ["pre-sub1"]
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
sub2 = root.joinpath("sub2")
|
||||
sub2.mkdir()
|
||||
@@ -4264,8 +4236,7 @@ class TestScopeOrdering:
|
||||
yield values
|
||||
assert values.pop() == "pre-sub2"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
sub2.joinpath("test_2.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -4274,8 +4245,7 @@ class TestScopeOrdering:
|
||||
def test_2(fix):
|
||||
assert values == ["pre-sub2"]
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
reprec = pytester.inline_run()
|
||||
reprec.assertoutcome(passed=2)
|
||||
|
||||
@@ -1443,8 +1443,7 @@ class TestMetafuncFunctional:
|
||||
def pytest_generate_tests(metafunc):
|
||||
assert metafunc.function.__name__ == "test_1"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
sub2.joinpath("conftest.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -1452,15 +1451,10 @@ class TestMetafuncFunctional:
|
||||
def pytest_generate_tests(metafunc):
|
||||
assert metafunc.function.__name__ == "test_2"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
sub1.joinpath("test_in_sub1.py").write_text(
|
||||
"def test_1(): pass", encoding="utf-8"
|
||||
)
|
||||
sub2.joinpath("test_in_sub2.py").write_text(
|
||||
"def test_2(): pass", encoding="utf-8"
|
||||
)
|
||||
)
|
||||
sub1.joinpath("test_in_sub1.py").write_text("def test_1(): pass")
|
||||
sub2.joinpath("test_in_sub2.py").write_text("def test_2(): pass")
|
||||
result = pytester.runpytest("--keep-duplicates", "-v", "-s", sub1, sub2, sub1)
|
||||
result.assert_outcomes(passed=3)
|
||||
|
||||
|
||||
@@ -1392,14 +1392,14 @@ def test_sequence_comparison_uses_repr(pytester: Pytester) -> None:
|
||||
def test_assertrepr_loaded_per_dir(pytester: Pytester) -> None:
|
||||
pytester.makepyfile(test_base=["def test_base(): assert 1 == 2"])
|
||||
a = pytester.mkdir("a")
|
||||
a.joinpath("test_a.py").write_text("def test_a(): assert 1 == 2", encoding="utf-8")
|
||||
a.joinpath("test_a.py").write_text("def test_a(): assert 1 == 2")
|
||||
a.joinpath("conftest.py").write_text(
|
||||
'def pytest_assertrepr_compare(): return ["summary a"]', encoding="utf-8"
|
||||
'def pytest_assertrepr_compare(): return ["summary a"]'
|
||||
)
|
||||
b = pytester.mkdir("b")
|
||||
b.joinpath("test_b.py").write_text("def test_b(): assert 1 == 2", encoding="utf-8")
|
||||
b.joinpath("test_b.py").write_text("def test_b(): assert 1 == 2")
|
||||
b.joinpath("conftest.py").write_text(
|
||||
'def pytest_assertrepr_compare(): return ["summary b"]', encoding="utf-8"
|
||||
'def pytest_assertrepr_compare(): return ["summary b"]'
|
||||
)
|
||||
|
||||
result = pytester.runpytest()
|
||||
|
||||
@@ -160,8 +160,7 @@ class TestAssertionRewrite:
|
||||
"def special_asserter():\n"
|
||||
" def special_assert(x, y):\n"
|
||||
" assert x == y\n"
|
||||
" return special_assert\n",
|
||||
encoding="utf-8",
|
||||
" return special_assert\n"
|
||||
)
|
||||
pytester.makeconftest('pytest_plugins = ["plugin"]')
|
||||
pytester.makepyfile("def test(special_asserter): special_asserter(1, 2)\n")
|
||||
@@ -174,9 +173,7 @@ class TestAssertionRewrite:
|
||||
pytester.makepyfile(test_y="x = 1")
|
||||
xdir = pytester.mkdir("x")
|
||||
pytester.mkpydir(str(xdir.joinpath("test_Y")))
|
||||
xdir.joinpath("test_Y").joinpath("__init__.py").write_text(
|
||||
"x = 2", encoding="utf-8"
|
||||
)
|
||||
xdir.joinpath("test_Y").joinpath("__init__.py").write_text("x = 2")
|
||||
pytester.makepyfile(
|
||||
"import test_y\n"
|
||||
"import test_Y\n"
|
||||
@@ -729,7 +726,7 @@ class TestAssertionRewrite:
|
||||
|
||||
class TestRewriteOnImport:
|
||||
def test_pycache_is_a_file(self, pytester: Pytester) -> None:
|
||||
pytester.path.joinpath("__pycache__").write_text("Hello", encoding="utf-8")
|
||||
pytester.path.joinpath("__pycache__").write_text("Hello")
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
def test_rewritten():
|
||||
@@ -906,8 +903,7 @@ def test_rewritten():
|
||||
pkg.joinpath("test_blah.py").write_text(
|
||||
"""
|
||||
def test_rewritten():
|
||||
assert "@py_builtins" in globals()""",
|
||||
encoding="utf-8",
|
||||
assert "@py_builtins" in globals()"""
|
||||
)
|
||||
assert pytester.runpytest().ret == 0
|
||||
|
||||
@@ -1070,7 +1066,7 @@ class TestAssertionRewriteHookDetails:
|
||||
source = tmp_path / "source.py"
|
||||
pyc = Path(str(source) + "c")
|
||||
|
||||
source.write_text("def test(): pass", encoding="utf-8")
|
||||
source.write_text("def test(): pass")
|
||||
py_compile.compile(str(source), str(pyc))
|
||||
|
||||
contents = pyc.read_bytes()
|
||||
@@ -1096,7 +1092,7 @@ class TestAssertionRewriteHookDetails:
|
||||
fn = tmp_path / "source.py"
|
||||
pyc = Path(str(fn) + "c")
|
||||
|
||||
fn.write_text("def test(): assert True", encoding="utf-8")
|
||||
fn.write_text("def test(): assert True")
|
||||
|
||||
source_stat, co = _rewrite_test(fn, config)
|
||||
_write_pyc(state, co, source_stat, pyc)
|
||||
@@ -1161,7 +1157,7 @@ class TestAssertionRewriteHookDetails:
|
||||
return False
|
||||
|
||||
def rewrite_self():
|
||||
with open(__file__, 'w', encoding='utf-8') as self:
|
||||
with open(__file__, 'w') as self:
|
||||
self.write('def reloaded(): return True')
|
||||
""",
|
||||
test_fun="""
|
||||
@@ -1191,10 +1187,9 @@ class TestAssertionRewriteHookDetails:
|
||||
data = pkgutil.get_data('foo.test_foo', 'data.txt')
|
||||
assert data == b'Hey'
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
path.joinpath("data.txt").write_text("Hey", encoding="utf-8")
|
||||
path.joinpath("data.txt").write_text("Hey")
|
||||
result = pytester.runpytest()
|
||||
result.stdout.fnmatch_lines(["*1 passed*"])
|
||||
|
||||
|
||||
@@ -38,9 +38,7 @@ class TestNewAPI:
|
||||
@pytest.mark.filterwarnings("ignore:could not create cache path")
|
||||
def test_cache_writefail_cachfile_silent(self, pytester: Pytester) -> None:
|
||||
pytester.makeini("[pytest]")
|
||||
pytester.path.joinpath(".pytest_cache").write_text(
|
||||
"gone wrong", encoding="utf-8"
|
||||
)
|
||||
pytester.path.joinpath(".pytest_cache").write_text("gone wrong")
|
||||
config = pytester.parseconfigure()
|
||||
cache = config.cache
|
||||
assert cache is not None
|
||||
@@ -1136,9 +1134,7 @@ class TestNewFirst:
|
||||
["*test_2/test_2.py::test_1 PASSED*", "*test_1/test_1.py::test_1 PASSED*"]
|
||||
)
|
||||
|
||||
p1.write_text(
|
||||
"def test_1(): assert 1\n" "def test_2(): assert 1\n", encoding="utf-8"
|
||||
)
|
||||
p1.write_text("def test_1(): assert 1\n" "def test_2(): assert 1\n")
|
||||
os.utime(p1, ns=(p1.stat().st_atime_ns, int(1e9)))
|
||||
|
||||
result = pytester.runpytest("--nf", "--collect-only", "-q")
|
||||
@@ -1211,8 +1207,7 @@ class TestNewFirst:
|
||||
p1.write_text(
|
||||
"import pytest\n"
|
||||
"@pytest.mark.parametrize('num', [1, 2, 3])\n"
|
||||
"def test_1(num): assert num\n",
|
||||
encoding="utf-8",
|
||||
"def test_1(num): assert num\n"
|
||||
)
|
||||
os.utime(p1, ns=(p1.stat().st_atime_ns, int(1e9)))
|
||||
|
||||
@@ -1264,7 +1259,7 @@ def test_gitignore(pytester: Pytester) -> None:
|
||||
assert gitignore_path.read_text(encoding="UTF-8") == msg
|
||||
|
||||
# Does not overwrite existing/custom one.
|
||||
gitignore_path.write_text("custom", encoding="utf-8")
|
||||
gitignore_path.write_text("custom")
|
||||
cache.set("something", "else")
|
||||
assert gitignore_path.read_text(encoding="UTF-8") == "custom"
|
||||
|
||||
|
||||
@@ -750,10 +750,9 @@ def test_setup_failure_does_not_kill_capturing(pytester: Pytester) -> None:
|
||||
def pytest_runtest_setup(item):
|
||||
raise ValueError(42)
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
sub1.joinpath("test_mod.py").write_text("def test_func1(): pass", encoding="utf-8")
|
||||
sub1.joinpath("test_mod.py").write_text("def test_func1(): pass")
|
||||
result = pytester.runpytest(pytester.path, "--traceconfig")
|
||||
result.stdout.fnmatch_lines(["*ValueError(42)*", "*1 error*"])
|
||||
|
||||
@@ -1524,9 +1523,9 @@ def test_global_capture_with_live_logging(pytester: Pytester) -> None:
|
||||
def pytest_runtest_logreport(report):
|
||||
if "test_global" in report.nodeid:
|
||||
if report.when == "teardown":
|
||||
with open("caplog", "w", encoding="utf-8") as f:
|
||||
with open("caplog", "w") as f:
|
||||
f.write(report.caplog)
|
||||
with open("capstdout", "w", encoding="utf-8") as f:
|
||||
with open("capstdout", "w") as f:
|
||||
f.write(report.capstdout)
|
||||
"""
|
||||
)
|
||||
@@ -1556,14 +1555,14 @@ def test_global_capture_with_live_logging(pytester: Pytester) -> None:
|
||||
result = pytester.runpytest_subprocess("--log-cli-level=INFO")
|
||||
assert result.ret == 0
|
||||
|
||||
with open("caplog", encoding="utf-8") as f:
|
||||
with open("caplog") as f:
|
||||
caplog = f.read()
|
||||
|
||||
assert "fix setup" in caplog
|
||||
assert "something in test" in caplog
|
||||
assert "fix teardown" in caplog
|
||||
|
||||
with open("capstdout", encoding="utf-8") as f:
|
||||
with open("capstdout") as f:
|
||||
capstdout = f.read()
|
||||
|
||||
assert "fix setup" in capstdout
|
||||
|
||||
+26
-56
@@ -140,7 +140,7 @@ class TestCollectFS:
|
||||
ensure_file(tmp_path / ".bzr" / "test_notfound.py")
|
||||
ensure_file(tmp_path / "normal" / "test_found.py")
|
||||
for x in tmp_path.rglob("test_*.py"):
|
||||
x.write_text("def test_hello(): pass", encoding="utf-8")
|
||||
x.write_text("def test_hello(): pass", "utf-8")
|
||||
|
||||
result = pytester.runpytest("--collect-only")
|
||||
s = result.stdout.str()
|
||||
@@ -162,7 +162,7 @@ class TestCollectFS:
|
||||
bindir = "Scripts" if sys.platform.startswith("win") else "bin"
|
||||
ensure_file(pytester.path / "virtual" / bindir / fname)
|
||||
testfile = ensure_file(pytester.path / "virtual" / "test_invenv.py")
|
||||
testfile.write_text("def test_hello(): pass", encoding="utf-8")
|
||||
testfile.write_text("def test_hello(): pass")
|
||||
|
||||
# by default, ignore tests inside a virtualenv
|
||||
result = pytester.runpytest()
|
||||
@@ -192,7 +192,7 @@ class TestCollectFS:
|
||||
# norecursedirs takes priority
|
||||
ensure_file(pytester.path / ".virtual" / bindir / fname)
|
||||
testfile = ensure_file(pytester.path / ".virtual" / "test_invenv.py")
|
||||
testfile.write_text("def test_hello(): pass", encoding="utf-8")
|
||||
testfile.write_text("def test_hello(): pass")
|
||||
result = pytester.runpytest("--collect-in-virtualenv")
|
||||
result.stdout.no_fnmatch_line("*test_invenv*")
|
||||
# ...unless the virtualenv is explicitly given on the CLI
|
||||
@@ -231,14 +231,10 @@ class TestCollectFS:
|
||||
)
|
||||
tmp_path = pytester.path
|
||||
ensure_file(tmp_path / "mydir" / "test_hello.py").write_text(
|
||||
"def test_1(): pass", encoding="utf-8"
|
||||
)
|
||||
ensure_file(tmp_path / "xyz123" / "test_2.py").write_text(
|
||||
"def test_2(): 0/0", encoding="utf-8"
|
||||
)
|
||||
ensure_file(tmp_path / "xy" / "test_ok.py").write_text(
|
||||
"def test_3(): pass", encoding="utf-8"
|
||||
"def test_1(): pass"
|
||||
)
|
||||
ensure_file(tmp_path / "xyz123" / "test_2.py").write_text("def test_2(): 0/0")
|
||||
ensure_file(tmp_path / "xy" / "test_ok.py").write_text("def test_3(): pass")
|
||||
rec = pytester.inline_run()
|
||||
rec.assertoutcome(passed=1)
|
||||
rec = pytester.inline_run("xyz123/test_2.py")
|
||||
@@ -252,14 +248,12 @@ class TestCollectFS:
|
||||
"""
|
||||
)
|
||||
tmp_path = pytester.path
|
||||
ensure_file(tmp_path / "a" / "test_1.py").write_text(
|
||||
"def test_a(): pass", encoding="utf-8"
|
||||
)
|
||||
ensure_file(tmp_path / "a" / "test_1.py").write_text("def test_a(): pass")
|
||||
ensure_file(tmp_path / "b" / "tests" / "test_2.py").write_text(
|
||||
"def test_b(): pass", encoding="utf-8"
|
||||
"def test_b(): pass"
|
||||
)
|
||||
ensure_file(tmp_path / "c" / "tests" / "test_3.py").write_text(
|
||||
"def test_c(): pass", encoding="utf-8"
|
||||
"def test_c(): pass"
|
||||
)
|
||||
|
||||
# executing from rootdir only tests from `testpaths` directories
|
||||
@@ -355,8 +349,8 @@ class TestCustomConftests:
|
||||
"""
|
||||
)
|
||||
sub = pytester.mkdir("xy123")
|
||||
ensure_file(sub / "test_hello.py").write_text("syntax error", encoding="utf-8")
|
||||
sub.joinpath("conftest.py").write_text("syntax error", encoding="utf-8")
|
||||
ensure_file(sub / "test_hello.py").write_text("syntax error")
|
||||
sub.joinpath("conftest.py").write_text("syntax error")
|
||||
pytester.makepyfile("def test_hello(): pass")
|
||||
pytester.makepyfile(test_one="syntax error")
|
||||
result = pytester.runpytest("--fulltrace")
|
||||
@@ -1066,18 +1060,13 @@ def test_fixture_scope_sibling_conftests(pytester: Pytester) -> None:
|
||||
def fix():
|
||||
return 1
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
foo_path.joinpath("test_foo.py").write_text(
|
||||
"def test_foo(fix): assert fix == 1", encoding="utf-8"
|
||||
)
|
||||
)
|
||||
foo_path.joinpath("test_foo.py").write_text("def test_foo(fix): assert fix == 1")
|
||||
|
||||
# Tests in `food/` should not see the conftest fixture from `foo/`
|
||||
food_path = pytester.mkpydir("food")
|
||||
food_path.joinpath("test_food.py").write_text(
|
||||
"def test_food(fix): assert fix == 1", encoding="utf-8"
|
||||
)
|
||||
food_path.joinpath("test_food.py").write_text("def test_food(fix): assert fix == 1")
|
||||
|
||||
res = pytester.runpytest()
|
||||
assert res.ret == 1
|
||||
@@ -1208,8 +1197,7 @@ def test_collect_with_chdir_during_import(pytester: Pytester) -> None:
|
||||
os.chdir(%r)
|
||||
"""
|
||||
% (str(subdir),)
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
@@ -1239,12 +1227,8 @@ def test_collect_pyargs_with_testpaths(
|
||||
) -> None:
|
||||
testmod = pytester.mkdir("testmod")
|
||||
# NOTE: __init__.py is not collected since it does not match python_files.
|
||||
testmod.joinpath("__init__.py").write_text(
|
||||
"def test_func(): pass", encoding="utf-8"
|
||||
)
|
||||
testmod.joinpath("test_file.py").write_text(
|
||||
"def test_func(): pass", encoding="utf-8"
|
||||
)
|
||||
testmod.joinpath("__init__.py").write_text("def test_func(): pass")
|
||||
testmod.joinpath("test_file.py").write_text("def test_func(): pass")
|
||||
|
||||
root = pytester.mkdir("root")
|
||||
root.joinpath("pytest.ini").write_text(
|
||||
@@ -1254,8 +1238,7 @@ def test_collect_pyargs_with_testpaths(
|
||||
addopts = --pyargs
|
||||
testpaths = testmod
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
monkeypatch.setenv("PYTHONPATH", str(pytester.path), prepend=os.pathsep)
|
||||
with monkeypatch.context() as mp:
|
||||
@@ -1273,8 +1256,7 @@ def test_initial_conftests_with_testpaths(pytester: Pytester) -> None:
|
||||
def pytest_sessionstart(session):
|
||||
raise Exception("pytest_sessionstart hook successfully run")
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
pytester.makeini(
|
||||
"""
|
||||
@@ -1282,18 +1264,11 @@ def test_initial_conftests_with_testpaths(pytester: Pytester) -> None:
|
||||
testpaths = some_path
|
||||
"""
|
||||
)
|
||||
|
||||
# No command line args - falls back to testpaths.
|
||||
result = pytester.runpytest()
|
||||
assert result.ret == ExitCode.INTERNAL_ERROR
|
||||
result.stdout.fnmatch_lines(
|
||||
"INTERNALERROR* Exception: pytest_sessionstart hook successfully run"
|
||||
)
|
||||
|
||||
# No fallback.
|
||||
result = pytester.runpytest(".")
|
||||
assert result.ret == ExitCode.NO_TESTS_COLLECTED
|
||||
|
||||
|
||||
def test_large_option_breaks_initial_conftests(pytester: Pytester) -> None:
|
||||
"""Long option values do not break initial conftests handling (#10169)."""
|
||||
@@ -1341,7 +1316,6 @@ def test_collect_symlink_out_of_tree(pytester: Pytester) -> None:
|
||||
assert request.node.nodeid == "test_real.py::test_nodeid"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
out_of_tree = pytester.mkdir("out_of_tree")
|
||||
@@ -1370,16 +1344,12 @@ def test_collect_symlink_dir(pytester: Pytester) -> None:
|
||||
def test_collectignore_via_conftest(pytester: Pytester) -> None:
|
||||
"""collect_ignore in parent conftest skips importing child (issue #4592)."""
|
||||
tests = pytester.mkpydir("tests")
|
||||
tests.joinpath("conftest.py").write_text(
|
||||
"collect_ignore = ['ignore_me']", encoding="utf-8"
|
||||
)
|
||||
tests.joinpath("conftest.py").write_text("collect_ignore = ['ignore_me']")
|
||||
|
||||
ignore_me = tests.joinpath("ignore_me")
|
||||
ignore_me.mkdir()
|
||||
ignore_me.joinpath("__init__.py").touch()
|
||||
ignore_me.joinpath("conftest.py").write_text(
|
||||
"assert 0, 'should_not_be_called'", encoding="utf-8"
|
||||
)
|
||||
ignore_me.joinpath("conftest.py").write_text("assert 0, 'should_not_be_called'")
|
||||
|
||||
result = pytester.runpytest()
|
||||
assert result.ret == ExitCode.NO_TESTS_COLLECTED
|
||||
@@ -1388,9 +1358,9 @@ def test_collectignore_via_conftest(pytester: Pytester) -> None:
|
||||
def test_collect_pkg_init_and_file_in_args(pytester: Pytester) -> None:
|
||||
subdir = pytester.mkdir("sub")
|
||||
init = subdir.joinpath("__init__.py")
|
||||
init.write_text("def test_init(): pass", encoding="utf-8")
|
||||
init.write_text("def test_init(): pass")
|
||||
p = subdir.joinpath("test_file.py")
|
||||
p.write_text("def test_file(): pass", encoding="utf-8")
|
||||
p.write_text("def test_file(): pass")
|
||||
|
||||
# NOTE: without "-o python_files=*.py" this collects test_file.py twice.
|
||||
# This changed/broke with "Add package scoped fixtures #2283" (2b1410895)
|
||||
@@ -1417,7 +1387,7 @@ def test_collect_pkg_init_and_file_in_args(pytester: Pytester) -> None:
|
||||
def test_collect_pkg_init_only(pytester: Pytester) -> None:
|
||||
subdir = pytester.mkdir("sub")
|
||||
init = subdir.joinpath("__init__.py")
|
||||
init.write_text("def test_init(): pass", encoding="utf-8")
|
||||
init.write_text("def test_init(): pass")
|
||||
|
||||
result = pytester.runpytest(str(init))
|
||||
result.stdout.fnmatch_lines(["*no tests ran in*"])
|
||||
@@ -1432,7 +1402,7 @@ def test_collect_sub_with_symlinks(use_pkg: bool, pytester: Pytester) -> None:
|
||||
sub = pytester.mkdir("sub")
|
||||
if use_pkg:
|
||||
sub.joinpath("__init__.py").touch()
|
||||
sub.joinpath("test_file.py").write_text("def test_file(): pass", encoding="utf-8")
|
||||
sub.joinpath("test_file.py").write_text("def test_file(): pass")
|
||||
|
||||
# Create a broken symlink.
|
||||
symlink_or_skip("test_doesnotexist.py", sub.joinpath("test_broken.py"))
|
||||
@@ -1470,7 +1440,7 @@ def test_collector_respects_tbstyle(pytester: Pytester) -> None:
|
||||
def test_does_not_eagerly_collect_packages(pytester: Pytester) -> None:
|
||||
pytester.makepyfile("def test(): pass")
|
||||
pydir = pytester.mkpydir("foopkg")
|
||||
pydir.joinpath("__init__.py").write_text("assert False", encoding="utf-8")
|
||||
pydir.joinpath("__init__.py").write_text("assert False")
|
||||
result = pytester.runpytest()
|
||||
assert result.ret == ExitCode.OK
|
||||
|
||||
|
||||
+11
-20
@@ -87,8 +87,7 @@ class TestParseIni:
|
||||
[pytest]
|
||||
addopts = --verbose
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
config = pytester.parseconfig(tmp_path)
|
||||
assert config.option.color == "no"
|
||||
@@ -128,8 +127,7 @@ class TestParseIni:
|
||||
""".format(
|
||||
section=section
|
||||
)
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
config = pytester.parseconfig()
|
||||
assert config.getini("minversion") == "3.36"
|
||||
@@ -152,8 +150,7 @@ class TestParseIni:
|
||||
[pytest]
|
||||
minversion = 2.0
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
pytester.path.joinpath("pytest.ini").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -161,16 +158,13 @@ class TestParseIni:
|
||||
[pytest]
|
||||
minversion = 1.5
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
config = pytester.parseconfigure(sub)
|
||||
assert config.getini("minversion") == "2.0"
|
||||
|
||||
def test_ini_parse_error(self, pytester: Pytester) -> None:
|
||||
pytester.path.joinpath("pytest.ini").write_text(
|
||||
"addopts = -x", encoding="utf-8"
|
||||
)
|
||||
pytester.path.joinpath("pytest.ini").write_text("addopts = -x")
|
||||
result = pytester.runpytest()
|
||||
assert result.ret != 0
|
||||
result.stderr.fnmatch_lines("ERROR: *pytest.ini:1: no section header defined")
|
||||
@@ -640,7 +634,7 @@ class TestConfigAPI:
|
||||
def test_getconftest_pathlist(self, pytester: Pytester, tmp_path: Path) -> None:
|
||||
somepath = tmp_path.joinpath("x", "y", "z")
|
||||
p = tmp_path.joinpath("conftest.py")
|
||||
p.write_text(f"mylist = {['.', str(somepath)]}", encoding="utf-8")
|
||||
p.write_text(f"mylist = {['.', str(somepath)]}")
|
||||
config = pytester.parseconfigure(p)
|
||||
assert (
|
||||
config._getconftest_pathlist("notexist", path=tmp_path, rootpath=tmp_path)
|
||||
@@ -916,8 +910,7 @@ class TestConfigFromdictargs:
|
||||
[pytest]
|
||||
name = value
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
|
||||
inifilename = "../../foo/bar.ini"
|
||||
@@ -934,8 +927,7 @@ class TestConfigFromdictargs:
|
||||
name = wrong-value
|
||||
should_not_be_set = true
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
with MonkeyPatch.context() as mp:
|
||||
mp.chdir(cwd)
|
||||
@@ -1395,7 +1387,7 @@ class TestRootdir:
|
||||
)
|
||||
def test_with_ini(self, tmp_path: Path, name: str, contents: str) -> None:
|
||||
inipath = tmp_path / name
|
||||
inipath.write_text(contents, encoding="utf-8")
|
||||
inipath.write_text(contents, "utf-8")
|
||||
|
||||
a = tmp_path / "a"
|
||||
a.mkdir()
|
||||
@@ -1454,7 +1446,7 @@ class TestRootdir:
|
||||
) -> None:
|
||||
p = tmp_path / name
|
||||
p.touch()
|
||||
p.write_text(contents, encoding="utf-8")
|
||||
p.write_text(contents, "utf-8")
|
||||
rootpath, inipath, ini_config = determine_setup(str(p), [str(tmp_path)])
|
||||
assert rootpath == tmp_path
|
||||
assert inipath == p
|
||||
@@ -1550,8 +1542,7 @@ class TestOverrideIniArgs:
|
||||
custom = 1.0""".format(
|
||||
section=section
|
||||
)
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
pytester.makeconftest(
|
||||
"""
|
||||
|
||||
+36
-62
@@ -1,3 +1,4 @@
|
||||
import argparse
|
||||
import os
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
@@ -6,8 +7,6 @@ from typing import Dict
|
||||
from typing import Generator
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import Sequence
|
||||
from typing import Union
|
||||
|
||||
import pytest
|
||||
from _pytest.config import ExitCode
|
||||
@@ -25,18 +24,18 @@ def ConftestWithSetinitial(path) -> PytestPluginManager:
|
||||
|
||||
|
||||
def conftest_setinitial(
|
||||
conftest: PytestPluginManager,
|
||||
args: Sequence[Union[str, Path]],
|
||||
confcutdir: Optional[Path] = None,
|
||||
conftest: PytestPluginManager, args, confcutdir: Optional["os.PathLike[str]"] = None
|
||||
) -> None:
|
||||
conftest._set_initial_conftests(
|
||||
args=args,
|
||||
pyargs=False,
|
||||
noconftest=False,
|
||||
rootpath=Path(args[0]),
|
||||
confcutdir=confcutdir,
|
||||
importmode="prepend",
|
||||
)
|
||||
class Namespace:
|
||||
def __init__(self) -> None:
|
||||
self.file_or_dir = args
|
||||
self.confcutdir = os.fspath(confcutdir) if confcutdir is not None else None
|
||||
self.noconftest = False
|
||||
self.pyargs = False
|
||||
self.importmode = "prepend"
|
||||
|
||||
namespace = cast(argparse.Namespace, Namespace())
|
||||
conftest._set_initial_conftests(namespace, rootpath=Path(args[0]), testpaths_ini=[])
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("_sys_snapshot")
|
||||
@@ -47,12 +46,8 @@ class TestConftestValueAccessGlobal:
|
||||
) -> Generator[Path, None, None]:
|
||||
tmp_path = tmp_path_factory.mktemp("basedir", numbered=True)
|
||||
tmp_path.joinpath("adir/b").mkdir(parents=True)
|
||||
tmp_path.joinpath("adir/conftest.py").write_text(
|
||||
"a=1 ; Directory = 3", encoding="utf-8"
|
||||
)
|
||||
tmp_path.joinpath("adir/b/conftest.py").write_text(
|
||||
"b=2 ; a = 1.5", encoding="utf-8"
|
||||
)
|
||||
tmp_path.joinpath("adir/conftest.py").write_text("a=1 ; Directory = 3")
|
||||
tmp_path.joinpath("adir/b/conftest.py").write_text("b=2 ; a = 1.5")
|
||||
if request.param == "inpackage":
|
||||
tmp_path.joinpath("adir/__init__.py").touch()
|
||||
tmp_path.joinpath("adir/b/__init__.py").touch()
|
||||
@@ -127,12 +122,8 @@ class TestConftestValueAccessGlobal:
|
||||
|
||||
def test_conftest_in_nonpkg_with_init(tmp_path: Path, _sys_snapshot) -> None:
|
||||
tmp_path.joinpath("adir-1.0/b").mkdir(parents=True)
|
||||
tmp_path.joinpath("adir-1.0/conftest.py").write_text(
|
||||
"a=1 ; Directory = 3", encoding="utf-8"
|
||||
)
|
||||
tmp_path.joinpath("adir-1.0/b/conftest.py").write_text(
|
||||
"b=2 ; a = 1.5", encoding="utf-8"
|
||||
)
|
||||
tmp_path.joinpath("adir-1.0/conftest.py").write_text("a=1 ; Directory = 3")
|
||||
tmp_path.joinpath("adir-1.0/b/conftest.py").write_text("b=2 ; a = 1.5")
|
||||
tmp_path.joinpath("adir-1.0/b/__init__.py").touch()
|
||||
tmp_path.joinpath("adir-1.0/__init__.py").touch()
|
||||
ConftestWithSetinitial(tmp_path.joinpath("adir-1.0", "b"))
|
||||
@@ -175,7 +166,7 @@ def test_conftest_global_import(pytester: Pytester) -> None:
|
||||
sub = Path("sub")
|
||||
sub.mkdir()
|
||||
subconf = sub / "conftest.py"
|
||||
subconf.write_text("y=4", encoding="utf-8")
|
||||
subconf.write_text("y=4")
|
||||
mod2 = conf._importconftest(subconf, importmode="prepend", rootpath=Path.cwd())
|
||||
assert mod != mod2
|
||||
assert mod2.y == 4
|
||||
@@ -254,8 +245,7 @@ def test_conftest_confcutdir(pytester: Pytester) -> None:
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption("--xyz", action="store_true")
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
result = pytester.runpytest("-h", "--confcutdir=%s" % x, x)
|
||||
result.stdout.fnmatch_lines(["*--xyz*"])
|
||||
@@ -283,12 +273,9 @@ def test_installed_conftest_is_picked_up(pytester: Pytester, tmp_path: Path) ->
|
||||
@pytest.fixture
|
||||
def fix(): return None
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
tmp_path.joinpath("foo", "test_it.py").write_text(
|
||||
"def test_it(fix): pass", encoding="utf-8"
|
||||
)
|
||||
)
|
||||
tmp_path.joinpath("foo", "test_it.py").write_text("def test_it(fix): pass")
|
||||
result = pytester.runpytest("--pyargs", "foo")
|
||||
assert result.ret == 0
|
||||
|
||||
@@ -413,8 +400,7 @@ def test_conftest_existing_junitxml(pytester: Pytester) -> None:
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption("--xyz", action="store_true")
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
pytester.makefile(ext=".xml", junit="") # Writes junit.xml
|
||||
result = pytester.runpytest("-h", "--junitxml", "junit.xml")
|
||||
@@ -425,7 +411,7 @@ def test_conftest_import_order(pytester: Pytester, monkeypatch: MonkeyPatch) ->
|
||||
ct1 = pytester.makeconftest("")
|
||||
sub = pytester.mkdir("sub")
|
||||
ct2 = sub / "conftest.py"
|
||||
ct2.write_text("", encoding="utf-8")
|
||||
ct2.write_text("")
|
||||
|
||||
def impct(p, importmode, root):
|
||||
return p
|
||||
@@ -463,8 +449,7 @@ def test_fixture_dependency(pytester: Pytester) -> None:
|
||||
def bar(foo):
|
||||
return 'bar'
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
subsub = sub.joinpath("subsub")
|
||||
subsub.mkdir()
|
||||
@@ -481,8 +466,7 @@ def test_fixture_dependency(pytester: Pytester) -> None:
|
||||
def test_event_fixture(bar):
|
||||
assert bar == 'sub bar'
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
result = pytester.runpytest("sub")
|
||||
result.stdout.fnmatch_lines(["*1 passed*"])
|
||||
@@ -496,11 +480,10 @@ def test_conftest_found_with_double_dash(pytester: Pytester) -> None:
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption("--hello-world", action="store_true")
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
p = sub.joinpath("test_hello.py")
|
||||
p.write_text("def test_hello(): pass", encoding="utf-8")
|
||||
p.write_text("def test_hello(): pass")
|
||||
result = pytester.runpytest(str(p) + "::test_hello", "-h")
|
||||
result.stdout.fnmatch_lines(
|
||||
"""
|
||||
@@ -524,8 +507,7 @@ class TestConftestVisibility:
|
||||
def fxtr():
|
||||
return "from-package"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
package.joinpath("test_pkgroot.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -533,8 +515,7 @@ class TestConftestVisibility:
|
||||
def test_pkgroot(fxtr):
|
||||
assert fxtr == "from-package"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
|
||||
swc = package.joinpath("swc")
|
||||
@@ -548,8 +529,7 @@ class TestConftestVisibility:
|
||||
def fxtr():
|
||||
return "from-swc"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
swc.joinpath("test_with_conftest.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -557,8 +537,7 @@ class TestConftestVisibility:
|
||||
def test_with_conftest(fxtr):
|
||||
assert fxtr == "from-swc"
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
|
||||
snc = package.joinpath("snc")
|
||||
@@ -571,8 +550,7 @@ class TestConftestVisibility:
|
||||
assert fxtr == "from-package" # No local conftest.py, so should
|
||||
# use value from parent dir's
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
print("created directory structure:")
|
||||
for x in pytester.path.glob("**/"):
|
||||
@@ -638,7 +616,7 @@ def test_search_conftest_up_to_inifile(
|
||||
root = pytester.path
|
||||
src = root.joinpath("src")
|
||||
src.mkdir()
|
||||
src.joinpath("pytest.ini").write_text("[pytest]", encoding="utf-8")
|
||||
src.joinpath("pytest.ini").write_text("[pytest]")
|
||||
src.joinpath("conftest.py").write_text(
|
||||
textwrap.dedent(
|
||||
"""\
|
||||
@@ -646,8 +624,7 @@ def test_search_conftest_up_to_inifile(
|
||||
@pytest.fixture
|
||||
def fix1(): pass
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
src.joinpath("test_foo.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -657,8 +634,7 @@ def test_search_conftest_up_to_inifile(
|
||||
def test_2(out_of_reach):
|
||||
pass
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
root.joinpath("conftest.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -667,8 +643,7 @@ def test_search_conftest_up_to_inifile(
|
||||
@pytest.fixture
|
||||
def out_of_reach(): pass
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
|
||||
args = [str(src)]
|
||||
@@ -751,8 +726,7 @@ def test_required_option_help(pytester: Pytester) -> None:
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption("--xyz", action="store_true", required=True)
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
result = pytester.runpytest("-h", x)
|
||||
result.stdout.no_fnmatch_line("*argument --xyz is required*")
|
||||
|
||||
+4
-30
@@ -357,8 +357,7 @@ class TestDoctests:
|
||||
>>> 1/0
|
||||
'''
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
result = pytester.runpytest("--doctest-modules")
|
||||
result.stdout.fnmatch_lines(
|
||||
@@ -449,8 +448,7 @@ class TestDoctests:
|
||||
"""\
|
||||
import asdalsdkjaslkdjasd
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
pytester.maketxtfile(
|
||||
"""
|
||||
@@ -482,27 +480,6 @@ class TestDoctests:
|
||||
reprec = pytester.inline_run(p, "--doctest-modules")
|
||||
reprec.assertoutcome(failed=1)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info[:2] <= (3, 7), reason="Only Python 3.7 or less"
|
||||
)
|
||||
def test_doctest_cached_property(self, pytester: Pytester):
|
||||
p = pytester.makepyfile(
|
||||
"""
|
||||
import functools
|
||||
|
||||
class Foo:
|
||||
@functools.cached_property
|
||||
def foo(self):
|
||||
'''
|
||||
>>> assert False, "Tacos!"
|
||||
'''
|
||||
...
|
||||
"""
|
||||
)
|
||||
result = pytester.runpytest(p, "--doctest-modules")
|
||||
result.assert_outcomes(failed=1)
|
||||
assert "Tacos!" in result.stdout.str()
|
||||
|
||||
def test_doctestmodule_external_and_issue116(self, pytester: Pytester):
|
||||
p = pytester.mkpydir("hello")
|
||||
p.joinpath("__init__.py").write_text(
|
||||
@@ -515,8 +492,7 @@ class TestDoctests:
|
||||
2
|
||||
'''
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
result = pytester.runpytest(p, "--doctest-modules")
|
||||
result.stdout.fnmatch_lines(
|
||||
@@ -1590,9 +1566,7 @@ def test_warning_on_unwrap_of_broken_object(
|
||||
|
||||
def test_is_setup_py_not_named_setup_py(tmp_path: Path) -> None:
|
||||
not_setup_py = tmp_path.joinpath("not_setup.py")
|
||||
not_setup_py.write_text(
|
||||
'from setuptools import setup; setup(name="foo")', encoding="utf-8"
|
||||
)
|
||||
not_setup_py.write_text('from setuptools import setup; setup(name="foo")')
|
||||
assert not _is_setup_py(not_setup_py)
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ from _pytest.stash import Stash
|
||||
def schema() -> xmlschema.XMLSchema:
|
||||
"""Return an xmlschema.XMLSchema object for the junit-10.xsd file."""
|
||||
fn = Path(__file__).parent / "example_scripts/junit-10.xsd"
|
||||
with fn.open(encoding="utf-8") as f:
|
||||
with fn.open() as f:
|
||||
return xmlschema.XMLSchema(f)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class RunAndParse:
|
||||
xml_path = self.pytester.path.joinpath("junit.xml")
|
||||
result = self.pytester.runpytest("--junitxml=%s" % xml_path, *args)
|
||||
if family == "xunit2":
|
||||
with xml_path.open(encoding="utf-8") as f:
|
||||
with xml_path.open() as f:
|
||||
self.schema.validate(f)
|
||||
xmldoc = minidom.parse(str(xml_path))
|
||||
return result, DomNode(xmldoc)
|
||||
@@ -469,7 +469,7 @@ class TestPython:
|
||||
self, pytester: Pytester, run_and_parse: RunAndParse, xunit_family: str
|
||||
) -> None:
|
||||
p = pytester.mkdir("sub").joinpath("test_hello.py")
|
||||
p.write_text("def test_func(): 0/0", encoding="utf-8")
|
||||
p.write_text("def test_func(): 0/0")
|
||||
result, dom = run_and_parse(family=xunit_family)
|
||||
assert result.ret
|
||||
node = dom.find_first_by_tag("testsuite")
|
||||
@@ -987,7 +987,7 @@ class TestNonPython:
|
||||
return "custom item runtest failed"
|
||||
"""
|
||||
)
|
||||
pytester.path.joinpath("myfile.xyz").write_text("hello", encoding="utf-8")
|
||||
pytester.path.joinpath("myfile.xyz").write_text("hello")
|
||||
result, dom = run_and_parse(family=xunit_family)
|
||||
assert result.ret
|
||||
node = dom.find_first_by_tag("testsuite")
|
||||
@@ -1013,7 +1013,7 @@ def test_nullbyte(pytester: Pytester, junit_logging: str) -> None:
|
||||
)
|
||||
xmlf = pytester.path.joinpath("junit.xml")
|
||||
pytester.runpytest("--junitxml=%s" % xmlf, "-o", "junit_logging=%s" % junit_logging)
|
||||
text = xmlf.read_text(encoding="utf-8")
|
||||
text = xmlf.read_text()
|
||||
assert "\x00" not in text
|
||||
if junit_logging == "system-out":
|
||||
assert "#x00" in text
|
||||
@@ -1035,7 +1035,7 @@ def test_nullbyte_replace(pytester: Pytester, junit_logging: str) -> None:
|
||||
)
|
||||
xmlf = pytester.path.joinpath("junit.xml")
|
||||
pytester.runpytest("--junitxml=%s" % xmlf, "-o", "junit_logging=%s" % junit_logging)
|
||||
text = xmlf.read_text(encoding="utf-8")
|
||||
text = xmlf.read_text()
|
||||
if junit_logging == "system-out":
|
||||
assert "#x0" in text
|
||||
if junit_logging == "no":
|
||||
@@ -1228,36 +1228,6 @@ def test_record_property(pytester: Pytester, run_and_parse: RunAndParse) -> None
|
||||
result.stdout.fnmatch_lines(["*= 1 passed in *"])
|
||||
|
||||
|
||||
def test_record_property_on_test_and_teardown_failure(
|
||||
pytester: Pytester, run_and_parse: RunAndParse
|
||||
) -> None:
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
import pytest
|
||||
|
||||
@pytest.fixture
|
||||
def other(record_property):
|
||||
record_property("bar", 1)
|
||||
yield
|
||||
assert 0
|
||||
|
||||
def test_record(record_property, other):
|
||||
record_property("foo", "<1")
|
||||
assert 0
|
||||
"""
|
||||
)
|
||||
result, dom = run_and_parse()
|
||||
node = dom.find_first_by_tag("testsuite")
|
||||
tnodes = node.find_by_tag("testcase")
|
||||
for tnode in tnodes:
|
||||
psnode = tnode.find_first_by_tag("properties")
|
||||
assert psnode, f"testcase didn't had expected properties:\n{tnode}"
|
||||
pnodes = psnode.find_by_tag("property")
|
||||
pnodes[0].assert_attr(name="bar", value="1")
|
||||
pnodes[1].assert_attr(name="foo", value="<1")
|
||||
result.stdout.fnmatch_lines(["*= 1 failed, 1 error *"])
|
||||
|
||||
|
||||
def test_record_property_same_name(
|
||||
pytester: Pytester, run_and_parse: RunAndParse
|
||||
) -> None:
|
||||
|
||||
@@ -59,8 +59,7 @@ def test_link_resolve(pytester: Pytester) -> None:
|
||||
def test_foo():
|
||||
raise AssertionError()
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
|
||||
subst = subst_path_linux
|
||||
|
||||
@@ -262,34 +262,3 @@ def test_module_full_path_without_drive(pytester: Pytester) -> None:
|
||||
"* 1 passed in *",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_very_long_cmdline_arg(pytester: Pytester) -> None:
|
||||
"""
|
||||
Regression test for #11394.
|
||||
|
||||
Note: we could not manage to actually reproduce the error with this code, we suspect
|
||||
GitHub runners are configured to support very long paths, however decided to leave
|
||||
the test in place in case this ever regresses in the future.
|
||||
"""
|
||||
pytester.makeconftest(
|
||||
"""
|
||||
import pytest
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption("--long-list", dest="long_list", action="store", default="all", help="List of things")
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def specified_feeds(request):
|
||||
list_string = request.config.getoption("--long-list")
|
||||
return list_string.split(',')
|
||||
"""
|
||||
)
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
def test_foo(specified_feeds):
|
||||
assert len(specified_feeds) == 100_000
|
||||
"""
|
||||
)
|
||||
result = pytester.runpytest("--long-list", ",".join(["helloworld"] * 100_000))
|
||||
result.stdout.fnmatch_lines("* 1 passed *")
|
||||
|
||||
@@ -324,8 +324,7 @@ def test_importerror(pytester: Pytester) -> None:
|
||||
|
||||
x = 1
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
pytester.path.joinpath("test_importerror.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -333,8 +332,7 @@ def test_importerror(pytester: Pytester) -> None:
|
||||
def test_importerror(monkeypatch):
|
||||
monkeypatch.setattr('package.a.x', 2)
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
result = pytester.runpytest()
|
||||
result.stdout.fnmatch_lines(
|
||||
@@ -436,13 +434,11 @@ def test_syspath_prepend_with_namespace_packages(
|
||||
ns = d.joinpath("ns_pkg")
|
||||
ns.mkdir()
|
||||
ns.joinpath("__init__.py").write_text(
|
||||
"__import__('pkg_resources').declare_namespace(__name__)", encoding="utf-8"
|
||||
"__import__('pkg_resources').declare_namespace(__name__)"
|
||||
)
|
||||
lib = ns.joinpath(dirname)
|
||||
lib.mkdir()
|
||||
lib.joinpath("__init__.py").write_text(
|
||||
"def check(): return %r" % dirname, encoding="utf-8"
|
||||
)
|
||||
lib.joinpath("__init__.py").write_text("def check(): return %r" % dirname)
|
||||
|
||||
monkeypatch.syspath_prepend("hello")
|
||||
import ns_pkg.hello
|
||||
@@ -461,5 +457,5 @@ def test_syspath_prepend_with_namespace_packages(
|
||||
# Should invalidate caches via importlib.invalidate_caches.
|
||||
modules_tmpdir = pytester.mkdir("modules_tmpdir")
|
||||
monkeypatch.syspath_prepend(str(modules_tmpdir))
|
||||
modules_tmpdir.joinpath("main_app.py").write_text("app = True", encoding="utf-8")
|
||||
modules_tmpdir.joinpath("main_app.py").write_text("app = True")
|
||||
from main_app import app # noqa: F401
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import argparse
|
||||
import locale
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
@@ -290,10 +289,6 @@ class TestParser:
|
||||
|
||||
|
||||
def test_argcomplete(pytester: Pytester, monkeypatch: MonkeyPatch) -> None:
|
||||
try:
|
||||
encoding = locale.getencoding() # New in Python 3.11, ignores utf-8 mode
|
||||
except AttributeError:
|
||||
encoding = locale.getpreferredencoding(False)
|
||||
try:
|
||||
bash_version = subprocess.run(
|
||||
["bash", "--version"],
|
||||
@@ -301,7 +296,6 @@ def test_argcomplete(pytester: Pytester, monkeypatch: MonkeyPatch) -> None:
|
||||
stderr=subprocess.DEVNULL,
|
||||
check=True,
|
||||
text=True,
|
||||
encoding=encoding,
|
||||
).stdout
|
||||
except (OSError, subprocess.CalledProcessError):
|
||||
pytest.skip("bash is not available")
|
||||
@@ -311,7 +305,7 @@ def test_argcomplete(pytester: Pytester, monkeypatch: MonkeyPatch) -> None:
|
||||
|
||||
script = str(pytester.path.joinpath("test_argcomplete"))
|
||||
|
||||
with open(str(script), "w", encoding="utf-8") as fp:
|
||||
with open(str(script), "w") as fp:
|
||||
# redirect output from argcomplete to stdin and stderr is not trivial
|
||||
# http://stackoverflow.com/q/12589419/1307905
|
||||
# so we use bash
|
||||
|
||||
+21
-126
@@ -1,4 +1,3 @@
|
||||
import errno
|
||||
import os.path
|
||||
import pickle
|
||||
import sys
|
||||
@@ -8,7 +7,6 @@ from textwrap import dedent
|
||||
from types import ModuleType
|
||||
from typing import Any
|
||||
from typing import Generator
|
||||
from typing import Iterator
|
||||
|
||||
import pytest
|
||||
from _pytest.monkeypatch import MonkeyPatch
|
||||
@@ -19,13 +17,11 @@ from _pytest.pathlib import fnmatch_ex
|
||||
from _pytest.pathlib import get_extended_length_path_str
|
||||
from _pytest.pathlib import get_lock_path
|
||||
from _pytest.pathlib import import_path
|
||||
from _pytest.pathlib import ImportMode
|
||||
from _pytest.pathlib import ImportPathMismatchError
|
||||
from _pytest.pathlib import insert_missing_modules
|
||||
from _pytest.pathlib import maybe_delete_a_numbered_dir
|
||||
from _pytest.pathlib import module_name_from_path
|
||||
from _pytest.pathlib import resolve_package_path
|
||||
from _pytest.pathlib import safe_exists
|
||||
from _pytest.pathlib import symlink_or_skip
|
||||
from _pytest.pathlib import visit
|
||||
from _pytest.tmpdir import TempPathFactory
|
||||
@@ -104,13 +100,13 @@ class TestImportPath:
|
||||
def setuptestfs(self, path: Path) -> None:
|
||||
# print "setting up test fs for", repr(path)
|
||||
samplefile = path / "samplefile"
|
||||
samplefile.write_text("samplefile\n", encoding="utf-8")
|
||||
samplefile.write_text("samplefile\n")
|
||||
|
||||
execfile = path / "execfile"
|
||||
execfile.write_text("x=42", encoding="utf-8")
|
||||
execfile.write_text("x=42")
|
||||
|
||||
execfilepy = path / "execfile.py"
|
||||
execfilepy.write_text("x=42", encoding="utf-8")
|
||||
execfilepy.write_text("x=42")
|
||||
|
||||
d = {1: 2, "hello": "world", "answer": 42}
|
||||
path.joinpath("samplepickle").write_bytes(pickle.dumps(d, 1))
|
||||
@@ -124,9 +120,9 @@ class TestImportPath:
|
||||
otherdir.joinpath("__init__.py").touch()
|
||||
|
||||
module_a = otherdir / "a.py"
|
||||
module_a.write_text("from .b import stuff as result\n", encoding="utf-8")
|
||||
module_a.write_text("from .b import stuff as result\n")
|
||||
module_b = otherdir / "b.py"
|
||||
module_b.write_text('stuff="got it"\n', encoding="utf-8")
|
||||
module_b.write_text('stuff="got it"\n')
|
||||
module_c = otherdir / "c.py"
|
||||
module_c.write_text(
|
||||
dedent(
|
||||
@@ -135,8 +131,7 @@ class TestImportPath:
|
||||
import otherdir.a
|
||||
value = otherdir.a.result
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
module_d = otherdir / "d.py"
|
||||
module_d.write_text(
|
||||
@@ -146,8 +141,7 @@ class TestImportPath:
|
||||
from otherdir import a
|
||||
value2 = a.result
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
|
||||
def test_smoke_test(self, path1: Path) -> None:
|
||||
@@ -286,36 +280,29 @@ class TestImportPath:
|
||||
import_path(tmp_path / "invalid.py", root=tmp_path)
|
||||
|
||||
@pytest.fixture
|
||||
def simple_module(
|
||||
self, tmp_path: Path, request: pytest.FixtureRequest
|
||||
) -> Iterator[Path]:
|
||||
name = f"mymod_{request.node.name}"
|
||||
fn = tmp_path / f"_src/tests/{name}.py"
|
||||
def simple_module(self, tmp_path: Path) -> Path:
|
||||
fn = tmp_path / "_src/tests/mymod.py"
|
||||
fn.parent.mkdir(parents=True)
|
||||
fn.write_text("def foo(x): return 40 + x", encoding="utf-8")
|
||||
module_name = module_name_from_path(fn, root=tmp_path)
|
||||
yield fn
|
||||
sys.modules.pop(module_name, None)
|
||||
fn.write_text("def foo(x): return 40 + x")
|
||||
return fn
|
||||
|
||||
def test_importmode_importlib(
|
||||
self, simple_module: Path, tmp_path: Path, request: pytest.FixtureRequest
|
||||
) -> None:
|
||||
def test_importmode_importlib(self, simple_module: Path, tmp_path: Path) -> None:
|
||||
"""`importlib` mode does not change sys.path."""
|
||||
module = import_path(simple_module, mode="importlib", root=tmp_path)
|
||||
assert module.foo(2) == 42 # type: ignore[attr-defined]
|
||||
assert str(simple_module.parent) not in sys.path
|
||||
assert module.__name__ in sys.modules
|
||||
assert module.__name__ == f"_src.tests.mymod_{request.node.name}"
|
||||
assert module.__name__ == "_src.tests.mymod"
|
||||
assert "_src" in sys.modules
|
||||
assert "_src.tests" in sys.modules
|
||||
|
||||
def test_remembers_previous_imports(
|
||||
def test_importmode_twice_is_different_module(
|
||||
self, simple_module: Path, tmp_path: Path
|
||||
) -> None:
|
||||
"""`importlib` mode called remembers previous module (#10341, #10811)."""
|
||||
"""`importlib` mode always returns a new module."""
|
||||
module1 = import_path(simple_module, mode="importlib", root=tmp_path)
|
||||
module2 = import_path(simple_module, mode="importlib", root=tmp_path)
|
||||
assert module1 is module2
|
||||
assert module1 is not module2
|
||||
|
||||
def test_no_meta_path_found(
|
||||
self, simple_module: Path, monkeypatch: MonkeyPatch, tmp_path: Path
|
||||
@@ -328,9 +315,6 @@ class TestImportPath:
|
||||
# mode='importlib' fails if no spec is found to load the module
|
||||
import importlib.util
|
||||
|
||||
# Force module to be re-imported.
|
||||
del sys.modules[module.__name__]
|
||||
|
||||
monkeypatch.setattr(
|
||||
importlib.util, "spec_from_file_location", lambda *args: None
|
||||
)
|
||||
@@ -463,7 +447,7 @@ def test_samefile_false_negatives(tmp_path: Path, monkeypatch: MonkeyPatch) -> N
|
||||
return False, even when they are clearly equal.
|
||||
"""
|
||||
module_path = tmp_path.joinpath("my_module.py")
|
||||
module_path.write_text("def foo(): return 42", encoding="utf-8")
|
||||
module_path.write_text("def foo(): return 42")
|
||||
monkeypatch.syspath_prepend(tmp_path)
|
||||
|
||||
with monkeypatch.context() as mp:
|
||||
@@ -489,8 +473,7 @@ class TestImportLibMode:
|
||||
class Data:
|
||||
value: str
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
|
||||
module = import_path(fn, mode="importlib", root=tmp_path)
|
||||
@@ -515,8 +498,7 @@ class TestImportLibMode:
|
||||
s = pickle.dumps(_action)
|
||||
return pickle.loads(s)
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
|
||||
module = import_path(fn, mode="importlib", root=tmp_path)
|
||||
@@ -543,8 +525,7 @@ class TestImportLibMode:
|
||||
class Data:
|
||||
x: int = 42
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
|
||||
fn2 = tmp_path.joinpath("_src/m2/tests/test.py")
|
||||
@@ -559,8 +540,7 @@ class TestImportLibMode:
|
||||
class Data:
|
||||
x: str = ""
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
|
||||
import pickle
|
||||
@@ -588,10 +568,6 @@ class TestImportLibMode:
|
||||
result = module_name_from_path(Path("/home/foo/test_foo.py"), Path("/bar"))
|
||||
assert result == "home.foo.test_foo"
|
||||
|
||||
# Importing __init__.py files should return the package as module name.
|
||||
result = module_name_from_path(tmp_path / "src/app/__init__.py", tmp_path)
|
||||
assert result == "src.app"
|
||||
|
||||
def test_insert_missing_modules(
|
||||
self, monkeypatch: MonkeyPatch, tmp_path: Path
|
||||
) -> None:
|
||||
@@ -610,84 +586,3 @@ class TestImportLibMode:
|
||||
modules = {}
|
||||
insert_missing_modules(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"]
|
||||
|
||||
def test_importlib_package(self, monkeypatch: MonkeyPatch, tmp_path: Path):
|
||||
"""
|
||||
Importing a package using --importmode=importlib should not import the
|
||||
package's __init__.py file more than once (#11306).
|
||||
"""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
monkeypatch.syspath_prepend(tmp_path)
|
||||
|
||||
package_name = "importlib_import_package"
|
||||
tmp_path.joinpath(package_name).mkdir()
|
||||
init = tmp_path.joinpath(f"{package_name}/__init__.py")
|
||||
init.write_text(
|
||||
dedent(
|
||||
"""
|
||||
from .singleton import Singleton
|
||||
|
||||
instance = Singleton()
|
||||
"""
|
||||
),
|
||||
encoding="ascii",
|
||||
)
|
||||
singleton = tmp_path.joinpath(f"{package_name}/singleton.py")
|
||||
singleton.write_text(
|
||||
dedent(
|
||||
"""
|
||||
class Singleton:
|
||||
INSTANCES = []
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.INSTANCES.append(self)
|
||||
if len(self.INSTANCES) > 1:
|
||||
raise RuntimeError("Already initialized")
|
||||
"""
|
||||
),
|
||||
encoding="ascii",
|
||||
)
|
||||
|
||||
mod = import_path(init, root=tmp_path, mode=ImportMode.importlib)
|
||||
assert len(mod.instance.INSTANCES) == 1
|
||||
|
||||
|
||||
def test_safe_exists(tmp_path: Path) -> None:
|
||||
d = tmp_path.joinpath("some_dir")
|
||||
d.mkdir()
|
||||
assert safe_exists(d) is True
|
||||
|
||||
f = tmp_path.joinpath("some_file")
|
||||
f.touch()
|
||||
assert safe_exists(f) is True
|
||||
|
||||
# Use unittest.mock() as a context manager to have a very narrow
|
||||
# patch lifetime.
|
||||
p = tmp_path.joinpath("some long filename" * 100)
|
||||
with unittest.mock.patch.object(
|
||||
Path,
|
||||
"exists",
|
||||
autospec=True,
|
||||
side_effect=OSError(errno.ENAMETOOLONG, "name too long"),
|
||||
):
|
||||
assert safe_exists(p) is False
|
||||
|
||||
with unittest.mock.patch.object(
|
||||
Path,
|
||||
"exists",
|
||||
autospec=True,
|
||||
side_effect=ValueError("name too long"),
|
||||
):
|
||||
assert safe_exists(p) is False
|
||||
|
||||
@@ -242,12 +242,8 @@ class TestPytestPluginManager:
|
||||
mod = types.ModuleType("temp")
|
||||
mod.__dict__["pytest_plugins"] = ["pytest_p1", "pytest_p2"]
|
||||
pytestpm.consider_module(mod)
|
||||
p1 = pytestpm.get_plugin("pytest_p1")
|
||||
assert p1 is not None
|
||||
assert p1.__name__ == "pytest_p1"
|
||||
p2 = pytestpm.get_plugin("pytest_p2")
|
||||
assert p2 is not None
|
||||
assert p2.__name__ == "pytest_p2"
|
||||
assert pytestpm.get_plugin("pytest_p1").__name__ == "pytest_p1"
|
||||
assert pytestpm.get_plugin("pytest_p2").__name__ == "pytest_p2"
|
||||
|
||||
def test_consider_module_import_module(
|
||||
self, pytester: Pytester, _config_for_test: Config
|
||||
@@ -340,7 +336,6 @@ class TestPytestPluginManager:
|
||||
len2 = len(pytestpm.get_plugins())
|
||||
assert len1 == len2
|
||||
plugin1 = pytestpm.get_plugin("pytest_hello")
|
||||
assert plugin1 is not None
|
||||
assert plugin1.__name__.endswith("pytest_hello")
|
||||
plugin2 = pytestpm.get_plugin("pytest_hello")
|
||||
assert plugin2 is plugin1
|
||||
@@ -352,11 +347,10 @@ class TestPytestPluginManager:
|
||||
pytest.raises(ImportError, pytestpm.import_plugin, "pytest_qweqwex.y")
|
||||
|
||||
pytester.syspathinsert()
|
||||
pytester.mkpydir("pkg").joinpath("plug.py").write_text("x=3", encoding="utf-8")
|
||||
pytester.mkpydir("pkg").joinpath("plug.py").write_text("x=3")
|
||||
pluginname = "pkg.plug"
|
||||
pytestpm.import_plugin(pluginname)
|
||||
mod = pytestpm.get_plugin("pkg.plug")
|
||||
assert mod is not None
|
||||
assert mod.x == 3
|
||||
|
||||
def test_consider_conftest_deps(
|
||||
|
||||
@@ -222,7 +222,7 @@ class TestInlineRunModulesCleanup:
|
||||
result = pytester.inline_run(str(test_mod))
|
||||
assert result.ret == ExitCode.OK
|
||||
# rewrite module, now test should fail if module was re-imported
|
||||
test_mod.write_text("def test_foo(): assert False", encoding="utf-8")
|
||||
test_mod.write_text("def test_foo(): assert False")
|
||||
result2 = pytester.inline_run(str(test_mod))
|
||||
assert result2.ret == ExitCode.TESTS_FAILED
|
||||
|
||||
|
||||
@@ -410,7 +410,7 @@ class TestReportSerialization:
|
||||
) -> None:
|
||||
sub_dir = pytester.path.joinpath("ns")
|
||||
sub_dir.mkdir()
|
||||
sub_dir.joinpath("conftest.py").write_text("import unknown", encoding="utf-8")
|
||||
sub_dir.joinpath("conftest.py").write_text("import unknown")
|
||||
|
||||
result = pytester.runpytest_subprocess(".")
|
||||
result.stdout.fnmatch_lines(["E *Error: No module named 'unknown'"])
|
||||
|
||||
@@ -265,9 +265,9 @@ def test_plugin_already_exists(pytester: Pytester) -> None:
|
||||
|
||||
def test_exclude(pytester: Pytester) -> None:
|
||||
hellodir = pytester.mkdir("hello")
|
||||
hellodir.joinpath("test_hello.py").write_text("x y syntaxerror", encoding="utf-8")
|
||||
hellodir.joinpath("test_hello.py").write_text("x y syntaxerror")
|
||||
hello2dir = pytester.mkdir("hello2")
|
||||
hello2dir.joinpath("test_hello2.py").write_text("x y syntaxerror", encoding="utf-8")
|
||||
hello2dir.joinpath("test_hello2.py").write_text("x y syntaxerror")
|
||||
pytester.makepyfile(test_ok="def test_pass(): pass")
|
||||
result = pytester.runpytest("--ignore=hello", "--ignore=hello2")
|
||||
assert result.ret == 0
|
||||
@@ -276,13 +276,13 @@ def test_exclude(pytester: Pytester) -> None:
|
||||
|
||||
def test_exclude_glob(pytester: Pytester) -> None:
|
||||
hellodir = pytester.mkdir("hello")
|
||||
hellodir.joinpath("test_hello.py").write_text("x y syntaxerror", encoding="utf-8")
|
||||
hellodir.joinpath("test_hello.py").write_text("x y syntaxerror")
|
||||
hello2dir = pytester.mkdir("hello2")
|
||||
hello2dir.joinpath("test_hello2.py").write_text("x y syntaxerror", encoding="utf-8")
|
||||
hello2dir.joinpath("test_hello2.py").write_text("x y syntaxerror")
|
||||
hello3dir = pytester.mkdir("hallo3")
|
||||
hello3dir.joinpath("test_hello3.py").write_text("x y syntaxerror", encoding="utf-8")
|
||||
hello3dir.joinpath("test_hello3.py").write_text("x y syntaxerror")
|
||||
subdir = pytester.mkdir("sub")
|
||||
subdir.joinpath("test_hello4.py").write_text("x y syntaxerror", encoding="utf-8")
|
||||
subdir.joinpath("test_hello4.py").write_text("x y syntaxerror")
|
||||
pytester.makepyfile(test_ok="def test_pass(): pass")
|
||||
result = pytester.runpytest("--ignore-glob=*h[ea]llo*")
|
||||
assert result.ret == 0
|
||||
|
||||
@@ -195,8 +195,7 @@ class TestEvaluation:
|
||||
def pytest_markeval_namespace():
|
||||
return {"arg": "root"}
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
root.joinpath("test_root.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -207,8 +206,7 @@ class TestEvaluation:
|
||||
def test_root():
|
||||
assert False
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
foo = root.joinpath("foo")
|
||||
foo.mkdir()
|
||||
@@ -221,8 +219,7 @@ class TestEvaluation:
|
||||
def pytest_markeval_namespace():
|
||||
return {"arg": "foo"}
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
foo.joinpath("test_foo.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -233,8 +230,7 @@ class TestEvaluation:
|
||||
def test_foo():
|
||||
assert False
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
bar = root.joinpath("bar")
|
||||
bar.mkdir()
|
||||
@@ -247,8 +243,7 @@ class TestEvaluation:
|
||||
def pytest_markeval_namespace():
|
||||
return {"arg": "bar"}
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
bar.joinpath("test_bar.py").write_text(
|
||||
textwrap.dedent(
|
||||
@@ -259,8 +254,7 @@ class TestEvaluation:
|
||||
def test_bar():
|
||||
assert False
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
|
||||
reprec = pytester.inline_run("-vs", "--capture=no")
|
||||
@@ -635,8 +629,7 @@ class TestXFail:
|
||||
|
||||
@pytest.mark.xfail(reason='unsupported feature', strict=%s)
|
||||
def test_foo():
|
||||
with open('foo_executed', 'w', encoding='utf-8'):
|
||||
pass # make sure test executes
|
||||
with open('foo_executed', 'w'): pass # make sure test executes
|
||||
"""
|
||||
% strict
|
||||
)
|
||||
|
||||
@@ -352,6 +352,6 @@ def test_one():
|
||||
assert result.ret == 0
|
||||
|
||||
assert Path(stepwise_cache_file).exists()
|
||||
with stepwise_cache_file.open(encoding="utf-8") as file_handle:
|
||||
with stepwise_cache_file.open() as file_handle:
|
||||
observed_value = file_handle.readlines()
|
||||
assert [expected_value] == observed_value
|
||||
|
||||
@@ -244,8 +244,7 @@ class TestTerminal:
|
||||
def test_method(self):
|
||||
pass
|
||||
"""
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
)
|
||||
result = pytester.runpytest("-vv")
|
||||
assert result.ret == 0
|
||||
@@ -1568,8 +1567,7 @@ class TestGenericReporting:
|
||||
"""
|
||||
def pytest_report_header(config, start_path):
|
||||
return ["line1", str(start_path)]
|
||||
""",
|
||||
encoding="utf-8",
|
||||
"""
|
||||
)
|
||||
result = pytester.runpytest("a")
|
||||
result.stdout.fnmatch_lines(["*hello: 42*", "line1", str(pytester.path)])
|
||||
@@ -1673,7 +1671,7 @@ def test_fdopen_kept_alive_issue124(pytester: Pytester) -> None:
|
||||
import os, sys
|
||||
k = []
|
||||
def test_open_file_and_keep_alive(capfd):
|
||||
stdout = os.fdopen(1, 'w', buffering=1, encoding='utf-8')
|
||||
stdout = os.fdopen(1, 'w', 1)
|
||||
k.append(stdout)
|
||||
|
||||
def test_close_kept_alive_file():
|
||||
|
||||
@@ -561,7 +561,7 @@ def test_basetemp_with_read_only_files(pytester: Pytester) -> None:
|
||||
|
||||
def test(tmp_path):
|
||||
fn = tmp_path / 'foo.txt'
|
||||
fn.write_text('hello', encoding='utf-8')
|
||||
fn.write_text('hello')
|
||||
mode = os.stat(str(fn)).st_mode
|
||||
os.chmod(str(fn), mode & ~stat.S_IREAD)
|
||||
"""
|
||||
|
||||
@@ -810,12 +810,12 @@ def test_resource_warning(pytester: Pytester, monkeypatch: pytest.MonkeyPatch) -
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
def open_file(p):
|
||||
f = p.open("r", encoding="utf-8")
|
||||
f = p.open("r")
|
||||
assert p.read_text() == "hello"
|
||||
|
||||
def test_resource_warning(tmp_path):
|
||||
p = tmp_path.joinpath("foo.txt")
|
||||
p.write_text("hello", encoding="utf-8")
|
||||
p.write_text("hello")
|
||||
open_file(p)
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -38,10 +38,6 @@ passenv =
|
||||
setenv =
|
||||
_PYTEST_TOX_DEFAULT_POSARGS={env:_PYTEST_TOX_POSARGS_DOCTESTING:} {env:_PYTEST_TOX_POSARGS_LSOF:} {env:_PYTEST_TOX_POSARGS_XDIST:}
|
||||
|
||||
# See https://docs.python.org/3/library/io.html#io-encoding-warning
|
||||
# If we don't enable this, neither can any of our downstream users!
|
||||
PYTHONWARNDEFAULTENCODING=1
|
||||
|
||||
# Configuration to run with coverage similar to CI, e.g.
|
||||
# "tox -e py37-coverage".
|
||||
coverage: _PYTEST_TOX_COVERAGE_RUN=coverage run -m
|
||||
|
||||
Reference in New Issue
Block a user