Skip to content

Commit cd05c6e

Browse files
authored
fix: Configuration.add()/discard() write through model setter for persistence (#596)
In-place mutation of the OrderedSet returned by self.value lost state changes when the model uses a deserializing property (e.g., Django model field backed by a DB column). Each getter call returned a fresh object, the in-place mutation modified a temporary, and the model was never updated. Changed add() and discard() to create a new OrderedSet and assign via self.value = new, which calls setattr on the model. This only affects atomic_configuration_update=False (StateChart default); the atomic path was never affected. Benchmark impact: ~4-5% on parallel region events (~2µs per event), negligible vs. callback execution in the same microstep. Signed-off-by: Fernando Macedo <fernando.macedo@jusbrasil.com.br>
1 parent 2476d20 commit cd05c6e

File tree

3 files changed

+570
-7
lines changed

3 files changed

+570
-7
lines changed

statemachine/configuration.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,21 +106,23 @@ def add(self, state: "State"):
106106
if csv is None:
107107
self.value = state.value
108108
elif isinstance(csv, MutableSet):
109-
csv.add(state.value)
110-
self._invalidate()
109+
new = OrderedSet(csv)
110+
new.add(state.value)
111+
self.value = new
111112
else:
112113
self.value = OrderedSet([csv, state.value])
113114

114115
def discard(self, state: "State"):
115116
"""Remove *state* from the configuration, normalizing back to scalar."""
116117
csv = self.value
117118
if isinstance(csv, MutableSet):
118-
csv.discard(state.value)
119-
self._invalidate()
120-
if len(csv) == 1:
121-
self.value = next(iter(csv))
122-
elif len(csv) == 0:
119+
new = OrderedSet(v for v in csv if v != state.value)
120+
if len(new) == 0:
123121
self.value = None
122+
elif len(new) == 1:
123+
self.value = next(iter(new))
124+
else:
125+
self.value = new
124126
elif csv == state.value:
125127
self.value = None
126128

0 commit comments

Comments
 (0)