Skip to content

Commit af7008e

Browse files
committed
replace 'self' with Machine.self_literal
This enables identity checks to determine whether a machine should add itself as a model (#545)
1 parent baa0909 commit af7008e

File tree

9 files changed

+16
-11
lines changed

9 files changed

+16
-11
lines changed

Changelog.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 0.8.10
4+
5+
- Feature #545: The literal 'self' (default model parameter of `Machine`) has been replaced by the class variable `Machine.self_literal = 'self'`. `Machine` now performs an identity check (instead of a value check) with `mod is self.self_literal` to determine whether it should act as a model. While 'self' should still work when passed to the `model` parameter, we encourage using `Machine.self_literal` from now on. This was done to enable easier override of `Machine.__eq__` in subclasses (thanks @VKSolovev).
6+
37
## 0.8.9 (September 2021)
48

59
Release 0.8.9 is a minor release and contains a bugfix for HSM, a feature for `GraphSupport` and changes internal cache handling:

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,7 @@ lump.state
987987
Here you get to consolidate all state machine functionality into your existing model, which often feels more natural way than sticking all of the functionality we want in a separate standalone `Machine` instance.
988988

989989
A machine can handle multiple models which can be passed as a list like `Machine(model=[model1, model2, ...])`.
990-
In cases where you want to add models *as well as* the machine instance itself, you can pass the string placeholder `'self'` during initialization like `Machine(model=['self', model1, ...])`.
990+
In cases where you want to add models *as well as* the machine instance itself, you can pass the class variable placeholder (string) `Machine.self_literal` during initialization like `Machine(model=[Machine.self_literal, model1, ...])`.
991991
You can also create a standalone machine, and register models dynamically via `machine.add_model` by passing `model=None` to the constructor.
992992
Furthermore, you can use `machine.dispatch` to trigger events on all currently added models.
993993
Remember to call `machine.remove_model` if machine is long-lasting and your models are temporary and should be garbage collected:

examples/Frequently asked questions.ipynb

+1-1
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@
546546
" # override Machine.add_model to assign 'can_trigger' to the model\n",
547547
" def add_model(self, model, initial=None):\n",
548548
" for mod in listify(model):\n",
549-
" mod = self if mod == 'self' else mod\n",
549+
" mod = self if mod is self.self_literal else mod\n",
550550
" if mod not in self.models:\n",
551551
" setattr(mod, 'can_trigger', partial(self._can_trigger, mod))\n",
552552
" super(PeekMachine, self).add_model(mod, initial)\n",

transitions/core.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -502,17 +502,18 @@ class Machine(object):
502502
state_cls = State
503503
transition_cls = Transition
504504
event_cls = Event
505+
self_literal = 'self'
505506

506-
def __init__(self, model='self', states=None, initial='initial', transitions=None,
507+
def __init__(self, model=self_literal, states=None, initial='initial', transitions=None,
507508
send_event=False, auto_transitions=True,
508509
ordered_transitions=False, ignore_invalid_triggers=None,
509510
before_state_change=None, after_state_change=None, name=None,
510511
queued=False, prepare_event=None, finalize_event=None, model_attribute='state', on_exception=None,
511512
**kwargs):
512513
"""
513514
Args:
514-
model (object or list): The object(s) whose states we want to manage. If 'self',
515-
the current Machine instance will be used the model (i.e., all
515+
model (object or list): The object(s) whose states we want to manage. If set to `Machine.self_literal`
516+
(default value), the current Machine instance will be used as the model (i.e., all
516517
triggering events will be attached to the Machine itself). Note that an empty list
517518
is treated like no model.
518519
states (list or Enum): A list or enumeration of valid states. Each list element can be either a
@@ -616,7 +617,7 @@ def add_model(self, model, initial=None):
616617
initial = self.initial
617618

618619
for mod in models:
619-
mod = self if mod == 'self' else mod
620+
mod = self if mod is self.self_literal else mod
620621
if mod not in self.models:
621622
self._checked_assignment(mod, 'trigger', partial(self._get_trigger, mod))
622623

transitions/extensions/asyncio.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ def add_model(self, model, initial=None):
326326
super().add_model(model, initial)
327327
if self.has_queue == 'model':
328328
for mod in listify(model):
329-
self._transition_queue_dict[id(mod) if mod != 'self' else id(self)] = deque()
329+
self._transition_queue_dict[id(self) if mod is self.self_literal else id(mod)] = deque()
330330

331331
async def dispatch(self, trigger, *args, **kwargs): # ToDo: not tested
332332
""" Trigger an event on all models assigned to the machine.

transitions/extensions/diagrams.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ def add_model(self, model, initial=None):
224224
models = listify(model)
225225
super(GraphMachine, self).add_model(models, initial)
226226
for mod in models:
227-
mod = self if mod == 'self' else mod
227+
mod = self if mod is self.self_literal else mod
228228
if hasattr(mod, 'get_graph'):
229229
raise AttributeError('Model already has a get_graph attribute. Graph retrieval cannot be bound.')
230230
setattr(mod, 'get_graph', partial(self._get_graph, mod))

transitions/extensions/locking.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def add_model(self, model, initial=None, model_context=None):
145145
output = _super(LockedMachine, self).add_model(models, initial)
146146

147147
for mod in models:
148-
mod = self if mod == 'self' else mod
148+
mod = self if mod is self.self_literal else mod
149149
self.model_context_map[id(mod)].extend(self.machine_context)
150150
self.model_context_map[id(mod)].extend(model_context)
151151

transitions/extensions/nesting.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ def add_model(self, model, initial=None):
418418
""" Extends transitions.core.Machine.add_model by applying a custom 'to' function to
419419
the added model.
420420
"""
421-
models = [mod if mod != 'self' else self for mod in listify(model)]
421+
models = [self if mod is self.self_literal else mod for mod in listify(model)]
422422
_super(HierarchicalMachine, self).add_model(models, initial=initial)
423423
initial_name = getattr(models[0], self.model_attribute)
424424
if hasattr(initial_name, 'name'):

transitions/extensions/nesting_legacy.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ def add_model(self, model, initial=None):
259259
_super(HierarchicalMachine, self).add_model(model, initial=initial)
260260
models = listify(model)
261261
for mod in models:
262-
mod = self if mod == 'self' else mod
262+
mod = self if mod is self.self_literal else mod
263263
# TODO: Remove 'mod != self' in 0.7.0
264264
if hasattr(mod, 'to') and mod != self:
265265
_LOGGER.warning("%sModel already has a 'to'-method. It will NOT "

0 commit comments

Comments
 (0)