@@ -18,317 +18,4 @@ The code here is influenced by pytest-asyncio but with some differences:
1818Like pytest-asyncio it supports async tests, coroutine fixtures and async
1919generator fixtures.
2020
21- Changelog
22- ---------
23-
24- 0.9.0 - 20 October 2024
25- * Enabling the plugin must now be done by adding ``alt_pytest_asyncio.enable ``
26- to the pytest list of enabled plugins if it's not being manually enabled.
27- * Removed ``pytest.mark.async_timeout `` and replaced the functionality with
28- a fixture.
29- * Changed the exported api of the plugin
30-
31- * ``alt_pytest_asyncio.plugin.OverrideLoop `` is now ``alt_pytest_asyncio.Loop ``
32- * ``alt_pytest_asyncio.plugin.AltPytestAsyncioPlugin `` now takes ``managed_loop ``
33- as a keyword argument instead of the first positional argument with the
34- name ``loop ``.
35- * The new ``Loop `` that replaces ``OverrideLoop `` now has an attributed
36- ``controlled_loop `` instead of ``loop ``.
37-
38- 0.8.2 - 12 October 2024
39- * Added type annotations
40- * CI now tests against python 3.13
41-
42- 0.8.1 - 3 June 2024
43- * Remove a namespace conflict that restricted what names could be used as
44- parametrize arguments.
45-
46- 0.8.0 - 1 June 2024
47- * Provide simple support for tests being aware of asyncio.Context
48- * Remove support for python less than 3.11
49- * Added support for asyncio ContextVars
50-
51- 0.7.2 - 1 October 2023
52- * Timeouts don't take affect if the debugger is active
53-
54- 0.7.1 - 23 June 2023
55- * No functional changes, only fixing how hatchling understands the
56- license field in the pyproject.toml with thanks to @piotrm-nvidia
57-
58- 0.7.0 - 12 April 2023
59- * Changed the pytest dependency to be greater than pytest version 7
60- * Using isort now
61- * Went from setuptools to hatch
62- * CI now runs against python 3.11
63-
64- 0.6.0 - 23 October 2021
65- * Fix bug where it was possible for an async generator fixture to
66- be cleaned up even if it was never started.
67- * This library is now 3.7+ only
68- * Added an equivalent ``shutdown_asyncgen `` to the OverrideLoop helper
69-
70- 0.5.4 - 26 January 2021
71- * Added a ``--default-async-timeout `` option from the CLI. With many thanks
72- to @andredias.
73- * Renamed existing pytest.ini option from ``default_alt_async_timeout `` to
74- be ``default_async_timeout ``.
75-
76- 0.5.3 - 25 July 2020
77- * Make sure a KeyboardInterrupt on running tests still shows errors from
78- failed tests
79-
80- 0.5.2 - 6 February 2020
81- * Added ability to make a different event loop for some tests
82-
83- 0.5.1 - 15 December 2019
84- * Added an ini option ``default_alt_async_timeout `` for the default async
85- timeout for fixtures and tests. The default is now 5 seconds. So say
86- you wanted the default to be 3.5 seconds, you would set
87- ``default_alt_async_timeout `` to be 3.5
88-
89- 0.5 - 16 August 2019
90- * I made this functionality in a work project where I needed to run
91- pytest.main from an existing event loop. I decided to make this it's
92- own module so I can have tests for this code.
93-
94- Installation
95- ------------
96-
97- Most users of this plugin won't need to manually construct the plugin as that's
98- only required if you're doing funky things where you want to manually call
99- ``pytest.main `` (see next section).
100-
101- For this majority case, enabling the plugin requires:
102- * The plugin be installed in the python environment
103- * Adding ``alt_pytest_asyncio.enable `` to the list of pytest plugins that are
104- enabled.
105-
106- Running from your own event loop
107- --------------------------------
108-
109- If you want to run pytest.main from with an existing event loop then you can
110- do something like:
111-
112- .. code-block :: python
113-
114- import alt_pytest_asyncio
115- import nest_asyncio
116- import asyncio
117- import pytest
118-
119- async def my_tests ():
120- await do_some_setup_before_pytest()
121-
122- loop: asyncio.AbstractEventLoop = ...
123-
124- plugins = [
125- alt_pytest_asyncio.plugin.AltPytestAsyncioPlugin(
126- managed_loop = loop
127- ),
128- ]
129-
130- try :
131- code = pytest.main([], plugins = plugins)
132- finally :
133- # Note that alt_pytest_asyncio will make sure all your async tests
134- # have been finalized by this point, even if you KeyboardInterrupt
135- # the pytest.main
136- await do_any_teardown_after_pytest()
137-
138- if code != 0 :
139- raise Exception (repr (code))
140-
141- if __name__ == ' __main__' :
142- # Nest asyncio is required so that we can do run_until_complete in an
143- # existing event loop - https://github.com/erdewit/nest_asyncio
144- loop = asyncio.get_event_loop()
145- nest_asyncio.apply(loop)
146-
147- alt_pytest_asyncio.run_coro_as_main(loop, my_tests())
148-
149- Note that if you don't need to run pytest from an existing event loop, you don't
150- need to do anything other than have ``alt_pytest_asyncio `` installed in your
151- environment and ``alt_pytest_asyncio.enable `` in your pytest plugins list
152- and you'll be able to just use async keywords on your fixtures and
153- tests.
154-
155- Timeouts
156- --------
157-
158- .. note :: The ``pytest.mark.async_timeout(seconds)`` that existed before
159- version 0.9.0 no longer has an effect and has been replaced with the fixtures
160- as mentioned below
161-
162- This plugin can configure the timeout for any async fixture or test using the
163- ``async_timeout `` fixture or by creating a ``default_async_timeout `` fixture.
164-
165- For example:
166-
167- .. code-block :: python
168-
169- import pytest
170- import alt_pytest_asyncio
171-
172- AsyncTimeout = alt_pytest_asyncio.protocols.AsyncTimeout
173-
174- async def test_something (async_timeout : AsyncTimeout) -> None :
175- async_timeout.set_timeout_seconds(10 )
176- await something_that_may_take_a_while()
177-
178- This test will be cancelled after 10 seconds and raise an assertion error saying
179- the test took too long and the file and line number where the test is.
180-
181- .. note :: The async_timeout passed into a fixture or a test is a new instance
182- specific to that fixture or test. Setting it in a fixture only affects that
183- fixture and setting it in a test only affects that test.
184-
185- You can also set a ``default_async_timeout `` fixture to change the default:
186-
187- .. code-block :: python
188-
189- import pytest
190- import alt_pytest_asyncio
191-
192- AsyncTimeout = alt_pytest_asyncio.protocols.AsyncTimeout
193-
194-
195- @pytest.fixture ()
196- def default_async_timeout () -> float :
197- return 0.5
198-
199- @pytest.fixture
200- async def my_amazing_fixture () -> int :
201- # Will timeout because of our default 0.5
202- await asyncio.sleep(1 )
203- return 1
204-
205- @pytest.fixture
206- async def my_amazing_fixture (async_timeout : AsyncTimeout) -> int :
207- # Change timeout for just this fixture
208- async_timeout.set_timeout_seconds(2 )
209- await asyncio.sleep(1 )
210- return 1
211-
212- For fixtures that have a non function scope, they require a
213- ``{scope}_default_async_timeout `` fixture:
214-
215- .. code-block :: python
216-
217- import pytest
218-
219-
220- @pytest.fixture (scope = " session" )
221- def session_default_async_timeout () -> float :
222- return 5
223-
224- @pytest.fixture (scope = " session" )
225- async def some_fixture () -> None :
226- # timeout here is 5
227- pass
228-
229- class TestStuff :
230- @pytest.fixture (scope = " class" )
231- async def some_fixture () -> None :
232- # timeout here is 5
233- pass
234-
235- class TestMore :
236- @pytest.fixture (scope = " class" )
237- async def class_default_async_timeout () -> int :
238- return 8
239-
240- @pytest.fixture (scope = " class" )
241- async def some_fixture () -> None :
242- # timeout here is 8
243- pass
244-
245- The plugin knows about the scopes ``function ``, ``class ``, ``module ``, ``package ``
246- and ``session ``. So say a ``scope="class" `` async fixture is executed, the closest
247- ``class_default_async_timeout `` fixture is used unless that doesn't exist, in which
248- case ``module_default_async_timeout `` is used, otherwise ``package_default_async_timeout ``,
249- otherwise ``session_default_async_timeout ``.
250-
251- There is a default ``session_default_async_timeout `` available which returns the
252- value set by the ``default_async_timeout `` pytest option the plugin provides.
253-
254- And you can have a timeout on generator fixtures:
255-
256- .. code-block :: python
257-
258- import pytest
259- from collections.abc import Iterator
260- import alt_pytest_asyncio
261-
262- AsyncTimeout = alt_pytest_asyncio.protocols.AsyncTimeout
263-
264- @pytest.fixture ()
265- async def my_amazing_fixture (async_timeout : AsyncTimeout) -> Iterator[int ]:
266- async_timeout.set_timeout_seconds(0.5 )
267-
268- try :
269- await asyncio.sleep(1 )
270- yield 1
271- finally :
272- await asyncio.sleep(1 )
273-
274- Note that for generator fixtures, the timeout is applied in whole to both the
275- setup and finalization of the fixture. As in the real timeout for the entire
276- fixture is essentially double the single timeout specified.
277-
278- The default timeout is 5 seconds. You can change this default by setting the
279- ``default_async_timeout `` option to the number of seconds you want.
280-
281- This setting is also available from the CLI using the ``--default-async-timeout ``
282- option.
283-
284- Note that if the timeout fires whilst you have the debugger active then the timeout
285- will not cancel the current test. This is determined by checking if ``sys.gettrace() ``
286- returns a non-None value.
287-
288- The object that is provided when the fixture/test asks for ``async_timeout `` can
289- be modified by overriding the ``async_timeout `` session scope'd fixture and
290- returning an object that inherits from and implements
291- ``alt_pytest_asyncio.base.AsyncTimeoutProvider ``. This is a python "abc" class
292- with a single method ``load `` which is called to return the object given to the
293- fixture or test. This object must implement
294- ``alt_pytest_asyncio.base.AsyncTimeout ``. The default implementation can be found
295- at ``alt_pytest_asyncio.plugin.LoadedAsyncTimeout ``.
296-
297- Overriding the loop
298- -------------------
299-
300- Sometimes it may be necessary to close the current loop in a test. For this to
301- not then break the rest of your tests, you will need to set a new event loop for
302- your test and then restore the old loop afterwards.
303-
304- For this, we have a context manager that will install a new asyncio loop and
305- then restore the original loop on exit.
306-
307- Usage looks like::
308-
309- import alt_pytest_asyncio
310-
311- class TestThing:
312- @pytest.fixture(autouse=True)
313- def custom_loop(self) -> alt_pytest_asyncio.protocols.Loop:
314- with alt_pytest_asyncio.Loop() as custom_loop:
315- yield custom_loop
316-
317- def test_thing(self, custom_loop: alt_pytest_asyncio.protocols.Loop):
318- custom_loop.run_until_complete(my_thing())
319-
320- By putting the loop into an autouse fixture, all fixtures used by the test
321- will have the custom loop. If you want to include module level fixtures too
322- then use the OverrideLoop in a module level fixture too.
323-
324- If the Loop is instantiated with ``new_loop=True `` then it will create and manage
325- a new event loop whilst it's being used as a context manager. This new loop
326- will be available on the object as ``.controlled_loop ``.
327-
328- The ``run_until_complete `` on the ``custom_loop `` in the above example will
329- do a ``run_until_complete `` on the new loop, but in a way that means you
330- won't get ``unhandled exception during shutdown `` errors when the context
331- manager closes the new loop.
332-
333- When the context manager exits and closes the new loop, it will first cancel
334- all tasks to ensure finally blocks are run.
21+ Full documentation can be found at https://alt-pytest-asyncio.readthedocs.io
0 commit comments