pytest-asyncio-concurrent 0.2.3__tar.gz → 0.2.4__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 (24) hide show
  1. {pytest_asyncio_concurrent-0.2.3/pytest_asyncio_concurrent.egg-info → pytest_asyncio_concurrent-0.2.4}/PKG-INFO +1 -1
  2. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/pyproject.toml +2 -2
  3. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/pytest_asyncio_concurrent/plugin.py +32 -72
  4. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4/pytest_asyncio_concurrent.egg-info}/PKG-INFO +1 -1
  5. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/pytest_asyncio_concurrent.egg-info/SOURCES.txt +1 -0
  6. pytest_asyncio_concurrent-0.2.4/tests/test_logging.py +30 -0
  7. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/LICENSE +0 -0
  8. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/README.rst +0 -0
  9. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/pytest_asyncio_concurrent/__init__.py +0 -0
  10. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/pytest_asyncio_concurrent/fixture_async.py +0 -0
  11. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/pytest_asyncio_concurrent/grouping.py +0 -0
  12. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/pytest_asyncio_concurrent/hooks.py +0 -0
  13. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/pytest_asyncio_concurrent.egg-info/dependency_links.txt +0 -0
  14. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/pytest_asyncio_concurrent.egg-info/entry_points.txt +0 -0
  15. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/pytest_asyncio_concurrent.egg-info/requires.txt +0 -0
  16. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/pytest_asyncio_concurrent.egg-info/top_level.txt +0 -0
  17. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/setup.cfg +0 -0
  18. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/tests/test_async_fixture.py +0 -0
  19. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/tests/test_compatibility.py +0 -0
  20. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/tests/test_error.py +0 -0
  21. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/tests/test_fixture_lifecycle.py +0 -0
  22. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/tests/test_fixture_scoping.py +0 -0
  23. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/tests/test_grouping.py +0 -0
  24. {pytest_asyncio_concurrent-0.2.3 → pytest_asyncio_concurrent-0.2.4}/tests/test_status.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pytest-asyncio-concurrent
3
- Version: 0.2.3
3
+ Version: 0.2.4
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.3"
10
+ version = "0.2.4"
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.3"
87
+ current_version = "0.2.4"
88
88
  parse = """(?x)
89
89
  (?P<major>0|[1-9]\\d*)\\.
90
90
  (?P<minor>0|[1-9]\\d*)\\.
@@ -17,7 +17,6 @@ from typing import (
17
17
  Dict,
18
18
  Sequence,
19
19
  Union,
20
- ContextManager,
21
20
  )
22
21
 
23
22
  import pluggy
@@ -169,11 +168,11 @@ def pytest_runtest_protocol_async_group(
169
168
 
170
169
  Hooks order:
171
170
  - pytest_runtest_logstart (batch)
172
- - pytest_runtest_setup_async_group (bank reporting under tests)
171
+ - pytest_runtest_setup_async_group (reporting under first tests)
173
172
  - pytest_runtest_setup (batch) (and reporting)
174
173
  - pytest_runtest_call_async (batch) (and reporting)
175
174
  - pytest_runtest_teardown (batch) (and reporting)
176
- - pytest_runtest_teardown_async_group (bank reporting under tests)
175
+ - pytest_runtest_teardown_async_group (reporting under last tests)
177
176
  - pytest_runtest_logfinish (batch)
178
177
  """
179
178
 
@@ -191,7 +190,6 @@ def pytest_runtest_protocol_async_group(
191
190
  )
192
191
 
193
192
  item_passed_setup: List[AsyncioConcurrentGroupMember] = []
194
- coros: List[Coroutine] = []
195
193
  loop = asyncio.get_event_loop()
196
194
 
197
195
  for childFunc in group.children:
@@ -203,10 +201,12 @@ def pytest_runtest_protocol_async_group(
203
201
  if report.passed:
204
202
  item_passed_setup.append(childFunc)
205
203
 
206
- for childFunc in item_passed_setup:
207
- coros.append(_call_and_report_runtest_async(childFunc))
204
+ coros = [_call_runtest_async(childFunc) for childFunc in item_passed_setup]
205
+ callinfos = loop.run_until_complete(asyncio.gather(*coros))
208
206
 
209
- loop.run_until_complete(asyncio.gather(*coros))
207
+ for childFunc, callinfo in zip(item_passed_setup, callinfos):
208
+ report = childFunc.ihook.pytest_runtest_makereport(item=childFunc, call=callinfo)
209
+ childFunc.ihook.pytest_runtest_logreport(report=report)
210
210
 
211
211
  for childFunc in group.children:
212
212
  _call_and_report(_teardown_child(childFunc, nextgroup=nextgroup), childFunc, "teardown")
@@ -218,17 +218,15 @@ def pytest_runtest_protocol_async_group(
218
218
  return True
219
219
 
220
220
 
221
- async def _call_and_report_runtest_async(item: AsyncioConcurrentGroupMember) -> None:
221
+ async def _call_runtest_async(item: AsyncioConcurrentGroupMember) -> pytest.CallInfo:
222
222
  mark = _get_asyncio_concurrent_mark(item)
223
223
  assert mark
224
224
  timeout = mark.kwargs.get("timeout")
225
225
 
226
- callinfo = await _async_callinfo_from_call(
226
+ return await _async_callinfo_from_call(
227
227
  functools.partial(item.ihook.pytest_runtest_call_async, item=item), # type: ignore
228
228
  timeout=timeout,
229
229
  )
230
- report = item.ihook.pytest_runtest_makereport(item=item, call=callinfo)
231
- item.ihook.pytest_runtest_logreport(report=report)
232
230
 
233
231
 
234
232
  def _setup_child(item: AsyncioConcurrentGroupMember) -> Callable[[], None]:
@@ -314,9 +312,10 @@ async def pytest_runtest_call_async(item: pytest.Function) -> object:
314
312
 
315
313
  pytest.skip("Marking a sync function with @asyncio_concurrent is invalid.")
316
314
 
317
- testfunction = item.obj
318
- testargs = {arg: item.funcargs[arg] for arg in item._fixtureinfo.argnames}
319
- return await testfunction(**testargs)
315
+ with hook_wrapper_entered(item.ihook.pytest_runtest_call, item=item):
316
+ testfunction = item.obj
317
+ testargs = {arg: item.funcargs[arg] for arg in item._fixtureinfo.argnames}
318
+ return await testfunction(**testargs)
320
319
 
321
320
 
322
321
  @pytest.hookimpl(specname="pytest_runtest_setup_async_group")
@@ -374,47 +373,8 @@ def pytest_runtest_teardown_handle_async_function(
374
373
  def pytest_runtest_protocol_async_group_warning(
375
374
  group: "AsyncioConcurrentGroup", nextgroup: Optional["AsyncioConcurrentGroup"]
376
375
  ) -> Generator[None, object, object]:
377
- with_pytest_runtest_protocol_warning = _with_specific_hook_wrapped(
378
- group.ihook.pytest_runtest_protocol, "warnings"
379
- )
380
-
381
- if with_pytest_runtest_protocol_warning:
382
- with with_pytest_runtest_protocol_warning(item=group, nextitem=nextgroup):
383
- result = yield
384
-
385
- return result
386
-
387
- return (yield)
388
-
389
-
390
- @pytest.hookimpl(specname="pytest_runtest_call_async", wrapper=True, tryfirst=True)
391
- def pytest_runtest_call_async_logging(item: pytest.Item) -> Generator[None, object, object]:
392
- with_pytest_runtest_call_logging = _with_specific_hook_wrapped(
393
- item.ihook.pytest_runtest_call, "logging-plugin"
394
- )
395
-
396
- if with_pytest_runtest_call_logging:
397
- with with_pytest_runtest_call_logging(item=item):
398
- result = yield
399
-
400
- return result
401
-
402
- return (yield)
403
-
404
-
405
- @pytest.hookimpl(specname="pytest_runtest_call_async", wrapper=True, tryfirst=True)
406
- def pytest_runtest_call_async_capture(item: pytest.Item) -> Generator[None, object, object]:
407
- with_pytest_runtest_call_capture = _with_specific_hook_wrapped(
408
- item.ihook.pytest_runtest_call, "capturemanager"
409
- )
410
-
411
- if with_pytest_runtest_call_capture:
412
- with with_pytest_runtest_call_capture(item=item):
413
- result = yield
414
-
415
- return result
416
-
417
- return (yield)
376
+ with hook_wrapper_entered(group.ihook.pytest_runtest_protocol, item=group, nextitem=nextgroup):
377
+ return (yield)
418
378
 
419
379
 
420
380
  # =========================== # helper #===========================#
@@ -488,23 +448,23 @@ def _call_and_report(
488
448
  return report
489
449
 
490
450
 
491
- def _with_specific_hook_wrapped(
451
+ @contextlib.contextmanager
452
+ def hook_wrapper_entered(
492
453
  hook: pluggy.HookCaller,
493
- plugin: str,
494
- ) -> Optional[Callable[..., ContextManager]]:
495
- try:
496
- hookimpl = next(h for h in hook.get_hookimpls() if h.plugin_name == plugin)
497
- except StopIteration:
498
- return None
454
+ **kwds: Any,
455
+ ) -> Generator[None, None, Any]:
456
+ """
457
+ # Capture and logging are hard to handle without duplicating huge amount of code,
458
+ # so reusing defined hooks wrapper here.
459
+ """
460
+ with contextlib.ExitStack() as es:
461
+ for hookimpl in hook.get_hookimpls():
462
+ if not hookimpl.wrapper:
463
+ continue
464
+ es.enter_context(
465
+ contextlib.contextmanager(hookimpl.function)( # type: ignore
466
+ **{k: v for k, v in kwds.items() if k in hookimpl.argnames}
467
+ )
468
+ )
499
469
 
500
- @contextlib.contextmanager
501
- def cm(**kwargs: Dict) -> Generator:
502
- gen = hookimpl.function(**{k: v for k, v in kwargs.items() if k in hookimpl.argnames})
503
- next(gen) # type: ignore
504
470
  yield
505
- try:
506
- next(gen) # type: ignore
507
- except StopIteration:
508
- pass
509
-
510
- return cm
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pytest-asyncio-concurrent
3
- Version: 0.2.3
3
+ Version: 0.2.4
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>
@@ -18,4 +18,5 @@ tests/test_error.py
18
18
  tests/test_fixture_lifecycle.py
19
19
  tests/test_fixture_scoping.py
20
20
  tests/test_grouping.py
21
+ tests/test_logging.py
21
22
  tests/test_status.py
@@ -0,0 +1,30 @@
1
+ from textwrap import dedent
2
+ import pytest
3
+
4
+
5
+ def test_log(pytester: pytest.Pytester):
6
+ """log should not break tests"""
7
+
8
+ pytester.makepyfile(
9
+ dedent(
10
+ """\
11
+ import asyncio
12
+ import pytest
13
+ import logging
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ @pytest.mark.parametrize("p", [0, 1, 2, 3, 4])
18
+ @pytest.mark.asyncio_concurrent(group="log")
19
+ async def test_log(p):
20
+ await asyncio.sleep(p / 10)
21
+ logger.info("info log would be captured")
22
+ logger.debug("debug log would not be captured")
23
+ """
24
+ )
25
+ )
26
+
27
+ result = pytester.runpytest("--log-cli-level=INFO")
28
+ result.assert_outcomes(passed=5, errors=0)
29
+ assert len([line for line in result.outlines if "info log would be captured" in line]) == 5
30
+ assert len([line for line in result.outlines if "debug log would not be captured" in line]) == 0