pytest-asyncio-concurrent 0.2.0__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. {pytest_asyncio_concurrent-0.2.0/pytest_asyncio_concurrent.egg-info → pytest_asyncio_concurrent-0.2.2}/PKG-INFO +2 -2
  2. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/pyproject.toml +2 -2
  3. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/pytest_asyncio_concurrent/plugin.py +88 -52
  4. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2/pytest_asyncio_concurrent.egg-info}/PKG-INFO +2 -2
  5. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/LICENSE +0 -0
  6. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/README.rst +0 -0
  7. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/pytest_asyncio_concurrent/__init__.py +0 -0
  8. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/pytest_asyncio_concurrent/fixture_async.py +0 -0
  9. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/pytest_asyncio_concurrent/grouping.py +0 -0
  10. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/pytest_asyncio_concurrent/hooks.py +0 -0
  11. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/pytest_asyncio_concurrent.egg-info/SOURCES.txt +0 -0
  12. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/pytest_asyncio_concurrent.egg-info/dependency_links.txt +0 -0
  13. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/pytest_asyncio_concurrent.egg-info/entry_points.txt +0 -0
  14. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/pytest_asyncio_concurrent.egg-info/requires.txt +0 -0
  15. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/pytest_asyncio_concurrent.egg-info/top_level.txt +0 -0
  16. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/setup.cfg +0 -0
  17. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/tests/test_async_fixture.py +0 -0
  18. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/tests/test_compatibility.py +0 -0
  19. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/tests/test_error.py +0 -0
  20. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/tests/test_fixture_lifecycle.py +0 -0
  21. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/tests/test_fixture_scoping.py +0 -0
  22. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/tests/test_grouping.py +0 -0
  23. {pytest_asyncio_concurrent-0.2.0 → pytest_asyncio_concurrent-0.2.2}/tests/test_status.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: pytest-asyncio-concurrent
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Pytest plugin to execute python async tests concurrently.
5
5
  Author-email: Zane Chen <czl970721@gmail.com>
6
6
  Maintainer-email: Zane Chen <czl970721@gmail.com>
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
  [project]
8
8
  name = "pytest-asyncio-concurrent"
9
9
  description = "Pytest plugin to execute python async tests concurrently."
10
- version = "0.2.0"
10
+ version = "0.2.2"
11
11
  readme = "README.rst"
12
12
  requires-python = ">=3.8"
13
13
  authors = [
@@ -84,7 +84,7 @@ concurrency = [
84
84
  show_missing = true
85
85
 
86
86
  [tool.bumpversion]
87
- current_version = "0.2.0"
87
+ current_version = "0.2.2"
88
88
  parse = """(?x)
89
89
  (?P<major>0|[1-9]\\d*)\\.
90
90
  (?P<minor>0|[1-9]\\d*)\\.
@@ -1,8 +1,10 @@
1
1
  import asyncio
2
+ import functools
2
3
  import inspect
3
4
  import uuid
4
5
  import warnings
5
6
  import sys
7
+ import contextlib
6
8
 
7
9
  from typing import (
8
10
  Any,
@@ -15,12 +17,13 @@ from typing import (
15
17
  Dict,
16
18
  Sequence,
17
19
  Union,
20
+ ContextManager,
18
21
  )
19
22
 
23
+ import pluggy
20
24
  import pytest
21
25
  from _pytest import timing
22
26
  from _pytest import outcomes
23
- from _pytest import warnings as pytest_warnings
24
27
 
25
28
  from .grouping import (
26
29
  AsyncioConcurrentGroup,
@@ -187,37 +190,27 @@ def pytest_runtest_protocol_async_group(
187
190
  )
188
191
  )
189
192
 
190
- children_passed_setup: List[pytest.Function] = []
193
+ item_passed_setup: List[AsyncioConcurrentGroupMember] = []
194
+ coros: List[Coroutine] = []
195
+ loop = asyncio.get_event_loop()
191
196
 
192
197
  for childFunc in group.children:
193
198
  childFunc.ihook.pytest_runtest_logstart(
194
199
  nodeid=childFunc.nodeid, location=childFunc.location
195
200
  )
196
201
 
197
- for childFunc in group.children:
198
- # bundle group setup with test setup until it pass
199
- # (which should either pass on first item, or fail all the way till end)
200
- report = _call_and_report(
201
- _setup_child(childFunc, with_group=(not group.has_setup)), childFunc, "setup"
202
- )
202
+ report = _call_and_report(_setup_child(childFunc), childFunc, "setup")
203
+ if report.passed:
204
+ item_passed_setup.append(childFunc)
203
205
 
204
- if report.passed and group.has_setup:
205
- children_passed_setup.append(childFunc)
206
- continue
206
+ for childFunc in item_passed_setup:
207
+ coros.append(_call_and_report_runtest_async(childFunc))
207
208
 
208
- _pytest_runtest_call_and_report_async_group(children_passed_setup)
209
-
210
- for i, childFunc in enumerate(group.children):
211
- # teardown group with the last test.
212
- _call_and_report(
213
- _teardown_child(
214
- childFunc, nextgroup=nextgroup, with_group=(i == len(group.children) - 1)
215
- ),
216
- childFunc,
217
- "teardown",
218
- )
209
+ loop.run_until_complete(asyncio.gather(*coros))
219
210
 
220
211
  for childFunc in group.children:
212
+ _call_and_report(_teardown_child(childFunc, nextgroup=nextgroup), childFunc, "teardown")
213
+
221
214
  childFunc.ihook.pytest_runtest_logfinish(
222
215
  nodeid=childFunc.nodeid, location=childFunc.location
223
216
  )
@@ -225,29 +218,15 @@ def pytest_runtest_protocol_async_group(
225
218
  return True
226
219
 
227
220
 
228
- def _pytest_runtest_call_and_report_async_group(items: List[pytest.Function]) -> None:
229
- def hook_invoker(item: pytest.Function) -> Callable[[], Coroutine]:
230
- def inner() -> Coroutine:
231
- return childFunc.ihook.pytest_runtest_call_async(item=item)
232
-
233
- return inner
234
-
235
- coros: List[Coroutine] = []
236
- loop = asyncio.get_event_loop()
237
-
238
- for childFunc in items:
239
- coros.append(_async_callinfo_from_call(hook_invoker(childFunc)))
240
-
241
- call_result = loop.run_until_complete(asyncio.gather(*coros))
242
-
243
- for childFunc, call in zip(items, call_result):
244
- report = childFunc.ihook.pytest_runtest_makereport(item=childFunc, call=call)
245
- childFunc.ihook.pytest_runtest_logreport(report=report)
221
+ async def _call_and_report_runtest_async(item: AsyncioConcurrentGroupMember) -> None:
222
+ callinfo = await _async_callinfo_from_call(
223
+ functools.partial(item.ihook.pytest_runtest_call_async, item=item) # type: ignore
224
+ )
225
+ report = item.ihook.pytest_runtest_makereport(item=item, call=callinfo)
226
+ item.ihook.pytest_runtest_logreport(report=report)
246
227
 
247
228
 
248
- def _setup_child(
249
- item: AsyncioConcurrentGroupMember, with_group: bool = False
250
- ) -> Callable[[], None]:
229
+ def _setup_child(item: AsyncioConcurrentGroupMember) -> Callable[[], None]:
251
230
  """
252
231
  Setup flow for normal pytest tests:
253
232
  - Push all nodes onto `SetupState`, start from furthest.
@@ -263,7 +242,7 @@ def _setup_child(
263
242
  """
264
243
 
265
244
  def inner() -> None:
266
- if with_group:
245
+ if not item.group.has_setup:
267
246
  item.ihook.pytest_runtest_setup_async_group(item=item.group)
268
247
 
269
248
  item.config.pluginmanager.subset_hook_caller(
@@ -276,7 +255,6 @@ def _setup_child(
276
255
  def _teardown_child(
277
256
  item: AsyncioConcurrentGroupMember,
278
257
  nextgroup: Optional[AsyncioConcurrentGroup],
279
- with_group: bool = False,
280
258
  ) -> Callable[[], None]:
281
259
  """
282
260
  Similar to setup.
@@ -300,7 +278,7 @@ def _teardown_child(
300
278
  exceptions.append(e)
301
279
 
302
280
  try:
303
- if with_group:
281
+ if len(item.group.children_finalizer) == 0:
304
282
  item.ihook.pytest_runtest_teardown_async_group(item=item.group, nextitem=nextgroup)
305
283
  except Exception as e:
306
284
  if isinstance(e, BaseExceptionGroup):
@@ -384,18 +362,54 @@ def pytest_runtest_teardown_handle_async_function(
384
362
  item.group.teardown_child(item)
385
363
 
386
364
 
387
- # =========================== # warnings #===========================#
365
+ # =========================== # Captures #===========================#
388
366
 
389
367
 
390
368
  @pytest.hookimpl(specname="pytest_runtest_protocol_async_group", wrapper=True, tryfirst=True)
391
369
  def pytest_runtest_protocol_async_group_warning(
392
370
  group: "AsyncioConcurrentGroup", nextgroup: Optional["AsyncioConcurrentGroup"]
393
371
  ) -> Generator[None, object, object]:
394
- config = group.children[0].config
395
- with pytest_warnings.catch_warnings_for_item(
396
- config=config, ihook=group.children[0].ihook, when="runtest", item=None
397
- ):
398
- return (yield)
372
+ with_pytest_runtest_protocol_warning = _with_specific_hook_wrapped(
373
+ group.ihook.pytest_runtest_protocol, "warnings"
374
+ )
375
+
376
+ if with_pytest_runtest_protocol_warning:
377
+ with with_pytest_runtest_protocol_warning(item=group, nextitem=nextgroup):
378
+ result = yield
379
+
380
+ return result
381
+
382
+ return (yield)
383
+
384
+
385
+ @pytest.hookimpl(specname="pytest_runtest_call_async", wrapper=True, tryfirst=True)
386
+ def pytest_runtest_call_async_logging(item: pytest.Item) -> Generator[None, object, object]:
387
+ with_pytest_runtest_call_logging = _with_specific_hook_wrapped(
388
+ item.ihook.pytest_runtest_call, "logging-plugin"
389
+ )
390
+
391
+ if with_pytest_runtest_call_logging:
392
+ with with_pytest_runtest_call_logging(item=item):
393
+ result = yield
394
+
395
+ return result
396
+
397
+ return (yield)
398
+
399
+
400
+ @pytest.hookimpl(specname="pytest_runtest_call_async", wrapper=True, tryfirst=True)
401
+ def pytest_runtest_call_async_capture(item: pytest.Item) -> Generator[None, object, object]:
402
+ with_pytest_runtest_call_capture = _with_specific_hook_wrapped(
403
+ item.ihook.pytest_runtest_call, "capturemanager"
404
+ )
405
+
406
+ if with_pytest_runtest_call_capture:
407
+ with with_pytest_runtest_call_capture(item=item):
408
+ result = yield
409
+
410
+ return result
411
+
412
+ return (yield)
399
413
 
400
414
 
401
415
  # =========================== # helper #===========================#
@@ -465,3 +479,25 @@ def _call_and_report(
465
479
  ):
466
480
  item.ihook.pytest_exception_interact(node=item, call=call, report=report)
467
481
  return report
482
+
483
+
484
+ def _with_specific_hook_wrapped(
485
+ hook: pluggy.HookCaller,
486
+ plugin: str,
487
+ ) -> Optional[Callable[..., ContextManager]]:
488
+ try:
489
+ hookimpl = next(h for h in hook.get_hookimpls() if h.plugin_name == plugin)
490
+ except StopIteration:
491
+ return None
492
+
493
+ @contextlib.contextmanager
494
+ def cm(**kwargs: Dict) -> Generator:
495
+ gen = hookimpl.function(**{k: v for k, v in kwargs.items() if k in hookimpl.argnames})
496
+ next(gen) # type: ignore
497
+ yield
498
+ try:
499
+ next(gen) # type: ignore
500
+ except StopIteration:
501
+ pass
502
+
503
+ return cm
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: pytest-asyncio-concurrent
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Pytest plugin to execute python async tests concurrently.
5
5
  Author-email: Zane Chen <czl970721@gmail.com>
6
6
  Maintainer-email: Zane Chen <czl970721@gmail.com>