From 8e397d8dd70a2493590933517f8048c69301673a Mon Sep 17 00:00:00 2001 From: Ian Kenney Date: Mon, 16 Mar 2026 22:38:12 -0400 Subject: [PATCH 1/2] Remove side-effect of weight mutation in StrategyResult.resolve Immutability is needed to guarantee stable keys in GufeTokenizable instances. The weights property now returns a copy of the weights and resolve no longer uses the update method. --- src/stratocaster/base/strategy.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/stratocaster/base/strategy.py b/src/stratocaster/base/strategy.py index a7e3d3e..18c7f85 100644 --- a/src/stratocaster/base/strategy.py +++ b/src/stratocaster/base/strategy.py @@ -29,19 +29,18 @@ def _from_dict(cls, dct: dict): @property def weights(self) -> dict[GufeKey, float | None]: - return self._weights + return self._weights.copy() def resolve(self) -> dict[GufeKey, float | None]: - """Normalize the proposal weights relative to all non-None Transformation weights.""" - weights = self.weights - weight_sum = sum([weight for weight in weights.values() if weight is not None]) - modified_weights = { - key: weight / weight_sum - for key, weight in weights.items() - if weight is not None + """Get normalized proposal weights relative to all non-None Transformation weights.""" + weight_sum = sum( + [weight for weight in self._weights.values() if weight is not None] + ) + normalized_weights = { + key: weight / weight_sum if weight is not None else None + for key, weight in self._weights.items() } - weights.update(modified_weights) - return weights + return normalized_weights class Strategy(GufeTokenizable): From cc6908626ef1efabd75940f459961ec5498f306a Mon Sep 17 00:00:00 2001 From: Ian Kenney Date: Wed, 8 Apr 2026 11:33:12 -0400 Subject: [PATCH 2/2] Extend testing for StrategyResult objects --- src/stratocaster/tests/test_strategy_base.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/stratocaster/tests/test_strategy_base.py b/src/stratocaster/tests/test_strategy_base.py index 6b20058..aaabf58 100644 --- a/src/stratocaster/tests/test_strategy_base.py +++ b/src/stratocaster/tests/test_strategy_base.py @@ -17,6 +17,17 @@ class TestStrategyResult: def test_dict_roundtrip(self): assert StrategyResult.from_dict(self.result.to_dict()) == self.result + def test_resolve_no_weight_side_effect(self): + """Resolve returns a normalized copy of the result + weights and doesn't modify the original data.""" + res = self.result.resolve() + assert res != self.result.weights + + def test_resolve_normalization(self): + """Resolve produces normalized weights for all non-None values.""" + res = self.result.resolve() + assert 1 == sum([value for _, value in res.items() if value is not None]) + class DummyStrategySettings(StrategySettings): pass