Compare commits

...

20 Commits
7.0.0 ... 6.2.2

Author SHA1 Message Date
pytest bot
b9c98762f5 Prepare release version 6.2.2 2021-01-25 12:30:53 +00:00
Bruno Oliveira
8003fd23b9 Merge pull request #8259 from nicoddemus/backport-8250
[6.2.x] Fix faulthandler for Twisted Logger when used with "--capture=no"
2021-01-20 10:14:34 -03:00
Bruno Oliveira
8d605b9b26 Merge pull request #8250 from daq-tools/fix-twisted-capture 2021-01-20 09:47:10 -03:00
Bruno Oliveira
14e0c3e105 Merge pull request #8225 from The-Compiler/training-update (#8226)
doc: Add note about training early bird discount
2021-01-05 20:49:50 +01:00
Bruno Oliveira
45facc16c8 Merge pull request #8224 from nicoddemus/backport-8220
[6.2.x] DOC: Mark pytest module
2021-01-05 13:31:19 -03:00
Bruno Oliveira
99fe887d7c Merge pull request #8220 from xuhdev/module-doc
DOC: Mark pytest module
2021-01-05 13:26:19 -03:00
Bruno Oliveira
8dbf9dc1aa Merge pull request #8167 from nicoddemus/backport-8166
[6.2.x] Add Changelog to setup.cfg (#8166)
2020-12-17 13:59:14 -03:00
Adam Johnson
baaee2148d Add Changelog to setup.cfg (#8166)
Co-authored-by: Thomas Grainger <tagrain@gmail.com>
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2020-12-17 13:56:18 -03:00
Bruno Oliveira
f7d1ab870f Merge pull request #8163 from bluetech/backport-8152
[6.2.x] terminal: fix "(<Skipped instance>)" skip reason in test status line
2020-12-17 08:31:53 -03:00
Ran Benita
b8201c280e Merge pull request #8152 from bluetech/empty-skip
terminal: fix "(<Skipped instance>)" skip reason in test status line
(cherry picked from commit 02e69e5cdc)
2020-12-17 12:59:01 +02:00
Bruno Oliveira
1f0c50b475 Merge pull request #8160 from nicoddemus/backport-7381
[6.2.x] Clarify fixture execution order and provide visual aids (#7381)
2020-12-16 14:02:02 -03:00
Chris NeJame
da82e1853c Clarify fixture execution order and provide visual aids (#7381)
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
Co-authored-by: Ran Benita <ran@unusedvar.com>
2020-12-16 13:54:52 -03:00
Bruno Oliveira
a566eb9c70 Merge pull request #8149 from pytest-dev/release-6.2.1
Prepare release 6.2.1
2020-12-15 12:39:06 -03:00
pytest bot
d3971c30f4 Prepare release version 6.2.1 2020-12-15 13:06:34 +00:00
Bruno Oliveira
780044b64a Merge pull request #8147 from nicoddemus/backport-8137
[6.2.x] python_api: handle array-like args in approx() #8137
2020-12-15 09:08:58 -03:00
Jakob van Santen
8354995abc python_api: handle array-like args in approx() (#8137) 2020-12-15 08:50:11 -03:00
Bruno Oliveira
8b8b1214f4 Merge pull request #8135 from nicoddemus/backport-8123
[6.2] Merge pull request #8123 from nicoddemus/import-mismatch-unc
2020-12-13 10:50:49 -03:00
Bruno Oliveira
f854cf66f4 Merge pull request #8123 from nicoddemus/import-mismatch-unc
Compare also paths on Windows when considering ImportPathMismatchError
2020-12-13 10:35:59 -03:00
Ran Benita
c475106f12 Merge pull request #8130 from pytest-dev/release-6.2.0
Prepare release 6.2.0
2020-12-12 23:21:28 +02:00
pytest bot
e7073afe6e Prepare release version 6.2.0 2020-12-12 22:45:09 +02:00
75 changed files with 2921 additions and 566 deletions

View File

@@ -21,6 +21,7 @@ Anders Hovmöller
Andras Mitzki
Andras Tim
Andrea Cimatoribus
Andreas Motl
Andreas Zeidler
Andrey Paramonov
Andrzej Klajnert
@@ -56,6 +57,7 @@ Charles Cloud
Charles Machalow
Charnjit SiNGH (CCSJ)
Chris Lamb
Chris NeJame
Christian Boelsen
Christian Fetzer
Christian Neumüller

View File

@@ -1 +0,0 @@
Added an ``__str__`` implementation to the :class:`~pytest.pytester.LineMatcher` class which is returned from ``pytester.run_pytest().stdout`` and similar. It returns the entire output, like the existing ``str()`` method.

View File

@@ -1 +0,0 @@
Verbose mode now shows the reason that a test was skipped in the test's terminal line after the "SKIPPED", "XFAIL" or "XPASS".

View File

@@ -1 +0,0 @@
Fixed quadratic behavior and improved performance of collection of items using autouse fixtures and xunit fixtures.

View File

@@ -1,2 +0,0 @@
pytest now warns about unraisable exceptions and unhandled thread exceptions that occur in tests on Python>=3.8.
See :ref:`unraisable` for more information.

View File

@@ -1,5 +0,0 @@
New :fixture:`pytester` fixture, which is identical to :fixture:`testdir` but its methods return :class:`pathlib.Path` when appropriate instead of ``py.path.local``.
This is part of the movement to use :class:`pathlib.Path` objects internally, in order to remove the dependency to ``py`` in the future.
Internally, the old :class:`Testdir <_pytest.pytester.Testdir>` is now a thin wrapper around :class:`Pytester <_pytest.pytester.Pytester>`, preserving the old interface.

View File

@@ -1 +0,0 @@
Add more information and use cases about skipping doctests.

View File

@@ -1,18 +0,0 @@
Directly constructing/calling the following classes/functions is now deprecated:
- ``_pytest.cacheprovider.Cache``
- ``_pytest.cacheprovider.Cache.for_config()``
- ``_pytest.cacheprovider.Cache.clear_cache()``
- ``_pytest.cacheprovider.Cache.cache_dir_from_config()``
- ``_pytest.capture.CaptureFixture``
- ``_pytest.fixtures.FixtureRequest``
- ``_pytest.fixtures.SubRequest``
- ``_pytest.logging.LogCaptureFixture``
- ``_pytest.pytester.Pytester``
- ``_pytest.pytester.Testdir``
- ``_pytest.recwarn.WarningsRecorder``
- ``_pytest.recwarn.WarningsChecker``
- ``_pytest.tmpdir.TempPathFactory``
- ``_pytest.tmpdir.TempdirFactory``
These have always been considered private, but now issue a deprecation warning, which may become a hard error in pytest 7.0.0.

View File

@@ -1,23 +0,0 @@
It is now possible to construct a :class:`MonkeyPatch` object directly as ``pytest.MonkeyPatch()``,
in cases when the :fixture:`monkeypatch` fixture cannot be used. Previously some users imported it
from the private `_pytest.monkeypatch.MonkeyPatch` namespace.
The types of builtin pytest fixtures are now exported so they may be used in type annotations of test functions.
The newly-exported types are:
- ``pytest.FixtureRequest`` for the :fixture:`request` fixture.
- ``pytest.Cache`` for the :fixture:`cache` fixture.
- ``pytest.CaptureFixture[str]`` for the :fixture:`capfd` and :fixture:`capsys` fixtures.
- ``pytest.CaptureFixture[bytes]`` for the :fixture:`capfdbinary` and :fixture:`capsysbinary` fixtures.
- ``pytest.LogCaptureFixture`` for the :fixture:`caplog` fixture.
- ``pytest.Pytester`` for the :fixture:`pytester` fixture.
- ``pytest.Testdir`` for the :fixture:`testdir` fixture.
- ``pytest.TempdirFactory`` for the :fixture:`tmpdir_factory` fixture.
- ``pytest.TempPathFactory`` for the :fixture:`tmp_path_factory` fixture.
- ``pytest.MonkeyPatch`` for the :fixture:`monkeypatch` fixture.
- ``pytest.WarningsRecorder`` for the :fixture:`recwarn` fixture.
Constructing them is not supported (except for `MonkeyPatch`); they are only meant for use in type annotations.
Doing so will emit a deprecation warning, and may become a hard-error in pytest 7.0.
Subclassing them is also not supported. This is not currently enforced at runtime, but is detected by type-checkers such as mypy.

View File

@@ -1 +0,0 @@
When a comparison between :func:`namedtuple <collections.namedtuple>` instances of the same type fails, pytest now shows the differing field names (possibly nested) instead of their indexes.

View File

@@ -1,4 +0,0 @@
The ``--strict`` command-line option has been deprecated, use ``--strict-markers`` instead.
We have plans to maybe in the future to reintroduce ``--strict`` and make it an encompassing flag for all strictness
related options (``--strict-markers`` and ``--strict-config`` at the moment, more might be introduced in the future).

View File

@@ -1 +0,0 @@
:meth:`Node.warn <_pytest.nodes.Node.warn>` now permits any subclass of :class:`Warning`, not just :class:`PytestWarning <pytest.PytestWarning>`.

View File

@@ -1,19 +0,0 @@
A new hook was added, `pytest_markeval_namespace` which should return a dictionary.
This dictionary will be used to augment the "global" variables available to evaluate skipif/xfail/xpass markers.
Pseudo example
``conftest.py``:
.. code-block:: python
def pytest_markeval_namespace():
return {"color": "red"}
``test_func.py``:
.. code-block:: python
@pytest.mark.skipif("color == 'blue'", reason="Color is not red")
def test_func():
assert False

View File

@@ -1 +0,0 @@
Improved reporting when using ``--collected-only``. It will now show the number of collected tests in the summary stats.

View File

@@ -1,4 +0,0 @@
Use strict equality comparison for non-numeric types in :func:`pytest.approx` instead of
raising :class:`TypeError`.
This was the undocumented behavior before 3.7, but is now officially a supported feature.

View File

@@ -1 +0,0 @@
Fixed an issue where some files in packages are getting lost from ``--lf`` even though they contain tests that failed. Regressed in pytest 5.4.0.

View File

@@ -1 +0,0 @@
Classes which should not be inherited from are now marked ``final class`` in the API reference.

View File

@@ -1 +0,0 @@
The ``attrs`` dependency requirement is now >=19.2.0 instead of >=17.4.0.

View File

@@ -1 +0,0 @@
pytest now supports python3.6+ only.

View File

@@ -1 +0,0 @@
``_pytest.config.argparsing.Parser.addini()`` accepts explicit ``None`` and ``"string"``.

View File

@@ -1 +0,0 @@
In pull request section, ask to commit after editing changelog and authors file.

View File

@@ -1 +0,0 @@
Directories created by by :fixture:`tmp_path` and :fixture:`tmpdir` are now considered stale after 3 days without modification (previous value was 3 hours) to avoid deleting directories still in use in long running test suites.

View File

@@ -1 +0,0 @@
Fixed a crash or hang in :meth:`pytester.spawn <_pytest.pytester.Pytester.spawn>` when the :mod:`readline` module is involved.

View File

@@ -1 +0,0 @@
New ``--sw-skip`` argument which is a shorthand for ``--stepwise-skip``.

View File

@@ -1 +0,0 @@
Fixed handling of recursive symlinks when collecting tests.

View File

@@ -1 +0,0 @@
Fixed symlinked directories not being followed during collection. Regressed in pytest 6.1.0.

View File

@@ -1,3 +0,0 @@
The ``@pytest.yield_fixture`` decorator/function is now deprecated. Use :func:`pytest.fixture` instead.
``yield_fixture`` has been an alias for ``fixture`` for a very long time, so can be search/replaced safely.

View File

@@ -1,8 +0,0 @@
It is now possible to construct a :class:`~pytest.MonkeyPatch` object directly as ``pytest.MonkeyPatch()``,
in cases when the :fixture:`monkeypatch` fixture cannot be used. Previously some users imported it
from the private `_pytest.monkeypatch.MonkeyPatch` namespace.
Additionally, :meth:`MonkeyPatch.context <pytest.MonkeyPatch.context>` is now a classmethod,
and can be used as ``with MonkeyPatch.context() as mp: ...``. This is the recommended way to use
``MonkeyPatch`` directly, since unlike the ``monkeypatch`` fixture, an instance created directly
is not ``undo()``-ed automatically.

View File

@@ -1,2 +0,0 @@
`.pyc` files created by pytest's assertion rewriting now conform to the newer PEP-552 format on Python>=3.7.
(These files are internal and only interpreted by pytest itself.)

View File

@@ -1 +0,0 @@
Fixed only one doctest being collected when using ``pytest --doctest-modules path/to/an/__init__.py``.

View File

@@ -1 +0,0 @@
Added ``'node_modules'`` to default value for :confval:`norecursedirs`.

View File

@@ -1 +0,0 @@
:meth:`doClassCleanups <unittest.TestCase.doClassCleanups>` (introduced in :mod:`unittest` in Python and 3.8) is now called appropriately.

View File

@@ -6,6 +6,9 @@ Release announcements
:maxdepth: 2
release-6.2.2
release-6.2.1
release-6.2.0
release-6.1.2
release-6.1.1
release-6.1.0

View File

@@ -0,0 +1,76 @@
pytest-6.2.0
=======================================
The pytest team is proud to announce the 6.2.0 release!
This release contains new features, improvements, bug fixes, and breaking changes, so users
are encouraged to take a look at the CHANGELOG carefully:
https://docs.pytest.org/en/stable/changelog.html
For complete documentation, please visit:
https://docs.pytest.org/en/stable/
As usual, you can upgrade from PyPI via:
pip install -U pytest
Thanks to all of the contributors to this release:
* Adam Johnson
* Albert Villanova del Moral
* Anthony Sottile
* Anton
* Ariel Pillemer
* Bruno Oliveira
* Charles Aracil
* Christine M
* Christine Mecklenborg
* Cserna Zsolt
* Dominic Mortlock
* Emiel van de Laar
* Florian Bruhin
* Garvit Shubham
* Gustavo Camargo
* Hugo Martins
* Hugo van Kemenade
* Jakob van Santen
* Josias Aurel
* Jürgen Gmach
* Karthikeyan Singaravelan
* Katarzyna
* Kyle Altendorf
* Manuel Mariñez
* Matthew Hughes
* Matthias Gabriel
* Max Voitko
* Maximilian Cosmo Sitter
* Mikhail Fesenko
* Nimesh Vashistha
* Pedro Algarvio
* Petter Strandmark
* Prakhar Gurunani
* Prashant Sharma
* Ran Benita
* Ronny Pfannschmidt
* Sanket Duthade
* Shubham Adep
* Simon K
* Tanvi Mehta
* Thomas Grainger
* Tim Hoffmann
* Vasilis Gerakaris
* William Jamir Silva
* Zac Hatfield-Dodds
* crricks
* dependabot[bot]
* duthades
* frankgerhardt
* kwgchi
* mickeypash
* symonk
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,20 @@
pytest-6.2.1
=======================================
pytest 6.2.1 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
Thanks to all of the contributors to this release:
* Bruno Oliveira
* Jakob van Santen
* Ran Benita
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,21 @@
pytest-6.2.2
=======================================
pytest 6.2.2 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
Thanks to all of the contributors to this release:
* Adam Johnson
* Bruno Oliveira
* Chris NeJame
* Ran Benita
Happy testing,
The pytest Development Team

View File

@@ -158,6 +158,11 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
function invocation, created as a sub directory of the base temporary
directory.
By default, a new base temporary directory is created each test session,
and old bases are removed after 3 sessions, to aid in debugging. If
``--basetemp`` is used then it is cleared each session. See :ref:`base
temporary directory`.
The returned object is a `py.path.local`_ path object.
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
@@ -167,6 +172,11 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
function invocation, created as a sub directory of the base temporary
directory.
By default, a new base temporary directory is created each test session,
and old bases are removed after 3 sessions, to aid in debugging. If
``--basetemp`` is used then it is cleared each session. See :ref:`base
temporary directory`.
The returned object is a :class:`pathlib.Path` object.

View File

@@ -28,6 +28,237 @@ with advance notice in the **Deprecations** section of releases.
.. towncrier release notes start
pytest 6.2.2 (2021-01-25)
=========================
Bug Fixes
---------
- `#8152 <https://github.com/pytest-dev/pytest/issues/8152>`_: Fixed "(<Skipped instance>)" being shown as a skip reason in the verbose test summary line when the reason is empty.
- `#8249 <https://github.com/pytest-dev/pytest/issues/8249>`_: Fix the ``faulthandler`` plugin for occasions when running with ``twisted.logger`` and using ``pytest --capture=no``.
pytest 6.2.1 (2020-12-15)
=========================
Bug Fixes
---------
- `#7678 <https://github.com/pytest-dev/pytest/issues/7678>`_: Fixed bug where ``ImportPathMismatchError`` would be raised for files compiled in
the host and loaded later from an UNC mounted path (Windows).
- `#8132 <https://github.com/pytest-dev/pytest/issues/8132>`_: Fixed regression in ``approx``: in 6.2.0 ``approx`` no longer raises
``TypeError`` when dealing with non-numeric types, falling back to normal comparison.
Before 6.2.0, array types like tf.DeviceArray fell through to the scalar case,
and happened to compare correctly to a scalar if they had only one element.
After 6.2.0, these types began failing, because they inherited neither from
standard Python number hierarchy nor from ``numpy.ndarray``.
``approx`` now converts arguments to ``numpy.ndarray`` if they expose the array
protocol and are not scalars. This treats array-like objects like numpy arrays,
regardless of size.
pytest 6.2.0 (2020-12-12)
=========================
Breaking Changes
----------------
- `#7808 <https://github.com/pytest-dev/pytest/issues/7808>`_: pytest now supports python3.6+ only.
Deprecations
------------
- `#7469 <https://github.com/pytest-dev/pytest/issues/7469>`_: Directly constructing/calling the following classes/functions is now deprecated:
- ``_pytest.cacheprovider.Cache``
- ``_pytest.cacheprovider.Cache.for_config()``
- ``_pytest.cacheprovider.Cache.clear_cache()``
- ``_pytest.cacheprovider.Cache.cache_dir_from_config()``
- ``_pytest.capture.CaptureFixture``
- ``_pytest.fixtures.FixtureRequest``
- ``_pytest.fixtures.SubRequest``
- ``_pytest.logging.LogCaptureFixture``
- ``_pytest.pytester.Pytester``
- ``_pytest.pytester.Testdir``
- ``_pytest.recwarn.WarningsRecorder``
- ``_pytest.recwarn.WarningsChecker``
- ``_pytest.tmpdir.TempPathFactory``
- ``_pytest.tmpdir.TempdirFactory``
These have always been considered private, but now issue a deprecation warning, which may become a hard error in pytest 7.0.0.
- `#7530 <https://github.com/pytest-dev/pytest/issues/7530>`_: The ``--strict`` command-line option has been deprecated, use ``--strict-markers`` instead.
We have plans to maybe in the future to reintroduce ``--strict`` and make it an encompassing flag for all strictness
related options (``--strict-markers`` and ``--strict-config`` at the moment, more might be introduced in the future).
- `#7988 <https://github.com/pytest-dev/pytest/issues/7988>`_: The ``@pytest.yield_fixture`` decorator/function is now deprecated. Use :func:`pytest.fixture` instead.
``yield_fixture`` has been an alias for ``fixture`` for a very long time, so can be search/replaced safely.
Features
--------
- `#5299 <https://github.com/pytest-dev/pytest/issues/5299>`_: pytest now warns about unraisable exceptions and unhandled thread exceptions that occur in tests on Python>=3.8.
See :ref:`unraisable` for more information.
- `#7425 <https://github.com/pytest-dev/pytest/issues/7425>`_: New :fixture:`pytester` fixture, which is identical to :fixture:`testdir` but its methods return :class:`pathlib.Path` when appropriate instead of ``py.path.local``.
This is part of the movement to use :class:`pathlib.Path` objects internally, in order to remove the dependency to ``py`` in the future.
Internally, the old :class:`Testdir <_pytest.pytester.Testdir>` is now a thin wrapper around :class:`Pytester <_pytest.pytester.Pytester>`, preserving the old interface.
- `#7695 <https://github.com/pytest-dev/pytest/issues/7695>`_: A new hook was added, `pytest_markeval_namespace` which should return a dictionary.
This dictionary will be used to augment the "global" variables available to evaluate skipif/xfail/xpass markers.
Pseudo example
``conftest.py``:
.. code-block:: python
def pytest_markeval_namespace():
return {"color": "red"}
``test_func.py``:
.. code-block:: python
@pytest.mark.skipif("color == 'blue'", reason="Color is not red")
def test_func():
assert False
- `#8006 <https://github.com/pytest-dev/pytest/issues/8006>`_: It is now possible to construct a :class:`~pytest.MonkeyPatch` object directly as ``pytest.MonkeyPatch()``,
in cases when the :fixture:`monkeypatch` fixture cannot be used. Previously some users imported it
from the private `_pytest.monkeypatch.MonkeyPatch` namespace.
Additionally, :meth:`MonkeyPatch.context <pytest.MonkeyPatch.context>` is now a classmethod,
and can be used as ``with MonkeyPatch.context() as mp: ...``. This is the recommended way to use
``MonkeyPatch`` directly, since unlike the ``monkeypatch`` fixture, an instance created directly
is not ``undo()``-ed automatically.
Improvements
------------
- `#1265 <https://github.com/pytest-dev/pytest/issues/1265>`_: Added an ``__str__`` implementation to the :class:`~pytest.pytester.LineMatcher` class which is returned from ``pytester.run_pytest().stdout`` and similar. It returns the entire output, like the existing ``str()`` method.
- `#2044 <https://github.com/pytest-dev/pytest/issues/2044>`_: Verbose mode now shows the reason that a test was skipped in the test's terminal line after the "SKIPPED", "XFAIL" or "XPASS".
- `#7469 <https://github.com/pytest-dev/pytest/issues/7469>`_ The types of builtin pytest fixtures are now exported so they may be used in type annotations of test functions.
The newly-exported types are:
- ``pytest.FixtureRequest`` for the :fixture:`request` fixture.
- ``pytest.Cache`` for the :fixture:`cache` fixture.
- ``pytest.CaptureFixture[str]`` for the :fixture:`capfd` and :fixture:`capsys` fixtures.
- ``pytest.CaptureFixture[bytes]`` for the :fixture:`capfdbinary` and :fixture:`capsysbinary` fixtures.
- ``pytest.LogCaptureFixture`` for the :fixture:`caplog` fixture.
- ``pytest.Pytester`` for the :fixture:`pytester` fixture.
- ``pytest.Testdir`` for the :fixture:`testdir` fixture.
- ``pytest.TempdirFactory`` for the :fixture:`tmpdir_factory` fixture.
- ``pytest.TempPathFactory`` for the :fixture:`tmp_path_factory` fixture.
- ``pytest.MonkeyPatch`` for the :fixture:`monkeypatch` fixture.
- ``pytest.WarningsRecorder`` for the :fixture:`recwarn` fixture.
Constructing them is not supported (except for `MonkeyPatch`); they are only meant for use in type annotations.
Doing so will emit a deprecation warning, and may become a hard-error in pytest 7.0.
Subclassing them is also not supported. This is not currently enforced at runtime, but is detected by type-checkers such as mypy.
- `#7527 <https://github.com/pytest-dev/pytest/issues/7527>`_: When a comparison between :func:`namedtuple <collections.namedtuple>` instances of the same type fails, pytest now shows the differing field names (possibly nested) instead of their indexes.
- `#7615 <https://github.com/pytest-dev/pytest/issues/7615>`_: :meth:`Node.warn <_pytest.nodes.Node.warn>` now permits any subclass of :class:`Warning`, not just :class:`PytestWarning <pytest.PytestWarning>`.
- `#7701 <https://github.com/pytest-dev/pytest/issues/7701>`_: Improved reporting when using ``--collected-only``. It will now show the number of collected tests in the summary stats.
- `#7710 <https://github.com/pytest-dev/pytest/issues/7710>`_: Use strict equality comparison for non-numeric types in :func:`pytest.approx` instead of
raising :class:`TypeError`.
This was the undocumented behavior before 3.7, but is now officially a supported feature.
- `#7938 <https://github.com/pytest-dev/pytest/issues/7938>`_: New ``--sw-skip`` argument which is a shorthand for ``--stepwise-skip``.
- `#8023 <https://github.com/pytest-dev/pytest/issues/8023>`_: Added ``'node_modules'`` to default value for :confval:`norecursedirs`.
- `#8032 <https://github.com/pytest-dev/pytest/issues/8032>`_: :meth:`doClassCleanups <unittest.TestCase.doClassCleanups>` (introduced in :mod:`unittest` in Python and 3.8) is now called appropriately.
Bug Fixes
---------
- `#4824 <https://github.com/pytest-dev/pytest/issues/4824>`_: Fixed quadratic behavior and improved performance of collection of items using autouse fixtures and xunit fixtures.
- `#7758 <https://github.com/pytest-dev/pytest/issues/7758>`_: Fixed an issue where some files in packages are getting lost from ``--lf`` even though they contain tests that failed. Regressed in pytest 5.4.0.
- `#7911 <https://github.com/pytest-dev/pytest/issues/7911>`_: Directories created by by :fixture:`tmp_path` and :fixture:`tmpdir` are now considered stale after 3 days without modification (previous value was 3 hours) to avoid deleting directories still in use in long running test suites.
- `#7913 <https://github.com/pytest-dev/pytest/issues/7913>`_: Fixed a crash or hang in :meth:`pytester.spawn <_pytest.pytester.Pytester.spawn>` when the :mod:`readline` module is involved.
- `#7951 <https://github.com/pytest-dev/pytest/issues/7951>`_: Fixed handling of recursive symlinks when collecting tests.
- `#7981 <https://github.com/pytest-dev/pytest/issues/7981>`_: Fixed symlinked directories not being followed during collection. Regressed in pytest 6.1.0.
- `#8016 <https://github.com/pytest-dev/pytest/issues/8016>`_: Fixed only one doctest being collected when using ``pytest --doctest-modules path/to/an/__init__.py``.
Improved Documentation
----------------------
- `#7429 <https://github.com/pytest-dev/pytest/issues/7429>`_: Add more information and use cases about skipping doctests.
- `#7780 <https://github.com/pytest-dev/pytest/issues/7780>`_: Classes which should not be inherited from are now marked ``final class`` in the API reference.
- `#7872 <https://github.com/pytest-dev/pytest/issues/7872>`_: ``_pytest.config.argparsing.Parser.addini()`` accepts explicit ``None`` and ``"string"``.
- `#7878 <https://github.com/pytest-dev/pytest/issues/7878>`_: In pull request section, ask to commit after editing changelog and authors file.
Trivial/Internal Changes
------------------------
- `#7802 <https://github.com/pytest-dev/pytest/issues/7802>`_: The ``attrs`` dependency requirement is now >=19.2.0 instead of >=17.4.0.
- `#8014 <https://github.com/pytest-dev/pytest/issues/8014>`_: `.pyc` files created by pytest's assertion rewriting now conform to the newer PEP-552 format on Python>=3.7.
(These files are internal and only interpreted by pytest itself.)
pytest 6.1.2 (2020-10-28)
=========================

View File

@@ -0,0 +1,132 @@
<svg xmlns="http://www.w3.org/2000/svg" width="572" height="542">
<style>
text {
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
dominant-baseline: middle;
text-anchor: middle;
fill: #062886;
font-size: medium;
}
ellipse.fixture, rect.test {
fill: #eeffcc;
stroke: #007020;
stroke-width: 2;
}
text.fixture {
color: #06287e;
}
circle.class, circle.module, circle.package {
fill: #c3e0ec;
stroke: #0e84b5;
stroke-width: 2;
}
text.class, text.module, text.package {
fill: #0e84b5;
}
line, path {
stroke: black;
stroke-width: 2;
fill: none;
}
</style>
<!-- main scope -->
<circle class="package" r="270" cx="286" cy="271" />
<!-- scope name -->
<defs>
<path d="M 26,271 A 260 260 0 0 1 546 271" id="testp"/>
</defs>
<text class="package">
<textPath href="#testp" startOffset="50%">tests</textPath>
</text>
<!-- subpackage -->
<circle class="package" r="140" cx="186" cy="271" />
<!-- scope name -->
<defs>
<path d="M 56,271 A 130 130 0 0 1 316 271" id="subpackage"/>
</defs>
<text class="package">
<textPath href="#subpackage" startOffset="50%">subpackage</textPath>
</text>
<!-- test_subpackage.py -->
<circle class="module" r="90" cx="186" cy="311" />
<!-- scope name -->
<defs>
<path d="M 106,311 A 80 80 0 0 1 266 311" id="testSubpackage"/>
</defs>
<text class="module">
<textPath href="#testSubpackage" startOffset="50%">test_subpackage.py</textPath>
</text>
<!-- innermost -->
<line x1="186" x2="186" y1="271" y2="351"/>
<!-- mid -->
<path d="M 186 351 L 136 351 L 106 331 L 106 196" />
<!-- order -->
<path d="M 186 351 L 256 351 L 316 291 L 316 136" />
<!-- top -->
<path d="M 186 351 L 186 391 L 231 436 L 331 436" />
<ellipse class="fixture" rx="50" ry="25" cx="186" cy="271" />
<text x="186" y="271">innermost</text>
<rect class="test" width="110" height="50" x="131" y="326" />
<text x="186" y="351">test_order</text>
<ellipse class="fixture" rx="50" ry="25" cx="126" cy="196" />
<text x="126" y="196">mid</text>
<!-- scope order number -->
<mask id="testSubpackageOrderMask">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<circle fill="black" stroke="white" stroke-width="2" r="90" cx="186" cy="311" />
</mask>
<circle class="module" r="15" cx="96" cy="311" mask="url(#testSubpackageOrderMask)"/>
<text class="module" x="96" y="311">1</text>
<!-- scope order number -->
<mask id="subpackageOrderMask">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<circle fill="black" stroke="white" stroke-width="2" r="140" cx="186" cy="271" />
</mask>
<circle class="module" r="15" cx="46" cy="271" mask="url(#subpackageOrderMask)"/>
<text class="module" x="46" y="271">2</text>
<!-- scope order number -->
<mask id="testsOrderMask">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<circle fill="black" stroke="white" stroke-width="2" r="270" cx="286" cy="271" />
</mask>
<circle class="module" r="15" cx="16" cy="271" mask="url(#testsOrderMask)"/>
<text class="module" x="16" y="271">3</text>
<!-- test_top.py -->
<circle class="module" r="85" cx="441" cy="271" />
<!-- scope name -->
<defs>
<path d="M 366,271 A 75 75 0 0 1 516 271" id="testTop"/>
</defs>
<text class="module">
<textPath href="#testTop" startOffset="50%">test_top.py</textPath>
</text>
<!-- innermost -->
<line x1="441" x2="441" y1="306" y2="236"/>
<!-- order -->
<path d="M 441 306 L 376 306 L 346 276 L 346 136" />
<!-- top -->
<path d="M 441 306 L 441 411 L 411 436 L 331 436" />
<ellipse class="fixture" rx="50" ry="25" cx="441" cy="236" />
<text x="441" y="236">innermost</text>
<rect class="test" width="110" height="50" x="386" y="281" />
<text x="441" y="306">test_order</text>
<!-- scope order number -->
<mask id="testTopOrderMask">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<circle fill="black" stroke="white" stroke-width="2" r="85" cx="441" cy="271" />
</mask>
<circle class="module" r="15" cx="526" cy="271" mask="url(#testTopOrderMask)"/>
<text class="module" x="526" y="271">1</text>
<!-- scope order number -->
<circle class="module" r="15" cx="556" cy="271" mask="url(#testsOrderMask)"/>
<text class="module" x="556" y="271">2</text>
<ellipse class="fixture" rx="50" ry="25" cx="331" cy="436" />
<text x="331" y="436">top</text>
<ellipse class="fixture" rx="50" ry="25" cx="331" cy="136" />
<text x="331" y="136">order</text>
</svg>

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@@ -0,0 +1,142 @@
<svg xmlns="http://www.w3.org/2000/svg" width="587" height="382">
<style>
text {
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
dominant-baseline: middle;
text-anchor: middle;
fill: #062886;
font-size: medium;
alignment-baseline: center;
}
ellipse.fixture, rect.test {
fill: #eeffcc;
stroke: #007020;
stroke-width: 2;
}
text.fixture {
color: #06287e;
}
circle.class, circle.module, circle.package, circle.plugin {
fill: #c3e0ec;
stroke: #0e84b5;
stroke-width: 2;
}
text.class, text.module, text.package, text.plugin {
fill: #0e84b5;
}
line, path {
stroke: black;
stroke-width: 2;
fill: none;
}
</style>
<!-- plugin_a.py scope -->
<circle class="plugin" r="85" cx="486" cy="86" />
<!-- plugin name -->
<defs>
<path d="M 411,86 A 75 75 0 0 1 561 86" id="pluginA"/>
</defs>
<text class="plugin">
<textPath href="#pluginA" startOffset="50%">plugin_a</textPath>
</text>
<!-- scope order number -->
<mask id="pluginAOrderMask">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<circle fill="black" stroke="white" stroke-width="2" r="85" cx="486" cy="86" />
</mask>
<circle class="module" r="15" cx="571" cy="86" mask="url(#pluginAOrderMask)"/>
<text class="module" x="571" y="86">4</text>
<!-- plugin_b.py scope -->
<circle class="plugin" r="85" cx="486" cy="296" />
<!-- plugin name -->
<defs>
<path d="M 411,296 A 75 75 0 0 1 561 296" id="pluginB"/>
</defs>
<text class="plugin">
<textPath href="#pluginB" startOffset="50%">plugin_b</textPath>
</text>
<!-- scope order number -->
<mask id="pluginBOrderMask">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<circle fill="black" stroke="white" stroke-width="2" r="85" cx="486" cy="296" />
</mask>
<circle class="module" r="15" cx="571" cy="296" mask="url(#pluginBOrderMask)"/>
<text class="module" x="571" y="296">4</text>
<!-- main scope -->
<circle class="package" r="190" cx="191" cy="191" />
<!-- scope name -->
<defs>
<path d="M 11,191 A 180 180 0 0 1 371 191" id="testp"/>
</defs>
<text class="package">
<textPath href="#testp" startOffset="50%">tests</textPath>
</text>
<!-- scope order number -->
<mask id="mainOrderMask">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<circle fill="black" stroke="white" stroke-width="2" r="190" cx="191" cy="191" />
</mask>
<circle class="module" r="15" cx="381" cy="191" mask="url(#mainOrderMask)"/>
<text class="module" x="381" y="191">3</text>
<!-- subpackage -->
<circle class="package" r="140" cx="191" cy="231" />
<!-- scope name -->
<defs>
<path d="M 61,231 A 130 130 0 0 1 321 231" id="subpackage"/>
</defs>
<text class="package">
<textPath href="#subpackage" startOffset="50%">subpackage</textPath>
</text>
<!-- scope order number -->
<mask id="subpackageOrderMask">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<circle fill="black" stroke="white" stroke-width="2" r="140" cx="191" cy="231" />
</mask>
<circle class="module" r="15" cx="331" cy="231" mask="url(#subpackageOrderMask)"/>
<text class="module" x="331" y="231">2</text>
<!-- test_subpackage.py -->
<circle class="module" r="90" cx="191" cy="271" />
<!-- scope name -->
<defs>
<path d="M 111,271 A 80 80 0 0 1 271 271" id="testSubpackage"/>
</defs>
<text class="module">
<textPath href="#testSubpackage" startOffset="50%">test_subpackage.py</textPath>
</text>
<!-- scope order number -->
<mask id="testSubpackageOrderMask">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<circle fill="black" stroke="white" stroke-width="2" r="90" cx="191" cy="271" />
</mask>
<circle class="module" r="15" cx="281" cy="271" mask="url(#testSubpackageOrderMask)"/>
<text class="module" x="281" y="271">1</text>
<!-- innermost -->
<line x1="191" x2="191" y1="231" y2="311"/>
<!-- mid -->
<path d="M 191 306 L 101 306 L 91 296 L 91 156 L 101 146 L 191 146" />
<!-- order -->
<path d="M 191 316 L 91 316 L 81 306 L 81 61 L 91 51 L 191 51" />
<!-- a_fix -->
<path d="M 191 306 L 291 306 L 301 296 L 301 96 L 311 86 L 486 86" />
<!-- b_fix -->
<path d="M 191 316 L 316 316 L 336 296 L 486 296" />
<ellipse class="fixture" rx="50" ry="25" cx="191" cy="231" />
<text x="191" y="231">inner</text>
<rect class="test" width="110" height="50" x="136" y="286" />
<text x="191" y="311">test_order</text>
<ellipse class="fixture" rx="50" ry="25" cx="191" cy="146" />
<text x="191" y="146">mid</text>
<ellipse class="fixture" rx="50" ry="25" cx="191" cy="51" />
<text x="191" y="51">order</text>
<ellipse class="fixture" rx="50" ry="25" cx="486" cy="86" />
<text x="486" y="86">a_fix</text>
<ellipse class="fixture" rx="50" ry="25" cx="486" cy="296" />
<text x="486" y="296">b_fix</text>
</svg>

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -1,38 +0,0 @@
import pytest
# fixtures documentation order example
order = []
@pytest.fixture(scope="session")
def s1():
order.append("s1")
@pytest.fixture(scope="module")
def m1():
order.append("m1")
@pytest.fixture
def f1(f3):
order.append("f1")
@pytest.fixture
def f3():
order.append("f3")
@pytest.fixture(autouse=True)
def a1():
order.append("a1")
@pytest.fixture
def f2():
order.append("f2")
def test_order(f1, m1, f2, s1):
assert order == ["s1", "m1", "a1", "f3", "f1", "f2"]

View File

@@ -0,0 +1,45 @@
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def a(order):
order.append("a")
@pytest.fixture
def b(a, order):
order.append("b")
@pytest.fixture(autouse=True)
def c(b, order):
order.append("c")
@pytest.fixture
def d(b, order):
order.append("d")
@pytest.fixture
def e(d, order):
order.append("e")
@pytest.fixture
def f(e, order):
order.append("f")
@pytest.fixture
def g(f, c, order):
order.append("g")
def test_order_and_g(g, order):
assert order == ["a", "b", "c", "d", "e", "f", "g"]

View File

@@ -0,0 +1,64 @@
<svg xmlns="http://www.w3.org/2000/svg" width="252" height="682">
<style>
text {
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
dominant-baseline: middle;
text-anchor: middle;
fill: #062886;
font-size: medium;
}
ellipse.fixture, rect.test {
fill: #eeffcc;
stroke: #007020;
stroke-width: 2;
}
text.fixture {
color: #06287e;
}
circle.class {
fill: #c3e0ec;
stroke: #0e84b5;
stroke-width: 2;
}
text.class {
fill: #0e84b5;
}
path, line {
stroke: black;
stroke-width: 2;
fill: none;
}
rect.autouse {
fill: #ca7f3d;
}
</style>
<path d="M126,586 L26,506 L26,236" />
<path d="M226,446 L226,236 L126,166" />
<line x1="126" x2="126" y1="656" y2="516" />
<line x1="126" x2="226" y1="516" y2="446" />
<line x1="226" x2="126" y1="446" y2="376" />
<line x1="126" x2="126" y1="376" y2="166" />
<line x1="26" x2="126" y1="236" y2="166" />
<line x1="126" x2="126" y1="166" y2="26" />
<line x1="126" x2="126" y1="96" y2="26" />
<rect class="autouse" width="251" height="40" x="0" y="286" />
<text x="126" y="306">autouse</text>
<ellipse class="fixture" rx="50" ry="25" cx="126" cy="26" />
<text x="126" y="26">order</text>
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="96" />
<text x="126" y="96">a</text>
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="166" />
<text x="126" y="166">b</text>
<ellipse class="fixture" rx="25" ry="25" cx="26" cy="236" />
<text x="26" y="236">c</text>
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="376" />
<text x="126" y="376">d</text>
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="446" />
<text x="226" y="446">e</text>
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="516" />
<text x="126" y="516">f</text>
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="586" />
<text x="126" y="586">g</text>
<rect class="test" width="110" height="50" x="71" y="631" />
<text x="126" y="656">test_order</text>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,31 @@
import pytest
@pytest.fixture(scope="class")
def order():
return []
@pytest.fixture(scope="class", autouse=True)
def c1(order):
order.append("c1")
@pytest.fixture(scope="class")
def c2(order):
order.append("c2")
@pytest.fixture(scope="class")
def c3(order, c1):
order.append("c3")
class TestClassWithC1Request:
def test_order(self, order, c1, c3):
assert order == ["c1", "c3"]
class TestClassWithoutC1Request:
def test_order(self, order, c2):
assert order == ["c1", "c2"]

View File

@@ -0,0 +1,76 @@
<svg xmlns="http://www.w3.org/2000/svg" width="862" height="402">
<style>
text {
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
dominant-baseline: middle;
text-anchor: middle;
fill: #062886;
font-size: medium;
}
ellipse.fixture, rect.test {
fill: #eeffcc;
stroke: #007020;
stroke-width: 2;
}
text.fixture {
color: #06287e;
}
circle.class {
fill: #c3e0ec;
stroke: #0e84b5;
stroke-width: 2;
}
text.class {
fill: #0e84b5;
}
line {
stroke: black;
stroke-width: 2;
}
rect.autouse {
fill: #ca7f3d;
}
</style>
<!-- TestWithC1Request -->
<circle class="class" r="200" cx="221" cy="201" />
<line x1="221" x2="221" y1="61" y2="316"/>
<ellipse class="fixture" rx="50" ry="25" cx="221" cy="61" />
<text x="221" y="61">order</text>
<ellipse class="fixture" rx="25" ry="25" cx="221" cy="131" />
<text x="221" y="131">c1</text>
<ellipse class="fixture" rx="25" ry="25" cx="221" cy="271" />
<text x="221" y="271">c3</text>
<rect class="test" width="110" height="50" x="166" y="316" />
<text x="221" y="341">test_order</text>
<!-- scope name -->
<defs>
<path d="M31,201 A 190 190 0 0 1 411 201" id="testClassWith"/>
</defs>
<text class="class">
<textPath href="#testClassWith" startOffset="50%">TestWithC1Request</textPath>
</text>
<!-- TestWithoutC1Request -->
<circle class="class" r="200" cx="641" cy="201" />
<line x1="641" x2="641" y1="61" y2="316"/>
<ellipse class="fixture" rx="50" ry="25" cx="641" cy="61" />
<text x="641" y="61">order</text>
<ellipse class="fixture" rx="25" ry="25" cx="641" cy="131" />
<text x="641" y="131">c1</text>
<ellipse class="fixture" rx="25" ry="25" cx="641" cy="271" />
<text x="641" y="271">c2</text>
<rect class="test" width="110" height="50" x="586" y="316" />
<text x="641" y="341">test_order</text>
<!-- scope name -->
<defs>
<path d="M451,201 A 190 190 0 0 1 831 201" id="testClassWithout"/>
</defs>
<text class="class">
<textPath href="#testClassWithout" startOffset="50%">TestWithoutC1Request</textPath>
</text>
<rect class="autouse" width="862" height="40" x="1" y="181" />
<rect width="10" height="100" class="autouse" x="426" y="151" />
<text x="431" y="201">autouse</text>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,36 @@
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def c1(order):
order.append("c1")
@pytest.fixture
def c2(order):
order.append("c2")
class TestClassWithAutouse:
@pytest.fixture(autouse=True)
def c3(self, order, c2):
order.append("c3")
def test_req(self, order, c1):
assert order == ["c2", "c3", "c1"]
def test_no_req(self, order):
assert order == ["c2", "c3"]
class TestClassWithoutAutouse:
def test_req(self, order, c1):
assert order == ["c1"]
def test_no_req(self, order):
assert order == []

View File

@@ -0,0 +1,100 @@
<svg xmlns="http://www.w3.org/2000/svg" width="862" height="502">
<style>
text {
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
dominant-baseline: middle;
text-anchor: middle;
fill: #062886;
font-size: medium;
}
ellipse.fixture, rect.test {
fill: #eeffcc;
stroke: #007020;
stroke-width: 2;
}
text.fixture {
color: #06287e;
}
circle.class {
fill: #c3e0ec;
stroke: #0e84b5;
stroke-width: 2;
}
text.class {
fill: #0e84b5;
}
line {
stroke: black;
stroke-width: 2;
}
rect.autouse {
fill: #ca7f3d;
}
</style>
<!-- TestWithAutouse -->
<circle class="class" r="250" cx="251" cy="251" />
<!-- scope name -->
<defs>
<path d="M11,251 A 240 240 0 0 1 491 251" id="testClassWith"/>
</defs>
<text class="class">
<textPath href="#testClassWith" startOffset="50%">TestWithAutouse</textPath>
</text>
<mask id="autouseScope">
<circle fill="white" r="249" cx="251" cy="251" />
</mask>
<!-- TestWithAutouse.test_req -->
<line x1="176" x2="176" y1="76" y2="426"/>
<ellipse class="fixture" rx="50" ry="25" cx="176" cy="76" />
<text x="176" y="76">order</text>
<ellipse class="fixture" rx="25" ry="25" cx="176" cy="146" />
<text x="176" y="146">c2</text>
<ellipse class="fixture" rx="25" ry="25" cx="176" cy="216" />
<text x="176" y="216">c3</text>
<ellipse class="fixture" rx="25" ry="25" cx="176" cy="356" />
<text x="176" y="356">c1</text>
<rect class="test" width="100" height="50" x="126" y="401" />
<text x="176" y="426">test_req</text>
<!-- TestWithAutouse.test_no_req -->
<line x1="326" x2="326" y1="76" y2="346"/>
<ellipse class="fixture" rx="50" ry="25" cx="326" cy="76" />
<text x="326" y="76">order</text>
<ellipse class="fixture" rx="25" ry="25" cx="326" cy="146" />
<text x="326" y="146">c2</text>
<ellipse class="fixture" rx="25" ry="25" cx="326" cy="216" />
<text x="326" y="216">c3</text>
<rect class="test" width="120" height="50" x="266" y="331" />
<text x="326" y="356">test_no_req</text>
<rect class="autouse" width="500" height="40" x="1" y="266" mask="url(#autouseScope)"/>
<text x="261" y="286">autouse</text>
<!-- TestWithoutAutouse -->
<circle class="class" r="170" cx="691" cy="251" />
<!-- scope name -->
<defs>
<path d="M 531,251 A 160 160 0 0 1 851 251" id="testClassWithout"/>
</defs>
<text class="class">
<textPath href="#testClassWithout" startOffset="50%">TestWithoutAutouse</textPath>
</text>
<!-- TestWithoutAutouse.test_req -->
<line x1="616" x2="616" y1="181" y2="321"/>
<ellipse class="fixture" rx="50" ry="25" cx="616" cy="181" />
<text x="616" y="181">order</text>
<ellipse class="fixture" rx="25" ry="25" cx="616" cy="251" />
<text x="616" y="251">c1</text>
<rect class="test" width="100" height="50" x="566" y="296" />
<text x="616" y="321">test_req</text>
<!-- TestWithoutAutouse.test_no_req -->
<line x1="766" x2="766" y1="181" y2="251"/>
<ellipse class="fixture" rx="50" ry="25" cx="766" cy="181" />
<text x="766" y="181">order</text>
<rect class="test" width="120" height="50" x="706" y="226" />
<text x="766" y="251">test_no_req</text>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,45 @@
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def a(order):
order.append("a")
@pytest.fixture
def b(a, order):
order.append("b")
@pytest.fixture
def c(a, b, order):
order.append("c")
@pytest.fixture
def d(c, b, order):
order.append("d")
@pytest.fixture
def e(d, b, order):
order.append("e")
@pytest.fixture
def f(e, order):
order.append("f")
@pytest.fixture
def g(f, c, order):
order.append("g")
def test_order(g, order):
assert order == ["a", "b", "c", "d", "e", "f", "g"]

View File

@@ -0,0 +1,60 @@
<svg xmlns="http://www.w3.org/2000/svg" width="252" height="612">
<style>
text {
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
dominant-baseline: middle;
text-anchor: middle;
fill: #062886;
font-size: medium;
}
ellipse.fixture, rect.test {
fill: #eeffcc;
stroke: #007020;
stroke-width: 2;
}
text.fixture {
color: #06287e;
}
circle.class {
fill: #c3e0ec;
stroke: #0e84b5;
stroke-width: 2;
}
text.class {
fill: #0e84b5;
}
path, line {
stroke: black;
stroke-width: 2;
fill: none;
}
</style>
<path d="M126,516 L26,436 L26,236" />
<path d="M226,376 L226,236 L126,166" />
<line x1="126" x2="126" y1="586" y2="446" />
<line x1="126" x2="226" y1="446" y2="376" />
<line x1="226" x2="126" y1="376" y2="306" />
<line x1="126" x2="26" y1="306" y2="236" />
<line x1="126" x2="126" y1="306" y2="166" />
<line x1="26" x2="126" y1="236" y2="166" />
<line x1="126" x2="126" y1="166" y2="26" />
<line x1="126" x2="126" y1="96" y2="26" />
<ellipse class="fixture" rx="50" ry="25" cx="126" cy="26" />
<text x="126" y="26">order</text>
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="96" />
<text x="126" y="96">a</text>
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="166" />
<text x="126" y="166">b</text>
<ellipse class="fixture" rx="25" ry="25" cx="26" cy="236" />
<text x="26" y="236">c</text>
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="306" />
<text x="126" y="306">d</text>
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="376" />
<text x="226" y="376">e</text>
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="446" />
<text x="126" y="446">f</text>
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="516" />
<text x="126" y="516">g</text>
<rect class="test" width="110" height="50" x="71" y="561" />
<text x="126" y="586">test_order</text>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,51 @@
<svg xmlns="http://www.w3.org/2000/svg" width="112" height="612">
<style>
text {
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
dominant-baseline: middle;
text-anchor: middle;
fill: #062886;
font-size: medium;
}
ellipse.fixture, rect.test {
fill: #eeffcc;
stroke: #007020;
stroke-width: 2;
}
text.fixture {
color: #06287e;
}
circle.class {
fill: #c3e0ec;
stroke: #0e84b5;
stroke-width: 2;
}
text.class {
fill: #0e84b5;
}
path, line {
stroke: black;
stroke-width: 2;
fill: none;
}
</style>
<line x1="56" x2="56" y1="611" y2="26" />
<ellipse class="fixture" rx="50" ry="25" cx="56" cy="26" />
<text x="56" y="26">order</text>
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="96" />
<text x="56" y="96">a</text>
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="166" />
<text x="56" y="166">b</text>
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="236" />
<text x="56" y="236">c</text>
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="306" />
<text x="56" y="306">d</text>
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="376" />
<text x="56" y="376">e</text>
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="446" />
<text x="56" y="446">f</text>
<ellipse class="fixture" rx="25" ry="25" cx="56" cy="516" />
<text x="56" y="516">g</text>
<rect class="test" width="110" height="50" x="1" y="561" />
<text x="56" y="586">test_order</text>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,60 @@
<svg xmlns="http://www.w3.org/2000/svg" width="252" height="542">
<style>
text {
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
dominant-baseline: middle;
text-anchor: middle;
fill: #062886;
font-size: medium;
}
ellipse.fixture, rect.test {
fill: #eeffcc;
stroke: #007020;
stroke-width: 2;
}
text.fixture {
color: #06287e;
}
circle.class {
fill: #c3e0ec;
stroke: #0e84b5;
stroke-width: 2;
}
text.class {
fill: #0e84b5;
}
path, line {
stroke: black;
stroke-width: 2;
fill: none;
}
</style>
<path d="M126,446 L26,376 L26,236" />
<path d="M226,306 L126,236 L126,166" />
<line x1="126" x2="126" y1="516" y2="446" />
<line x1="226" x2="226" y1="376" y2="306" />
<line x1="226" x2="226" y1="306" y2="236" />
<line x1="226" x2="126" y1="236" y2="166" />
<line x1="126" x2="226" y1="446" y2="376" />
<line x1="26" x2="126" y1="236" y2="166" />
<line x1="126" x2="126" y1="166" y2="96" />
<line x1="126" x2="126" y1="96" y2="26" />
<ellipse class="fixture" rx="50" ry="25" cx="126" cy="26" />
<text x="126" y="26">order</text>
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="96" />
<text x="126" y="96">a</text>
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="166" />
<text x="126" y="166">b</text>
<ellipse class="fixture" rx="25" ry="25" cx="26" cy="236" />
<text x="26" y="236">c</text>
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="236" />
<text x="226" y="236">d</text>
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="306" />
<text x="226" y="306">e</text>
<ellipse class="fixture" rx="25" ry="25" cx="226" cy="376" />
<text x="226" y="376">f</text>
<ellipse class="fixture" rx="25" ry="25" cx="126" cy="446" />
<text x="126" y="446">g</text>
<rect class="test" width="110" height="50" x="71" y="491" />
<text x="126" y="516">test_order</text>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,36 @@
import pytest
@pytest.fixture(scope="session")
def order():
return []
@pytest.fixture
def func(order):
order.append("function")
@pytest.fixture(scope="class")
def cls(order):
order.append("class")
@pytest.fixture(scope="module")
def mod(order):
order.append("module")
@pytest.fixture(scope="package")
def pack(order):
order.append("package")
@pytest.fixture(scope="session")
def sess(order):
order.append("session")
class TestClass:
def test_order(self, func, cls, mod, pack, sess, order):
assert order == ["session", "package", "module", "class", "function"]

View File

@@ -0,0 +1,55 @@
<svg xmlns="http://www.w3.org/2000/svg" width="262" height="537">
<style>
text {
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
dominant-baseline: middle;
text-anchor: middle;
fill: #062886;
font-size: medium;
}
ellipse.fixture, rect.test {
fill: #eeffcc;
stroke: #007020;
stroke-width: 2;
}
text.fixture {
color: #06287e;
}
circle.class {
fill: #c3e0ec;
stroke: #0e84b5;
stroke-width: 2;
}
text.class {
fill: #0e84b5;
}
line {
stroke: black;
stroke-width: 2;
}
</style>
<!-- TestClass -->
<circle class="class" r="130" cx="131" cy="406" />
<line x1="131" x2="131" y1="21" y2="446"/>
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="26" />
<text x="131" y="26">order</text>
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="96" />
<text x="131" y="96">sess</text>
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="166" />
<text x="131" y="166">pack</text>
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="236" />
<text x="131" y="236">mod</text>
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="306" />
<text x="131" y="306">cls</text>
<ellipse class="fixture" rx="50" ry="25" cx="131" cy="376" />
<text x="131" y="376">func</text>
<rect class="test" width="110" height="50" x="76" y="421" />
<text x="131" y="446">test_order</text>
<!-- scope name -->
<defs>
<path d="M131,526 A 120 120 0 0 1 136 286" id="testClass"/>
</defs>
<text class="class">
<textPath href="#testClass" startOffset="50%">TestClass</textPath>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,29 @@
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def outer(order, inner):
order.append("outer")
class TestOne:
@pytest.fixture
def inner(self, order):
order.append("one")
def test_order(self, order, outer):
assert order == ["one", "outer"]
class TestTwo:
@pytest.fixture
def inner(self, order):
order.append("two")
def test_order(self, order, outer):
assert order == ["two", "outer"]

View File

@@ -0,0 +1,115 @@
<svg xmlns="http://www.w3.org/2000/svg" width="562" height="532">
<style>
text {
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
dominant-baseline: middle;
text-anchor: middle;
fill: #062886;
font-size: medium;
}
ellipse.fixture, rect.test {
fill: #eeffcc;
stroke: #007020;
stroke-width: 2;
}
text.fixture {
color: #06287e;
}
circle.class {
fill: #c3e0ec;
stroke: #0e84b5;
stroke-width: 2;
}
circle.module {
fill: #c3e0ec;
stroke: #0e84b5;
stroke-width: 2;
}
text.class, text.module {
fill: #0e84b5;
}
line, path {
stroke: black;
stroke-width: 2;
fill: none;
}
</style>
<!-- main scope -->
<circle class="module" r="265" cx="281" cy="266" />
<!-- scope name -->
<defs>
<path d="M 26,266 A 255 255 0 0 1 536 266" id="testModule"/>
</defs>
<text class="module">
<textPath href="#testModule" startOffset="50%">test_fixtures_request_different_scope.py</textPath>
</text>
<!-- TestOne -->
<circle class="class" r="100" cx="141" cy="266" />
<!-- inner -->
<line x1="141" x2="141" y1="231" y2="301"/>
<!-- order -->
<path d="M 141 296 L 201 296 L 211 286 L 211 146 L 221 136 L 281 136" />
<!-- outer -->
<path d="M 141 306 L 201 306 L 211 316 L 211 386 L 221 396 L 281 396" />
<ellipse class="fixture" rx="50" ry="25" cx="141" cy="231" />
<text x="141" y="231">inner</text>
<rect class="test" width="110" height="50" x="86" y="276" />
<text x="141" y="301">test_order</text>
<!-- scope name -->
<defs>
<path d="M 51,266 A 90 90 0 0 1 231 266" id="testOne"/>
</defs>
<text class="class">
<textPath href="#testOne" startOffset="50%">TestOne</textPath>
</text>
<!-- scope order number -->
<mask id="testOneOrderMask">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<circle fill="black" stroke="white" stroke-width="2" r="100" cx="141" cy="266" />
</mask>
<circle class="module" r="15" cx="41" cy="266" mask="url(#testOneOrderMask)"/>
<text class="module" x="41" y="266">1</text>
<!-- scope order number -->
<mask id="testMainOrderMask">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<circle fill="black" stroke="white" stroke-width="2" r="265" cx="281" cy="266" />
</mask>
<circle class="module" r="15" cx="16" cy="266" mask="url(#testMainOrderMask)"/>
<text class="module" x="16" y="266">2</text>
<!-- TestTwo -->
<circle class="class" r="100" cx="421" cy="266" />
<!-- inner -->
<line x1="421" x2="421" y1="231" y2="301"/>
<!-- order -->
<path d="M 421 296 L 361 296 L 351 286 L 351 146 L 341 136 L 281 136" />
<!-- outer -->
<path d="M 421 306 L 361 306 L 351 316 L 351 386 L 341 396 L 281 396" />
<ellipse class="fixture" rx="50" ry="25" cx="421" cy="231" />
<text x="421" y="231">inner</text>
<rect class="test" width="110" height="50" x="366" y="276" />
<text x="421" y="301">test_order</text>
<!-- scope name -->
<defs>
<path d="M 331,266 A 90 90 0 0 1 511 266" id="testTwo"/>
</defs>
<text class="class">
<textPath href="#testTwo" startOffset="50%">TestTwo</textPath>
</text>
<!-- scope order number -->
<mask id="testTwoOrderMask">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<circle fill="black" stroke="white" stroke-width="2" r="100" cx="421" cy="266" />
</mask>
<circle class="module" r="15" cx="521" cy="266" mask="url(#testTwoOrderMask)"/>
<text class="module" x="521" y="266">1</text>
<!-- scope order number -->
<circle class="module" r="15" cx="546" cy="266" mask="url(#testMainOrderMask)"/>
<text class="module" x="546" y="266">2</text>
<ellipse class="fixture" rx="50" ry="25" cx="281" cy="396" />
<text x="281" y="396">outer</text>
<ellipse class="fixture" rx="50" ry="25" cx="281" cy="136" />
<text x="281" y="136">order</text>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -102,4 +102,4 @@ interesting to just look at the collection tree:
<YamlItem hello>
<YamlItem ok>
========================== 2 tests found in 0.12s ===========================
======================== 2 tests collected in 0.12s ========================

View File

@@ -175,7 +175,7 @@ objects, they are still using the default pytest representation:
<Function test_timedistance_v3[forward]>
<Function test_timedistance_v3[backward]>
========================== 8 tests found in 0.12s ===========================
======================== 8 tests collected in 0.12s ========================
In ``test_timedistance_v3``, we used ``pytest.param`` to specify the test IDs
together with the actual data, instead of listing them separately.
@@ -252,7 +252,7 @@ If you just collect tests you'll also nicely see 'advanced' and 'basic' as varia
<Function test_demo1[advanced]>
<Function test_demo2[advanced]>
========================== 4 tests found in 0.12s ===========================
======================== 4 tests collected in 0.12s ========================
Note that we told ``metafunc.parametrize()`` that your scenario values
should be considered class-scoped. With pytest-2.3 this leads to a
@@ -328,7 +328,7 @@ Let's first see how it looks like at collection time:
<Function test_db_initialized[d1]>
<Function test_db_initialized[d2]>
========================== 2/2 tests found in 0.12s ===========================
======================== 2 tests collected in 0.12s ========================
And then when we run the test:
@@ -637,13 +637,13 @@ Then run ``pytest`` with verbose mode and with only the ``basic`` marker:
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collecting ... collected 14 items / 11 deselected / 3 selected
collecting ... collected 24 items / 21 deselected / 3 selected
test_pytest_param_example.py::test_eval[1+7-8] PASSED [ 33%]
test_pytest_param_example.py::test_eval[basic_2+4] PASSED [ 66%]
test_pytest_param_example.py::test_eval[basic_6*9] XFAIL [100%]
=============== 2 passed, 11 deselected, 1 xfailed in 0.12s ================
=============== 2 passed, 21 deselected, 1 xfailed in 0.12s ================
As the result:

View File

@@ -157,7 +157,7 @@ The test collection would look like this:
<Function simple_check>
<Function complex_check>
========================== 2 tests found in 0.12s ===========================
======================== 2 tests collected in 0.12s ========================
You can check for multiple glob patterns by adding a space between the patterns:
@@ -220,7 +220,7 @@ You can always peek at the collection tree without running tests like this:
<Function test_method>
<Function test_anothermethod>
========================== 3 tests found in 0.12s ===========================
======================== 3 tests collected in 0.12s ========================
.. _customizing-test-collection:
@@ -296,7 +296,7 @@ file will be left out:
rootdir: $REGENDOC_TMPDIR, configfile: pytest.ini
collected 0 items
========================== no tests found in 0.12s ===========================
======================= no tests collected in 0.12s ========================
It's also possible to ignore files based on Unix shell-style wildcards by adding
patterns to :globalvar:`collect_ignore_glob`.

View File

@@ -446,7 +446,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
def test_reinterpret_fails_with_print_for_the_fun_of_it(self):
items = [1, 2, 3]
print("items is {!r}".format(items))
print(f"items is {items!r}")
> a, b = items.pop()
E TypeError: cannot unpack non-iterable int object

File diff suppressed because it is too large Load Diff

View File

@@ -28,7 +28,7 @@ Install ``pytest``
.. code-block:: bash
$ pytest --version
pytest 6.1.2
pytest 6.2.2
.. _`simpletest`:

View File

@@ -2,7 +2,7 @@
.. sidebar:: Next Open Trainings
- `Professional testing with Python <https://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_, via Python Academy, February 1-3 2021, Leipzig (Germany) and remote.
- `Professional testing with Python <https://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_, via Python Academy, February 1-3 2021, remote and Leipzig (Germany). **Early-bird discount available until January 15th**.
Also see `previous talks and blogposts <talks.html>`_.

View File

@@ -3,6 +3,8 @@
API Reference
=============
.. module:: pytest
This page contains the full reference to pytest's API.
.. contents::
@@ -1749,7 +1751,8 @@ All the command-line flags can be obtained by running ``pytest --help``::
failures.
--sw, --stepwise exit on test failure and continue from last failing
test next time
--stepwise-skip ignore the first failing test but stop on the next
--sw-skip, --stepwise-skip
ignore the first failing test but stop on the next
failing test
reporting:
@@ -1791,9 +1794,9 @@ All the command-line flags can be obtained by running ``pytest --help``::
--maxfail=num exit after first num failures or errors.
--strict-config any warnings encountered while parsing the `pytest`
section of the configuration file raise errors.
--strict-markers, --strict
markers not registered in the `markers` section of
--strict-markers markers not registered in the `markers` section of
the configuration file raise errors.
--strict (deprecated) alias to --strict-markers.
-c file load configuration from `file` instead of trying to
locate one of the implicit configuration files.
--continue-on-collection-errors

View File

@@ -61,7 +61,7 @@ Running this would result in a passed test except for the last
> assert 0
E assert 0
test_tmp_path.py:13: AssertionError
test_tmp_path.py:11: AssertionError
========================= short test summary info ==========================
FAILED test_tmp_path.py::test_create_file - assert 0
============================ 1 failed in 0.12s =============================
@@ -129,7 +129,7 @@ Running this would result in a passed test except for the last
> assert 0
E assert 0
test_tmpdir.py:9: AssertionError
test_tmpdir.py:6: AssertionError
========================= short test summary info ==========================
FAILED test_tmpdir.py::test_create_file - assert 0
============================ 1 failed in 0.12s =============================

View File

@@ -449,13 +449,7 @@ Additionally it is possible to copy examples for an example folder before runnin
test_example.py .. [100%]
============================= warnings summary =============================
test_example.py::test_plugin
$REGENDOC_TMPDIR/test_example.py:4: PytestExperimentalApiWarning: testdir.copy_example is an experimental api that may change over time
testdir.copy_example("test_example.py")
-- Docs: https://docs.pytest.org/en/stable/warnings.html
======================= 2 passed, 1 warning in 0.12s =======================
============================ 2 passed in 0.12s =============================
For more information about the result object that ``runpytest()`` returns, and
the methods that it provides please check out the :py:class:`RunResult

View File

@@ -26,6 +26,8 @@ classifiers =
Topic :: Utilities
keywords = test, unittest
project_urls =
Changelog=https://docs.pytest.org/en/stable/changelog.html
Twitter=https://twitter.com/pytestdotorg
Source=https://github.com/pytest-dev/pytest
Tracker=https://github.com/pytest-dev/pytest/issues

View File

@@ -69,7 +69,12 @@ class FaultHandlerHooks:
@staticmethod
def _get_stderr_fileno():
try:
return sys.stderr.fileno()
fileno = sys.stderr.fileno()
# The Twisted Logger will return an invalid file descriptor since it is not backed
# by an FD. So, let's also forward this to the same code path as with pytest-xdist.
if fileno == -1:
raise AttributeError()
return fileno
except (AttributeError, io.UnsupportedOperation):
# pytest-xdist monkeypatches sys.stderr with an object that is not an actual file.
# https://docs.python.org/3/library/faulthandler.html#issue-with-file-descriptors

View File

@@ -38,7 +38,7 @@ class OutcomeException(BaseException):
self.pytrace = pytrace
def __repr__(self) -> str:
if self.msg:
if self.msg is not None:
return self.msg
return f"<{self.__class__.__name__} instance>"

View File

@@ -543,7 +543,7 @@ def import_path(
module_file = module_file[: -(len(os.path.sep + "__init__.py"))]
try:
is_same = os.path.samefile(str(path), module_file)
is_same = _is_same(str(path), module_file)
except FileNotFoundError:
is_same = False
@@ -553,6 +553,20 @@ def import_path(
return mod
# Implement a special _is_same function on Windows which returns True if the two filenames
# compare equal, to circumvent os.path.samefile returning False for mounts in UNC (#7678).
if sys.platform.startswith("win"):
def _is_same(f1: str, f2: str) -> bool:
return Path(f1) == Path(f2) or os.path.samefile(f1, f2)
else:
def _is_same(f1: str, f2: str) -> bool:
return os.path.samefile(f1, f2)
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.

View File

@@ -15,9 +15,14 @@ from typing import overload
from typing import Pattern
from typing import Tuple
from typing import Type
from typing import TYPE_CHECKING
from typing import TypeVar
from typing import Union
if TYPE_CHECKING:
from numpy import ndarray
import _pytest._code
from _pytest.compat import final
from _pytest.compat import STRING_TYPES
@@ -232,10 +237,11 @@ class ApproxScalar(ApproxBase):
def __eq__(self, actual) -> bool:
"""Return whether the given value is equal to the expected value
within the pre-specified tolerance."""
if _is_numpy_array(actual):
asarray = _as_numpy_array(actual)
if asarray is not None:
# Call ``__eq__()`` manually to prevent infinite-recursion with
# numpy<1.13. See #3748.
return all(self.__eq__(a) for a in actual.flat)
return all(self.__eq__(a) for a in asarray.flat)
# Short-circuit exact equality.
if actual == self.expected:
@@ -521,6 +527,7 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
elif isinstance(expected, Mapping):
cls = ApproxMapping
elif _is_numpy_array(expected):
expected = _as_numpy_array(expected)
cls = ApproxNumpy
elif (
isinstance(expected, Iterable)
@@ -536,16 +543,30 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
def _is_numpy_array(obj: object) -> bool:
"""Return true if the given object is a numpy array.
"""
Return true if the given object is implicitly convertible to ndarray,
and numpy is already imported.
"""
return _as_numpy_array(obj) is not None
A special effort is made to avoid importing numpy unless it's really necessary.
def _as_numpy_array(obj: object) -> Optional["ndarray"]:
"""
Return an ndarray if the given object is implicitly convertible to ndarray,
and numpy is already imported, otherwise None.
"""
import sys
np: Any = sys.modules.get("numpy")
if np is not None:
return isinstance(obj, np.ndarray)
return False
# avoid infinite recursion on numpy scalars, which have __array__
if np.isscalar(obj):
return None
elif isinstance(obj, np.ndarray):
return obj
elif hasattr(obj, "__array__") or hasattr("obj", "__array_interface__"):
return np.asarray(obj)
return None
# builtin pytest.raises helper

View File

@@ -1400,4 +1400,6 @@ def _get_raw_skip_reason(report: TestReport) -> str:
_, _, reason = report.longrepr
if reason.startswith("Skipped: "):
reason = reason[len("Skipped: ") :]
elif reason == "Skipped":
reason = ""
return reason

View File

@@ -447,6 +447,36 @@ class TestApprox:
assert a12 != approx(a21)
assert a21 != approx(a12)
def test_numpy_array_protocol(self):
"""
array-like objects such as tensorflow's DeviceArray are handled like ndarray.
See issue #8132
"""
np = pytest.importorskip("numpy")
class DeviceArray:
def __init__(self, value, size):
self.value = value
self.size = size
def __array__(self):
return self.value * np.ones(self.size)
class DeviceScalar:
def __init__(self, value):
self.value = value
def __array__(self):
return np.array(self.value)
expected = 1
actual = 1 + 1e-6
assert approx(expected) == DeviceArray(actual, size=1)
assert approx(expected) == DeviceArray(actual, size=2)
assert approx(expected) == DeviceScalar(actual)
assert approx(DeviceScalar(expected)) == actual
assert approx(DeviceScalar(expected)) == DeviceScalar(actual)
def test_doctests(self, mocked_doctest_runner) -> None:
import doctest

View File

@@ -1,3 +1,4 @@
import io
import sys
import pytest
@@ -135,3 +136,27 @@ def test_already_initialized(faulthandler_timeout: int, pytester: Pytester) -> N
result.stdout.no_fnmatch_line(warning_line)
result.stdout.fnmatch_lines("*1 passed*")
assert result.ret == 0
def test_get_stderr_fileno_invalid_fd() -> None:
"""Test for faulthandler being able to handle invalid file descriptors for stderr (#8249)."""
from _pytest.faulthandler import FaultHandlerHooks
class StdErrWrapper(io.StringIO):
"""
Mimic ``twisted.logger.LoggingFile`` to simulate returning an invalid file descriptor.
https://github.com/twisted/twisted/blob/twisted-20.3.0/src/twisted/logger/_io.py#L132-L139
"""
def fileno(self):
return -1
wrapper = StdErrWrapper()
with pytest.MonkeyPatch.context() as mp:
mp.setattr("sys.stderr", wrapper)
# Even when the stderr wrapper signals an invalid file descriptor,
# ``_get_stderr_fileno()`` should return the real one.
assert FaultHandlerHooks._get_stderr_fileno() == 2

View File

@@ -7,6 +7,7 @@ from textwrap import dedent
import py
import pytest
from _pytest.monkeypatch import MonkeyPatch
from _pytest.pathlib import bestrelpath
from _pytest.pathlib import commonpath
from _pytest.pathlib import ensure_deletable
@@ -414,3 +415,23 @@ def test_visit_ignores_errors(tmpdir) -> None:
"bar",
"foo",
]
@pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only")
def test_samefile_false_negatives(tmp_path: Path, monkeypatch: MonkeyPatch) -> None:
"""
import_file() should not raise ImportPathMismatchError if the paths are exactly
equal on Windows. It seems directories mounted as UNC paths make os.path.samefile
return False, even when they are clearly equal.
"""
module_path = tmp_path.joinpath("my_module.py")
module_path.write_text("def foo(): return 42")
monkeypatch.syspath_prepend(tmp_path)
with monkeypatch.context() as mp:
# Forcibly make os.path.samefile() return False here to ensure we are comparing
# the paths too. Using a context to narrow the patch as much as possible given
# this is an important system function.
mp.setattr(os.path, "samefile", lambda x, y: False)
module = import_path(module_path)
assert getattr(module, "foo")() == 42

View File

@@ -366,6 +366,26 @@ class TestTerminal:
@pytest.mark.xfail(reason="")
def test_4():
assert False
@pytest.mark.skip
def test_5():
pass
@pytest.mark.xfail
def test_6():
pass
def test_7():
pytest.skip()
def test_8():
pytest.skip("888 is great")
def test_9():
pytest.xfail()
def test_10():
pytest.xfail("It's 🕙 o'clock")
"""
)
result = pytester.runpytest("-v")
@@ -375,6 +395,12 @@ class TestTerminal:
"test_verbose_skip_reason.py::test_2 XPASS (456) *",
"test_verbose_skip_reason.py::test_3 XFAIL (789) *",
"test_verbose_skip_reason.py::test_4 XFAIL *",
"test_verbose_skip_reason.py::test_5 SKIPPED (unconditional skip) *",
"test_verbose_skip_reason.py::test_6 XPASS *",
"test_verbose_skip_reason.py::test_7 SKIPPED *",
"test_verbose_skip_reason.py::test_8 SKIPPED (888 is great) *",
"test_verbose_skip_reason.py::test_9 XFAIL *",
"test_verbose_skip_reason.py::test_10 XFAIL (It's 🕙 o'clock) *",
]
)