diff --git a/src/ape/pytest/runners.py b/src/ape/pytest/runners.py index d8e89faa7c..f15adba0d1 100644 --- a/src/ape/pytest/runners.py +++ b/src/ape/pytest/runners.py @@ -242,13 +242,47 @@ def pytest_runtest_setup(self, item): snapshot = self.isolation_manager.get_snapshot(scope) + # Gather new fixtures. Also, be mindful of parametrized fixtures + # which strangely have the same name. + new_fixtures = [] + for custom_fixture in custom_fixtures: + if custom_fixture not in snapshot.fixtures: + # Is simply a new a fixture. + new_fixtures.append(custom_fixture) + continue + + # Check if it is the next iteration of a parametrized fixture. + if custom_fixture in fixture_defs: + fixture_infos = fixture_defs[custom_fixture] + for fixture_info in fixture_infos: + params = fixture_info.params + if params is None: + # Not a parametrized fixture. + continue + + cached_result = fixture_info.cached_result + if cached_result is None: + # Already added but not yet ran? + continue + + last_known_fixture_param = cached_result[1] + if last_known_fixture_param == params[-1]: + # We have already updated since the last iteration. + continue + + # Else, this fixture has come up again, meaning we are now + # on the next iteration. This is basically the same situation + # as more fixtures of a certain scope coming in late, and + # has all the same performance problems. Thus, it is highly + # not recommended to use parametrized fixtures in Ape. + new_fixtures.append(custom_fixture) + # Check for fixtures that are now invalid. For example, imagine a session # fixtures comes into play after the module snapshot has been set. # Once we restore the module's state and move to the next module, # that session fixture will no longer exist. To remedy this situation, # we invalidate the lower-scoped fixtures and re-run them and re-snapshot # everything (mega performance loss, unfortunately). - new_fixtures = [f for f in custom_fixtures if f not in snapshot.fixtures] if new_fixtures and snapshot.fixtures: invalid_fixtures = defaultdict(list) scope_to_revert = None diff --git a/tests/integration/cli/projects/test/tests/test_fixture_isolation.py b/tests/integration/cli/projects/test/tests/test_fixture_isolation.py index 4e06d4f589..bca4b9b83f 100644 --- a/tests/integration/cli/projects/test/tests/test_fixture_isolation.py +++ b/tests/integration/cli/projects/test/tests/test_fixture_isolation.py @@ -98,3 +98,21 @@ def test_isolation_module_ran_after(chain): def test_parametrized_fixtures(start_block_number, chain, parametrized_mining): assert chain.blocks.height == start_block_number + parametrized_mining + + +@pytest.fixture(scope="session", params=(5, 6, 7)) +def parametrized_transaction(request, alice, bob): + """ + 2 more get added to the session here! + """ + return alice.transfer(bob, f"{request.param} wei") + + +def test_use_parametrized_transaction(parametrized_transaction): + """ + The real test is in the next file `test_iso_session.py`. + The session fixtures should know about these and add an additional + `3` to the `6` to make `9.` + """ + _ = parametrized_transaction + assert True # Testing isolation after the fixture runs. diff --git a/tests/integration/cli/projects/test/tests/test_fixture_isolation_session.py b/tests/integration/cli/projects/test/tests/test_fixture_isolation_session.py index f198df7ec6..37633d62af 100644 --- a/tests/integration/cli/projects/test/tests/test_fixture_isolation_session.py +++ b/tests/integration/cli/projects/test/tests/test_fixture_isolation_session.py @@ -9,14 +9,16 @@ def test_session(chain): """ `session_one` mines 4 and `session_two` mines 2, - so we expected 6. + so we expected 6. Then, at the end of the module, + 3 more get added to the session. """ - assert chain.blocks.height == 6 + assert chain.blocks.height == 9 def test_session2(chain): """ Session isolation doesn't revert other session fixtures, - so we are still at 6. + so we are still at 6. Then, at the end of the module, + 3 more get added to the session. """ - assert chain.blocks.height == 6 + assert chain.blocks.height == 9 diff --git a/tests/integration/cli/test_test.py b/tests/integration/cli/test_test.py index fcaedfecb3..1e2a47035c 100644 --- a/tests/integration/cli/test_test.py +++ b/tests/integration/cli/test_test.py @@ -177,6 +177,10 @@ def run_gas_test( def test_test(setup_pytester, integ_project, pytester, eth_tester_provider): _ = eth_tester_provider # Ensure using EthTester for this test. passed, failed = setup_pytester(integ_project) + + if integ_project.name == "test": + passed += 4 # Correct tests being added from parametrized fixtures + from ape.logging import logger logger.set_level("DEBUG")