From 57be9d064f933626aaa0c3d6bbcd713ccc59289d Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 7 Dec 2021 16:51:11 +0100 Subject: [PATCH 1/4] update per-test config to be unique per-test --- tests/core/pyspec/eth2spec/test/context.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 2a6f2e324..4916e008c 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -491,22 +491,18 @@ def with_config_overrides(config_overrides): """ def decorator(fn): def wrapper(*args, spec: Spec, **kw): - # remember the old config - old_config = spec.config + spec = deepcopy(spec) # apply our overrides to a copy of it, and apply it to the spec - tmp_config = deepcopy(old_config._asdict()) # not a private method, there are multiple - tmp_config.update(config_overrides) - config_types = spec.Configuration.__annotations__ - # Retain types of all config values - test_config = {k: config_types[k](v) for k, v in tmp_config.items()} + spec.config.update(config_overrides) # To output the changed config to could be serialized with yaml test vectors, # the dict SSZ objects have to be converted into Python built-in types. - output_config = _get_basic_dict(test_config) + output_config = _get_basic_dict(spec.config) yield 'config', 'data', output_config - spec.config = spec.Configuration(**test_config) + # Output the config for test vectors (TODO: check config YAML encoding) + yield 'config', 'data', spec.config # Run the function out = fn(*args, spec=spec, **kw) @@ -514,10 +510,6 @@ def with_config_overrides(config_overrides): # it's generating things, and we need to complete it before setting back the config. if out is not None: yield from out - - # Restore the old config and apply it - spec.config = old_config - return wrapper return decorator From 733f37715e342823a0a9a93810051e573d62b0a4 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 7 Dec 2021 17:51:32 +0100 Subject: [PATCH 2/4] use `importlib` to perform an actual spec copy --- tests/core/pyspec/eth2spec/test/context.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 4916e008c..0764bbe4a 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -1,6 +1,6 @@ import pytest -from copy import deepcopy from dataclasses import dataclass +import importlib from eth_utils import encode_hex from eth2spec.phase0 import mainnet as spec_phase0_mainnet, minimal as spec_phase0_minimal @@ -481,6 +481,16 @@ def _get_basic_dict(ssz_dict: Dict[str, Any]) -> Dict[str, Any]: return result +def _get_copy_of_spec(spec): + fork = spec.fork + preset = spec.config.PRESET_BASE + path = f"eth2spec.{fork}.{preset}" + + module_spec = importlib.util.find_spec(path) + module = importlib.util.module_from_spec(module_spec) + return module + + def with_config_overrides(config_overrides): """ WARNING: the spec_test decorator must wrap this, to ensure the decorated test actually runs. @@ -491,7 +501,7 @@ def with_config_overrides(config_overrides): """ def decorator(fn): def wrapper(*args, spec: Spec, **kw): - spec = deepcopy(spec) + spec = _get_copy_of_spec(spec) # apply our overrides to a copy of it, and apply it to the spec spec.config.update(config_overrides) @@ -501,9 +511,6 @@ def with_config_overrides(config_overrides): output_config = _get_basic_dict(spec.config) yield 'config', 'data', output_config - # Output the config for test vectors (TODO: check config YAML encoding) - yield 'config', 'data', spec.config - # Run the function out = fn(*args, spec=spec, **kw) # If it's not returning None like a normal test function, From 55c9c03f08696693af9f4e30e235d50e799f0bcd Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 7 Dec 2021 18:11:22 +0100 Subject: [PATCH 3/4] simply module import and fix config adjustment --- tests/core/pyspec/eth2spec/test/context.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 0764bbe4a..726723992 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -484,10 +484,10 @@ def _get_basic_dict(ssz_dict: Dict[str, Any]) -> Dict[str, Any]: def _get_copy_of_spec(spec): fork = spec.fork preset = spec.config.PRESET_BASE - path = f"eth2spec.{fork}.{preset}" - - module_spec = importlib.util.find_spec(path) + module_path = f"eth2spec.{fork}.{preset}" + module_spec = importlib.util.find_spec(module_path) module = importlib.util.module_from_spec(module_spec) + module_spec.loader.exec_module(module) return module @@ -504,13 +504,18 @@ def with_config_overrides(config_overrides): spec = _get_copy_of_spec(spec) # apply our overrides to a copy of it, and apply it to the spec - spec.config.update(config_overrides) + config = spec.config._asdict() + config.update(config_overrides) + config_types = spec.Configuration.__annotations__ + modified_config = {k: config_types[k](v) for k, v in config.items()} # To output the changed config to could be serialized with yaml test vectors, # the dict SSZ objects have to be converted into Python built-in types. - output_config = _get_basic_dict(spec.config) + output_config = _get_basic_dict(modified_config) yield 'config', 'data', output_config + spec.config = spec.Configuration(**modified_config) + # Run the function out = fn(*args, spec=spec, **kw) # If it's not returning None like a normal test function, From db2be42baaf763d44b409deff4c84700143d70cf Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 7 Dec 2021 18:50:00 +0100 Subject: [PATCH 4/4] use a specific `spec` rather than the pre-defined phases --- tests/core/pyspec/eth2spec/test/context.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 726723992..260cb4d7d 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -86,10 +86,9 @@ class SpecForks(TypedDict, total=False): def _prepare_state(balances_fn: Callable[[Any], Sequence[int]], threshold_fn: Callable[[Any], int], spec: Spec, phases: SpecForks): - phase = phases[spec.fork] - balances = balances_fn(phase) - activation_threshold = threshold_fn(phase) - state = create_genesis_state(spec=phase, validator_balances=balances, + balances = balances_fn(spec) + activation_threshold = threshold_fn(spec) + state = create_genesis_state(spec=spec, validator_balances=balances, activation_threshold=activation_threshold) return state