Coverage for human_requests/pytest_plugin/_runtime.py: 90%
69 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-05-28 00:39 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-05-28 00:39 +0000
1from __future__ import annotations
3import asyncio
4from collections.abc import Coroutine
5from typing import Any, Callable, TypeVar
7import pytest
9from ..autotest import execute_autotests, execute_autotests_with_subtests
10from ._config import (
11 get_trace_limit,
12 get_truncation_context_lines,
13 get_typecheck_mode,
14 resolve_runtime_dependencies,
15)
17T = TypeVar("T")
20def run_autotest_tree_sync(request: pytest.FixtureRequest) -> None:
21 api, schemashot = resolve_runtime_dependencies(request)
22 typecheck_mode = get_typecheck_mode(request.config)
23 trace_limit = get_trace_limit(request.config)
24 truncation_context_lines = get_truncation_context_lines(request.config)
25 subtests = _resolve_subtests_fixture(request)
26 case_status_recorder = _resolve_case_status_recorder(request)
27 success_recorder = _resolve_success_recorder(request)
28 executed_count = run_coroutine(
29 _execute_autotests_async(
30 api=api,
31 schemashot=schemashot,
32 typecheck_mode=typecheck_mode,
33 trace_limit=trace_limit,
34 truncation_context_lines=truncation_context_lines,
35 subtests=subtests,
36 case_status_recorder=case_status_recorder,
37 success_recorder=success_recorder,
38 )
39 )
40 if executed_count == 0:
41 pytest.skip("No methods marked with @autotest were found in the api tree.")
44@pytest.mark.usefixtures("_autotest_anyio_runner")
45def run_autotest_tree_anyio(request: pytest.FixtureRequest) -> None:
46 runner = request.getfixturevalue("_autotest_anyio_runner")
47 api, schemashot = resolve_runtime_dependencies(request)
48 typecheck_mode = get_typecheck_mode(request.config)
49 trace_limit = get_trace_limit(request.config)
50 truncation_context_lines = get_truncation_context_lines(request.config)
51 subtests = _resolve_subtests_fixture(request)
52 case_status_recorder = _resolve_case_status_recorder(request)
53 success_recorder = _resolve_success_recorder(request)
54 executed_count = runner.run_test(
55 _execute_autotests_async,
56 {
57 "api": api,
58 "schemashot": schemashot,
59 "typecheck_mode": typecheck_mode,
60 "trace_limit": trace_limit,
61 "truncation_context_lines": truncation_context_lines,
62 "subtests": subtests,
63 "case_status_recorder": case_status_recorder,
64 "success_recorder": success_recorder,
65 },
66 )
67 if executed_count == 0:
68 pytest.skip("No methods marked with @autotest were found in the api tree.")
71@pytest.fixture
72def _autotest_anyio_runner(anyio_backend: Any) -> Any:
73 from anyio.pytest_plugin import extract_backend_and_options, get_runner
75 backend_name, backend_options = extract_backend_and_options(anyio_backend)
76 with get_runner(backend_name, backend_options) as runner:
77 yield runner
80async def _execute_autotests_async(
81 api: object,
82 schemashot: Any,
83 typecheck_mode: str,
84 trace_limit: int,
85 truncation_context_lines: int,
86 subtests: Any | None = None,
87 case_status_recorder: Callable[[str, str], None] | None = None,
88 success_recorder: Any | None = None,
89) -> int:
90 if subtests is not None:
91 return await execute_autotests_with_subtests(
92 api=api,
93 schemashot=schemashot,
94 subtests=subtests,
95 typecheck_mode=typecheck_mode,
96 trace_limit=trace_limit,
97 truncation_context_lines=truncation_context_lines,
98 case_status_recorder=case_status_recorder,
99 success_recorder=success_recorder,
100 )
101 return await execute_autotests(
102 api=api,
103 schemashot=schemashot,
104 typecheck_mode=typecheck_mode,
105 trace_limit=trace_limit,
106 truncation_context_lines=truncation_context_lines,
107 case_status_recorder=case_status_recorder,
108 success_recorder=success_recorder,
109 )
112def _resolve_subtests_fixture(request: pytest.FixtureRequest) -> Any | None:
113 if not request.config.pluginmanager.has_plugin("subtests"):
114 return None
115 try:
116 return request.getfixturevalue("subtests")
117 except pytest.FixtureLookupError:
118 return None
121def _resolve_success_recorder(request: pytest.FixtureRequest) -> Callable[[str], None]:
122 config = request.config
123 setattr(config, "_human_requests_autotest_success_labels", [])
125 def _record_success(label: str) -> None:
126 labels = getattr(config, "_human_requests_autotest_success_labels", [])
127 labels.append(label)
129 return _record_success
132def _resolve_case_status_recorder(request: pytest.FixtureRequest) -> Callable[[str, str], None]:
133 config = request.config
134 setattr(config, "_human_requests_autotest_case_records", [])
136 def _record_status(label: str, status: str) -> None:
137 records = getattr(config, "_human_requests_autotest_case_records", [])
138 records.append((label, status))
140 return _record_status
143def run_coroutine(coro: Coroutine[Any, Any, T]) -> T:
144 try:
145 asyncio.get_running_loop()
146 except RuntimeError:
147 return asyncio.run(coro)
148 raise RuntimeError(
149 "Autotest plugin is running inside an active event loop. "
150 "Run it from a synchronous pytest context."
151 )