Compare commits
18 Commits
8.3.0.dev0
...
8.2.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66ff8dffdf | ||
|
|
3ffcfd122c | ||
|
|
0b28313b46 | ||
|
|
f3dd93ad8d | ||
|
|
bb5a1257b0 | ||
|
|
f179bf252f | ||
|
|
2b671b5f92 | ||
|
|
65ab7cb96c | ||
|
|
4d5fb7d71c | ||
|
|
cbe5996cc6 | ||
|
|
c9e9315725 | ||
|
|
328001eab1 | ||
|
|
8fdb72947e | ||
|
|
5c1c73b961 | ||
|
|
a152c2cee4 | ||
|
|
69c3bcea36 | ||
|
|
6bd3f31344 | ||
|
|
9b6219b5e8 |
9
.github/workflows/deploy.yml
vendored
9
.github/workflows/deploy.yml
vendored
@@ -19,6 +19,11 @@ jobs:
|
||||
SETUPTOOLS_SCM_PRETEND_VERSION: ${{ github.event.inputs.version }}
|
||||
timeout-minutes: 10
|
||||
|
||||
# Required by attest-build-provenance-github.
|
||||
permissions:
|
||||
id-token: write
|
||||
attestations: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -26,7 +31,9 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Build and Check Package
|
||||
uses: hynek/build-and-inspect-python-package@v2.4.0
|
||||
uses: hynek/build-and-inspect-python-package@v2.5.0
|
||||
with:
|
||||
attest-build-provenance-github: 'true'
|
||||
|
||||
deploy:
|
||||
if: github.repository == 'pytest-dev/pytest'
|
||||
|
||||
24
.github/workflows/test.yml
vendored
24
.github/workflows/test.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- name: Build and Check Package
|
||||
uses: hynek/build-and-inspect-python-package@v2.4.0
|
||||
uses: hynek/build-and-inspect-python-package@v2.5.0
|
||||
|
||||
build:
|
||||
needs: [package]
|
||||
@@ -55,6 +55,7 @@ jobs:
|
||||
"windows-py310",
|
||||
"windows-py311",
|
||||
"windows-py312",
|
||||
"windows-py313",
|
||||
|
||||
"ubuntu-py38",
|
||||
"ubuntu-py38-pluggy",
|
||||
@@ -63,12 +64,14 @@ jobs:
|
||||
"ubuntu-py310",
|
||||
"ubuntu-py311",
|
||||
"ubuntu-py312",
|
||||
"ubuntu-py313",
|
||||
"ubuntu-pypy3",
|
||||
|
||||
"macos-py38",
|
||||
"macos-py39",
|
||||
"macos-py310",
|
||||
"macos-py312",
|
||||
"macos-py313",
|
||||
|
||||
"doctesting",
|
||||
"plugins",
|
||||
@@ -97,9 +100,13 @@ jobs:
|
||||
os: windows-latest
|
||||
tox_env: "py311"
|
||||
- name: "windows-py312"
|
||||
python: "3.12-dev"
|
||||
python: "3.12"
|
||||
os: windows-latest
|
||||
tox_env: "py312"
|
||||
- name: "windows-py313"
|
||||
python: "3.13-dev"
|
||||
os: windows-latest
|
||||
tox_env: "py313"
|
||||
|
||||
- name: "ubuntu-py38"
|
||||
python: "3.8"
|
||||
@@ -128,10 +135,15 @@ jobs:
|
||||
tox_env: "py311"
|
||||
use_coverage: true
|
||||
- name: "ubuntu-py312"
|
||||
python: "3.12-dev"
|
||||
python: "3.12"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py312"
|
||||
use_coverage: true
|
||||
- name: "ubuntu-py313"
|
||||
python: "3.13-dev"
|
||||
os: ubuntu-latest
|
||||
tox_env: "py313"
|
||||
use_coverage: true
|
||||
- name: "ubuntu-pypy3"
|
||||
python: "pypy-3.8"
|
||||
os: ubuntu-latest
|
||||
@@ -151,9 +163,13 @@ jobs:
|
||||
os: macos-latest
|
||||
tox_env: "py310-xdist"
|
||||
- name: "macos-py312"
|
||||
python: "3.12-dev"
|
||||
python: "3.12"
|
||||
os: macos-latest
|
||||
tox_env: "py312-xdist"
|
||||
- name: "macos-py313"
|
||||
python: "3.13-dev"
|
||||
os: macos-latest
|
||||
tox_env: "py313-xdist"
|
||||
|
||||
- name: "plugins"
|
||||
python: "3.12"
|
||||
|
||||
2
AUTHORS
2
AUTHORS
@@ -36,6 +36,7 @@ Andrey Paramonov
|
||||
Andrzej Klajnert
|
||||
Andrzej Ostrowski
|
||||
Andy Freeland
|
||||
Anita Hammer
|
||||
Anthon van der Neut
|
||||
Anthony Shaw
|
||||
Anthony Sottile
|
||||
@@ -440,6 +441,7 @@ Yao Xiao
|
||||
Yoav Caspi
|
||||
Yuliang Shao
|
||||
Yusuke Kadowaki
|
||||
Yutian Li
|
||||
Yuval Shimon
|
||||
Zac Hatfield-Dodds
|
||||
Zachary Kneupper
|
||||
|
||||
@@ -6,6 +6,7 @@ Release announcements
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
release-8.2.1
|
||||
release-8.2.0
|
||||
release-8.1.2
|
||||
release-8.1.1
|
||||
|
||||
@@ -62,7 +62,7 @@ New Features
|
||||
- new "-q" option which decreases verbosity and prints a more
|
||||
nose/unittest-style "dot" output.
|
||||
|
||||
- many many more detailed improvements details
|
||||
- many, many, more detailed improvements details
|
||||
|
||||
Fixes
|
||||
-----------------------
|
||||
@@ -109,7 +109,7 @@ Important Notes
|
||||
in conftest.py files. They will cause nothing special.
|
||||
- removed support for calling the pre-1.0 collection API of "run()" and "join"
|
||||
- removed reading option values from conftest.py files or env variables.
|
||||
This can now be done much much better and easier through the ini-file
|
||||
This can now be done much, much, better and easier through the ini-file
|
||||
mechanism and the "addopts" entry in particular.
|
||||
- removed the "disabled" attribute in test classes. Use the skipping
|
||||
and pytestmark mechanism to skip or xfail a test class.
|
||||
|
||||
@@ -4,7 +4,7 @@ pytest-2.2.2: bug fixes
|
||||
pytest-2.2.2 (updated to 2.2.3 to fix packaging issues) is a minor
|
||||
backward-compatible release of the versatile py.test testing tool. It
|
||||
contains bug fixes and a few refinements particularly to reporting with
|
||||
"--collectonly", see below for betails.
|
||||
"--collectonly", see below for details.
|
||||
|
||||
For general information see here:
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ Bug fixes:
|
||||
partially failed (finalizers would not always be called before)
|
||||
|
||||
- fix issue320 - fix class scope for fixtures when mixed with
|
||||
module-level functions. Thanks Anatloy Bubenkoff.
|
||||
module-level functions. Thanks Anatoly Bubenkoff.
|
||||
|
||||
- you can specify "-q" or "-qq" to get different levels of "quieter"
|
||||
reporting (thanks Katarzyna Jachim)
|
||||
|
||||
@@ -83,7 +83,7 @@ holger krekel
|
||||
Thanks Ralph Schmitt for the precise failure example.
|
||||
|
||||
- fix issue244 by implementing special index for parameters to only use
|
||||
indices for paramentrized test ids
|
||||
indices for parametrized test ids
|
||||
|
||||
- fix issue287 by running all finalizers but saving the exception
|
||||
from the first failing finalizer and re-raising it so teardown will
|
||||
|
||||
@@ -73,7 +73,7 @@ holger krekel
|
||||
- cleanup setup.py a bit and specify supported versions. Thanks Jurko
|
||||
Gospodnetic for the PR.
|
||||
|
||||
- change XPASS colour to yellow rather then red when tests are run
|
||||
- change XPASS colour to yellow rather than red when tests are run
|
||||
with -v.
|
||||
|
||||
- fix issue473: work around mock putting an unbound method into a class
|
||||
|
||||
@@ -55,7 +55,7 @@ holger krekel
|
||||
github. See https://pytest.org/en/stable/contributing.html .
|
||||
Thanks to Anatoly for pushing and initial work on this.
|
||||
|
||||
- fix issue650: new option ``--docttest-ignore-import-errors`` which
|
||||
- fix issue650: new option ``--doctest-ignore-import-errors`` which
|
||||
will turn import errors in doctests into skips. Thanks Charles Cloud
|
||||
for the complete PR.
|
||||
|
||||
|
||||
19
doc/en/announce/release-8.2.1.rst
Normal file
19
doc/en/announce/release-8.2.1.rst
Normal file
@@ -0,0 +1,19 @@
|
||||
pytest-8.2.1
|
||||
=======================================
|
||||
|
||||
pytest 8.2.1 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Bruno Oliveira
|
||||
* Ran Benita
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -49,7 +49,7 @@ place on 20th, 21st, 22nd, 24th and 25th. On the 23rd we took a break
|
||||
day for some hot hiking in the Black Forest.
|
||||
|
||||
Sprint activity was organised heavily around pairing, with plenty of group
|
||||
discusssions to take advantage of the high bandwidth, and lightning talks
|
||||
discussions to take advantage of the high bandwidth, and lightning talks
|
||||
as well.
|
||||
|
||||
|
||||
|
||||
@@ -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:542
|
||||
cache -- .../_pytest/cacheprovider.py:549
|
||||
Return a cache object that can persist state between testing sessions.
|
||||
|
||||
cache.get(key, default)
|
||||
|
||||
@@ -28,9 +28,59 @@ with advance notice in the **Deprecations** section of releases.
|
||||
|
||||
.. towncrier release notes start
|
||||
|
||||
pytest 8.2.1 (2024-05-19)
|
||||
=========================
|
||||
|
||||
Improvements
|
||||
------------
|
||||
|
||||
- `#12334 <https://github.com/pytest-dev/pytest/issues/12334>`_: Support for Python 3.13 (beta1 at the time of writing).
|
||||
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#12120 <https://github.com/pytest-dev/pytest/issues/12120>`_: Fix `PermissionError` crashes arising from directories which are not selected on the command-line.
|
||||
|
||||
|
||||
- `#12191 <https://github.com/pytest-dev/pytest/issues/12191>`_: Keyboard interrupts and system exits are now properly handled during the test collection.
|
||||
|
||||
|
||||
- `#12300 <https://github.com/pytest-dev/pytest/issues/12300>`_: Fixed handling of 'Function not implemented' error under squashfuse_ll, which is a different way to say that the mountpoint is read-only.
|
||||
|
||||
|
||||
- `#12308 <https://github.com/pytest-dev/pytest/issues/12308>`_: Fix a regression in pytest 8.2.0 where the permissions of automatically-created ``.pytest_cache`` directories became ``rwx------`` instead of the expected ``rwxr-xr-x``.
|
||||
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- `#12333 <https://github.com/pytest-dev/pytest/issues/12333>`_: pytest releases are now attested using the recent `Artifact Attestation <https://github.blog/2024-05-02-introducing-artifact-attestations-now-in-public-beta/>` support from GitHub, allowing users to verify the provenance of pytest's sdist and wheel artifacts.
|
||||
|
||||
|
||||
pytest 8.2.0 (2024-04-27)
|
||||
=========================
|
||||
|
||||
Breaking Changes
|
||||
----------------
|
||||
|
||||
- `#12089 <https://github.com/pytest-dev/pytest/pull/12089>`_: pytest now requires that :class:`unittest.TestCase` subclasses can be instantiated freely using ``MyTestCase('runTest')``.
|
||||
|
||||
If the class doesn't allow this, you may see an error during collection such as ``AttributeError: 'MyTestCase' object has no attribute 'runTest'``.
|
||||
|
||||
Classes which do not override ``__init__``, or do not access the test method in ``__init__`` using ``getattr`` or similar, are unaffected.
|
||||
|
||||
Classes which do should take care to not crash when ``"runTest"`` is given, as is shown in `unittest.TestCases's implementation <https://github.com/python/cpython/blob/51aefc5bf907ddffaaf083ded0de773adcdf08c8/Lib/unittest/case.py#L419-L426>`_.
|
||||
Alternatively, consider using :meth:`setUp <unittest.TestCase.setUp>` instead of ``__init__``.
|
||||
|
||||
If you run into this issue using ``tornado.AsyncTestCase``, please see `issue 12263 <https://github.com/pytest-dev/pytest/issues/12263>`_.
|
||||
|
||||
If you run into this issue using an abstract ``TestCase`` subclass, please see `issue 12275 <https://github.com/pytest-dev/pytest/issues/12275>`_.
|
||||
|
||||
Historical note: the effect of this change on custom TestCase implementations was not properly considered initially, this is why it was done in a minor release. We apologize for the inconvenience.
|
||||
|
||||
Deprecations
|
||||
------------
|
||||
|
||||
@@ -150,7 +200,7 @@ Improvements
|
||||
- `#11311 <https://github.com/pytest-dev/pytest/issues/11311>`_: When using ``--override-ini`` for paths in invocations without a configuration file defined, the current working directory is used
|
||||
as the relative directory.
|
||||
|
||||
Previoulsy this would raise an :class:`AssertionError`.
|
||||
Previously this would raise an :class:`AssertionError`.
|
||||
|
||||
|
||||
- `#11475 <https://github.com/pytest-dev/pytest/issues/11475>`_: :ref:`--import-mode=importlib <import-mode-importlib>` now tries to import modules using the standard import mechanism (but still without changing :py:data:`sys.path`), falling back to importing modules directly only if that fails.
|
||||
@@ -1393,7 +1443,7 @@ Deprecations
|
||||
``__init__`` method, they should take ``**kwargs``. See
|
||||
:ref:`uncooperative-constructors-deprecated` for details.
|
||||
|
||||
Note that a deprection warning is only emitted when there is a conflict in the
|
||||
Note that a deprecation warning is only emitted when there is a conflict in the
|
||||
arguments pytest expected to pass. This deprecation was already part of pytest
|
||||
7.0.0rc1 but wasn't documented.
|
||||
|
||||
@@ -1435,7 +1485,7 @@ Breaking Changes
|
||||
- `#7259 <https://github.com/pytest-dev/pytest/issues/7259>`_: The :ref:`Node.reportinfo() <non-python tests>` function first return value type has been expanded from `py.path.local | str` to `os.PathLike[str] | str`.
|
||||
|
||||
Most plugins which refer to `reportinfo()` only define it as part of a custom :class:`pytest.Item` implementation.
|
||||
Since `py.path.local` is an `os.PathLike[str]`, these plugins are unaffacted.
|
||||
Since `py.path.local` is an `os.PathLike[str]`, these plugins are unaffected.
|
||||
|
||||
Plugins and users which call `reportinfo()`, use the first return value and interact with it as a `py.path.local`, would need to adjust by calling `py.path.local(fspath)`.
|
||||
Although preferably, avoid the legacy `py.path.local` and use `pathlib.Path`, or use `item.location` or `item.path`, instead.
|
||||
@@ -1943,7 +1993,7 @@ Bug Fixes
|
||||
the ``tmp_path``/``tmpdir`` fixture). Now the directories are created with
|
||||
private permissions.
|
||||
|
||||
pytest used to silently use a pre-existing ``/tmp/pytest-of-<username>`` directory,
|
||||
pytest used to silently use a preexisting ``/tmp/pytest-of-<username>`` directory,
|
||||
even if owned by another user. This means another user could pre-create such a
|
||||
directory and gain control of another user's temporary directory. Now such a
|
||||
condition results in an error.
|
||||
@@ -2670,7 +2720,7 @@ Features
|
||||
also changes ``sys.modules`` as a side-effect), which works but has a number of drawbacks, like requiring test modules
|
||||
that don't live in packages to have unique names (as they need to reside under a unique name in ``sys.modules``).
|
||||
|
||||
``--import-mode=importlib`` uses more fine grained import mechanisms from ``importlib`` which don't
|
||||
``--import-mode=importlib`` uses more fine-grained import mechanisms from ``importlib`` which don't
|
||||
require pytest to change ``sys.path`` or ``sys.modules`` at all, eliminating much of the drawbacks
|
||||
of the previous mode.
|
||||
|
||||
@@ -2687,7 +2737,7 @@ Improvements
|
||||
------------
|
||||
|
||||
- :issue:`4375`: The ``pytest`` command now suppresses the ``BrokenPipeError`` error message that
|
||||
is printed to stderr when the output of ``pytest`` is piped and and the pipe is
|
||||
is printed to stderr when the output of ``pytest`` is piped and the pipe is
|
||||
closed by the piped-to program (common examples are ``less`` and ``head``).
|
||||
|
||||
|
||||
@@ -2989,7 +3039,7 @@ Breaking Changes
|
||||
This hook has been marked as deprecated and not been even called by pytest for over 10 years now.
|
||||
|
||||
|
||||
- :issue:`6673`: Reversed / fix meaning of "+/-" in error diffs. "-" means that sth. expected is missing in the result and "+" means that there are unexpected extras in the result.
|
||||
- :issue:`6673`: Reversed / fix meaning of "+/-" in error diffs. "-" means that something expected is missing in the result and "+" means that there are unexpected extras in the result.
|
||||
|
||||
|
||||
- :issue:`6737`: The ``cached_result`` attribute of ``FixtureDef`` is now set to ``None`` when
|
||||
@@ -4594,7 +4644,7 @@ Bug Fixes
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- :issue:`4974`: Update docs for ``pytest_cmdline_parse`` hook to note availability liminations
|
||||
- :issue:`4974`: Update docs for ``pytest_cmdline_parse`` hook to note availability limitations
|
||||
|
||||
|
||||
|
||||
@@ -6452,7 +6502,7 @@ Features
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Fix hanging pexpect test on MacOS by using flush() instead of wait().
|
||||
- Fix hanging pexpect test on macOS by using flush() instead of wait().
|
||||
(:issue:`2022`)
|
||||
|
||||
- Fix restoring Python state after in-process pytest runs with the
|
||||
@@ -6500,7 +6550,7 @@ Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- Show a simple and easy error when keyword expressions trigger a syntax error
|
||||
(for example, ``"-k foo and import"`` will show an error that you can not use
|
||||
(for example, ``"-k foo and import"`` will show an error that you cannot use
|
||||
the ``import`` keyword in expressions). (:issue:`2953`)
|
||||
|
||||
- Change parametrized automatic test id generation to use the ``__name__``
|
||||
@@ -8276,7 +8326,7 @@ time or change existing behaviors in order to make them less surprising/more use
|
||||
one will also have a "reprec" attribute with the recorded events/reports.
|
||||
|
||||
- fix monkeypatch.setattr("x.y", raising=False) to actually not raise
|
||||
if "y" is not a pre-existing attribute. Thanks Florian Bruhin.
|
||||
if "y" is not a preexisting attribute. Thanks Florian Bruhin.
|
||||
|
||||
- fix issue741: make running output from testdir.run copy/pasteable
|
||||
Thanks Bruno Oliveira.
|
||||
@@ -8332,7 +8382,7 @@ time or change existing behaviors in order to make them less surprising/more use
|
||||
|
||||
- fix issue854: autouse yield_fixtures defined as class members of
|
||||
unittest.TestCase subclasses now work as expected.
|
||||
Thannks xmo-odoo for the report and Bruno Oliveira for the PR.
|
||||
Thanks xmo-odoo for the report and Bruno Oliveira for the PR.
|
||||
|
||||
- fix issue833: --fixtures now shows all fixtures of collected test files, instead of just the
|
||||
fixtures declared on the first one.
|
||||
@@ -8436,7 +8486,7 @@ time or change existing behaviors in order to make them less surprising/more use
|
||||
github. See https://pytest.org/en/stable/contributing.html .
|
||||
Thanks to Anatoly for pushing and initial work on this.
|
||||
|
||||
- fix issue650: new option ``--docttest-ignore-import-errors`` which
|
||||
- fix issue650: new option ``--doctest-ignore-import-errors`` which
|
||||
will turn import errors in doctests into skips. Thanks Charles Cloud
|
||||
for the complete PR.
|
||||
|
||||
@@ -8624,7 +8674,7 @@ time or change existing behaviors in order to make them less surprising/more use
|
||||
- cleanup setup.py a bit and specify supported versions. Thanks Jurko
|
||||
Gospodnetic for the PR.
|
||||
|
||||
- change XPASS colour to yellow rather then red when tests are run
|
||||
- change XPASS colour to yellow rather than red when tests are run
|
||||
with -v.
|
||||
|
||||
- fix issue473: work around mock putting an unbound method into a class
|
||||
@@ -8797,7 +8847,7 @@ time or change existing behaviors in order to make them less surprising/more use
|
||||
Thanks Ralph Schmitt for the precise failure example.
|
||||
|
||||
- fix issue244 by implementing special index for parameters to only use
|
||||
indices for paramentrized test ids
|
||||
indices for parametrized test ids
|
||||
|
||||
- fix issue287 by running all finalizers but saving the exception
|
||||
from the first failing finalizer and re-raising it so teardown will
|
||||
@@ -8805,7 +8855,7 @@ time or change existing behaviors in order to make them less surprising/more use
|
||||
it might be the cause for other finalizers to fail.
|
||||
|
||||
- fix ordering when mock.patch or other standard decorator-wrappings
|
||||
are used with test methods. This fixues issue346 and should
|
||||
are used with test methods. This fixes issue346 and should
|
||||
help with random "xdist" collection failures. Thanks to
|
||||
Ronny Pfannschmidt and Donald Stufft for helping to isolate it.
|
||||
|
||||
@@ -9062,7 +9112,7 @@ Bug fixes:
|
||||
partially failed (finalizers would not always be called before)
|
||||
|
||||
- fix issue320 - fix class scope for fixtures when mixed with
|
||||
module-level functions. Thanks Anatloy Bubenkoff.
|
||||
module-level functions. Thanks Anatoly Bubenkoff.
|
||||
|
||||
- you can specify "-q" or "-qq" to get different levels of "quieter"
|
||||
reporting (thanks Katarzyna Jachim)
|
||||
@@ -9484,7 +9534,7 @@ Bug fixes:
|
||||
unexpected exceptions
|
||||
- fix issue47: timing output in junitxml for test cases is now correct
|
||||
- fix issue48: typo in MarkInfo repr leading to exception
|
||||
- fix issue49: avoid confusing error when initizaliation partially fails
|
||||
- fix issue49: avoid confusing error when initialization partially fails
|
||||
- fix issue44: env/username expansion for junitxml file path
|
||||
- show releaselevel information in test runs for pypy
|
||||
- reworked doc pages for better navigation and PDF generation
|
||||
@@ -9609,7 +9659,7 @@ Bug fixes:
|
||||
collection-before-running semantics were not
|
||||
setup as with pytest 1.3.4. Note, however, that
|
||||
the recommended and much cleaner way to do test
|
||||
parametraization remains the "pytest_generate_tests"
|
||||
parameterization remains the "pytest_generate_tests"
|
||||
mechanism, see the docs.
|
||||
|
||||
2.0.0 (2010-11-25)
|
||||
|
||||
@@ -462,7 +462,7 @@ Now :class:`~pytest.Class` collects the test methods directly.
|
||||
Most plugins which reference ``Instance`` do so in order to ignore or skip it,
|
||||
using a check such as ``if isinstance(node, Instance): return``.
|
||||
Such plugins should simply remove consideration of ``Instance`` on pytest>=7.
|
||||
However, to keep such uses working, a dummy type has been instanted in ``pytest.Instance`` and ``_pytest.python.Instance``,
|
||||
However, to keep such uses working, a dummy type has been instanced in ``pytest.Instance`` and ``_pytest.python.Instance``,
|
||||
and importing it emits a deprecation warning. This was removed in pytest 8.
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ class ManifestDirectory(pytest.Directory):
|
||||
|
||||
@pytest.hookimpl
|
||||
def pytest_collect_directory(path, parent):
|
||||
# Use our custom collector for directories containing a `mainfest.json` file.
|
||||
# Use our custom collector for directories containing a `manifest.json` file.
|
||||
if path.joinpath("manifest.json").is_file():
|
||||
return ManifestDirectory.from_parent(parent=parent, path=path)
|
||||
# Otherwise fallback to the standard behavior.
|
||||
|
||||
@@ -162,7 +162,7 @@ objects, they are still using the default pytest representation:
|
||||
rootdir: /home/sweet/project
|
||||
collected 8 items
|
||||
|
||||
<Dir parametrize.rst-198>
|
||||
<Dir parametrize.rst-199>
|
||||
<Module test_time.py>
|
||||
<Function test_timedistance_v0[a0-b0-expected0]>
|
||||
<Function test_timedistance_v0[a1-b1-expected1]>
|
||||
@@ -239,7 +239,7 @@ If you just collect tests you'll also nicely see 'advanced' and 'basic' as varia
|
||||
rootdir: /home/sweet/project
|
||||
collected 4 items
|
||||
|
||||
<Dir parametrize.rst-198>
|
||||
<Dir parametrize.rst-199>
|
||||
<Module test_scenarios.py>
|
||||
<Class TestSampleWithScenarios>
|
||||
<Function test_demo1[basic]>
|
||||
@@ -318,7 +318,7 @@ Let's first see how it looks like at collection time:
|
||||
rootdir: /home/sweet/project
|
||||
collected 2 items
|
||||
|
||||
<Dir parametrize.rst-198>
|
||||
<Dir parametrize.rst-199>
|
||||
<Module test_backends.py>
|
||||
<Function test_db_initialized[d1]>
|
||||
<Function test_db_initialized[d2]>
|
||||
|
||||
@@ -152,7 +152,7 @@ The test collection would look like this:
|
||||
configfile: pytest.ini
|
||||
collected 2 items
|
||||
|
||||
<Dir pythoncollection.rst-199>
|
||||
<Dir pythoncollection.rst-200>
|
||||
<Module check_myapp.py>
|
||||
<Class CheckMyApp>
|
||||
<Function simple_check>
|
||||
@@ -215,7 +215,7 @@ You can always peek at the collection tree without running tests like this:
|
||||
configfile: pytest.ini
|
||||
collected 3 items
|
||||
|
||||
<Dir pythoncollection.rst-199>
|
||||
<Dir pythoncollection.rst-200>
|
||||
<Dir CWD>
|
||||
<Module pythoncollection.py>
|
||||
<Function test_function>
|
||||
|
||||
@@ -22,7 +22,7 @@ Install ``pytest``
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest --version
|
||||
pytest 8.2.0
|
||||
pytest 8.2.1
|
||||
|
||||
.. _`simpletest`:
|
||||
|
||||
@@ -274,7 +274,7 @@ Continue reading
|
||||
Check out additional pytest resources to help you customize tests for your unique workflow:
|
||||
|
||||
* ":ref:`usage`" for command line invocation examples
|
||||
* ":ref:`existingtestsuite`" for working with pre-existing tests
|
||||
* ":ref:`existingtestsuite`" for working with preexisting tests
|
||||
* ":ref:`mark`" for information on the ``pytest.mark`` mechanism
|
||||
* ":ref:`fixtures`" for providing a functional baseline to your tests
|
||||
* ":ref:`plugins`" for managing and writing plugins
|
||||
|
||||
@@ -1418,7 +1418,7 @@ Running the above tests results in the following test IDs being used:
|
||||
rootdir: /home/sweet/project
|
||||
collected 12 items
|
||||
|
||||
<Dir fixtures.rst-217>
|
||||
<Dir fixtures.rst-218>
|
||||
<Module test_anothersmtp.py>
|
||||
<Function test_showhelo[smtp.gmail.com]>
|
||||
<Function test_showhelo[mail.python.org]>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
- `Professional Testing with Python <https://python-academy.com/courses/python_course_testing.html>`_, via `Python Academy <https://www.python-academy.com/>`_ (3 day in-depth training):
|
||||
* **June 11th to 13th 2024**, Remote
|
||||
* **March 4th to 6th 2025**, Leipzig, Germany / Remote
|
||||
- `pytest development sprint <https://github.com/pytest-dev/pytest/discussions/11655>`_, **June 17th -- 22nd 2024**
|
||||
- `pytest development sprint <https://github.com/pytest-dev/sprint>`_, **June 17th -- 22nd 2024**
|
||||
- pytest tips and tricks for a better testsuite, `Europython 2024 <https://ep2024.europython.eu/>`_, **July 8th -- 14th 2024** (3h), Prague
|
||||
|
||||
Also see :doc:`previous talks and blogposts <talks>`.
|
||||
|
||||
@@ -8,7 +8,7 @@ If you used older version of the ``py`` distribution (which
|
||||
included the py.test command line tool and Python name space)
|
||||
you accessed helpers and possibly collection classes through
|
||||
the ``py.test`` Python namespaces. The new ``pytest``
|
||||
Python module flaty provides the same objects, following
|
||||
Python module flatly provides the same objects, following
|
||||
these renaming rules::
|
||||
|
||||
py.test.XYZ -> pytest.XYZ
|
||||
|
||||
@@ -39,7 +39,7 @@ Built-in fixtures
|
||||
Store and retrieve values across pytest runs.
|
||||
|
||||
:fixture:`doctest_namespace`
|
||||
Provide a dict injected into the docstests namespace.
|
||||
Provide a dict injected into the doctests namespace.
|
||||
|
||||
:fixture:`monkeypatch`
|
||||
Temporarily modify classes, functions, dictionaries,
|
||||
|
||||
@@ -59,11 +59,19 @@ pytest.fail
|
||||
|
||||
.. autofunction:: pytest.fail(reason, [pytrace=True, msg=None])
|
||||
|
||||
.. class:: pytest.fail.Exception
|
||||
|
||||
The exception raised by :func:`pytest.fail`.
|
||||
|
||||
pytest.skip
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. autofunction:: pytest.skip(reason, [allow_module_level=False, msg=None])
|
||||
|
||||
.. class:: pytest.skip.Exception
|
||||
|
||||
The exception raised by :func:`pytest.skip`.
|
||||
|
||||
.. _`pytest.importorskip ref`:
|
||||
|
||||
pytest.importorskip
|
||||
@@ -76,11 +84,19 @@ pytest.xfail
|
||||
|
||||
.. autofunction:: pytest.xfail
|
||||
|
||||
.. class:: pytest.xfail.Exception
|
||||
|
||||
The exception raised by :func:`pytest.xfail`.
|
||||
|
||||
pytest.exit
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. autofunction:: pytest.exit(reason, [returncode=None, msg=None])
|
||||
|
||||
.. class:: pytest.exit.Exception
|
||||
|
||||
The exception raised by :func:`pytest.exit`.
|
||||
|
||||
pytest.main
|
||||
~~~~~~~~~~~
|
||||
|
||||
@@ -246,9 +262,10 @@ Marks a test function as *expected to fail*.
|
||||
to specify ``reason`` (see :ref:`condition string <string conditions>`).
|
||||
:keyword str reason:
|
||||
Reason why the test function is marked as xfail.
|
||||
:keyword Type[Exception] raises:
|
||||
:keyword raises:
|
||||
Exception class (or tuple of classes) expected to be raised by the test function; other exceptions will fail the test.
|
||||
Note that subclasses of the classes passed will also result in a match (similar to how the ``except`` statement works).
|
||||
:type raises: Type[:py:exc:`Exception`]
|
||||
|
||||
:keyword bool run:
|
||||
Whether the test function should actually be executed. If ``False``, the function will always xfail and will
|
||||
@@ -1923,7 +1940,7 @@ All the command-line flags can be obtained by running ``pytest --help``::
|
||||
|
||||
general:
|
||||
-k EXPRESSION Only run tests which match the given substring
|
||||
expression. An expression is a Python evaluatable
|
||||
expression. An expression is a Python evaluable
|
||||
expression where all names are substring-matched
|
||||
against test names and their parent classes.
|
||||
Example: -k 'test_method or test_other' matches all
|
||||
|
||||
@@ -31,6 +31,7 @@ classifiers = [
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Topic :: Software Development :: Libraries",
|
||||
"Topic :: Software Development :: Testing",
|
||||
"Topic :: Utilities",
|
||||
|
||||
@@ -424,15 +424,14 @@ class Traceback(List[TracebackEntry]):
|
||||
# which generates code objects that have hash/value equality
|
||||
# XXX needs a test
|
||||
key = entry.frame.code.path, id(entry.frame.code.raw), entry.lineno
|
||||
# print "checking for recursion at", key
|
||||
values = cache.setdefault(key, [])
|
||||
# Since Python 3.13 f_locals is a proxy, freeze it.
|
||||
loc = dict(entry.frame.f_locals)
|
||||
if values:
|
||||
f = entry.frame
|
||||
loc = f.f_locals
|
||||
for otherloc in values:
|
||||
if otherloc == loc:
|
||||
return i
|
||||
values.append(entry.frame.f_locals)
|
||||
values.append(loc)
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ _winerrnomap = {
|
||||
3: errno.ENOENT,
|
||||
17: errno.EEXIST,
|
||||
18: errno.EXDEV,
|
||||
13: errno.EBUSY, # empty cd drive, but ENOMEDIUM seems unavailiable
|
||||
13: errno.EBUSY, # empty cd drive, but ENOMEDIUM seems unavailable
|
||||
22: errno.ENOTDIR,
|
||||
20: errno.ENOTDIR,
|
||||
267: errno.ENOTDIR,
|
||||
|
||||
@@ -836,7 +836,7 @@ class LocalPath:
|
||||
def copy(self, target, mode=False, stat=False):
|
||||
"""Copy path to target.
|
||||
|
||||
If mode is True, will copy copy permission from path to target.
|
||||
If mode is True, will copy permission from path to target.
|
||||
If stat is True, copy permission, last modification
|
||||
time, last access time, and flags from path to target.
|
||||
"""
|
||||
@@ -1047,7 +1047,7 @@ class LocalPath:
|
||||
def pypkgpath(self):
|
||||
"""Return the Python package path by looking for the last
|
||||
directory upwards which still contains an __init__.py.
|
||||
Return None if a pkgpath can not be determined.
|
||||
Return None if a pkgpath cannot be determined.
|
||||
"""
|
||||
pkgpath = None
|
||||
for parent in self.parts(reverse=True):
|
||||
|
||||
@@ -584,7 +584,7 @@ def _get_assertion_exprs(src: bytes) -> Dict[int, str]:
|
||||
# multi-line assert with message
|
||||
elif lineno in seen_lines:
|
||||
lines[-1] = lines[-1][:offset]
|
||||
# multi line assert with escapd newline before message
|
||||
# multi line assert with escaped newline before message
|
||||
else:
|
||||
lines.append(line[:offset])
|
||||
_write_and_reset()
|
||||
@@ -1171,7 +1171,10 @@ def try_makedirs(cache_dir: Path) -> bool:
|
||||
return False
|
||||
except OSError as e:
|
||||
# as of now, EROFS doesn't have an equivalent OSError-subclass
|
||||
if e.errno == errno.EROFS:
|
||||
#
|
||||
# squashfuse_ll returns ENOSYS "OSError: [Errno 38] Function not
|
||||
# implemented" for a read-only error
|
||||
if e.errno in {errno.EROFS, errno.ENOSYS}:
|
||||
return False
|
||||
raise
|
||||
return True
|
||||
|
||||
@@ -325,7 +325,7 @@ def _diff_text(left: str, right: str, verbose: int = 0) -> List[str]:
|
||||
def _compare_eq_iterable(
|
||||
left: Iterable[Any],
|
||||
right: Iterable[Any],
|
||||
highligher: _HighlightFunc,
|
||||
highlighter: _HighlightFunc,
|
||||
verbose: int = 0,
|
||||
) -> List[str]:
|
||||
if verbose <= 0 and not running_on_ci():
|
||||
@@ -340,7 +340,7 @@ def _compare_eq_iterable(
|
||||
# "right" is the expected base against which we compare "left",
|
||||
# see https://github.com/pytest-dev/pytest/issues/3333
|
||||
explanation.extend(
|
||||
highligher(
|
||||
highlighter(
|
||||
"\n".join(
|
||||
line.rstrip()
|
||||
for line in difflib.ndiff(right_formatting, left_formatting)
|
||||
|
||||
@@ -213,6 +213,13 @@ class Cache:
|
||||
dir=self._cachedir.parent,
|
||||
) as newpath:
|
||||
path = Path(newpath)
|
||||
|
||||
# Reset permissions to the default, see #12308.
|
||||
# Note: there's no way to get the current umask atomically, eek.
|
||||
umask = os.umask(0o022)
|
||||
os.umask(umask)
|
||||
path.chmod(0o777 - umask)
|
||||
|
||||
with open(path.joinpath("README.md"), "xt", encoding="UTF-8") as f:
|
||||
f.write(README_CONTENT)
|
||||
with open(path.joinpath(".gitignore"), "xt", encoding="UTF-8") as f:
|
||||
@@ -244,7 +251,7 @@ class LFPluginCollWrapper:
|
||||
# Sort any lf-paths to the beginning.
|
||||
lf_paths = self.lfplugin._last_failed_paths
|
||||
|
||||
# Use stable sort to priorize last failed.
|
||||
# Use stable sort to prioritize last failed.
|
||||
def sort_key(node: Union[nodes.Item, nodes.Collector]) -> bool:
|
||||
return node.path in lf_paths
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ def iscoroutinefunction(func: object) -> bool:
|
||||
def syntax, and doesn't contain yield), or a function decorated with
|
||||
@asyncio.coroutine.
|
||||
|
||||
Note: copied and modified from Python 3.5's builtin couroutines.py to avoid
|
||||
Note: copied and modified from Python 3.5's builtin coroutines.py to avoid
|
||||
importing asyncio directly, which in turns also initializes the "logging"
|
||||
module as a side-effect (see issue #8).
|
||||
"""
|
||||
|
||||
@@ -462,7 +462,7 @@ class PytestPluginManager(PluginManager):
|
||||
# (see issue #1073).
|
||||
if not name.startswith("pytest_"):
|
||||
return None
|
||||
# Ignore names which can not be hooks.
|
||||
# Ignore names which cannot be hooks.
|
||||
if name == "pytest_plugins":
|
||||
return None
|
||||
|
||||
@@ -574,8 +574,8 @@ class PytestPluginManager(PluginManager):
|
||||
self._noconftest = noconftest
|
||||
self._using_pyargs = pyargs
|
||||
foundanchor = False
|
||||
for intitial_path in args:
|
||||
path = str(intitial_path)
|
||||
for initial_path in args:
|
||||
path = str(initial_path)
|
||||
# remove node-id syntax
|
||||
i = path.find("::")
|
||||
if i != -1:
|
||||
|
||||
@@ -325,7 +325,7 @@ class FuncFixtureInfo:
|
||||
working_set = set(self.initialnames)
|
||||
while working_set:
|
||||
argname = working_set.pop()
|
||||
# Argname may be smth not included in the original names_closure,
|
||||
# Argname may be something not included in the original names_closure,
|
||||
# in which case we ignore it. This currently happens with pseudo
|
||||
# FixtureDefs which wrap 'get_direct_param_fixture_func(request)'.
|
||||
# So they introduce the new dependency 'request' which might have
|
||||
@@ -1701,7 +1701,7 @@ class FixtureManager:
|
||||
|
||||
If `node_or_object` is a collection node (with an underlying Python
|
||||
object), the node's object is traversed and the node's nodeid is used to
|
||||
determine the fixtures' visibilty. `nodeid` must not be specified in
|
||||
determine the fixtures' visibility. `nodeid` must not be specified in
|
||||
this case.
|
||||
|
||||
If `node_or_object` is an object (e.g. a plugin), the object is
|
||||
|
||||
@@ -650,7 +650,7 @@ def pytest_runtest_protocol(
|
||||
- ``pytest_runtest_logreport(report)``
|
||||
- ``pytest_exception_interact(call, report)`` if an interactive exception occurred
|
||||
|
||||
- Call phase, if the the setup passed and the ``setuponly`` pytest option is not set:
|
||||
- Call phase, if the setup passed and the ``setuponly`` pytest option is not set:
|
||||
- ``call = pytest_runtest_call(item)`` (wrapped in ``CallInfo(when="call")``)
|
||||
- ``report = pytest_runtest_makereport(item, call)``
|
||||
- ``pytest_runtest_logreport(report)``
|
||||
@@ -860,7 +860,7 @@ def pytest_fixture_setup(
|
||||
) -> Optional[object]:
|
||||
"""Perform fixture setup execution.
|
||||
|
||||
:param fixturdef:
|
||||
:param fixturedef:
|
||||
The fixture definition object.
|
||||
:param request:
|
||||
The fixture request object.
|
||||
@@ -890,7 +890,7 @@ def pytest_fixture_post_finalizer(
|
||||
the fixture result ``fixturedef.cached_result`` is still available (not
|
||||
``None``).
|
||||
|
||||
:param fixturdef:
|
||||
:param fixturedef:
|
||||
The fixture definition object.
|
||||
:param request:
|
||||
The fixture request object.
|
||||
|
||||
@@ -384,7 +384,7 @@ def Config_inifile(self: Config) -> Optional[LEGACY_PATH]:
|
||||
return legacy_path(str(self.inipath)) if self.inipath else None
|
||||
|
||||
|
||||
def Session_stardir(self: Session) -> LEGACY_PATH:
|
||||
def Session_startdir(self: Session) -> LEGACY_PATH:
|
||||
"""The path from which pytest was invoked.
|
||||
|
||||
Prefer to use ``startpath`` which is a :class:`pathlib.Path`.
|
||||
@@ -439,7 +439,7 @@ def pytest_load_initial_conftests(early_config: Config) -> None:
|
||||
mp.setattr(Config, "inifile", property(Config_inifile), raising=False)
|
||||
|
||||
# Add Session.startdir property.
|
||||
mp.setattr(Session, "startdir", property(Session_stardir), raising=False)
|
||||
mp.setattr(Session, "startdir", property(Session_startdir), raising=False)
|
||||
|
||||
# Add pathlist configuration type.
|
||||
mp.setattr(Config, "_getini_unknown_type", Config__getini_unknown_type)
|
||||
|
||||
@@ -78,7 +78,7 @@ def pytest_addoption(parser: Parser) -> None:
|
||||
default="",
|
||||
metavar="EXPRESSION",
|
||||
help="Only run tests which match the given substring expression. "
|
||||
"An expression is a Python evaluatable expression "
|
||||
"An expression is a Python evaluable expression "
|
||||
"where all names are substring-matched against test names "
|
||||
"and their parent classes. Example: -k 'test_method or test_"
|
||||
"other' matches all test functions and classes whose name "
|
||||
|
||||
@@ -114,6 +114,9 @@ def exit(
|
||||
|
||||
:param returncode:
|
||||
Return code to be used when exiting pytest. None means the same as ``0`` (no error), same as :func:`sys.exit`.
|
||||
|
||||
:raises pytest.exit.Exception:
|
||||
The exception that is raised.
|
||||
"""
|
||||
__tracebackhide__ = True
|
||||
raise Exit(reason, returncode)
|
||||
@@ -142,6 +145,9 @@ def skip(
|
||||
|
||||
Defaults to False.
|
||||
|
||||
:raises pytest.skip.Exception:
|
||||
The exception that is raised.
|
||||
|
||||
.. note::
|
||||
It is better to use the :ref:`pytest.mark.skipif ref` marker when
|
||||
possible to declare a test to be skipped under certain conditions
|
||||
@@ -163,6 +169,9 @@ def fail(reason: str = "", pytrace: bool = True) -> NoReturn:
|
||||
:param pytrace:
|
||||
If False, msg represents the full failure information and no
|
||||
python traceback will be reported.
|
||||
|
||||
:raises pytest.fail.Exception:
|
||||
The exception that is raised.
|
||||
"""
|
||||
__tracebackhide__ = True
|
||||
raise Failed(msg=reason, pytrace=pytrace)
|
||||
@@ -188,6 +197,9 @@ def xfail(reason: str = "") -> NoReturn:
|
||||
It is better to use the :ref:`pytest.mark.xfail ref` marker when
|
||||
possible to declare a test to be xfailed under certain conditions
|
||||
like known bugs or missing features.
|
||||
|
||||
:raises pytest.xfail.Exception:
|
||||
The exception that is raised.
|
||||
"""
|
||||
__tracebackhide__ = True
|
||||
raise XFailed(reason)
|
||||
@@ -227,6 +239,9 @@ def importorskip(
|
||||
:returns:
|
||||
The imported module. This should be assigned to its canonical name.
|
||||
|
||||
:raises pytest.skip.Exception:
|
||||
If the module cannot be imported.
|
||||
|
||||
Example::
|
||||
|
||||
docutils = pytest.importorskip("docutils")
|
||||
|
||||
@@ -173,7 +173,7 @@ def rm_rf(path: Path) -> None:
|
||||
|
||||
|
||||
def find_prefixed(root: Path, prefix: str) -> Iterator["os.DirEntry[str]"]:
|
||||
"""Find all elements in root that begin with the prefix, case insensitive."""
|
||||
"""Find all elements in root that begin with the prefix, case-insensitive."""
|
||||
l_prefix = prefix.lower()
|
||||
for x in os.scandir(root):
|
||||
if x.name.lower().startswith(l_prefix):
|
||||
@@ -776,7 +776,7 @@ def resolve_package_path(path: Path) -> Optional[Path]:
|
||||
"""Return the Python package path by looking for the last
|
||||
directory upwards which still contains an __init__.py.
|
||||
|
||||
Returns None if it can not be determined.
|
||||
Returns None if it cannot be determined.
|
||||
"""
|
||||
result = None
|
||||
for parent in itertools.chain((path,), path.parents):
|
||||
|
||||
@@ -289,7 +289,8 @@ class HookRecorder:
|
||||
__tracebackhide__ = True
|
||||
i = 0
|
||||
entries = list(entries)
|
||||
backlocals = sys._getframe(1).f_locals
|
||||
# Since Python 3.13, f_locals is not a dict, but eval requires a dict.
|
||||
backlocals = dict(sys._getframe(1).f_locals)
|
||||
while entries:
|
||||
name, check = entries.pop(0)
|
||||
for ind, call in enumerate(self.calls[i:]):
|
||||
@@ -760,6 +761,9 @@ class Pytester:
|
||||
) -> Path:
|
||||
items = list(files.items())
|
||||
|
||||
if ext is None:
|
||||
raise TypeError("ext must not be None")
|
||||
|
||||
if ext and not ext.startswith("."):
|
||||
raise ValueError(
|
||||
f"pytester.makefile expects a file extension, try .{ext} instead of {ext}"
|
||||
|
||||
@@ -176,7 +176,12 @@ def pytest_collect_directory(
|
||||
path: Path, parent: nodes.Collector
|
||||
) -> Optional[nodes.Collector]:
|
||||
pkginit = path / "__init__.py"
|
||||
if pkginit.is_file():
|
||||
try:
|
||||
has_pkginit = pkginit.is_file()
|
||||
except PermissionError:
|
||||
# See https://github.com/pytest-dev/pytest/issues/12120#issuecomment-2106349096.
|
||||
return None
|
||||
if has_pkginit:
|
||||
return Package.from_parent(parent, path=path)
|
||||
return None
|
||||
|
||||
|
||||
@@ -388,7 +388,9 @@ def pytest_make_collect_report(collector: Collector) -> CollectReport:
|
||||
|
||||
return list(collector.collect())
|
||||
|
||||
call = CallInfo.from_call(collect, "collect")
|
||||
call = CallInfo.from_call(
|
||||
collect, "collect", reraise=(KeyboardInterrupt, SystemExit)
|
||||
)
|
||||
longrepr: Union[None, Tuple[str, int, str], str, TerminalRepr] = None
|
||||
if not call.excinfo:
|
||||
outcome: Literal["passed", "skipped", "failed"] = "passed"
|
||||
|
||||
@@ -40,7 +40,7 @@ def pytest_addoption(parser: Parser) -> None:
|
||||
@pytest.hookimpl
|
||||
def pytest_configure(config: Config) -> None:
|
||||
if config.option.stepwise_skip:
|
||||
# allow --stepwise-skip to work on it's own merits.
|
||||
# allow --stepwise-skip to work on its own merits.
|
||||
config.option.stepwise = True
|
||||
if config.getoption("stepwise"):
|
||||
config.pluginmanager.register(StepwisePlugin(config), "stepwiseplugin")
|
||||
|
||||
@@ -667,7 +667,7 @@ class TestLocalPath(CommonFSTests):
|
||||
assert p == os.path.expanduser("~")
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not sys.platform.startswith("win32"), reason="case insensitive only on windows"
|
||||
not sys.platform.startswith("win32"), reason="case-insensitive only on windows"
|
||||
)
|
||||
def test_eq_hash_are_case_insensitive_on_windows(self):
|
||||
a = local("/some/path")
|
||||
@@ -898,7 +898,7 @@ class TestExecutionOnWindows:
|
||||
class TestExecution:
|
||||
pytestmark = skiponwin32
|
||||
|
||||
def test_sysfind_no_permisson_ignored(self, monkeypatch, tmpdir):
|
||||
def test_sysfind_no_permission_ignored(self, monkeypatch, tmpdir):
|
||||
noperm = tmpdir.ensure("noperm", dir=True)
|
||||
monkeypatch.setenv("PATH", str(noperm), prepend=":")
|
||||
noperm.chmod(0)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# mypy: allow-untyped-defs
|
||||
from __future__ import annotations
|
||||
|
||||
import fnmatch
|
||||
import importlib
|
||||
import io
|
||||
import operator
|
||||
@@ -237,7 +238,7 @@ class TestTraceback_f_g_h:
|
||||
n += 1
|
||||
f(n)
|
||||
|
||||
excinfo = pytest.raises(RuntimeError, f, 8)
|
||||
excinfo = pytest.raises(RecursionError, f, 8)
|
||||
traceback = excinfo.traceback
|
||||
recindex = traceback.recursionindex()
|
||||
assert recindex == 3
|
||||
@@ -373,7 +374,10 @@ def test_excinfo_no_sourcecode():
|
||||
except ValueError:
|
||||
excinfo = _pytest._code.ExceptionInfo.from_current()
|
||||
s = str(excinfo.traceback[-1])
|
||||
assert s == " File '<string>':1 in <module>\n ???\n"
|
||||
# TODO: Since Python 3.13b1 under pytest-xdist, the * is `import
|
||||
# sys;exec(eval(sys.stdin.readline()))` (execnet bootstrap code)
|
||||
# instead of `???` like before. Is this OK?
|
||||
fnmatch.fnmatch(s, " File '<string>':1 in <module>\n *\n")
|
||||
|
||||
|
||||
def test_excinfo_no_python_sourcecode(tmp_path: Path) -> None:
|
||||
@@ -1515,7 +1519,7 @@ def test_cwd_deleted(pytester: Pytester) -> None:
|
||||
result.stderr.no_fnmatch_line("*INTERNALERROR*")
|
||||
|
||||
|
||||
def test_regression_nagative_line_index(pytester: Pytester) -> None:
|
||||
def test_regression_negative_line_index(pytester: Pytester) -> None:
|
||||
"""
|
||||
With Python 3.10 alphas, there was an INTERNALERROR reported in
|
||||
https://github.com/pytest-dev/pytest/pull/8227
|
||||
|
||||
@@ -255,7 +255,7 @@ def test_getfuncsource_dynamic() -> None:
|
||||
assert str(g_source).strip() == "def g():\n pass # pragma: no cover"
|
||||
|
||||
|
||||
def test_getfuncsource_with_multine_string() -> None:
|
||||
def test_getfuncsource_with_multiline_string() -> None:
|
||||
def f():
|
||||
c = """while True:
|
||||
pass
|
||||
@@ -370,7 +370,11 @@ def test_getfslineno() -> None:
|
||||
pass
|
||||
|
||||
B.__name__ = B.__qualname__ = "B2"
|
||||
assert getfslineno(B)[1] == -1
|
||||
# Since Python 3.13 this started working.
|
||||
if sys.version_info >= (3, 13):
|
||||
assert getfslineno(B)[1] != -1
|
||||
else:
|
||||
assert getfslineno(B)[1] == -1
|
||||
|
||||
|
||||
def test_code_of_object_instance_with_call() -> None:
|
||||
|
||||
@@ -117,7 +117,7 @@ def test_change_disabled_level_undo(pytester: Pytester) -> None:
|
||||
result.stdout.no_fnmatch_line("*log from test2*")
|
||||
|
||||
|
||||
def test_change_level_undos_handler_level(pytester: Pytester) -> None:
|
||||
def test_change_level_undoes_handler_level(pytester: Pytester) -> None:
|
||||
"""Ensure that 'set_level' is undone after the end of the test (handler).
|
||||
|
||||
Issue #7569. Tests the handler level specifically.
|
||||
@@ -302,7 +302,15 @@ def logging_during_setup_and_teardown(
|
||||
assert [x.message for x in caplog.get_records("teardown")] == ["a_teardown_log"]
|
||||
|
||||
|
||||
def test_caplog_captures_for_all_stages(
|
||||
def private_assert_caplog_records_is_setup_call(
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
# This reaches into private API, don't use this type of thing in real tests!
|
||||
caplog_records = caplog._item.stash[caplog_records_key]
|
||||
assert set(caplog_records) == {"setup", "call"}
|
||||
|
||||
|
||||
def test_captures_for_all_stages(
|
||||
caplog: pytest.LogCaptureFixture, logging_during_setup_and_teardown: None
|
||||
) -> None:
|
||||
assert not caplog.records
|
||||
@@ -312,9 +320,7 @@ def test_caplog_captures_for_all_stages(
|
||||
|
||||
assert [x.message for x in caplog.get_records("setup")] == ["a_setup_log"]
|
||||
|
||||
# This reaches into private API, don't use this type of thing in real tests!
|
||||
caplog_records = caplog._item.stash[caplog_records_key]
|
||||
assert set(caplog_records) == {"setup", "call"}
|
||||
private_assert_caplog_records_is_setup_call(caplog)
|
||||
|
||||
|
||||
def test_clear_for_call_stage(
|
||||
@@ -323,21 +329,18 @@ def test_clear_for_call_stage(
|
||||
logger.info("a_call_log")
|
||||
assert [x.message for x in caplog.get_records("call")] == ["a_call_log"]
|
||||
assert [x.message for x in caplog.get_records("setup")] == ["a_setup_log"]
|
||||
caplog_records = caplog._item.stash[caplog_records_key]
|
||||
assert set(caplog_records) == {"setup", "call"}
|
||||
private_assert_caplog_records_is_setup_call(caplog)
|
||||
|
||||
caplog.clear()
|
||||
|
||||
assert caplog.get_records("call") == []
|
||||
assert [x.message for x in caplog.get_records("setup")] == ["a_setup_log"]
|
||||
caplog_records = caplog._item.stash[caplog_records_key]
|
||||
assert set(caplog_records) == {"setup", "call"}
|
||||
private_assert_caplog_records_is_setup_call(caplog)
|
||||
|
||||
logging.info("a_call_log_after_clear")
|
||||
assert [x.message for x in caplog.get_records("call")] == ["a_call_log_after_clear"]
|
||||
assert [x.message for x in caplog.get_records("setup")] == ["a_setup_log"]
|
||||
caplog_records = caplog._item.stash[caplog_records_key]
|
||||
assert set(caplog_records) == {"setup", "call"}
|
||||
private_assert_caplog_records_is_setup_call(caplog)
|
||||
|
||||
|
||||
def test_ini_controls_global_log_level(pytester: Pytester) -> None:
|
||||
@@ -363,11 +366,11 @@ def test_ini_controls_global_log_level(pytester: Pytester) -> None:
|
||||
)
|
||||
|
||||
result = pytester.runpytest()
|
||||
# make sure that that we get a '0' exit code for the testsuite
|
||||
# make sure that we get a '0' exit code for the testsuite
|
||||
assert result.ret == 0
|
||||
|
||||
|
||||
def test_caplog_can_override_global_log_level(pytester: Pytester) -> None:
|
||||
def test_can_override_global_log_level(pytester: Pytester) -> None:
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
import pytest
|
||||
@@ -406,7 +409,7 @@ def test_caplog_can_override_global_log_level(pytester: Pytester) -> None:
|
||||
assert result.ret == 0
|
||||
|
||||
|
||||
def test_caplog_captures_despite_exception(pytester: Pytester) -> None:
|
||||
def test_captures_despite_exception(pytester: Pytester) -> None:
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
import pytest
|
||||
|
||||
@@ -933,7 +933,7 @@ class TestRequestBasic:
|
||||
) -> None:
|
||||
"""
|
||||
Ensure exceptions raised during teardown by finalizers are suppressed
|
||||
until all finalizers are called, then re-reaised together in an
|
||||
until all finalizers are called, then re-raised together in an
|
||||
exception group (#2440)
|
||||
"""
|
||||
pytester.makepyfile(
|
||||
|
||||
@@ -163,7 +163,7 @@ class TestMockDecoration:
|
||||
@mock.patch("os.path.abspath")
|
||||
@mock.patch("os.path.normpath")
|
||||
@mock.patch("os.path.basename", new=mock_basename)
|
||||
def test_someting(normpath, abspath, tmp_path):
|
||||
def test_something(normpath, abspath, tmp_path):
|
||||
abspath.return_value = "this"
|
||||
os.path.normpath(os.path.abspath("hello"))
|
||||
normpath.assert_any_call("this")
|
||||
@@ -176,7 +176,7 @@ class TestMockDecoration:
|
||||
funcnames = [
|
||||
call.report.location[2] for call in calls if call.report.when == "call"
|
||||
]
|
||||
assert funcnames == ["T.test_hello", "test_someting"]
|
||||
assert funcnames == ["T.test_hello", "test_something"]
|
||||
|
||||
def test_mock_sorting(self, pytester: Pytester) -> None:
|
||||
pytest.importorskip("mock", "1.0.1")
|
||||
|
||||
@@ -1974,6 +1974,11 @@ def test_try_makedirs(monkeypatch, tmp_path: Path) -> None:
|
||||
monkeypatch.setattr(os, "makedirs", partial(fake_mkdir, exc=err))
|
||||
assert not try_makedirs(p)
|
||||
|
||||
err = OSError()
|
||||
err.errno = errno.ENOSYS
|
||||
monkeypatch.setattr(os, "makedirs", partial(fake_mkdir, exc=err))
|
||||
assert not try_makedirs(p)
|
||||
|
||||
# unhandled OSError should raise
|
||||
err = OSError()
|
||||
err.errno = errno.ECHILD
|
||||
|
||||
@@ -31,6 +31,21 @@ class TestNewAPI:
|
||||
p = config.cache.mkdir("name")
|
||||
assert p.is_dir()
|
||||
|
||||
def test_cache_dir_permissions(self, pytester: Pytester) -> None:
|
||||
"""The .pytest_cache directory should have world-readable permissions
|
||||
(depending on umask).
|
||||
|
||||
Regression test for #12308.
|
||||
"""
|
||||
pytester.makeini("[pytest]")
|
||||
config = pytester.parseconfigure()
|
||||
assert config.cache is not None
|
||||
p = config.cache.mkdir("name")
|
||||
assert p.is_dir()
|
||||
# Instead of messing with umask, make sure .pytest_cache has the same
|
||||
# permissions as the default that `mkdir` gives `p`.
|
||||
assert (p.parent.stat().st_mode & 0o777) == (p.stat().st_mode & 0o777)
|
||||
|
||||
def test_config_cache_dataerror(self, pytester: Pytester) -> None:
|
||||
pytester.makeini("[pytest]")
|
||||
config = pytester.parseconfigure()
|
||||
@@ -43,7 +58,7 @@ class TestNewAPI:
|
||||
assert val == -2
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:could not create cache path")
|
||||
def test_cache_writefail_cachfile_silent(self, pytester: Pytester) -> None:
|
||||
def test_cache_writefail_cachefile_silent(self, pytester: Pytester) -> None:
|
||||
pytester.makeini("[pytest]")
|
||||
pytester.path.joinpath(".pytest_cache").write_text(
|
||||
"gone wrong", encoding="utf-8"
|
||||
@@ -179,7 +194,7 @@ class TestNewAPI:
|
||||
assert pytester.path.joinpath("custom_cache_dir").is_dir()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("env", ((), ("TOX_ENV_DIR", "/tox_env_dir")))
|
||||
@pytest.mark.parametrize("env", ((), ("TOX_ENV_DIR", "mydir/tox-env")))
|
||||
def test_cache_reportheader(
|
||||
env: Sequence[str], pytester: Pytester, monkeypatch: MonkeyPatch
|
||||
) -> None:
|
||||
|
||||
@@ -7,6 +7,7 @@ import sys
|
||||
import tempfile
|
||||
import textwrap
|
||||
from typing import List
|
||||
from typing import Type
|
||||
|
||||
from _pytest.assertion.util import running_on_ci
|
||||
from _pytest.config import ExitCode
|
||||
@@ -284,6 +285,23 @@ class TestCollectFS:
|
||||
items, reprec = pytester.inline_genitems()
|
||||
assert [x.name for x in items] == ["test_%s" % dirname]
|
||||
|
||||
def test_missing_permissions_on_unselected_directory_doesnt_crash(
|
||||
self, pytester: Pytester
|
||||
) -> None:
|
||||
"""Regression test for #12120."""
|
||||
test = pytester.makepyfile(test="def test(): pass")
|
||||
bad = pytester.mkdir("bad")
|
||||
try:
|
||||
bad.chmod(0)
|
||||
|
||||
result = pytester.runpytest(test)
|
||||
finally:
|
||||
bad.chmod(750)
|
||||
bad.rmdir()
|
||||
|
||||
assert result.ret == ExitCode.OK
|
||||
result.assert_outcomes(passed=1)
|
||||
|
||||
|
||||
class TestCollectPluginHookRelay:
|
||||
def test_pytest_collect_file(self, pytester: Pytester) -> None:
|
||||
@@ -1857,3 +1875,33 @@ def test_do_not_collect_symlink_siblings(
|
||||
# Ensure we collect it only once if we pass the symlinked directory.
|
||||
result = pytester.runpytest(symlink_path, "-sv")
|
||||
result.assert_outcomes(passed=1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"exception_class, msg",
|
||||
[
|
||||
(KeyboardInterrupt, "*!!! KeyboardInterrupt !!!*"),
|
||||
(SystemExit, "INTERNALERROR> SystemExit"),
|
||||
],
|
||||
)
|
||||
def test_respect_system_exceptions(
|
||||
pytester: Pytester,
|
||||
exception_class: Type[BaseException],
|
||||
msg: str,
|
||||
):
|
||||
head = "Before exception"
|
||||
tail = "After exception"
|
||||
ensure_file(pytester.path / "test_eggs.py").write_text(
|
||||
f"print('{head}')", encoding="UTF-8"
|
||||
)
|
||||
ensure_file(pytester.path / "test_ham.py").write_text(
|
||||
f"raise {exception_class.__name__}()", encoding="UTF-8"
|
||||
)
|
||||
ensure_file(pytester.path / "test_spam.py").write_text(
|
||||
f"print('{tail}')", encoding="UTF-8"
|
||||
)
|
||||
|
||||
result = pytester.runpytest_subprocess("-s")
|
||||
result.stdout.fnmatch_lines([f"*{head}*"])
|
||||
result.stdout.fnmatch_lines([msg])
|
||||
result.stdout.no_fnmatch_line(f"*{tail}*")
|
||||
|
||||
@@ -94,7 +94,7 @@ def test_get_real_func_partial() -> None:
|
||||
assert get_real_func(partial(foo)) is foo
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info >= (3, 11), reason="couroutine removed")
|
||||
@pytest.mark.skipif(sys.version_info >= (3, 11), reason="coroutine removed")
|
||||
def test_is_generator_asyncio(pytester: Pytester) -> None:
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
|
||||
@@ -217,7 +217,7 @@ class TestParseIni:
|
||||
|
||||
def test_confcutdir_default_without_configfile(self, pytester: Pytester) -> None:
|
||||
# If --confcutdir is not specified, and there is no configfile, default
|
||||
# to the roothpath.
|
||||
# to the rootpath.
|
||||
sub = pytester.mkdir("sub")
|
||||
os.chdir(sub)
|
||||
config = pytester.parseconfigure()
|
||||
@@ -1740,7 +1740,7 @@ class TestOverrideIniArgs:
|
||||
)
|
||||
pytester.makepyfile(
|
||||
r"""
|
||||
def test_overriden(pytestconfig):
|
||||
def test_overridden(pytestconfig):
|
||||
config_paths = pytestconfig.getini("paths")
|
||||
print(config_paths)
|
||||
for cpf in config_paths:
|
||||
|
||||
@@ -70,7 +70,7 @@ class TestConftestValueAccessGlobal:
|
||||
)
|
||||
assert conftest._rget_with_confmod("a", p)[1] == 1
|
||||
|
||||
def test_immediate_initialiation_and_incremental_are_the_same(
|
||||
def test_immediate_initialization_and_incremental_are_the_same(
|
||||
self, basedir: Path
|
||||
) -> None:
|
||||
conftest = PytestPluginManager()
|
||||
@@ -396,7 +396,7 @@ def test_conftest_symlink_files(pytester: Pytester) -> None:
|
||||
|
||||
@pytest.mark.skipif(
|
||||
os.path.normcase("x") != os.path.normcase("X"),
|
||||
reason="only relevant for case insensitive file systems",
|
||||
reason="only relevant for case-insensitive file systems",
|
||||
)
|
||||
def test_conftest_badcase(pytester: Pytester) -> None:
|
||||
"""Check conftest.py loading when directory casing is wrong (#5792)."""
|
||||
|
||||
@@ -1122,7 +1122,7 @@ class TestTraceOption:
|
||||
|
||||
|
||||
def test_trace_after_runpytest(pytester: Pytester) -> None:
|
||||
"""Test that debugging's pytest_configure is re-entrant."""
|
||||
"""Test that debugging's pytest_configure is reentrant."""
|
||||
p1 = pytester.makepyfile(
|
||||
"""
|
||||
from _pytest.debugging import pytestPDB
|
||||
@@ -1153,7 +1153,7 @@ def test_trace_after_runpytest(pytester: Pytester) -> None:
|
||||
|
||||
|
||||
def test_quit_with_swallowed_SystemExit(pytester: Pytester) -> None:
|
||||
"""Test that debugging's pytest_configure is re-entrant."""
|
||||
"""Test that debugging's pytest_configure is reentrant."""
|
||||
p1 = pytester.makepyfile(
|
||||
"""
|
||||
def call_pdb_set_trace():
|
||||
|
||||
@@ -224,11 +224,7 @@ class TestDoctests:
|
||||
"Traceback (most recent call last):",
|
||||
' File "*/doctest.py", line *, in __run',
|
||||
" *",
|
||||
*(
|
||||
(" *^^^^*",)
|
||||
if (3, 11, 0, "beta", 4) > sys.version_info >= (3, 11)
|
||||
else ()
|
||||
),
|
||||
*((" *^^^^*", " *", " *") if sys.version_info >= (3, 13) else ()),
|
||||
' File "<doctest test_doctest_unexpected_exception.txt[1]>", line 1, in <module>',
|
||||
"ZeroDivisionError: division by zero",
|
||||
"*/test_doctest_unexpected_exception.txt:2: UnexpectedException",
|
||||
@@ -385,7 +381,7 @@ class TestDoctests:
|
||||
"*= FAILURES =*",
|
||||
"*_ [[]doctest[]] test_doctest_linedata_on_property.Sample.some_property _*",
|
||||
"004 ",
|
||||
"005 >>> Sample().some_property",
|
||||
"005 *>>> Sample().some_property",
|
||||
"Expected:",
|
||||
" 'another thing'",
|
||||
"Got:",
|
||||
@@ -396,7 +392,7 @@ class TestDoctests:
|
||||
]
|
||||
)
|
||||
|
||||
def test_doctest_no_linedata_on_overriden_property(self, pytester: Pytester):
|
||||
def test_doctest_no_linedata_on_overridden_property(self, pytester: Pytester):
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
class Sample(object):
|
||||
@@ -414,7 +410,7 @@ class TestDoctests:
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"*= FAILURES =*",
|
||||
"*_ [[]doctest[]] test_doctest_no_linedata_on_overriden_property.Sample.some_property _*",
|
||||
"*_ [[]doctest[]] test_doctest_no_linedata_on_overridden_property.Sample.some_property _*",
|
||||
"EXAMPLE LOCATION UNKNOWN, not showing all tests of that example",
|
||||
"[?][?][?] >>> Sample().some_property",
|
||||
"Expected:",
|
||||
@@ -422,7 +418,7 @@ class TestDoctests:
|
||||
"Got:",
|
||||
" 'something'",
|
||||
"",
|
||||
"*/test_doctest_no_linedata_on_overriden_property.py:None: DocTestFailure",
|
||||
"*/test_doctest_no_linedata_on_overridden_property.py:None: DocTestFailure",
|
||||
"*= 1 failed in *",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -1002,7 +1002,7 @@ class TestNonPython:
|
||||
|
||||
@pytest.mark.parametrize("junit_logging", ["no", "system-out"])
|
||||
def test_nullbyte(pytester: Pytester, junit_logging: str) -> None:
|
||||
# A null byte can not occur in XML (see section 2.2 of the spec)
|
||||
# A null byte cannot occur in XML (see section 2.2 of the spec)
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
import sys
|
||||
|
||||
@@ -155,7 +155,7 @@ def test_override_ini_paths(pytester: pytest.Pytester) -> None:
|
||||
)
|
||||
pytester.makepyfile(
|
||||
r"""
|
||||
def test_overriden(pytestconfig):
|
||||
def test_overridden(pytestconfig):
|
||||
config_paths = pytestconfig.getini("paths")
|
||||
print(config_paths)
|
||||
for cpf in config_paths:
|
||||
|
||||
@@ -3,7 +3,6 @@ import argparse
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
from _pytest.config import ExitCode
|
||||
@@ -45,32 +44,18 @@ def test_wrap_session_notify_exception(ret_exc, pytester: Pytester) -> None:
|
||||
assert result.ret == ExitCode.INTERNAL_ERROR
|
||||
assert result.stdout.lines[0] == "INTERNALERROR> Traceback (most recent call last):"
|
||||
|
||||
end_lines = (
|
||||
result.stdout.lines[-4:]
|
||||
if (3, 11, 0, "beta", 4) > sys.version_info >= (3, 11)
|
||||
else result.stdout.lines[-3:]
|
||||
)
|
||||
end_lines = result.stdout.lines[-3:]
|
||||
|
||||
if exc == SystemExit:
|
||||
assert end_lines == [
|
||||
f'INTERNALERROR> File "{c1}", line 4, in pytest_sessionstart',
|
||||
'INTERNALERROR> raise SystemExit("boom")',
|
||||
*(
|
||||
("INTERNALERROR> ^^^^^^^^^^^^^^^^^^^^^^^^",)
|
||||
if (3, 11, 0, "beta", 4) > sys.version_info >= (3, 11)
|
||||
else ()
|
||||
),
|
||||
"INTERNALERROR> SystemExit: boom",
|
||||
]
|
||||
else:
|
||||
assert end_lines == [
|
||||
f'INTERNALERROR> File "{c1}", line 4, in pytest_sessionstart',
|
||||
'INTERNALERROR> raise ValueError("boom")',
|
||||
*(
|
||||
("INTERNALERROR> ^^^^^^^^^^^^^^^^^^^^^^^^",)
|
||||
if (3, 11, 0, "beta", 4) > sys.version_info >= (3, 11)
|
||||
else ()
|
||||
),
|
||||
"INTERNALERROR> ValueError: boom",
|
||||
]
|
||||
if returncode is False:
|
||||
|
||||
@@ -61,7 +61,7 @@ def test_basic(expr: str, expected: bool) -> None:
|
||||
("not not not not not true", False),
|
||||
),
|
||||
)
|
||||
def test_syntax_oddeties(expr: str, expected: bool) -> None:
|
||||
def test_syntax_oddities(expr: str, expected: bool) -> None:
|
||||
matcher = {"true": True, "false": False}.__getitem__
|
||||
assert evaluate(expr, matcher) is expected
|
||||
|
||||
|
||||
@@ -420,7 +420,7 @@ class TestPytestPluginManager:
|
||||
pytestpm.consider_conftest(mod, registration_name="unused")
|
||||
|
||||
|
||||
class TestPytestPluginManagerBootstrapming:
|
||||
class TestPytestPluginManagerBootstrapping:
|
||||
def test_preparse_args(self, pytestpm: PytestPluginManager) -> None:
|
||||
pytest.raises(
|
||||
ImportError, lambda: pytestpm.consider_preparse(["xyz", "-p", "hello123"])
|
||||
@@ -446,7 +446,7 @@ class TestPytestPluginManagerBootstrapming:
|
||||
assert len(l2) == len(l1)
|
||||
assert 42 not in l2
|
||||
|
||||
def test_plugin_prevent_register_unregistered_alredy_registered(
|
||||
def test_plugin_prevent_register_unregistered_already_registered(
|
||||
self, pytestpm: PytestPluginManager
|
||||
) -> None:
|
||||
pytestpm.register(42, name="abc")
|
||||
|
||||
@@ -409,7 +409,7 @@ class BaseFunctionalTests:
|
||||
# assert rep.outcome.when == "setup"
|
||||
# assert rep.outcome.where.lineno == 3
|
||||
# assert rep.outcome.where.path.basename == "test_func.py"
|
||||
# assert instanace(rep.failed.failurerepr, PythonFailureRepr)
|
||||
# assert isinstance(rep.failed.failurerepr, PythonFailureRepr)
|
||||
|
||||
def test_systemexit_does_not_bail_out(self, pytester: Pytester) -> None:
|
||||
try:
|
||||
|
||||
@@ -926,7 +926,7 @@ class TestTerminalFunctional:
|
||||
def test_header_absolute_testpath(
|
||||
self, pytester: Pytester, monkeypatch: MonkeyPatch
|
||||
) -> None:
|
||||
"""Regresstion test for #7814."""
|
||||
"""Regression test for #7814."""
|
||||
tests = pytester.path.joinpath("tests")
|
||||
tests.mkdir()
|
||||
pytester.makepyprojecttoml(
|
||||
|
||||
@@ -299,7 +299,7 @@ def test_setup_setUpClass(pytester: Pytester) -> None:
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
cls.x -= 1
|
||||
def test_teareddown():
|
||||
def test_torn_down():
|
||||
assert MyTestCase.x == 0
|
||||
"""
|
||||
)
|
||||
@@ -346,7 +346,7 @@ def test_setup_class(pytester: Pytester) -> None:
|
||||
assert self.x == 1
|
||||
def teardown_class(cls):
|
||||
cls.x -= 1
|
||||
def test_teareddown():
|
||||
def test_torn_down():
|
||||
assert MyTestCase.x == 0
|
||||
"""
|
||||
)
|
||||
@@ -881,7 +881,7 @@ def test_non_unittest_no_setupclass_support(pytester: Pytester) -> None:
|
||||
def tearDownClass(cls):
|
||||
cls.x = 1
|
||||
|
||||
def test_not_teareddown():
|
||||
def test_not_torn_down():
|
||||
assert TestFoo.x == 0
|
||||
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user