1919_ENV_VARS = ("SIFT_API_KEY" , "SIFT_GRPC_URI" , "SIFT_REST_URI" )
2020
2121_PARAMETRIZE_PATH_KEY = pytest .StashKey [tuple [str , ...]]()
22- _PARAMETRIZE_STACK : list [NewStep ] = []
22+ # Each frame: (path_key, open NewStep). Frames are shared across sibling test
23+ # items and drained at module teardown / session end.
24+ _PARAMETRIZE_STACK : list [tuple [str , NewStep ]] = []
25+
26+
27+ def _drain_parametrize_stack () -> None :
28+ while _PARAMETRIZE_STACK :
29+ _ , ns = _PARAMETRIZE_STACK .pop ()
30+ ns .__exit__ (None , None , None )
2331
2432
2533def _build_parametrize_path (item : pytest .Item ) -> tuple [str , ...]:
@@ -47,8 +55,7 @@ def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item
4755
4856def pytest_sessionfinish (session : pytest .Session , exitstatus : int ) -> None :
4957 """Drain any parametrize parents still open (e.g. when module_substep was disabled)."""
50- while _PARAMETRIZE_STACK :
51- _PARAMETRIZE_STACK .pop ().__exit__ (None , None , None )
58+ _drain_parametrize_stack ()
5259
5360
5461def pytest_addoption (parser : pytest .Parser ) -> None :
@@ -242,14 +249,8 @@ def _step_impl(
242249 report_context : ReportContext , request : pytest .FixtureRequest
243250) -> Generator [NewStep , None , None ]:
244251 item = request .node
245- callspec = getattr (item , "callspec" , None )
246- if callspec is not None and callspec .params :
247- # Bottom decorator's axis is first in callspec.params, which matches the
248- # innermost (leaf) frame in the parametrize path.
249- axis , value = next (iter (callspec .params .items ()))
250- name = f"{ axis } ={ value !r} "
251- else :
252- name = str (item .name )
252+ path = item .stash .get (_PARAMETRIZE_PATH_KEY , ())
253+ name = path [- 1 ] if path else str (item .name )
253254 existing_docstring = item .obj .__doc__ or None
254255 with report_context .new_step (
255256 name = name , description = existing_docstring , assertion_as_fail_not_error = False
@@ -278,19 +279,20 @@ def _parametrize_parents(
278279 """
279280 desired = request .node .stash .get (_PARAMETRIZE_PATH_KEY , ())
280281 parents = desired [:- 1 ]
281- open_keys = [getattr (ns , "_parametrize_key" , None ) for ns in _PARAMETRIZE_STACK ]
282282 common = 0
283283 while (
284- common < len (open_keys ) and common < len (parents ) and open_keys [common ] == parents [common ]
284+ common < len (_PARAMETRIZE_STACK )
285+ and common < len (parents )
286+ and _PARAMETRIZE_STACK [common ][0 ] == parents [common ]
285287 ):
286288 common += 1
287289 while len (_PARAMETRIZE_STACK ) > common :
288- _PARAMETRIZE_STACK .pop ().__exit__ (None , None , None )
290+ _ , ns = _PARAMETRIZE_STACK .pop ()
291+ ns .__exit__ (None , None , None )
289292 for display in parents [common :]:
290293 ns = report_context .new_step (name = display , assertion_as_fail_not_error = False )
291294 ns .__enter__ ()
292- ns ._parametrize_key = display # type: ignore[attr-defined]
293- _PARAMETRIZE_STACK .append (ns )
295+ _PARAMETRIZE_STACK .append ((display , ns ))
294296 yield
295297
296298
@@ -316,8 +318,6 @@ def module_substep(
316318 name = name , description = existing_docstring , assertion_as_fail_not_error = False
317319 ) as new_step :
318320 yield new_step
319- # Drain parametrize parents nested under this module before the module
320- # step exits — otherwise ReportContext.exit_step asserts that the module
321- # step is the stack top.
322- while _PARAMETRIZE_STACK :
323- _PARAMETRIZE_STACK .pop ().__exit__ (None , None , None )
321+ # Drain parametrize parents nested under this module step before it
322+ # exits — ReportContext.exit_step asserts the module step is the top.
323+ _drain_parametrize_stack ()
0 commit comments