Skip to content

Commit 72b5313

Browse files
authored
Added PreConditions functionality
1 parent 1519e3a commit 72b5313

9 files changed

Lines changed: 143 additions & 41 deletions

File tree

sample/sample2.xml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?xml version="1.0"?>
2+
<x:States xmlns:x="pystatemachine:sm">
3+
<State>
4+
<Name>Enter</Name>
5+
<Event>
6+
<Name>ToExit</Name>
7+
<ToState>Exit</ToState>
8+
<PreConditions>
9+
<Condition>
10+
<Expression>test2.everFalse</Expression>
11+
<Result>False</Result>
12+
</Condition>
13+
<Condition>
14+
<Expression>test2.test</Expression>
15+
<Result>2</Result>
16+
</Condition>
17+
</PreConditions>
18+
</Event>
19+
</State>
20+
<State>
21+
<Name>Exit</Name>
22+
<Event>
23+
<Name>ToNull</Name>
24+
<ToState>Null</ToState>
25+
<PreConditions>
26+
<Condition>
27+
<Expression>test2.everFalse</Expression>
28+
<Result>True</Result>
29+
</Condition>
30+
</PreConditions>
31+
</Event>
32+
</State>
33+
<State>
34+
<Name>Null</Name>
35+
<Event>
36+
<Name>ToNull</Name>
37+
<ToState>Null</ToState>
38+
</Event>
39+
</State>
40+
<Initial_State>Enter</Initial_State>
41+
</x:States>

schema/StateMachine.xsd

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
targetNamespace="pystatemachine:sm"
44
xmlns:sm="pystatemachine:sm">
55
<!-- definition of simple elements -->
6-
<xs:element name="Condition" type="sm:NonEmptyString"/>
6+
<!--xs:element name="Condition" type="sm:NonEmptyString"/-->
77
<xs:element name="Action" type="sm:NonEmptyString"/>
88
<!-- definition of simple type -->
99
<xs:simpleType name="NonEmptyString"> <!-- we can describe our types separately to reuse them later -->
@@ -14,9 +14,17 @@
1414
</xs:simpleType>
1515

1616
<!-- definition of Complex Type-->
17+
<xs:complexType name="Condition">
18+
<xs:sequence>
19+
<xs:element name="Expression" type="sm:NonEmptyString" minOccurs="1" maxOccurs="1"/>
20+
<xs:element name="Result" type="sm:NonEmptyString" minOccurs="1" maxOccurs="1"/>
21+
</xs:sequence>
22+
</xs:complexType>
23+
24+
1725
<xs:complexType name="Conditions">
1826
<xs:sequence>
19-
<xs:element ref="sm:Condition" minOccurs="1"/>
27+
<xs:element name="Condition" type="sm:Condition" minOccurs="1"/>
2028
</xs:sequence>
2129
</xs:complexType>
2230

src/Condition.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class Condition:
2+
def __init__(self, expression :str, result : str ):
3+
self.expression = expression
4+
self.result = result
5+
6+
def to_string(self):
7+
result_s = ""
8+
return result_s

src/Conditions.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
class Conditions:
2-
def __init__(self,condition:str):
3-
self.condition = condition
4-
2+
def __init__(self, conditions = [] ):
3+
self.conditions = conditions
4+
55
def to_string(self):
66
result_s = ""
77
return result_s

src/Event.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,6 @@ def __init__(self, name :str, to_state: str, pre_conditions: Conditions, post_co
99
self.post_conditions = post_conditions
1010
self.pre_actions = pre_actions
1111
self.post_actions = post_actions
12-
13-
def get_name(self):
14-
return self.name
15-
16-
def get_to_state(self):
17-
return self.to_state
18-
19-
def get_pre_conditions(self):
20-
return self.pre_conditions
21-
22-
def get_post_conditions(self):
23-
return self.post_conditions
24-
25-
def get_pre_actions(self):
26-
return self.pre_actions
27-
28-
def get_post_actions(self):
29-
return self.post_actions
3012

3113
def to_string(self):
3214
result_s = "Event: \n"

src/ReadStateMachine.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from Condition import Condition
12
from Conditions import Conditions
23
from Actions import Actions
34
from Event import Event
@@ -25,8 +26,8 @@ def ReadStateMachineFile(xml_file : str):
2526
# State->Event Element
2627
event_name = ""
2728
to_state = ""
28-
pre_conditions = Conditions("") # dummy
29-
post_conditions = Conditions("") # dummy
29+
pre_conditions = None # dummy
30+
post_conditions = None # dummy
3031
pre_actions = Actions("") #dummy
3132
post_actions = Actions("") #dummy
3233

@@ -43,10 +44,20 @@ def ReadStateMachineFile(xml_file : str):
4344
to_state = event_child.text
4445
elif event_child.tag == "PreConditions":
4546
# State->Event->PreConditions Element
47+
pre_condition_elements = []
4648
for preconditions_child in event_child:
4749
#print(preconditions_child.text)
4850
# State->Event->PreConditions->Condition Element
49-
None
51+
if preconditions_child.tag == "Condition":
52+
expression = ""
53+
result = ""
54+
for condition_child in preconditions_child:
55+
if condition_child.tag == "Expression":
56+
expression = condition_child.text
57+
elif condition_child.tag == "Result":
58+
result = condition_child.text
59+
pre_condition_elements.append(Condition(expression,result))
60+
pre_conditions = Conditions(pre_condition_elements)
5061
elif event_child.tag == "PostConditions":
5162
# State->Event->PostConditions Element
5263
for postconditions_child in event_child:

src/State.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
1-
import Event
2-
31
class State:
42
def __init__(self, name: str, events = {}):
53
self.name = name
64
self.events = events
7-
8-
def get_name(self):
9-
return self.name
10-
11-
def get_events(self):
12-
return self.events
13-
5+
146
def to_string(self):
157
result_s = "State:\n"
168
result_s += " Name: " + self.name + "\n"

src/StateMachine.py

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ def __init__(self, xml_file : str):
77
self.xml_file = xml_file
88
self.states = None
99
self.current_state = ""
10+
self.context = {}
1011

1112
def get_current_state(self):
1213
return self.current_state
@@ -17,18 +18,44 @@ def LoadStateMachine(self):
1718
else:
1819
self.xml_file
1920
self.states , self.current_state = ReadStateMachineFile(self.xml_file)
21+
22+
def addVariableToContext(self, module : str, variable : str):
23+
mod = __import__(module)
24+
func = getattr(mod, variable)
25+
self.context[module+"."+variable] = func
2026

2127
def InjectEvent(self, event : str):
2228
my_state = self.states[self.current_state]
23-
possible_events = my_state.get_events()
29+
possible_events = my_state.events
2430
if event in possible_events:
2531
handled_event = possible_events[event]
2632
## Preconditions
27-
## Preactions
28-
print("Transition ", self.current_state, " ------> ", handled_event.get_to_state())
29-
self.current_state = handled_event.get_to_state()
30-
## Postactions
31-
## Postconditions
33+
all_pre_conditions_satisfied = True
34+
if(handled_event.pre_conditions != None):
35+
pre_conditions = handled_event.pre_conditions.conditions
36+
for condition in pre_conditions:
37+
if condition.expression in self.context:
38+
func = self.context[condition.expression]
39+
result = None
40+
if callable(func):
41+
result = func()
42+
else:
43+
result = func
44+
if str(result) != condition.result:
45+
all_pre_conditions_satisfied = False
46+
break
47+
else:
48+
print("No Precondition")
49+
50+
if(all_pre_conditions_satisfied):
51+
## Preactions
52+
## Transition
53+
print("Transition ", self.current_state, " ------> ", handled_event.to_state)
54+
self.current_state = handled_event.to_state
55+
## Postactions
56+
## Postconditions
57+
else:
58+
print("Not all PreConditions satisfied")
3259
else:
3360
print("Not a possible event")
3461

tests/test2.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import sys
2+
sys.path.append('../src')
3+
4+
from StateMachine import StateMachine
5+
6+
test = 2
7+
8+
def main():
9+
10+
sm = StateMachine("../sample/sample2.xml")
11+
12+
sm.LoadStateMachine()
13+
14+
sm.addVariableToContext("test2", "everFalse")
15+
sm.addVariableToContext("test2", "test")
16+
17+
print(sm.get_current_state())
18+
sm.InjectEvent("ToExit")
19+
print(sm.get_current_state())
20+
sm.InjectEvent("ToExit")
21+
print(sm.get_current_state())
22+
sm.InjectEvent("ToNull")
23+
print(sm.get_current_state())
24+
sm.InjectEvent("ToExit")
25+
print(sm.get_current_state())
26+
sm.InjectEvent("ToNull")
27+
28+
def everFalse():
29+
return False
30+
31+
32+
if __name__ == "__main__":
33+
main()

0 commit comments

Comments
 (0)