Skip to content

Commit 1484446

Browse files
Merge branch 'main' into drop-python3.8
2 parents 9216e89 + 270c24a commit 1484446

File tree

18 files changed

+412
-196
lines changed

18 files changed

+412
-196
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ jobs:
261261

262262
- name: Upload coverage to Codecov
263263
if: "matrix.use_coverage"
264-
uses: codecov/codecov-action@v4
264+
uses: codecov/codecov-action@v5
265265
with:
266266
fail_ci_if_error: false
267267
files: ./coverage.xml

changelog/10839.deprecation.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Requesting an asynchronous fixture without a `pytest_fixture_setup` hook that resolves it will now give a DeprecationWarning. This most commonly happens if a sync test requests an async fixture. This should have no effect on a majority of users with async tests or fixtures using async pytest plugins, but may affect non-standard hook setups or ``autouse=True``. For guidance on how to work around this warning see :ref:`sync-test-async-fixture`.

changelog/12535.doc.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
`This
2+
example`<https://docs.pytest.org/en/latest/example/simple.html#making-test-result-information-available-in-fixtures>
3+
showed ``print`` statements that do not exactly reflect what the
4+
different branches actually do. The fix makes the example more precise.

changelog/12960.breaking.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Test functions containing a yield now cause an explicit error. They have not been run since pytest 4.0, and were previously marked as an expected failure and deprecation warning.
2+
3+
See :ref:`the docs <yield tests deprecated>` for more information.

changelog/12966.doc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Clarify :ref:`filterwarnings` docs on filter precedence/order when using multiple :ref:`@pytest.mark.filterwarnings <pytest.mark.filterwarnings ref>` marks.

doc/en/deprecations.rst

Lines changed: 106 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,76 @@ Below is a complete list of all pytest features which are considered deprecated.
1515
:class:`~pytest.PytestWarning` or subclasses, which can be filtered using :ref:`standard warning filters <warnings>`.
1616

1717

18+
.. _sync-test-async-fixture:
19+
20+
sync test depending on async fixture
21+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22+
23+
.. deprecated:: 8.4
24+
25+
Pytest has for a long time given an error when encountering an asynchronous test function, prompting the user to install
26+
a plugin that can handle it. It has not given any errors if you have an asynchronous fixture that's depended on by a
27+
synchronous test. If the fixture was an async function you did get an "unawaited coroutine" warning, but for async yield fixtures you didn't even get that.
28+
This is a problem even if you do have a plugin installed for handling async tests, as they may require
29+
special decorators for async fixtures to be handled, and some may not robustly handle if a user accidentally requests an
30+
async fixture from their sync tests. Fixture values being cached can make this even more unintuitive, where everything will
31+
"work" if the fixture is first requested by an async test, and then requested by a synchronous test.
32+
33+
Unfortunately there is no 100% reliable method of identifying when a user has made a mistake, versus when they expect an
34+
unawaited object from their fixture that they will handle on their own. To suppress this warning
35+
when you in fact did intend to handle this you can wrap your async fixture in a synchronous fixture:
36+
37+
.. code-block:: python
38+
39+
import asyncio
40+
import pytest
41+
42+
43+
@pytest.fixture
44+
async def unawaited_fixture():
45+
return 1
46+
47+
48+
def test_foo(unawaited_fixture):
49+
assert 1 == asyncio.run(unawaited_fixture)
50+
51+
should be changed to
52+
53+
54+
.. code-block:: python
55+
56+
import asyncio
57+
import pytest
58+
59+
60+
@pytest.fixture
61+
def unawaited_fixture():
62+
async def inner_fixture():
63+
return 1
64+
65+
return inner_fixture()
66+
67+
68+
def test_foo(unawaited_fixture):
69+
assert 1 == asyncio.run(unawaited_fixture)
70+
71+
72+
You can also make use of `pytest_fixture_setup` to handle the coroutine/asyncgen before pytest sees it - this is the way current async pytest plugins handle it.
73+
74+
If a user has an async fixture with ``autouse=True`` in their ``conftest.py``, or in a file
75+
containing both synchronous tests and the fixture, they will receive this warning.
76+
Unless you're using a plugin that specifically handles async fixtures
77+
with synchronous tests, we strongly recommend against this practice.
78+
It can lead to unpredictable behavior (with larger scopes, it may appear to "work" if an async
79+
test is the first to request the fixture, due to value caching) and will generate
80+
unawaited-coroutine runtime warnings (but only for non-yield fixtures).
81+
Additionally, it creates ambiguity for other developers about whether the fixture is intended to perform
82+
setup for synchronous tests.
83+
84+
The `anyio pytest plugin <https://anyio.readthedocs.io/en/stable/testing.html>`_ supports
85+
synchronous tests with async fixtures, though certain limitations apply.
86+
87+
1888
.. _import-or-skip-import-error:
1989

2090
``pytest.importorskip`` default behavior regarding :class:`ImportError`
@@ -304,6 +374,42 @@ an appropriate period of deprecation has passed.
304374

305375
Some breaking changes which could not be deprecated are also listed.
306376

377+
.. _yield tests deprecated:
378+
379+
``yield`` tests
380+
~~~~~~~~~~~~~~~
381+
382+
.. versionremoved:: 4.0
383+
384+
``yield`` tests ``xfail``.
385+
386+
.. versionremoved:: 8.4
387+
388+
``yield`` tests raise a collection error.
389+
390+
pytest no longer supports ``yield``-style tests, where a test function actually ``yield`` functions and values
391+
that are then turned into proper test methods. Example:
392+
393+
.. code-block:: python
394+
395+
def check(x, y):
396+
assert x**x == y
397+
398+
399+
def test_squared():
400+
yield check, 2, 4
401+
yield check, 3, 9
402+
403+
This would result in two actual test functions being generated.
404+
405+
This form of test function doesn't support fixtures properly, and users should switch to ``pytest.mark.parametrize``:
406+
407+
.. code-block:: python
408+
409+
@pytest.mark.parametrize("x, y", [(2, 4), (3, 9)])
410+
def test_squared(x, y):
411+
assert x**x == y
412+
307413
.. _nose-deprecation:
308414

309415
Support for tests written for nose
@@ -1200,36 +1306,6 @@ with the ``name`` parameter:
12001306
return cell()
12011307
12021308
1203-
.. _yield tests deprecated:
1204-
1205-
``yield`` tests
1206-
~~~~~~~~~~~~~~~
1207-
1208-
.. versionremoved:: 4.0
1209-
1210-
pytest supported ``yield``-style tests, where a test function actually ``yield`` functions and values
1211-
that are then turned into proper test methods. Example:
1212-
1213-
.. code-block:: python
1214-
1215-
def check(x, y):
1216-
assert x**x == y
1217-
1218-
1219-
def test_squared():
1220-
yield check, 2, 4
1221-
yield check, 3, 9
1222-
1223-
This would result into two actual test functions being generated.
1224-
1225-
This form of test function doesn't support fixtures properly, and users should switch to ``pytest.mark.parametrize``:
1226-
1227-
.. code-block:: python
1228-
1229-
@pytest.mark.parametrize("x, y", [(2, 4), (3, 9)])
1230-
def test_squared(x, y):
1231-
assert x**x == y
1232-
12331309
.. _internal classes accessed through node deprecated:
12341310

12351311
Internal classes accessed through ``Node``

doc/en/example/simple.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -904,7 +904,9 @@ here is a little example implemented via a local plugin:
904904
# "function" scope
905905
report = request.node.stash[phase_report_key]
906906
if report["setup"].failed:
907-
print("setting up a test failed or skipped", request.node.nodeid)
907+
print("setting up a test failed", request.node.nodeid)
908+
elif report["setup"].skipped:
909+
print("setting up a test skipped", request.node.nodeid)
908910
elif ("call" not in report) or report["call"].failed:
909911
print("executing test failed or skipped", request.node.nodeid)
910912

doc/en/how-to/capture-warnings.rst

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ is performed.
128128

129129

130130

131-
You can use the ``@pytest.mark.filterwarnings`` to add warning filters to specific test items,
131+
You can use the :ref:`@pytest.mark.filterwarnings <pytest.mark.filterwarnings ref>` mark to add warning filters to specific test items,
132132
allowing you to have finer control of which warnings should be captured at test, class or
133133
even module level:
134134

@@ -147,10 +147,30 @@ even module level:
147147
assert api_v1() == 1
148148
149149
150+
You can specify multiple filters with separate decorators:
151+
152+
.. code-block:: python
153+
154+
# Ignore "api v1" warnings, but fail on all other warnings
155+
@pytest.mark.filterwarnings("ignore:api v1")
156+
@pytest.mark.filterwarnings("error")
157+
def test_one():
158+
assert api_v1() == 1
159+
160+
.. important::
161+
162+
Regarding decorator order and filter precedence:
163+
it's important to remember that decorators are evaluated in reverse order,
164+
so you have to list the warning filters in the reverse order
165+
compared to traditional :py:func:`warnings.filterwarnings` and :option:`-W option <python:-W>` usage.
166+
This means in practice that filters from earlier :ref:`@pytest.mark.filterwarnings <pytest.mark.filterwarnings ref>` decorators
167+
take precedence over filters from later decorators, as illustrated in the example above.
168+
169+
150170
Filters applied using a mark take precedence over filters passed on the command line or configured
151-
by the ``filterwarnings`` ini option.
171+
by the :confval:`filterwarnings` ini option.
152172

153-
You may apply a filter to all tests of a class by using the ``filterwarnings`` mark as a class
173+
You may apply a filter to all tests of a class by using the :ref:`filterwarnings <pytest.mark.filterwarnings ref>` mark as a class
154174
decorator or to all tests in a module by setting the :globalvar:`pytestmark` variable:
155175

156176
.. code-block:: python
@@ -159,6 +179,13 @@ decorator or to all tests in a module by setting the :globalvar:`pytestmark` var
159179
pytestmark = pytest.mark.filterwarnings("error")
160180
161181
182+
.. note::
183+
184+
If you want to apply multiple filters
185+
(by assigning a list of :ref:`filterwarnings <pytest.mark.filterwarnings ref>` mark to :globalvar:`pytestmark`),
186+
you must use the traditional :py:func:`warnings.filterwarnings` ordering approach (later filters take precedence),
187+
which is the reverse of the decorator approach mentioned above.
188+
162189

163190
*Credits go to Florian Schulze for the reference implementation in the* `pytest-warnings`_
164191
*plugin.*

0 commit comments

Comments
 (0)