1111import pytest
1212
1313from consensus_testing .crypto_mode import AggregationProver , CryptoMode
14- from consensus_testing .forks import FORKS_BY_NAME
14+ from consensus_testing .forks import FORKS_BY_NAME , BaseFork
1515from consensus_testing .keys import DEFAULT_MAX_SLOT , XmssKeyManager
1616from consensus_testing .test_fixtures import FIXTURE_FORMATS , FixtureInfo
1717from lean_spec .spec .forks import Slot , ValidatorIndex
@@ -103,9 +103,11 @@ def add_fixture(
103103
104104 if config is not None :
105105 fixture_path = self .fixture_output_file (test_nodeid , fixture_format )
106- config .fixture_path_absolute = str (fixture_path .absolute ()) # type: ignore[attribute-defined]
107- config .fixture_path_relative = str (fixture_path .relative_to (self .output_directory )) # type: ignore[attribute-defined]
108- config .fixture_format = fixture_format # type: ignore[attribute-defined]
106+ config .stash [FIXTURE_PATH_ABSOLUTE_KEY ] = str (fixture_path .absolute ())
107+ config .stash [FIXTURE_PATH_RELATIVE_KEY ] = str (
108+ fixture_path .relative_to (self .output_directory )
109+ )
110+ config .stash [FIXTURE_FORMAT_KEY ] = fixture_format
109111
110112 def write_fixtures (self ) -> None :
111113 """Write all collected fixtures to disk, grouped by test function."""
@@ -127,6 +129,22 @@ def write_fixtures(self) -> None:
127129 json .dump (all_tests , output_handle , indent = 4 )
128130
129131
132+ FIXTURE_COLLECTOR_KEY : pytest .StashKey [FixtureCollector ] = pytest .StashKey ()
133+ """Stash key for the session's fixture collector."""
134+
135+ TEST_FORK_CLASS_KEY : pytest .StashKey [type [BaseFork ]] = pytest .StashKey ()
136+ """Stash key for the fork class selected by the fork option."""
137+
138+ FIXTURE_PATH_ABSOLUTE_KEY : pytest .StashKey [str ] = pytest .StashKey ()
139+ """Stash key for the absolute path of the current test's fixture file."""
140+
141+ FIXTURE_PATH_RELATIVE_KEY : pytest .StashKey [str ] = pytest .StashKey ()
142+ """Stash key for the current test's fixture path relative to the output directory."""
143+
144+ FIXTURE_FORMAT_KEY : pytest .StashKey [str ] = pytest .StashKey ()
145+ """Stash key for the current test's fixture format name."""
146+
147+
130148def pytest_addoption (parser : pytest .Parser ) -> None :
131149 """Add command-line options for fixture generation."""
132150 group = parser .getgroup ("fill" , "leanSpec fixture generation" )
@@ -219,8 +237,8 @@ def pytest_configure(config: pytest.Config) -> None:
219237 )
220238 pytest .exit ("Missing required --fork option." , returncode = pytest .ExitCode .USAGE_ERROR )
221239
222- fork_class = FORKS_BY_NAME . get ( fork_name .lower () )
223- if fork_class is None :
240+ fork_name_normalized = fork_name .lower ()
241+ if fork_name_normalized not in FORKS_BY_NAME :
224242 print (
225243 f"Error: Unsupported fork: { fork_name } \n " ,
226244 file = sys .stderr ,
@@ -231,6 +249,8 @@ def pytest_configure(config: pytest.Config) -> None:
231249 )
232250 pytest .exit ("Invalid fork specified." , returncode = pytest .ExitCode .USAGE_ERROR )
233251
252+ fork_class = FORKS_BY_NAME [fork_name_normalized ]
253+
234254 # Check output directory
235255 if output_directory .exists () and any (output_directory .iterdir ()):
236256 if not clean :
@@ -250,8 +270,8 @@ def pytest_configure(config: pytest.Config) -> None:
250270
251271 output_directory .mkdir (parents = True , exist_ok = True )
252272
253- config .fixture_collector = FixtureCollector (output_directory , fork_name ) # type: ignore[attribute-defined]
254- config .test_fork_class = fork_class # type: ignore[attribute-defined]
273+ config .stash [ FIXTURE_COLLECTOR_KEY ] = FixtureCollector (output_directory , fork_name )
274+ config .stash [ TEST_FORK_CLASS_KEY ] = fork_class
255275
256276
257277def pytest_collection_modifyitems (config : pytest .Config , items : list [pytest .Item ]) -> None :
@@ -261,10 +281,10 @@ def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item
261281 Real-crypto vectors cannot be mocked, so the fast mocked lane keeps only the
262282 smoke subset and leaves the rest to the real lane.
263283 """
264- if not hasattr ( config , "test_fork_class" ) :
284+ if TEST_FORK_CLASS_KEY not in config . stash :
265285 return
266286
267- fork_class = config .test_fork_class
287+ fork_class = config .stash [ TEST_FORK_CLASS_KEY ]
268288 verbose = config .getoption ("verbose" )
269289 mocking = AggregationProver .get_mode () == CryptoMode .MOCKED
270290 deselected_items = []
@@ -349,8 +369,8 @@ def pytest_sessionstart(session: pytest.Session) -> None:
349369
350370def pytest_sessionfinish (session : pytest .Session , exitstatus : int ) -> None :
351371 """Write all collected fixtures at the end of the session."""
352- if hasattr ( session .config , "fixture_collector" ) :
353- session .config .fixture_collector .write_fixtures ()
372+ if FIXTURE_COLLECTOR_KEY in session .config . stash :
373+ session .config .stash [ FIXTURE_COLLECTOR_KEY ] .write_fixtures ()
354374
355375
356376@pytest .hookimpl (tryfirst = True , hookwrapper = True )
@@ -360,17 +380,16 @@ def pytest_runtest_makereport(item: pytest.Item, call: pytest.CallInfo[None]) ->
360380 report = outcome .get_result ()
361381
362382 if call .when == "call" :
363- if hasattr (item .config , "fixture_path_absolute" ) and hasattr (
364- item .config , "fixture_path_relative"
365- ):
383+ stash = item .config .stash
384+ if FIXTURE_PATH_ABSOLUTE_KEY in stash and FIXTURE_PATH_RELATIVE_KEY in stash :
366385 report .user_properties .append (
367- ("fixture_path_absolute" , item . config . fixture_path_absolute )
386+ ("fixture_path_absolute" , stash [ FIXTURE_PATH_ABSOLUTE_KEY ] )
368387 )
369388 report .user_properties .append (
370- ("fixture_path_relative" , item . config . fixture_path_relative )
389+ ("fixture_path_relative" , stash [ FIXTURE_PATH_RELATIVE_KEY ] )
371390 )
372- if hasattr ( item . config , "fixture_format" ) :
373- report .user_properties .append (("fixture_format" , item . config . fixture_format ))
391+ if FIXTURE_FORMAT_KEY in stash :
392+ report .user_properties .append (("fixture_format" , stash [ FIXTURE_FORMAT_KEY ] ))
374393
375394
376395@pytest .fixture
@@ -470,8 +489,8 @@ def fill_and_collect(**spec_fields: Any) -> Any:
470489 network = fork .name (),
471490 ).model_copy (update = {"proof_setting" : proof_setting })
472491
473- if hasattr ( request .config , "fixture_collector" ) :
474- request .config .fixture_collector .add_fixture (
492+ if FIXTURE_COLLECTOR_KEY in request .config . stash :
493+ request .config .stash [ FIXTURE_COLLECTOR_KEY ] .add_fixture (
475494 fixture_format = spec_class .format_name ,
476495 fixture = filled_fixture ,
477496 test_nodeid = request .node .nodeid ,
@@ -489,7 +508,7 @@ def pytest_generate_tests(metafunc: pytest.Metafunc) -> None:
489508 if "fork" not in metafunc .fixturenames :
490509 return
491510
492- fork_class = metafunc .config .test_fork_class # type: ignore[attribute-defined ]
511+ fork_class = metafunc .config .stash [ TEST_FORK_CLASS_KEY ]
493512
494513 if not _check_markers_valid_for_fork (list (metafunc .definition .iter_markers ()), fork_class ):
495514 verbose = metafunc .config .getoption ("verbose" )
0 commit comments