allow extra args to enter function, don't pass oldState, newState but store them instead

This commit is contained in:
David Rose 2004-05-26 19:17:27 +00:00
parent 88ef2acf35
commit bbea3902db
2 changed files with 66 additions and 57 deletions

View File

@ -22,22 +22,22 @@ class FSM(DirectObject.DirectObject):
particular state, define a method named enterState() and/or particular state, define a method named enterState() and/or
exitState(), where "State" is the name of the state, e.g.: exitState(), where "State" is the name of the state, e.g.:
def enterRed(self, oldState, newState): def enterRed(self):
... do stuff ... ... do stuff ...
def exitRed(self, oldState, newState): def exitRed(self):
... cleanup stuff ... ... cleanup stuff ...
def enterYellow(self, oldState, newState): def enterYellow(self):
... do stuff ... ... do stuff ...
def exitYellow(self, oldState, newState): def exitYellow(self):
... cleanup stuff ... ... cleanup stuff ...
def enterGreen(self, oldState, newState): def enterGreen(self):
... do stuff ... ... do stuff ...
def exitGreen(self, oldState, newState): def exitGreen(self):
... cleanup stuff ... ... cleanup stuff ...
Both functions are supplied the previous state name and the new Both functions are supplied the previous state name and the new
@ -134,7 +134,7 @@ class FSM(DirectObject.DirectObject):
bypasses the filterState() function, and just calls bypasses the filterState() function, and just calls
exitState() followed by enterState().""" exitState() followed by enterState()."""
assert(isinstance(newState, types.StringType)) assert(isinstance(newState, types.StringTypes))
self.__setState(newState) self.__setState(newState)
@ -147,13 +147,14 @@ class FSM(DirectObject.DirectObject):
The return value is the same as the return value of The return value is the same as the return value of
filterState() (that is, None if the request does not provoke a filterState() (that is, None if the request does not provoke a
state transition, or the name of the new state otherwise.) state transition, otherwise it is a tuple containing the name
of the state followed by any optional args.)
If the FSM is currently in transition (i.e. in the middle of If the FSM is currently in transition (i.e. in the middle of
executing an enterState or exitState function), the request is executing an enterState or exitState function), the request is
denied and None is returned.""" denied and None is returned."""
assert(isinstance(request, types.StringType)) assert(isinstance(request, types.StringTypes))
self.notify.debug("%s.request(%s, %s" % (self.name, request, str(args)[1:])) self.notify.debug("%s.request(%s, %s" % (self.name, request, str(args)[1:]))
if not self.state: if not self.state:
@ -167,8 +168,13 @@ class FSM(DirectObject.DirectObject):
func = self.defaultFilter func = self.defaultFilter
result = func(request, args) result = func(request, args)
if result: if result:
assert(isinstance(result, types.StringType)) if isinstance(result, types.StringTypes):
self.__setState(result) # If the return value is a string, it's just the name
# of the state. Wrap it in a tuple for consistency.
result = (result,)
# Otherwise, assume it's a (name, *args) tuple
self.__setState(*result)
return result return result
@ -182,14 +188,14 @@ class FSM(DirectObject.DirectObject):
if request == 'Off': if request == 'Off':
# We can always go to the "Off" state. # We can always go to the "Off" state.
return request return (request,) + args
if self.defaultTransitions is None: if self.defaultTransitions is None:
# If self.defaultTransitions is None, it means to accept # If self.defaultTransitions is None, it means to accept
# all requests whose name begins with a capital letter. # all requests whose name begins with a capital letter.
# These are direct requests to a particular state. # These are direct requests to a particular state.
if request[0] in string.uppercase: if request[0] in string.uppercase:
return request return (request,) + args
else: else:
# If self.defaultTransitions is not None, it is a map of # If self.defaultTransitions is not None, it is a map of
@ -200,7 +206,7 @@ class FSM(DirectObject.DirectObject):
if request in self.defaultTransitions.get(self.state, []): if request in self.defaultTransitions.get(self.state, []):
# This transition is listed in the defaultTransitions map; # This transition is listed in the defaultTransitions map;
# accept it. # accept it.
return request return (request,) + args
# If self.defaultTransitions is not None, it is an error # If self.defaultTransitions is not None, it is an error
# to request a direct state transition (capital letter # to request a direct state transition (capital letter
@ -222,26 +228,29 @@ class FSM(DirectObject.DirectObject):
return self.defaultFilter(request, args) return self.defaultFilter(request, args)
def __setState(self, newState): def __setState(self, newState, *args):
# Internal function to change unconditionally to the indicated # Internal function to change unconditionally to the indicated
# state. # state.
assert(self.state) assert(self.state)
oldState = self.state self.oldState = self.state
self.newState = newState
self.state = None self.state = None
self.__callTransitionFunc("exit" + oldState, oldState, newState) self.__callTransitionFunc("exit" + self.oldState)
self.__callTransitionFunc("enter" + newState, oldState, newState) self.__callTransitionFunc("enter" + self.newState, *args)
self.state = newState self.state = newState
del self.oldState
del self.newState
def __callTransitionFunc(self, name, oldState, newState): def __callTransitionFunc(self, name, *args):
# Calls the appropriate enter or exit function when # Calls the appropriate enter or exit function when
# transitioning between states, if it exists. # transitioning between states, if it exists.
assert(self.state == None) assert(self.state == None)
func = getattr(self, name, None) func = getattr(self, name, None)
if func: if func:
func(oldState, newState) func(*args)
def __repr__(self): def __repr__(self):
return self.__str__() return self.__str__()

View File

@ -15,29 +15,29 @@ class ClassicStyle(FSM.FSM):
'Green' : ['Yellow'], 'Green' : ['Yellow'],
} }
def enterRed(self, oldState, newState): def enterRed(self):
print "enterRed(self, '%s', '%s')" % (oldState, newState) print "enterRed(self, '%s', '%s')" % (self.oldState, self.newState)
def exitRed(self, oldState, newState): def exitRed(self):
print "exitRed(self, '%s', '%s')" % (oldState, newState) print "exitRed(self, '%s', '%s')" % (self.oldState, self.newState)
def enterYellow(self, oldState, newState): def enterYellow(self):
print "enterYellow(self, '%s', '%s')" % (oldState, newState) print "enterYellow(self, '%s', '%s')" % (self.oldState, self.newState)
def exitYellow(self, oldState, newState): def exitYellow(self):
print "exitYellow(self, '%s', '%s')" % (oldState, newState) print "exitYellow(self, '%s', '%s')" % (self.oldState, self.newState)
def enterGreen(self, oldState, newState): def enterGreen(self):
print "enterGreen(self, '%s', '%s')" % (oldState, newState) print "enterGreen(self, '%s', '%s')" % (self.oldState, self.newState)
def exitGreen(self, oldState, newState): def exitGreen(self):
print "exitGreen(self, '%s', '%s')" % (oldState, newState) print "exitGreen(self, '%s', '%s')" % (self.oldState, self.newState)
class NewStyle(FSM.FSM): class NewStyle(FSM.FSM):
def enterRed(self, oldState, newState): def enterRed(self):
print "enterRed(self, '%s', '%s')" % (oldState, newState) print "enterRed(self, '%s', '%s')" % (self.oldState, self.newState)
def filterRed(self, request, args): def filterRed(self, request, args):
print "filterRed(self, '%s', %s)" % (request, args) print "filterRed(self, '%s', %s)" % (request, args)
@ -45,11 +45,11 @@ class NewStyle(FSM.FSM):
return 'Green' return 'Green'
return self.defaultFilter(request, args) return self.defaultFilter(request, args)
def exitRed(self, oldState, newState): def exitRed(self):
print "exitRed(self, '%s', '%s')" % (oldState, newState) print "exitRed(self, '%s', '%s')" % (self.oldState, self.newState)
def enterYellow(self, oldState, newState): def enterYellow(self):
print "enterYellow(self, '%s', '%s')" % (oldState, newState) print "enterYellow(self, '%s', '%s')" % (self.oldState, self.newState)
def filterYellow(self, request, args): def filterYellow(self, request, args):
print "filterYellow(self, '%s', %s)" % (request, args) print "filterYellow(self, '%s', %s)" % (request, args)
@ -57,11 +57,11 @@ class NewStyle(FSM.FSM):
return 'Red' return 'Red'
return self.defaultFilter(request, args) return self.defaultFilter(request, args)
def exitYellow(self, oldState, newState): def exitYellow(self):
print "exitYellow(self, '%s', '%s')" % (oldState, newState) print "exitYellow(self, '%s', '%s')" % (self.oldState, self.newState)
def enterGreen(self, oldState, newState): def enterGreen(self):
print "enterGreen(self, '%s', '%s')" % (oldState, newState) print "enterGreen(self, '%s', '%s')" % (self.oldState, self.newState)
def filterGreen(self, request, args): def filterGreen(self, request, args):
print "filterGreen(self, '%s', %s)" % (request, args) print "filterGreen(self, '%s', %s)" % (request, args)
@ -69,8 +69,8 @@ class NewStyle(FSM.FSM):
return 'Yellow' return 'Yellow'
return self.defaultFilter(request, args) return self.defaultFilter(request, args)
def exitGreen(self, oldState, newState): def exitGreen(self):
print "exitGreen(self, '%s', '%s')" % (oldState, newState) print "exitGreen(self, '%s', '%s')" % (self.oldState, self.newState)
class ToonEyes(FSM.FSM): class ToonEyes(FSM.FSM):
@ -91,7 +91,7 @@ class ToonEyes(FSM.FSM):
# Unexpected command requests are quietly ignored. # Unexpected command requests are quietly ignored.
return None return None
def enterOpen(self, oldState, newState): def enterOpen(self):
print "swap in eyes open model" print "swap in eyes open model"
def filterOpen(self, request, args): def filterOpen(self, request, args):
@ -105,7 +105,7 @@ class ToonEyes(FSM.FSM):
self.request('unblink') self.request('unblink')
return Task.done return Task.done
def enterClosed(self, oldState, newState): def enterClosed(self):
print "swap in eyes closed model" print "swap in eyes closed model"
def filterClosed(self, request, args): def filterClosed(self, request, args):
@ -113,10 +113,10 @@ class ToonEyes(FSM.FSM):
return 'Open' return 'Open'
return self.defaultFilter(request, args) return self.defaultFilter(request, args)
def enterSurprised(self, oldState, newState): def enterSurprised(self):
print "swap in eyes surprised model" print "swap in eyes surprised model"
def enterOff(self, oldState, newState): def enterOff(self):
taskMgr.remove(self.__unblinkName) taskMgr.remove(self.__unblinkName)
@ -127,7 +127,7 @@ class ToonEyes(FSM.FSM):
## >>> foo = SampleFSM.ClassicStyle('foo') ## >>> foo = SampleFSM.ClassicStyle('foo')
## >>> foo.request('Red') ## >>> foo.request('Red')
## enterRed(self, 'Off', 'Red') ## enterRed(self, 'Off', 'Red')
## 'Red' ## ('Red',)
## >>> foo.request('Yellow') ## >>> foo.request('Yellow')
## Traceback (most recent call last): ## Traceback (most recent call last):
## File "<stdin>", line 1, in ? ## File "<stdin>", line 1, in ?
@ -141,7 +141,7 @@ class ToonEyes(FSM.FSM):
## >>> foo.request('Green') ## >>> foo.request('Green')
## exitRed(self, 'Red', 'Green') ## exitRed(self, 'Red', 'Green')
## enterGreen(self, 'Red', 'Green') ## enterGreen(self, 'Red', 'Green')
## 'Green' ## ('Green',)
## >>> ## >>>
#### ####
@ -151,27 +151,27 @@ class ToonEyes(FSM.FSM):
## >>> foo = SampleFSM.NewStyle('foo') ## >>> foo = SampleFSM.NewStyle('foo')
## >>> foo.request('Red') ## >>> foo.request('Red')
## enterRed(self, 'Off', 'Red') ## enterRed(self, 'Off', 'Red')
## 'Red' ## ('Red',)
## >>> foo.request('advance') ## >>> foo.request('advance')
## filterRed(self, 'advance', ()) ## filterRed(self, 'advance', ())
## exitRed(self, 'Red', 'Green') ## exitRed(self, 'Red', 'Green')
## enterGreen(self, 'Red', 'Green') ## enterGreen(self, 'Red', 'Green')
## 'Green' ## ('Green',)
## >>> foo.request('advance') ## >>> foo.request('advance')
## filterGreen(self, 'advance', ()) ## filterGreen(self, 'advance', ())
## exitGreen(self, 'Green', 'Yellow') ## exitGreen(self, 'Green', 'Yellow')
## enterYellow(self, 'Green', 'Yellow') ## enterYellow(self, 'Green', 'Yellow')
## 'Yellow' ## ('Yellow',)
## >>> foo.request('advance') ## >>> foo.request('advance')
## filterYellow(self, 'advance', ()) ## filterYellow(self, 'advance', ())
## exitYellow(self, 'Yellow', 'Red') ## exitYellow(self, 'Yellow', 'Red')
## enterRed(self, 'Yellow', 'Red') ## enterRed(self, 'Yellow', 'Red')
## 'Red' ## ('Red',)
## >>> foo.request('advance') ## >>> foo.request('advance')
## filterRed(self, 'advance', ()) ## filterRed(self, 'advance', ())
## exitRed(self, 'Red', 'Green') ## exitRed(self, 'Red', 'Green')
## enterGreen(self, 'Red', 'Green') ## enterGreen(self, 'Red', 'Green')
## 'Green' ## ('Green',)
## >>> ## >>>
#### ####
@ -183,11 +183,11 @@ class ToonEyes(FSM.FSM):
## swap in eyes open model ## swap in eyes open model
## >>> eyes.request('blink') ## >>> eyes.request('blink')
## swap in eyes closed model ## swap in eyes closed model
## 'Closed' ## ('Closed',)
## >>> run() ## >>> run()
## swap in eyes open model ## swap in eyes open model
## >>> eyes.request('Surprised') ## >>> eyes.request('Surprised')
## swap in eyes surprised model ## swap in eyes surprised model
## 'Surprised' ## ('Surprised',)
## >>> eyes.request('blink') ## >>> eyes.request('blink')
## >>> ## >>>