Compare commits
28 Commits
Author | SHA1 | Date |
---|---|---|
|
1142d138e3 | |
|
296f468a7c | |
|
84247c4bab | |
|
1adbb04f02 | |
|
0dca7ee21a | |
|
8cf0bbdf75 | |
|
573860d71c | |
|
1ed903e8fc | |
|
4e8b50ba01 | |
|
cd221df8e2 | |
|
8c1c1ae310 | |
|
a88fe584ad | |
|
cd57271455 | |
|
46195edc3e | |
|
9237b5f633 | |
|
95fd566133 | |
|
c93962c491 | |
|
dc96e485a0 | |
|
7ccfc39f15 | |
|
69d903260d | |
|
0ad20b533f | |
|
9df5267648 | |
|
1521849c87 | |
|
bcb94c4c8b | |
|
0f83df4f55 | |
|
330caac2ca | |
|
08a1ab3a8a | |
|
868bc003ec |
|
@ -16,6 +16,7 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
timeout-minutes: 30
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
@ -187,6 +188,7 @@ jobs:
|
||||||
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') && github.repository == 'pytest-dev/pytest'
|
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') && github.repository == 'pytest-dev/pytest'
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 30
|
||||||
|
|
||||||
needs: [build]
|
needs: [build]
|
||||||
|
|
||||||
|
|
1
AUTHORS
1
AUTHORS
|
@ -310,3 +310,4 @@ Xuecong Liao
|
||||||
Yoav Caspi
|
Yoav Caspi
|
||||||
Zac Hatfield-Dodds
|
Zac Hatfield-Dodds
|
||||||
Zoltán Máté
|
Zoltán Máté
|
||||||
|
Zsolt Cserna
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Removed faq.rst and its reference in contents.rst.
|
|
|
@ -1,20 +0,0 @@
|
||||||
Fixed error when overwriting a parametrized fixture, while also reusing the super fixture value.
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# conftest.py
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(params=[1, 2])
|
|
||||||
def foo(request):
|
|
||||||
return request.param
|
|
||||||
|
|
||||||
|
|
||||||
# test_foo.py
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def foo(foo):
|
|
||||||
return foo * 2
|
|
|
@ -1,3 +0,0 @@
|
||||||
Fixed an internal error crash with ``IndexError: list index out of range`` when
|
|
||||||
collecting a module which starts with a decorated function, the decorator
|
|
||||||
raises, and assertion rewriting is enabled.
|
|
|
@ -1,18 +0,0 @@
|
||||||
As per our policy, the following features which have been deprecated in the 5.X series are now
|
|
||||||
removed:
|
|
||||||
|
|
||||||
* The ``funcargnames`` read-only property of ``FixtureRequest``, ``Metafunc``, and ``Function`` classes. Use ``fixturenames`` attribute.
|
|
||||||
|
|
||||||
* ``@pytest.fixture`` no longer supports positional arguments, pass all arguments by keyword instead.
|
|
||||||
|
|
||||||
* Direct construction of ``Node`` subclasses now raise an error, use ``from_parent`` instead.
|
|
||||||
|
|
||||||
* The default value for ``junit_family`` has changed to ``xunit2``. If you require the old format, add ``junit_family=xunit1`` to your configuration file.
|
|
||||||
|
|
||||||
* The ``TerminalReporter`` no longer has a ``writer`` attribute. Plugin authors may use the public functions of the ``TerminalReporter`` instead of accessing the ``TerminalWriter`` object directly.
|
|
||||||
|
|
||||||
* The ``--result-log`` option has been removed. Users are recommended to use the `pytest-reportlog <https://github.com/pytest-dev/pytest-reportlog>`__ plugin instead.
|
|
||||||
|
|
||||||
|
|
||||||
For more information consult
|
|
||||||
`Deprecations and Removals <https://docs.pytest.org/en/stable/deprecations.html>`__ in the docs.
|
|
|
@ -1,3 +0,0 @@
|
||||||
Internal pytest warnings issued during the early stages of initialization are now properly handled and can filtered through :confval:`filterwarnings` or ``--pythonwarnings/-W``.
|
|
||||||
|
|
||||||
This also fixes a number of long standing issues: `#2891 <https://github.com/pytest-dev/pytest/issues/2891>`__, `#7620 <https://github.com/pytest-dev/pytest/issues/7620>`__, `#7426 <https://github.com/pytest-dev/pytest/issues/7426>`__.
|
|
|
@ -1 +0,0 @@
|
||||||
The ``pytest.collect`` module is deprecated: all its names can be imported from ``pytest`` directly.
|
|
|
@ -1,6 +0,0 @@
|
||||||
The ``pytest._fillfuncargs`` function is deprecated. This function was kept
|
|
||||||
for backward compatibility with an older plugin.
|
|
||||||
|
|
||||||
It's functionality is not meant to be used directly, but if you must replace
|
|
||||||
it, use `function._request._fillfixtures()` instead, though note this is not
|
|
||||||
a public API and may break in the future.
|
|
|
@ -1,5 +0,0 @@
|
||||||
The special ``-k '-expr'`` syntax to ``-k`` is deprecated. Use ``-k 'not expr'``
|
|
||||||
instead.
|
|
||||||
|
|
||||||
The special ``-k 'expr:'`` syntax to ``-k`` is deprecated. Please open an issue
|
|
||||||
if you use this and want a replacement.
|
|
|
@ -1,2 +0,0 @@
|
||||||
The :func:`pytest_warning_captured <_pytest.hookspec.pytest_warning_captured>` hook is deprecated in favor
|
|
||||||
of :func:`pytest_warning_recorded <_pytest.hookspec.pytest_warning_recorded>`, and will be removed in a future version.
|
|
|
@ -1,3 +0,0 @@
|
||||||
The internal ``junitxml`` plugin has rewritten to use ``xml.etree.ElementTree``.
|
|
||||||
The order of attributes in XML elements might differ. Some unneeded escaping is
|
|
||||||
no longer performed.
|
|
|
@ -1 +0,0 @@
|
||||||
When a plugin listed in ``required_plugins`` is missing or an unknown config key is used with ``--strict-config``, a simple error message is now shown instead of a stacktrace.
|
|
|
@ -1 +0,0 @@
|
||||||
The dependency on the ``more-itertools`` package has been removed.
|
|
|
@ -1 +0,0 @@
|
||||||
pylint shouldn't complain anymore about unimplemented abstract methods when inheriting from :ref:`File <non-python tests>`.
|
|
|
@ -1 +0,0 @@
|
||||||
Fixed test collection when a full path without a drive letter was passed to pytest on Windows (for example ``\projects\tests\test.py`` instead of ``c:\projects\tests\pytest.py``).
|
|
|
@ -1,2 +0,0 @@
|
||||||
The result type of :meth:`capfd.readouterr() <_pytest.capture.CaptureFixture.readouterr>` (and similar) is no longer a namedtuple,
|
|
||||||
but should behave like one in all respects. This was done for technical reasons.
|
|
|
@ -1 +0,0 @@
|
||||||
Fix handling of command-line options that appear as paths but trigger an OS-level syntax error on Windows, such as the options used internally by ``pytest-xdist``.
|
|
|
@ -1,3 +0,0 @@
|
||||||
The ``gethookproxy()`` and ``isinitpath()`` methods of ``FSCollector`` and ``Package`` are deprecated;
|
|
||||||
use ``self.session.gethookproxy()`` and ``self.session.isinitpath()`` instead.
|
|
||||||
This should work on all pytest versions.
|
|
|
@ -1 +0,0 @@
|
||||||
New ``--durations-min`` command-line flag controls the minimal duration for inclusion in the slowest list of tests shown by ``--durations``. Previously this was hard-coded to ``0.005s``.
|
|
|
@ -1,6 +0,0 @@
|
||||||
When collecting tests, pytest finds test classes and functions by examining the
|
|
||||||
attributes of python objects (modules, classes and instances). To speed up this
|
|
||||||
process, pytest now ignores builtin attributes (like ``__class__``,
|
|
||||||
``__delattr__`` and ``__new__``) without consulting the :confval:`python_classes` and
|
|
||||||
:confval:`python_functions` configuration options and without passing them to plugins
|
|
||||||
using the :func:`pytest_pycollect_makeitem <_pytest.hookspec.pytest_pycollect_makeitem>` hook.
|
|
|
@ -1,3 +0,0 @@
|
||||||
Added two new attributes :attr:`rootpath <_pytest.config.Config.rootpath>` and :attr:`inipath <_pytest.config.Config.inipath>` to :class:`Config <_pytest.config.Config>`.
|
|
||||||
These attributes are :class:`pathlib.Path` versions of the existing :attr:`rootdir <_pytest.config.Config.rootdir>` and :attr:`inifile <_pytest.config.Config.inifile>` attributes,
|
|
||||||
and should be preferred over them when possible.
|
|
|
@ -1 +0,0 @@
|
||||||
Fixed INTERNALERROR when accessing locals / globals with faulty ``exec``.
|
|
|
@ -1,3 +0,0 @@
|
||||||
Public classes which are not designed to be inherited from are now marked `@final <https://docs.python.org/3/library/typing.html#typing.final>`_.
|
|
||||||
Code which inherits from these classes will trigger a type-checking (e.g. mypy) error, but will still work in runtime.
|
|
||||||
Currently the ``final`` designation does not appear in the API Reference but hopefully will in the future.
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fixed handling of recursive symlinks when collecting tests.
|
|
@ -0,0 +1 @@
|
||||||
|
Fixed symlinked directories not being followed during collection. Regressed in pytest 6.1.0.
|
|
@ -6,6 +6,9 @@ Release announcements
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
|
|
||||||
|
release-6.1.2
|
||||||
|
release-6.1.1
|
||||||
|
release-6.1.0
|
||||||
release-6.0.2
|
release-6.0.2
|
||||||
release-6.0.1
|
release-6.0.1
|
||||||
release-6.0.0
|
release-6.0.0
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
pytest-6.1.0
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
The pytest team is proud to announce the 6.1.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:
|
||||||
|
|
||||||
|
* Anthony Sottile
|
||||||
|
* Bruno Oliveira
|
||||||
|
* C. Titus Brown
|
||||||
|
* Drew Devereux
|
||||||
|
* Faris A Chugthai
|
||||||
|
* Florian Bruhin
|
||||||
|
* Hugo van Kemenade
|
||||||
|
* Hynek Schlawack
|
||||||
|
* Joseph Lucas
|
||||||
|
* Kamran Ahmad
|
||||||
|
* Mattreex
|
||||||
|
* Maximilian Cosmo Sitter
|
||||||
|
* Ran Benita
|
||||||
|
* Rüdiger Busche
|
||||||
|
* Sam Estep
|
||||||
|
* Sorin Sbarnea
|
||||||
|
* Thomas Grainger
|
||||||
|
* Vipul Kumar
|
||||||
|
* Yutaro Ikeda
|
||||||
|
* hp310780
|
||||||
|
|
||||||
|
|
||||||
|
Happy testing,
|
||||||
|
The pytest Development Team
|
|
@ -0,0 +1,18 @@
|
||||||
|
pytest-6.1.1
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
pytest 6.1.1 has just been released to PyPI.
|
||||||
|
|
||||||
|
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||||
|
|
||||||
|
pip install --upgrade pytest
|
||||||
|
|
||||||
|
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
|
||||||
|
|
||||||
|
Thanks to all of the contributors to this release:
|
||||||
|
|
||||||
|
* Ran Benita
|
||||||
|
|
||||||
|
|
||||||
|
Happy testing,
|
||||||
|
The pytest Development Team
|
|
@ -0,0 +1,22 @@
|
||||||
|
pytest-6.1.2
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
pytest 6.1.2 has just been released to PyPI.
|
||||||
|
|
||||||
|
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||||
|
|
||||||
|
pip install --upgrade pytest
|
||||||
|
|
||||||
|
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
|
||||||
|
|
||||||
|
Thanks to all of the contributors to this release:
|
||||||
|
|
||||||
|
* Bruno Oliveira
|
||||||
|
* Manuel Mariñez
|
||||||
|
* Ran Benita
|
||||||
|
* Vasilis Gerakaris
|
||||||
|
* William Jamir Silva
|
||||||
|
|
||||||
|
|
||||||
|
Happy testing,
|
||||||
|
The pytest Development Team
|
|
@ -23,7 +23,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||||
cache.get(key, default)
|
cache.get(key, default)
|
||||||
cache.set(key, value)
|
cache.set(key, value)
|
||||||
|
|
||||||
Keys must be a ``/`` separated value, where the first part is usually the
|
Keys must be ``/`` separated strings, where the first part is usually the
|
||||||
name of your plugin or application to avoid clashes with other cache users.
|
name of your plugin or application to avoid clashes with other cache users.
|
||||||
|
|
||||||
Values can be any object handled by the json stdlib module.
|
Values can be any object handled by the json stdlib module.
|
||||||
|
@ -57,7 +57,8 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||||
``out`` and ``err`` will be ``byte`` objects.
|
``out`` and ``err`` will be ``byte`` objects.
|
||||||
|
|
||||||
doctest_namespace [session scope]
|
doctest_namespace [session scope]
|
||||||
Fixture that returns a :py:class:`dict` that will be injected into the namespace of doctests.
|
Fixture that returns a :py:class:`dict` that will be injected into the
|
||||||
|
namespace of doctests.
|
||||||
|
|
||||||
pytestconfig [session scope]
|
pytestconfig [session scope]
|
||||||
Session-scoped fixture that returns the :class:`_pytest.config.Config` object.
|
Session-scoped fixture that returns the :class:`_pytest.config.Config` object.
|
||||||
|
@ -89,8 +90,10 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||||
automatically XML-encoded.
|
automatically XML-encoded.
|
||||||
|
|
||||||
record_testsuite_property [session scope]
|
record_testsuite_property [session scope]
|
||||||
Records a new ``<property>`` tag as child of the root ``<testsuite>``. This is suitable to
|
Record a new ``<property>`` tag as child of the root ``<testsuite>``.
|
||||||
writing global information regarding the entire test suite, and is compatible with ``xunit2`` JUnit family.
|
|
||||||
|
This is suitable to writing global information regarding the entire test
|
||||||
|
suite, and is compatible with ``xunit2`` JUnit family.
|
||||||
|
|
||||||
This is a ``session``-scoped fixture which is called with ``(name, value)``. Example:
|
This is a ``session``-scoped fixture which is called with ``(name, value)``. Example:
|
||||||
|
|
||||||
|
@ -102,6 +105,12 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||||
|
|
||||||
``name`` must be a string, ``value`` will be converted to a string and properly xml-escaped.
|
``name`` must be a string, ``value`` will be converted to a string and properly xml-escaped.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Currently this fixture **does not work** with the
|
||||||
|
`pytest-xdist <https://github.com/pytest-dev/pytest-xdist>`__ plugin. See issue
|
||||||
|
`#7767 <https://github.com/pytest-dev/pytest/issues/7767>`__ for details.
|
||||||
|
|
||||||
caplog
|
caplog
|
||||||
Access and control log capturing.
|
Access and control log capturing.
|
||||||
|
|
||||||
|
@ -114,8 +123,10 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||||
* caplog.clear() -> clear captured records and formatted log output string
|
* caplog.clear() -> clear captured records and formatted log output string
|
||||||
|
|
||||||
monkeypatch
|
monkeypatch
|
||||||
The returned ``monkeypatch`` fixture provides these
|
A convenient fixture for monkey-patching.
|
||||||
helper methods to modify objects, dictionaries or os.environ::
|
|
||||||
|
The fixture provides these methods to modify objects, dictionaries or
|
||||||
|
os.environ::
|
||||||
|
|
||||||
monkeypatch.setattr(obj, name, value, raising=True)
|
monkeypatch.setattr(obj, name, value, raising=True)
|
||||||
monkeypatch.delattr(obj, name, raising=True)
|
monkeypatch.delattr(obj, name, raising=True)
|
||||||
|
@ -126,10 +137,9 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||||
monkeypatch.syspath_prepend(path)
|
monkeypatch.syspath_prepend(path)
|
||||||
monkeypatch.chdir(path)
|
monkeypatch.chdir(path)
|
||||||
|
|
||||||
All modifications will be undone after the requesting
|
All modifications will be undone after the requesting test function or
|
||||||
test function or fixture has finished. The ``raising``
|
fixture has finished. The ``raising`` parameter determines if a KeyError
|
||||||
parameter determines if a KeyError or AttributeError
|
or AttributeError will be raised if the set/deletion operation has no target.
|
||||||
will be raised if the set/deletion operation has no target.
|
|
||||||
|
|
||||||
recwarn
|
recwarn
|
||||||
Return a :class:`WarningsRecorder` instance that records all warnings emitted by test functions.
|
Return a :class:`WarningsRecorder` instance that records all warnings emitted by test functions.
|
||||||
|
@ -140,30 +150,28 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
|
||||||
tmpdir_factory [session scope]
|
tmpdir_factory [session scope]
|
||||||
Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session.
|
Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session.
|
||||||
|
|
||||||
|
|
||||||
tmp_path_factory [session scope]
|
tmp_path_factory [session scope]
|
||||||
Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session.
|
Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session.
|
||||||
|
|
||||||
|
|
||||||
tmpdir
|
tmpdir
|
||||||
Return a temporary directory path object
|
Return a temporary directory path object which is unique to each test
|
||||||
which is unique to each test function invocation,
|
function invocation, created as a sub directory of the base temporary
|
||||||
created as a sub directory of the base temporary
|
directory.
|
||||||
directory. The returned object is a `py.path.local`_
|
|
||||||
path object.
|
The returned object is a `py.path.local`_ path object.
|
||||||
|
|
||||||
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
|
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
|
||||||
|
|
||||||
tmp_path
|
tmp_path
|
||||||
Return a temporary directory path object
|
Return a temporary directory path object which is unique to each test
|
||||||
which is unique to each test function invocation,
|
function invocation, created as a sub directory of the base temporary
|
||||||
created as a sub directory of the base temporary
|
directory.
|
||||||
directory. The returned object is a :class:`pathlib.Path`
|
|
||||||
object.
|
The returned object is a :class:`pathlib.Path` object.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
in python < 3.6 this is a pathlib2.Path
|
In python < 3.6 this is a pathlib2.Path.
|
||||||
|
|
||||||
|
|
||||||
no tests ran in 0.12s
|
no tests ran in 0.12s
|
||||||
|
|
|
@ -28,6 +28,197 @@ with advance notice in the **Deprecations** section of releases.
|
||||||
|
|
||||||
.. towncrier release notes start
|
.. towncrier release notes start
|
||||||
|
|
||||||
|
pytest 6.1.2 (2020-10-28)
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Bug Fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
- `#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 `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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Improved Documentation
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
- `#7815 <https://github.com/pytest-dev/pytest/issues/7815>`_: Improve deprecation warning message for ``pytest._fillfuncargs()``.
|
||||||
|
|
||||||
|
|
||||||
|
pytest 6.1.1 (2020-10-03)
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Bug Fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
- `#7807 <https://github.com/pytest-dev/pytest/issues/7807>`_: Fixed regression in pytest 6.1.0 causing incorrect rootdir to be determined in some non-trivial cases where parent directories have config files as well.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7814 <https://github.com/pytest-dev/pytest/issues/7814>`_: Fixed crash in header reporting when :confval:`testpaths` is used and contains absolute paths (regression in 6.1.0).
|
||||||
|
|
||||||
|
|
||||||
|
pytest 6.1.0 (2020-09-26)
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Breaking Changes
|
||||||
|
----------------
|
||||||
|
|
||||||
|
- `#5585 <https://github.com/pytest-dev/pytest/issues/5585>`_: As per our policy, the following features which have been deprecated in the 5.X series are now
|
||||||
|
removed:
|
||||||
|
|
||||||
|
* The ``funcargnames`` read-only property of ``FixtureRequest``, ``Metafunc``, and ``Function`` classes. Use ``fixturenames`` attribute.
|
||||||
|
|
||||||
|
* ``@pytest.fixture`` no longer supports positional arguments, pass all arguments by keyword instead.
|
||||||
|
|
||||||
|
* Direct construction of ``Node`` subclasses now raise an error, use ``from_parent`` instead.
|
||||||
|
|
||||||
|
* The default value for ``junit_family`` has changed to ``xunit2``. If you require the old format, add ``junit_family=xunit1`` to your configuration file.
|
||||||
|
|
||||||
|
* The ``TerminalReporter`` no longer has a ``writer`` attribute. Plugin authors may use the public functions of the ``TerminalReporter`` instead of accessing the ``TerminalWriter`` object directly.
|
||||||
|
|
||||||
|
* The ``--result-log`` option has been removed. Users are recommended to use the `pytest-reportlog <https://github.com/pytest-dev/pytest-reportlog>`__ plugin instead.
|
||||||
|
|
||||||
|
|
||||||
|
For more information consult
|
||||||
|
`Deprecations and Removals <https://docs.pytest.org/en/stable/deprecations.html>`__ in the docs.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Deprecations
|
||||||
|
------------
|
||||||
|
|
||||||
|
- `#6981 <https://github.com/pytest-dev/pytest/issues/6981>`_: The ``pytest.collect`` module is deprecated: all its names can be imported from ``pytest`` directly.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7097 <https://github.com/pytest-dev/pytest/issues/7097>`_: The ``pytest._fillfuncargs`` function is deprecated. This function was kept
|
||||||
|
for backward compatibility with an older plugin.
|
||||||
|
|
||||||
|
It's functionality is not meant to be used directly, but if you must replace
|
||||||
|
it, use `function._request._fillfixtures()` instead, though note this is not
|
||||||
|
a public API and may break in the future.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7210 <https://github.com/pytest-dev/pytest/issues/7210>`_: The special ``-k '-expr'`` syntax to ``-k`` is deprecated. Use ``-k 'not expr'``
|
||||||
|
instead.
|
||||||
|
|
||||||
|
The special ``-k 'expr:'`` syntax to ``-k`` is deprecated. Please open an issue
|
||||||
|
if you use this and want a replacement.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7255 <https://github.com/pytest-dev/pytest/issues/7255>`_: The :func:`pytest_warning_captured <_pytest.hookspec.pytest_warning_captured>` hook is deprecated in favor
|
||||||
|
of :func:`pytest_warning_recorded <_pytest.hookspec.pytest_warning_recorded>`, and will be removed in a future version.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7648 <https://github.com/pytest-dev/pytest/issues/7648>`_: The ``gethookproxy()`` and ``isinitpath()`` methods of ``FSCollector`` and ``Package`` are deprecated;
|
||||||
|
use ``self.session.gethookproxy()`` and ``self.session.isinitpath()`` instead.
|
||||||
|
This should work on all pytest versions.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
- `#7667 <https://github.com/pytest-dev/pytest/issues/7667>`_: New ``--durations-min`` command-line flag controls the minimal duration for inclusion in the slowest list of tests shown by ``--durations``. Previously this was hard-coded to ``0.005s``.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Improvements
|
||||||
|
------------
|
||||||
|
|
||||||
|
- `#6681 <https://github.com/pytest-dev/pytest/issues/6681>`_: Internal pytest warnings issued during the early stages of initialization are now properly handled and can filtered through :confval:`filterwarnings` or ``--pythonwarnings/-W``.
|
||||||
|
|
||||||
|
This also fixes a number of long standing issues: `#2891 <https://github.com/pytest-dev/pytest/issues/2891>`__, `#7620 <https://github.com/pytest-dev/pytest/issues/7620>`__, `#7426 <https://github.com/pytest-dev/pytest/issues/7426>`__.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7572 <https://github.com/pytest-dev/pytest/issues/7572>`_: When a plugin listed in ``required_plugins`` is missing or an unknown config key is used with ``--strict-config``, a simple error message is now shown instead of a stacktrace.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7685 <https://github.com/pytest-dev/pytest/issues/7685>`_: Added two new attributes :attr:`rootpath <_pytest.config.Config.rootpath>` and :attr:`inipath <_pytest.config.Config.inipath>` to :class:`Config <_pytest.config.Config>`.
|
||||||
|
These attributes are :class:`pathlib.Path` versions of the existing :attr:`rootdir <_pytest.config.Config.rootdir>` and :attr:`inifile <_pytest.config.Config.inifile>` attributes,
|
||||||
|
and should be preferred over them when possible.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7780 <https://github.com/pytest-dev/pytest/issues/7780>`_: Public classes which are not designed to be inherited from are now marked `@final <https://docs.python.org/3/library/typing.html#typing.final>`_.
|
||||||
|
Code which inherits from these classes will trigger a type-checking (e.g. mypy) error, but will still work in runtime.
|
||||||
|
Currently the ``final`` designation does not appear in the API Reference but hopefully will in the future.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Bug Fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
- `#1953 <https://github.com/pytest-dev/pytest/issues/1953>`_: Fixed error when overwriting a parametrized fixture, while also reusing the super fixture value.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# conftest.py
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(params=[1, 2])
|
||||||
|
def foo(request):
|
||||||
|
return request.param
|
||||||
|
|
||||||
|
|
||||||
|
# test_foo.py
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def foo(foo):
|
||||||
|
return foo * 2
|
||||||
|
|
||||||
|
|
||||||
|
- `#4984 <https://github.com/pytest-dev/pytest/issues/4984>`_: Fixed an internal error crash with ``IndexError: list index out of range`` when
|
||||||
|
collecting a module which starts with a decorated function, the decorator
|
||||||
|
raises, and assertion rewriting is enabled.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7591 <https://github.com/pytest-dev/pytest/issues/7591>`_: pylint shouldn't complain anymore about unimplemented abstract methods when inheriting from :ref:`File <non-python tests>`.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7628 <https://github.com/pytest-dev/pytest/issues/7628>`_: Fixed test collection when a full path without a drive letter was passed to pytest on Windows (for example ``\projects\tests\test.py`` instead of ``c:\projects\tests\pytest.py``).
|
||||||
|
|
||||||
|
|
||||||
|
- `#7638 <https://github.com/pytest-dev/pytest/issues/7638>`_: Fix handling of command-line options that appear as paths but trigger an OS-level syntax error on Windows, such as the options used internally by ``pytest-xdist``.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7742 <https://github.com/pytest-dev/pytest/issues/7742>`_: Fixed INTERNALERROR when accessing locals / globals with faulty ``exec``.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Improved Documentation
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
- `#1477 <https://github.com/pytest-dev/pytest/issues/1477>`_: Removed faq.rst and its reference in contents.rst.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Trivial/Internal Changes
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
- `#7536 <https://github.com/pytest-dev/pytest/issues/7536>`_: The internal ``junitxml`` plugin has rewritten to use ``xml.etree.ElementTree``.
|
||||||
|
The order of attributes in XML elements might differ. Some unneeded escaping is
|
||||||
|
no longer performed.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7587 <https://github.com/pytest-dev/pytest/issues/7587>`_: The dependency on the ``more-itertools`` package has been removed.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7631 <https://github.com/pytest-dev/pytest/issues/7631>`_: The result type of :meth:`capfd.readouterr() <_pytest.capture.CaptureFixture.readouterr>` (and similar) is no longer a namedtuple,
|
||||||
|
but should behave like one in all respects. This was done for technical reasons.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7671 <https://github.com/pytest-dev/pytest/issues/7671>`_: When collecting tests, pytest finds test classes and functions by examining the
|
||||||
|
attributes of python objects (modules, classes and instances). To speed up this
|
||||||
|
process, pytest now ignores builtin attributes (like ``__class__``,
|
||||||
|
``__delattr__`` and ``__new__``) without consulting the :confval:`python_classes` and
|
||||||
|
:confval:`python_functions` configuration options and without passing them to plugins
|
||||||
|
using the :func:`pytest_pycollect_makeitem <_pytest.hookspec.pytest_pycollect_makeitem>` hook.
|
||||||
|
|
||||||
|
|
||||||
pytest 6.0.2 (2020-09-04)
|
pytest 6.0.2 (2020-09-04)
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
@ -1682,6 +1873,44 @@ Improved Documentation
|
||||||
- `#5416 <https://github.com/pytest-dev/pytest/issues/5416>`_: Fix PytestUnknownMarkWarning in run/skip example.
|
- `#5416 <https://github.com/pytest-dev/pytest/issues/5416>`_: Fix PytestUnknownMarkWarning in run/skip example.
|
||||||
|
|
||||||
|
|
||||||
|
pytest 4.6.11 (2020-06-04)
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Bug Fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
- `#6334 <https://github.com/pytest-dev/pytest/issues/6334>`_: Fix summary entries appearing twice when ``f/F`` and ``s/S`` report chars were used at the same time in the ``-r`` command-line option (for example ``-rFf``).
|
||||||
|
|
||||||
|
The upper case variants were never documented and the preferred form should be the lower case.
|
||||||
|
|
||||||
|
|
||||||
|
- `#7310 <https://github.com/pytest-dev/pytest/issues/7310>`_: Fix ``UnboundLocalError: local variable 'letter' referenced before
|
||||||
|
assignment`` in ``_pytest.terminal.pytest_report_teststatus()``
|
||||||
|
when plugins return report objects in an unconventional state.
|
||||||
|
|
||||||
|
This was making ``pytest_report_teststatus()`` skip
|
||||||
|
entering if-block branches that declare the ``letter`` variable.
|
||||||
|
|
||||||
|
The fix was to set the initial value of the ``letter`` before
|
||||||
|
the if-block cascade so that it always has a value.
|
||||||
|
|
||||||
|
|
||||||
|
pytest 4.6.10 (2020-05-08)
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
- `#6870 <https://github.com/pytest-dev/pytest/issues/6870>`_: New ``Config.invocation_args`` attribute containing the unchanged arguments passed to ``pytest.main()``.
|
||||||
|
|
||||||
|
Remark: while this is technically a new feature and according to our `policy <https://docs.pytest.org/en/latest/py27-py34-deprecation.html#what-goes-into-4-6-x-releases>`_ it should not have been backported, we have opened an exception in this particular case because it fixes a serious interaction with ``pytest-xdist``, so it can also be considered a bugfix.
|
||||||
|
|
||||||
|
Trivial/Internal Changes
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
- `#6404 <https://github.com/pytest-dev/pytest/issues/6404>`_: Remove usage of ``parser`` module, deprecated in Python 3.9.
|
||||||
|
|
||||||
|
|
||||||
pytest 4.6.9 (2020-01-04)
|
pytest 4.6.9 (2020-01-04)
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ Install ``pytest``
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
$ pytest --version
|
$ pytest --version
|
||||||
pytest 6.0.2
|
pytest 6.1.2
|
||||||
|
|
||||||
.. _`simpletest`:
|
.. _`simpletest`:
|
||||||
|
|
||||||
|
|
|
@ -816,6 +816,13 @@ Function
|
||||||
:members:
|
:members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
FunctionDefinition
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: _pytest.python.FunctionDefinition()
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
Item
|
Item
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
@ -1236,12 +1243,13 @@ passed multiple times. The expected format is ``name=value``. For example::
|
||||||
.. confval:: junit_family
|
.. confval:: junit_family
|
||||||
|
|
||||||
.. versionadded:: 4.2
|
.. versionadded:: 4.2
|
||||||
|
.. versionchanged:: 6.1
|
||||||
|
Default changed to ``xunit2``.
|
||||||
|
|
||||||
Configures the format of the generated JUnit XML file. The possible options are:
|
Configures the format of the generated JUnit XML file. The possible options are:
|
||||||
|
|
||||||
* ``xunit1`` (or ``legacy``): produces old style output, compatible with the xunit 1.0 format. **This is the default**.
|
* ``xunit1`` (or ``legacy``): produces old style output, compatible with the xunit 1.0 format.
|
||||||
* ``xunit2``: produces `xunit 2.0 style output <https://github.com/jenkinsci/xunit-plugin/blob/xunit-2.3.2/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd>`__,
|
* ``xunit2``: produces `xunit 2.0 style output <https://github.com/jenkinsci/xunit-plugin/blob/xunit-2.3.2/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd>`__, which should be more compatible with latest Jenkins versions. **This is the default**.
|
||||||
which should be more compatible with latest Jenkins versions.
|
|
||||||
|
|
||||||
.. code-block:: ini
|
.. code-block:: ini
|
||||||
|
|
||||||
|
|
|
@ -33,26 +33,34 @@ Plugin discovery order at tool startup
|
||||||
|
|
||||||
``pytest`` loads plugin modules at tool startup in the following way:
|
``pytest`` loads plugin modules at tool startup in the following way:
|
||||||
|
|
||||||
* by loading all builtin plugins
|
1. by scanning the command line for the ``-p no:name`` option
|
||||||
|
and *blocking* that plugin from being loaded (even builtin plugins can
|
||||||
|
be blocked this way). This happens before normal command-line parsing.
|
||||||
|
|
||||||
* by loading all plugins registered through `setuptools entry points`_.
|
2. by loading all builtin plugins.
|
||||||
|
|
||||||
* by pre-scanning the command line for the ``-p name`` option
|
3. by scanning the command line for the ``-p name`` option
|
||||||
and loading the specified plugin before actual command line parsing.
|
and loading the specified plugin. This happens before normal command-line parsing.
|
||||||
|
|
||||||
* by loading all :file:`conftest.py` files as inferred by the command line
|
4. by loading all plugins registered through `setuptools entry points`_.
|
||||||
invocation:
|
|
||||||
|
|
||||||
- if no test paths are specified use current dir as a test path
|
5. by loading all plugins specified through the :envvar:`PYTEST_PLUGINS` environment variable.
|
||||||
- if exists, load ``conftest.py`` and ``test*/conftest.py`` relative
|
|
||||||
to the directory part of the first test path.
|
|
||||||
|
|
||||||
Note that pytest does not find ``conftest.py`` files in deeper nested
|
6. by loading all :file:`conftest.py` files as inferred by the command line
|
||||||
sub directories at tool startup. It is usually a good idea to keep
|
invocation:
|
||||||
your ``conftest.py`` file in the top level test or project root directory.
|
|
||||||
|
|
||||||
* by recursively loading all plugins specified by the
|
- if no test paths are specified, use the current dir as a test path
|
||||||
:globalvar:`pytest_plugins` variable in ``conftest.py`` files
|
- if exists, load ``conftest.py`` and ``test*/conftest.py`` relative
|
||||||
|
to the directory part of the first test path. After the ``conftest.py``
|
||||||
|
file is loaded, load all plugins specified in its
|
||||||
|
:globalvar:`pytest_plugins` variable if present.
|
||||||
|
|
||||||
|
Note that pytest does not find ``conftest.py`` files in deeper nested
|
||||||
|
sub directories at tool startup. It is usually a good idea to keep
|
||||||
|
your ``conftest.py`` file in the top level test or project root directory.
|
||||||
|
|
||||||
|
7. by recursively loading all plugins specified by the
|
||||||
|
:globalvar:`pytest_plugins` variable in ``conftest.py`` files.
|
||||||
|
|
||||||
|
|
||||||
.. _`pytest/plugin`: http://bitbucket.org/pytest-dev/pytest/src/tip/pytest/plugin/
|
.. _`pytest/plugin`: http://bitbucket.org/pytest-dev/pytest/src/tip/pytest/plugin/
|
||||||
|
|
|
@ -29,6 +29,7 @@ from _pytest.config.argparsing import Parser
|
||||||
from _pytest.fixtures import FixtureRequest
|
from _pytest.fixtures import FixtureRequest
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
from _pytest.python import Module
|
from _pytest.python import Module
|
||||||
|
from _pytest.python import Package
|
||||||
from _pytest.reports import TestReport
|
from _pytest.reports import TestReport
|
||||||
|
|
||||||
|
|
||||||
|
@ -233,7 +234,10 @@ class LFPluginCollSkipfiles:
|
||||||
def pytest_make_collect_report(
|
def pytest_make_collect_report(
|
||||||
self, collector: nodes.Collector
|
self, collector: nodes.Collector
|
||||||
) -> Optional[CollectReport]:
|
) -> Optional[CollectReport]:
|
||||||
if isinstance(collector, Module):
|
# Packages are Modules, but _last_failed_paths only contains
|
||||||
|
# test-bearing paths and doesn't try to include the paths of their
|
||||||
|
# packages, so don't filter them.
|
||||||
|
if isinstance(collector, Module) and not isinstance(collector, Package):
|
||||||
if Path(str(collector.fspath)) not in self.lfplugin._last_failed_paths:
|
if Path(str(collector.fspath)) not in self.lfplugin._last_failed_paths:
|
||||||
self.lfplugin._skipped_files += 1
|
self.lfplugin._skipped_files += 1
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import itertools
|
|
||||||
import os
|
import os
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
@ -100,7 +99,7 @@ def locate_config(
|
||||||
args = [Path.cwd()]
|
args = [Path.cwd()]
|
||||||
for arg in args:
|
for arg in args:
|
||||||
argpath = absolutepath(arg)
|
argpath = absolutepath(arg)
|
||||||
for base in itertools.chain((argpath,), reversed(argpath.parents)):
|
for base in (argpath, *argpath.parents):
|
||||||
for config_name in config_names:
|
for config_name in config_names:
|
||||||
p = base / config_name
|
p = base / config_name
|
||||||
if p.is_file():
|
if p.is_file():
|
||||||
|
@ -184,9 +183,7 @@ def determine_setup(
|
||||||
ancestor = get_common_ancestor(dirs)
|
ancestor = get_common_ancestor(dirs)
|
||||||
rootdir, inipath, inicfg = locate_config([ancestor])
|
rootdir, inipath, inicfg = locate_config([ancestor])
|
||||||
if rootdir is None and rootdir_cmd_arg is None:
|
if rootdir is None and rootdir_cmd_arg is None:
|
||||||
for possible_rootdir in itertools.chain(
|
for possible_rootdir in (ancestor, *ancestor.parents):
|
||||||
(ancestor,), reversed(ancestor.parents)
|
|
||||||
):
|
|
||||||
if (possible_rootdir / "setup.py").is_file():
|
if (possible_rootdir / "setup.py").is_file():
|
||||||
rootdir = possible_rootdir
|
rootdir = possible_rootdir
|
||||||
break
|
break
|
||||||
|
|
|
@ -20,9 +20,10 @@ DEPRECATED_EXTERNAL_PLUGINS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FILLFUNCARGS = PytestDeprecationWarning(
|
FILLFUNCARGS = UnformattedWarning(
|
||||||
"The `_fillfuncargs` function is deprecated, use "
|
PytestDeprecationWarning,
|
||||||
"function._request._fillfixtures() instead if you cannot avoid reaching into internals."
|
"{name} is deprecated, use "
|
||||||
|
"function._request._fillfixtures() instead if you cannot avoid reaching into internals.",
|
||||||
)
|
)
|
||||||
|
|
||||||
PYTEST_COLLECT_MODULE = UnformattedWarning(
|
PYTEST_COLLECT_MODULE = UnformattedWarning(
|
||||||
|
|
|
@ -339,9 +339,22 @@ def reorder_items_atscope(
|
||||||
return items_done
|
return items_done
|
||||||
|
|
||||||
|
|
||||||
|
def _fillfuncargs(function: "Function") -> None:
|
||||||
|
"""Fill missing fixtures for a test function, old public API (deprecated)."""
|
||||||
|
warnings.warn(FILLFUNCARGS.format(name="pytest._fillfuncargs()"), stacklevel=2)
|
||||||
|
_fill_fixtures_impl(function)
|
||||||
|
|
||||||
|
|
||||||
def fillfixtures(function: "Function") -> None:
|
def fillfixtures(function: "Function") -> None:
|
||||||
"""Fill missing funcargs for a test function."""
|
"""Fill missing fixtures for a test function (deprecated)."""
|
||||||
warnings.warn(FILLFUNCARGS, stacklevel=2)
|
warnings.warn(
|
||||||
|
FILLFUNCARGS.format(name="_pytest.fixtures.fillfixtures()"), stacklevel=2
|
||||||
|
)
|
||||||
|
_fill_fixtures_impl(function)
|
||||||
|
|
||||||
|
|
||||||
|
def _fill_fixtures_impl(function: "Function") -> None:
|
||||||
|
"""Internal implementation to fill fixtures on the given function object."""
|
||||||
try:
|
try:
|
||||||
request = function._request
|
request = function._request
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
|
|
@ -9,6 +9,10 @@ import sys
|
||||||
import uuid
|
import uuid
|
||||||
import warnings
|
import warnings
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from errno import EBADF
|
||||||
|
from errno import ELOOP
|
||||||
|
from errno import ENOENT
|
||||||
|
from errno import ENOTDIR
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from os.path import expanduser
|
from os.path import expanduser
|
||||||
from os.path import expandvars
|
from os.path import expandvars
|
||||||
|
@ -38,11 +42,29 @@ else:
|
||||||
__all__ = ["Path", "PurePath"]
|
__all__ = ["Path", "PurePath"]
|
||||||
|
|
||||||
|
|
||||||
LOCK_TIMEOUT = 60 * 60 * 3
|
LOCK_TIMEOUT = 60 * 60 * 24 * 3
|
||||||
|
|
||||||
|
|
||||||
_AnyPurePath = TypeVar("_AnyPurePath", bound=PurePath)
|
_AnyPurePath = TypeVar("_AnyPurePath", bound=PurePath)
|
||||||
|
|
||||||
|
# The following function, variables and comments were
|
||||||
|
# copied from cpython 3.9 Lib/pathlib.py file.
|
||||||
|
|
||||||
|
# EBADF - guard against macOS `stat` throwing EBADF
|
||||||
|
_IGNORED_ERRORS = (ENOENT, ENOTDIR, EBADF, ELOOP)
|
||||||
|
|
||||||
|
_IGNORED_WINERRORS = (
|
||||||
|
21, # ERROR_NOT_READY - drive exists but is not accessible
|
||||||
|
1921, # ERROR_CANT_RESOLVE_FILENAME - fix for broken symlink pointing to itself
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _ignore_error(exception):
|
||||||
|
return (
|
||||||
|
getattr(exception, "errno", None) in _IGNORED_ERRORS
|
||||||
|
or getattr(exception, "winerror", None) in _IGNORED_WINERRORS
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_lock_path(path: _AnyPurePath) -> _AnyPurePath:
|
def get_lock_path(path: _AnyPurePath) -> _AnyPurePath:
|
||||||
return path.joinpath(".lock")
|
return path.joinpath(".lock")
|
||||||
|
@ -563,10 +585,25 @@ def visit(
|
||||||
|
|
||||||
Entries at each directory level are sorted.
|
Entries at each directory level are sorted.
|
||||||
"""
|
"""
|
||||||
entries = sorted(os.scandir(path), key=lambda entry: entry.name)
|
|
||||||
|
# Skip entries with symlink loops and other brokenness, so the caller doesn't
|
||||||
|
# have to deal with it.
|
||||||
|
entries = []
|
||||||
|
for entry in os.scandir(path):
|
||||||
|
try:
|
||||||
|
entry.is_file()
|
||||||
|
except OSError as err:
|
||||||
|
if _ignore_error(err):
|
||||||
|
continue
|
||||||
|
raise
|
||||||
|
entries.append(entry)
|
||||||
|
|
||||||
|
entries.sort(key=lambda entry: entry.name)
|
||||||
|
|
||||||
yield from entries
|
yield from entries
|
||||||
|
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
if entry.is_dir(follow_symlinks=False) and recurse(entry):
|
if entry.is_dir() and recurse(entry):
|
||||||
yield from visit(entry.path, recurse)
|
yield from visit(entry.path, recurse)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -943,6 +943,7 @@ class Metafunc:
|
||||||
cls=None,
|
cls=None,
|
||||||
module=None,
|
module=None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
#: Access to the underlying :class:`_pytest.python.FunctionDefinition`.
|
||||||
self.definition = definition
|
self.definition = definition
|
||||||
|
|
||||||
#: Access to the :class:`_pytest.config.Config` object for the test session.
|
#: Access to the :class:`_pytest.config.Config` object for the test session.
|
||||||
|
@ -1664,10 +1665,12 @@ class Function(PyobjMixin, nodes.Item):
|
||||||
|
|
||||||
|
|
||||||
class FunctionDefinition(Function):
|
class FunctionDefinition(Function):
|
||||||
"""Internal hack until we get actual definition nodes instead of the
|
"""
|
||||||
crappy metafunc hack."""
|
This class is a step gap solution until we evolve to have actual function definition nodes
|
||||||
|
and manage to get rid of ``metafunc``.
|
||||||
|
"""
|
||||||
|
|
||||||
def runtest(self) -> None:
|
def runtest(self) -> None:
|
||||||
raise RuntimeError("function definitions are not supposed to be used")
|
raise RuntimeError("function definitions are not supposed to be run as tests")
|
||||||
|
|
||||||
setup = runtest
|
setup = runtest
|
||||||
|
|
|
@ -718,10 +718,10 @@ class TerminalReporter:
|
||||||
if config.inipath:
|
if config.inipath:
|
||||||
line += ", configfile: " + bestrelpath(config.rootpath, config.inipath)
|
line += ", configfile: " + bestrelpath(config.rootpath, config.inipath)
|
||||||
|
|
||||||
testpaths = config.getini("testpaths")
|
testpaths = config.getini("testpaths") # type: List[str]
|
||||||
if testpaths and config.args == testpaths:
|
if testpaths and config.args == testpaths:
|
||||||
rel_paths = [bestrelpath(config.rootpath, x) for x in testpaths]
|
line += ", testpaths: {}".format(", ".join(testpaths))
|
||||||
line += ", testpaths: {}".format(", ".join(rel_paths))
|
|
||||||
result = [line]
|
result = [line]
|
||||||
|
|
||||||
plugininfo = config.pluginmanager.list_plugin_distinfo()
|
plugininfo = config.pluginmanager.list_plugin_distinfo()
|
||||||
|
|
|
@ -11,7 +11,7 @@ from _pytest.config import hookspec
|
||||||
from _pytest.config import main
|
from _pytest.config import main
|
||||||
from _pytest.config import UsageError
|
from _pytest.config import UsageError
|
||||||
from _pytest.debugging import pytestPDB as __pytestPDB
|
from _pytest.debugging import pytestPDB as __pytestPDB
|
||||||
from _pytest.fixtures import fillfixtures as _fillfuncargs
|
from _pytest.fixtures import _fillfuncargs
|
||||||
from _pytest.fixtures import fixture
|
from _pytest.fixtures import fixture
|
||||||
from _pytest.fixtures import FixtureLookupError
|
from _pytest.fixtures import FixtureLookupError
|
||||||
from _pytest.fixtures import yield_fixture
|
from _pytest.fixtures import yield_fixture
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import re
|
||||||
import warnings
|
import warnings
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
@ -26,11 +27,27 @@ def test_external_plugins_integrated(testdir, plugin):
|
||||||
def test_fillfuncargs_is_deprecated() -> None:
|
def test_fillfuncargs_is_deprecated() -> None:
|
||||||
with pytest.warns(
|
with pytest.warns(
|
||||||
pytest.PytestDeprecationWarning,
|
pytest.PytestDeprecationWarning,
|
||||||
match="The `_fillfuncargs` function is deprecated",
|
match=re.escape(
|
||||||
|
"pytest._fillfuncargs() is deprecated, use "
|
||||||
|
"function._request._fillfixtures() instead if you cannot avoid reaching into internals."
|
||||||
|
),
|
||||||
):
|
):
|
||||||
pytest._fillfuncargs(mock.Mock())
|
pytest._fillfuncargs(mock.Mock())
|
||||||
|
|
||||||
|
|
||||||
|
def test_fillfixtures_is_deprecated() -> None:
|
||||||
|
import _pytest.fixtures
|
||||||
|
|
||||||
|
with pytest.warns(
|
||||||
|
pytest.PytestDeprecationWarning,
|
||||||
|
match=re.escape(
|
||||||
|
"_pytest.fixtures.fillfixtures() is deprecated, use "
|
||||||
|
"function._request._fillfixtures() instead if you cannot avoid reaching into internals."
|
||||||
|
),
|
||||||
|
):
|
||||||
|
_pytest.fixtures.fillfixtures(mock.Mock())
|
||||||
|
|
||||||
|
|
||||||
def test_minus_k_dash_is_deprecated(testdir) -> None:
|
def test_minus_k_dash_is_deprecated(testdir) -> None:
|
||||||
threepass = testdir.makepyfile(
|
threepass = testdir.makepyfile(
|
||||||
test_threepass="""
|
test_threepass="""
|
||||||
|
|
|
@ -87,7 +87,7 @@ def test_getfuncargnames_staticmethod_partial():
|
||||||
class TestFillFixtures:
|
class TestFillFixtures:
|
||||||
def test_fillfuncargs_exposed(self):
|
def test_fillfuncargs_exposed(self):
|
||||||
# used by oejskit, kept for compatibility
|
# used by oejskit, kept for compatibility
|
||||||
assert pytest._fillfuncargs == fixtures.fillfixtures
|
assert pytest._fillfuncargs == fixtures._fillfuncargs
|
||||||
|
|
||||||
def test_funcarg_lookupfails(self, testdir):
|
def test_funcarg_lookupfails(self, testdir):
|
||||||
testdir.copy_example()
|
testdir.copy_example()
|
||||||
|
|
|
@ -984,6 +984,36 @@ class TestLastFailed:
|
||||||
)
|
)
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
|
|
||||||
|
def test_packages(self, testdir: Testdir) -> None:
|
||||||
|
"""Regression test for #7758.
|
||||||
|
|
||||||
|
The particular issue here was that Package nodes were included in the
|
||||||
|
filtering, being themselves Modules for the __init__.py, even if they
|
||||||
|
had failed Modules in them.
|
||||||
|
|
||||||
|
The tests includes a test in an __init__.py file just to make sure the
|
||||||
|
fix doesn't somehow regress that, it is not critical for the issue.
|
||||||
|
"""
|
||||||
|
testdir.makepyfile(
|
||||||
|
**{
|
||||||
|
"__init__.py": "",
|
||||||
|
"a/__init__.py": "def test_a_init(): assert False",
|
||||||
|
"a/test_one.py": "def test_1(): assert False",
|
||||||
|
"b/__init__.py": "",
|
||||||
|
"b/test_two.py": "def test_2(): assert False",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
testdir.makeini(
|
||||||
|
"""
|
||||||
|
[pytest]
|
||||||
|
python_files = *.py
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.assert_outcomes(failed=3)
|
||||||
|
result = testdir.runpytest("--lf")
|
||||||
|
result.assert_outcomes(failed=3)
|
||||||
|
|
||||||
|
|
||||||
class TestNewFirst:
|
class TestNewFirst:
|
||||||
def test_newfirst_usecase(self, testdir):
|
def test_newfirst_usecase(self, testdir):
|
||||||
|
|
|
@ -1178,6 +1178,15 @@ def test_collect_symlink_out_of_tree(testdir):
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_collect_symlink_dir(testdir: Testdir) -> None:
|
||||||
|
"""A symlinked directory is collected."""
|
||||||
|
dir = testdir.mkdir("dir")
|
||||||
|
dir.join("test_it.py").write("def test_it(): pass")
|
||||||
|
symlink_or_skip(dir, testdir.tmpdir.join("symlink_dir"))
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.assert_outcomes(passed=2)
|
||||||
|
|
||||||
|
|
||||||
def test_collectignore_via_conftest(testdir):
|
def test_collectignore_via_conftest(testdir):
|
||||||
"""collect_ignore in parent conftest skips importing child (issue #4592)."""
|
"""collect_ignore in parent conftest skips importing child (issue #4592)."""
|
||||||
tests = testdir.mkpydir("tests")
|
tests = testdir.mkpydir("tests")
|
||||||
|
@ -1407,3 +1416,17 @@ def test_does_not_crash_on_error_from_decorated_function(testdir: Testdir) -> No
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
# Not INTERNAL_ERROR
|
# Not INTERNAL_ERROR
|
||||||
assert result.ret == ExitCode.INTERRUPTED
|
assert result.ret == ExitCode.INTERRUPTED
|
||||||
|
|
||||||
|
|
||||||
|
def test_does_not_crash_on_recursive_symlink(testdir: Testdir) -> None:
|
||||||
|
"""Regression test for an issue around recursive symlinks (#7951)."""
|
||||||
|
symlink_or_skip("recursive", testdir.tmpdir.join("recursive"))
|
||||||
|
testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
def test_foo(): assert True
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = testdir.runpytest()
|
||||||
|
|
||||||
|
assert result.ret == ExitCode.OK
|
||||||
|
assert result.parseoutcomes() == {"passed": 1}
|
||||||
|
|
|
@ -1375,6 +1375,21 @@ class TestRootdir:
|
||||||
assert rootpath == tmp_path
|
assert rootpath == tmp_path
|
||||||
assert inipath is None
|
assert inipath is None
|
||||||
|
|
||||||
|
def test_with_config_also_in_parent_directory(
|
||||||
|
self, tmp_path: Path, monkeypatch: MonkeyPatch
|
||||||
|
) -> None:
|
||||||
|
"""Regression test for #7807."""
|
||||||
|
(tmp_path / "setup.cfg").write_text("[tool:pytest]\n", "utf-8")
|
||||||
|
(tmp_path / "myproject").mkdir()
|
||||||
|
(tmp_path / "myproject" / "setup.cfg").write_text("[tool:pytest]\n", "utf-8")
|
||||||
|
(tmp_path / "myproject" / "tests").mkdir()
|
||||||
|
monkeypatch.chdir(tmp_path / "myproject")
|
||||||
|
|
||||||
|
rootpath, inipath, _ = determine_setup(None, ["tests/"])
|
||||||
|
|
||||||
|
assert rootpath == tmp_path / "myproject"
|
||||||
|
assert inipath == tmp_path / "myproject" / "setup.cfg"
|
||||||
|
|
||||||
|
|
||||||
class TestOverrideIniArgs:
|
class TestOverrideIniArgs:
|
||||||
@pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split())
|
@pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split())
|
||||||
|
|
|
@ -17,6 +17,8 @@ from _pytest.pathlib import ImportPathMismatchError
|
||||||
from _pytest.pathlib import maybe_delete_a_numbered_dir
|
from _pytest.pathlib import maybe_delete_a_numbered_dir
|
||||||
from _pytest.pathlib import Path
|
from _pytest.pathlib import Path
|
||||||
from _pytest.pathlib import resolve_package_path
|
from _pytest.pathlib import resolve_package_path
|
||||||
|
from _pytest.pathlib import symlink_or_skip
|
||||||
|
from _pytest.pathlib import visit
|
||||||
|
|
||||||
|
|
||||||
class TestFNMatcherPort:
|
class TestFNMatcherPort:
|
||||||
|
@ -401,3 +403,13 @@ def test_commonpath() -> None:
|
||||||
assert commonpath(subpath, path) == path
|
assert commonpath(subpath, path) == path
|
||||||
assert commonpath(Path(str(path) + "suffix"), path) == path.parent
|
assert commonpath(Path(str(path) + "suffix"), path) == path.parent
|
||||||
assert commonpath(path, path.parent.parent) == path.parent.parent
|
assert commonpath(path, path.parent.parent) == path.parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
def test_visit_ignores_errors(tmpdir: py.path.local) -> None:
|
||||||
|
symlink_or_skip("recursive", tmpdir.join("recursive"))
|
||||||
|
tmpdir.join("foo").write_binary(b"")
|
||||||
|
tmpdir.join("bar").write_binary(b"")
|
||||||
|
|
||||||
|
assert [
|
||||||
|
entry.name for entry in visit(str(tmpdir), recurse=lambda entry: False)
|
||||||
|
] == ["bar", "foo"]
|
||||||
|
|
|
@ -18,6 +18,7 @@ import pytest
|
||||||
from _pytest._io.wcwidth import wcswidth
|
from _pytest._io.wcwidth import wcswidth
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
|
from _pytest.monkeypatch import MonkeyPatch
|
||||||
from _pytest.pathlib import Path
|
from _pytest.pathlib import Path
|
||||||
from _pytest.pytester import Testdir
|
from _pytest.pytester import Testdir
|
||||||
from _pytest.reports import BaseReport
|
from _pytest.reports import BaseReport
|
||||||
|
@ -749,6 +750,29 @@ class TestTerminalFunctional:
|
||||||
result = testdir.runpytest("tests")
|
result = testdir.runpytest("tests")
|
||||||
result.stdout.fnmatch_lines(["rootdir: *test_header0, configfile: tox.ini"])
|
result.stdout.fnmatch_lines(["rootdir: *test_header0, configfile: tox.ini"])
|
||||||
|
|
||||||
|
def test_header_absolute_testpath(
|
||||||
|
self, testdir: Testdir, monkeypatch: MonkeyPatch
|
||||||
|
) -> None:
|
||||||
|
"""Regresstion test for #7814."""
|
||||||
|
tests = testdir.tmpdir.join("tests")
|
||||||
|
tests.ensure_dir()
|
||||||
|
testdir.makepyprojecttoml(
|
||||||
|
"""
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
testpaths = ['{}']
|
||||||
|
""".format(
|
||||||
|
tests
|
||||||
|
)
|
||||||
|
)
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.stdout.fnmatch_lines(
|
||||||
|
[
|
||||||
|
"rootdir: *absolute_testpath0, configfile: pyproject.toml, testpaths: {}".format(
|
||||||
|
tests
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
def test_no_header(self, testdir):
|
def test_no_header(self, testdir):
|
||||||
testdir.tmpdir.join("tests").ensure_dir()
|
testdir.tmpdir.join("tests").ensure_dir()
|
||||||
testdir.tmpdir.join("gui").ensure_dir()
|
testdir.tmpdir.join("gui").ensure_dir()
|
||||||
|
|
Loading…
Reference in New Issue