Skip to content

Commit

Permalink
Generating StateMachine from JSON file
Browse files Browse the repository at this point in the history
  • Loading branch information
Zentetsu committed Sep 10, 2020
1 parent a27b387 commit 3f07d0d
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 34 deletions.
10 changes: 7 additions & 3 deletions CorState/State.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@


from .CorStateError import *
from .Transition import Transition
import importlib


class State:
Expand All @@ -60,13 +60,17 @@ def getID(self) -> int:
"""
return self._id

def initBySFF(self, sff:dict):
def initBySFF(self, sff:dict, path):
"""Method that initialzes state from a dict
Args:
sff (dict, optional): state from file.
"""
pass
self.mod = importlib.import_module("sm", path)
globals().update(self.mod.__dict__)

self._id = sff["id"]
self._action = getattr(self.mod, sff["action"])

def addAction(self, action):
"""Method that adds action to this state
Expand Down
61 changes: 46 additions & 15 deletions CorState/StateMachine.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
----
HISTORY:
2020-09-10 Zen Generating StateMachine from JSON file
2020-09-10 Zen Refactoring the StateMachine structure
'''

Expand Down Expand Up @@ -65,20 +66,20 @@ def start(self):
_breaked = False

for tr in self._transitions.keys():
if self._transitions[tr].getInOutID()[0] == _stateID and _stateID and self._transitions[tr].evaluate():
if self._transitions[tr].getInOutID()[0] == _stateID and self._transitions[tr].evaluate():
_stateID = self._transitions[tr].getInOutID()[1]
_breaked = True
break

if _breaked and _stateID != -2:
self._states[_stateID].run()

def addState(self, value=None):
def addState(self, value=None, path:str=None):
"""Method that adds a state to the StateMachine
"""
if type(value) is dict:
_state = State()
_state.initBySFF(value)
_state.initBySFF(value, path)
elif type(value) is State:
_state = value
elif value is None:
Expand All @@ -97,12 +98,12 @@ def removeState(self, state_id:int):
def getStates(self):
return self._states

def addTransition(self, value=None):
def addTransition(self, value=None, path:str=None):
"""Method that adds a Transition to the TransitionMachine
"""
if type(value) is dict:
_transition = Transition()
_transition.initBySFF(value)
_transition.initByTFF(value, path)
elif type(value) is Transition:
_transition = value
elif value is None:
Expand All @@ -111,7 +112,7 @@ def addTransition(self, value=None):
else:
print("ERROR")

self._transitions[_transition.getInOutID()] = _transition
self._transitions[_transition.getID()] = _transition

def removeTransition(self, transition_id:int):
"""Method which removes a Transition from the Transition Machine
Expand All @@ -121,37 +122,67 @@ def removeTransition(self, transition_id:int):
def _checkStateMachineIntegrity(self):
"""Method that checks the integrity of the StateMachine
"""
pass
if [self._transitions[t].getInOutID()[0] == -1 and self._transitions[t].getInOutID()[1] in self._states.keys() for t in self._transitions.keys()].count(True) != 1:
print("ERROR")

def _checkIntegrity(self):
if [self._transitions[t].getInOutID()[1] == -2 and self._transitions[t].getInOutID()[0] in self._states.keys() for t in self._transitions.keys()].count(True) != 1:
print("ERROR")

def _checkJSONIntegrity(self):
"""Method that checks the JSON file integrity
"""
if not all([k in self._data.keys() for k in ["path", "StateMachine"]]):
print("ERROR")

if not all([k in self._data["StateMachine"].keys() for k in ["Variable", "State", "Transition"]]):
print("ERROR")

if len(self._data["StateMachine"]["State"].keys()) > 0 and not all([k in self._data["StateMachine"]["State"][s].keys() for k in ["id", "action"] for s in self._data["StateMachine"]["State"].keys()]):
print("ERROR")

if not all([t in self._data["StateMachine"]["Transition"].keys() for t in ["in", "out"]]):
print("ERROR")

if not all([k in self._data["StateMachine"]["Transition"][t].keys() for k in ["id_in", "id_out", "evaluation"] for t in self._data["StateMachine"]["Transition"].keys()]):
print("ERROR")

def _generateStateMachineStructure(self):
if not os.path.isfile(self._data["path"]):
print("ERROR")

file_sm = open(self._data["path"], "r+")
lines = file_sm.readlines()

for v in self._data["StateMachine"]["Variable"].keys():
if True not in [v in l for l in lines]:
file_sm.write(v + " = " + str(self._data["StateMachine"]["Variable"][v]) + "\n")

for s in self._data["StateMachine"]["State"].keys():
if True not in ["def state_" + s in l for l in lines]:
file_sm.write("def state_" + s +"():\n\t#TODO\n\tpass\n\n")
if True not in ["def " + self._data["StateMachine"]["State"][s]["action"] in l for l in lines]:
file_sm.write("def " + self._data["StateMachine"]["State"][s]["action"] +"():\n\t#TODO\n\tpass\n\n")

self.addState(self._data["StateMachine"]["State"][s], self._data["path"])

for t in self._data["StateMachine"]["Transition"].keys():
if True not in ["def transition_" + t in l for l in lines]:
file_sm.write("def transition_" + t +"():\n\t#TODO\n\tpass\n\n")
if True not in ["def " + self._data["StateMachine"]["Transition"][t]["evaluation"] in l for l in lines]:
file_sm.write("def " + self._data["StateMachine"]["Transition"][t]["evaluation"] +"():\n\t#TODO\n\tpass\n\n")

self.addTransition(self._data["StateMachine"]["Transition"][t], self._data["path"])

file_sm.close()

def loadJSON(self, path: str):

def loadJSON(self, path:str):
"""Method that loads JSON file
"""
json_file = open(path)
self._data = json.load(json_file)
json_file.close()

self._checkIntegrity()
self._checkJSONIntegrity()
self._generateStateMachineStructure()

def dumpJSON(self):
def dumpJSON(self, name:str):
"""Method that saves StateMachine to a JSON file
"""
pass
Expand Down
11 changes: 8 additions & 3 deletions CorState/Transition.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@


from .CorStateError import *
import importlib


class Transition:
Expand All @@ -50,7 +51,6 @@ def __init__(self):
Transition._nb_transition = Transition._nb_transition + 1

self._ioID = None
self._nsi = None
self._evaluation = None

def getID(self) -> int:
Expand All @@ -61,13 +61,18 @@ def getID(self) -> int:
"""
return self._id

def initByTFF(self, tff:dict):
def initByTFF(self, tff:dict, path):
"""Method that initialzes transition from a dict
Args:
tff (dict, optional): transition from file.
"""
pass
mod = importlib.import_module("sm", path)
globals().update(mod.__dict__)

self._id = tff["id"]
self._ioID = (tff["id_in"], tff["id_out"])
self._evaluation = getattr(mod, tff["evaluation"])

def setInOutID(self, ini:int, outi:int):
"""Method that initializes the in and out state id
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
Lightweight and versatile State Machine library

### Features
* ...
* State Machine implementation
* Load structure from JSON file

### Future improvement
* State Machine implementation

* Petry Net implementation
* GUI editor
* Load structure from JSON file


### More
[![PyPI version](https://badge.fury.io/py/CorState.svg)](https://badge.fury.io/py/CorState)
Expand Down
21 changes: 16 additions & 5 deletions tests/sm.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
def state_s0():
v1 = 0
v2 = False

def fa1():
#TODO
# print("fa1")
pass

def state_s1():
def fa2():
#TODO
# print("fa2")
pass

def transition_in():
def ft1():
#TODO
pass
# print("ft1")
return True

def transition_out():
def ft2():
#TODO
pass
# print("ft2")
return True

def transition_t0():
def ft3():
#TODO
pass
# print("ft3")
return True

17 changes: 13 additions & 4 deletions tests/test.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"path": "./tests/sm.py",
"StateMachine": {
"Variable": {
"v1": 0,
"v2": false
},
"State": {
"s0": {
"id": 0,
Expand All @@ -13,16 +17,21 @@
},
"Transition": {
"in": {
"id_in": 0,
"id": 0,
"id_in": -1,
"id_out": 0,
"evaluation": "ft1"
},
"out": {
"id_out": 1,
"id": 1,
"id_in": 1,
"id_out": -2,
"evaluation": "ft2"
},
"t0": {
"id_out": 0,
"id_in": 1,
"id": 2,
"id_in": 0,
"id_out": 1,
"evaluation": "ft3"
}
}
Expand Down
4 changes: 3 additions & 1 deletion tests/test_StateMachine.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
----
HISTORY:
2020-09-10 Zen Adding test to load and run StateMachine from JSON file
2020-09-10 Zen Adding test to check if the StateMachine works with a single state
'''

Expand Down Expand Up @@ -146,6 +147,7 @@ def test_loadJSONFile():
try:
sm = StateMachine("test")
sm.loadJSON("./tests/test.json")
sm.start()
print("SUCCESSED")
assert True
except:
Expand All @@ -160,5 +162,5 @@ def test_loadJSONFile():
test_addTransitionToSM()
test_simpleSM()
test_runSimpleSM()
# test_loadJSONFile()
test_loadJSONFile()
print("-"*10)

0 comments on commit 3f07d0d

Please sign in to comment.