Not quite, but there is a state machine module for Python that lets you use decorators to support implementing Harel style statecharts, including contexts with multiple states, nesting substates with and without history. The code winds up looking something like below.
Module is at http://wiki.python.org/moin/State%20Machine%20via%20Decorators
#!/bin/env/python
"""
This example now works. The state pattern module
allows defining states which are their their own context for
implementing substates. Substate Medium (class Medium) shows this here.
"""
"""
Example with 5 buttons. Two ,'up','down' cause state to rotate among the
several states. The other three, bx,by,bz, invoke state dependent behavior.
Switching into a state causes the labels of the three buttons bx,by,bz to
change. Pressing one of the buttons causes associated text to appear in
corresponding static text box. An 'onEnter' method changes the text.
"""
import wx
import DecoratorStateMachine as dsm
class MyFrame(wx.Frame, dsm.ContextBase):
xtable = dsm.TransitionTable('pstate')
def __init__(self):
MyFrame.xtable.initialize(self)
wx.Frame.__init__(self, None, -1, "My Frame", size=(470,220))
family = wx.SWISS
style = wx.NORMAL
weight = wx.BOLD
font = wx.Font(11,family,style,weight, False, "Verdana")
self.SetFont(font)
panel = wx.Panel(self, -1)
b = wx.Button(panel, -1, "Up", pos=(50,20), size=(80,35))
self.Bind(wx.EVT_BUTTON, self.OnUp, b)
b.SetDefault()
b = wx.Button(panel, -1, "Down", pos=(50,60), size=(80,35))
self.Bind(wx.EVT_BUTTON, self.OnDown, b)
self.bx = wx.Button(panel, -1, "xxx", pos=(50,100), size=(110,35))
self.Bind(wx.EVT_BUTTON, self.OnBA, self.bx)
self.tx = wx.StaticText(panel, -1, "", pos=(50,140), size=(110,35))
self.by = wx.Button(panel, -1, "yyy", pos=(180,100), size=(110,35))
self.Bind(wx.EVT_BUTTON, self.OnBB, self.by)
self.ty = wx.StaticText(panel, -1, "", pos=(180,140), size=(110,35))
self.bz = wx.Button(panel, -1, "zzz", pos=(310,100), size=(110,35))
self.Bind(wx.EVT_BUTTON, self.OnBC, self.bz )
self.tz = wx.StaticText(panel, -1, "", pos=(310,140), size=(110,35))
@dsm.transition(xtable)
def OnUp(self, event):
pass
@dsm.transition(xtable)
def OnDown(self, event):
pass
@dsm.event(xtable)
def OnBA(self, event):
pass
@dsm.event(xtable)
def OnBB(self, event):
pass
@dsm.event(xtable)
def OnBC(self, event):
self.tz.SetLabel("Bossy")
class Off(MyFrame):
"This is state Off "
def onEnter(self):
self.bx.SetLabel("Chase")
self.by.SetLabel("Onry")
self.bz.SetLabel("Cow")
def OnBA(self, event):
self.tx.SetLabel("Chase the")
def OnBB(self, event):
self.ty.SetLabel("Onry")
class Low(MyFrame):
"This is state Low "
items = ["Walk", "Green", "Llama"]
def onEnter(self):
self.bx.SetLabel(self.items[0])
self.by.SetLabel(self.items[1])
self.bz.SetLabel(self.items[2])
def OnBA(self, event):
self.tx.SetLabel("Walk the ")
def OnBB(self, event):
self.ty.SetLabel(self.items[1])
def OnBC(self, event):
self.tz.SetLabel(self.items[2])
class Medium(MyFrame):
"This is state Medium "
ytable = dsm.TransitionTable('qstate')
def onEnter(self):
if not hasattr(self, 'qstate'): #unconditionally initialize for no history
self.ytable.initialize(self)
self.doEnter()
@dsm.event(ytable)
def doEnter(): pass
@dsm.transitionevent(ytable)
def OnBA(self, event):
pass
@dsm.transitionevent(ytable)
def OnBB(self, event):
pass
@dsm.transitionevent(ytable)
def OnBC(self, event):
pass
class High(Low):
"This is state High "
items = ["Pet","Tame", "Dog"]
def OnBA(self, event):
self.tx.SetLabel("Pet his")
class MedBlue(Medium):
"""State med blu"""
items = ["Med BLue","Checkered", "Tractor"]
def onEnter(self):
self.bx.SetLabel(self.items[0])
self.by.SetLabel(self.items[1])
self.bz.SetLabel(self.items[2])
def doEnter(self):
self.onEnter()
def OnBA(self, event):
self.tx.SetLabel("Med Blue")
def OnBB(self, event):
self.ty.SetLabel("Chekered")
def OnBC(self, event):
self.tz.SetLabel("Tractor")
class MedRed(Medium):
"""State med red"""
items = ["Med Red","Striped", "Combine"]
def onEnter(self):
self.bx.SetLabel(self.items[0])
self.by.SetLabel(self.items[1])
self.bz.SetLabel(self.items[2])
def doEnter(self):
self.onEnter()
def OnBA(self, event):
self.tx.SetLabel("Med Red")
def OnBB(self, event):
self.ty.SetLabel("Striped")
def OnBC(self, event):
self.tz.SetLabel("Combine")
MyFrame.xtable.nextStates(Low, (Medium,Off))
MyFrame.xtable.nextStates(Medium, (High,Low))
MyFrame.xtable.nextStates(High, (Off,Medium))
MyFrame.xtable.nextStates(Off, (Low,High))
MyFrame.xtable.initialstate = Off
Medium.ytable.nextStates(MedBlue, (MedBlue, MedRed, MedRed))
Medium.ytable.nextStates(MedRed, (MedBlue, MedBlue, MedRed))
Medium.ytable.initialstate = MedBlue
if __name__=='__main__':
app = wx.PySimpleApp()
frame = MyFrame()
frame.Show(True)
app.MainLoop()