Skip to content

Commit

Permalink
stateengine plugin: attributes from items, structs, etc. referenced b…
Browse files Browse the repository at this point in the history
…y se_use are now evaluated correctly, even if they are defined as lists.
  • Loading branch information
onkelandy committed Jul 25, 2024
1 parent 6634e68 commit d6f96ff
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 78 deletions.
54 changes: 27 additions & 27 deletions stateengine/StateEngineAction.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,9 @@ def check_getitem_fromeval(self, check_item, check_value=None, check_mindelta=No
'issueorigin': [{'state': 'unknown', 'action': self._function}]}}
return check_item, check_value, check_mindelta, _issue

def check_complete(self, item_state, check_item, check_status, check_mindelta, check_value, action_type, evals_items=None):
def check_complete(self, state, check_item, check_status, check_mindelta, check_value, action_type, evals_items=None):
_issue = {self._name: {'issue': None,
'issueorigin': [{'state': item_state.property.path, 'action': self._function}]}}
'issueorigin': [{'state': state.id, 'action': self._function}]}}
self._log_develop("Check item {} status {} value {} evals_items {}", check_item, check_status, check_value, evals_items)
try:
_name = evals_items.get(self.name)
Expand All @@ -304,36 +304,36 @@ def check_complete(self, item_state, check_item, check_status, check_mindelta, c
else:
_returnissue = None
_issue = {self._name: {'issue': _returnissue,
'issueorigin': [{'state': item_state.property.path, 'action': self._function}]}}
'issueorigin': [{'state': state.id, 'action': self._function}]}}
self._log_debug("Check item {} status {} value {} _returnissue {}", check_item, check_status,
check_value, _returnissue)
except Exception as ex:
self._log_info("No valid item info for action {}, trying to get differently. Problem: {}", self._name, ex)
# missing item in action: Try to find it.
if check_item is None:
item = StateEngineTools.find_attribute(self._sh, item_state, "se_item_" + self._name)
item = StateEngineTools.find_attribute(self._sh, state, "se_item_" + self._name)
if item is not None:
check_item, _issue = self._abitem.return_item(item)
_issue = {self._name: {'issue': _issue,
'issueorigin': [{'state': item_state.property.path, 'action': self._function}]}}
'issueorigin': [{'state': state.id, 'action': self._function}]}}
else:
item = StateEngineTools.find_attribute(self._sh, item_state, "se_eval_" + self._name)
item = StateEngineTools.find_attribute(self._sh, state, "se_eval_" + self._name)
if item is not None:
check_item = str(item)

if check_item is None and _issue[self._name].get('issue') is None:
_issue = {self._name: {'issue': ['Item not defined in rules section'],
'issueorigin': [{'state': item_state.property.path, 'action': self._function}]}}
'issueorigin': [{'state': state.id, 'action': self._function}]}}
# missing status in action: Try to find it.
if check_status is None:
status = StateEngineTools.find_attribute(self._sh, item_state, "se_status_" + self._name)
status = StateEngineTools.find_attribute(self._sh, state, "se_status_" + self._name)
if status is not None:
check_status, _issue = self._abitem.return_item(status)
_issue = {self._name: {'issue': _issue,
'issueorigin': [{'state': item_state.property.path, 'action': self._function}]}}
'issueorigin': [{'state': state.id, 'action': self._function}]}}

if check_mindelta.is_empty():
mindelta = StateEngineTools.find_attribute(self._sh, item_state, "se_mindelta_" + self._name)
mindelta = StateEngineTools.find_attribute(self._sh, state, "se_mindelta_" + self._name)
if mindelta is not None:
check_mindelta.set(mindelta)

Expand All @@ -356,7 +356,7 @@ def check_complete(self, item_state, check_item, check_status, check_mindelta, c
self._log_develop("Issue with {} action {}", action_type, _issue)
else:
_issue = {self._name: {'issue': None,
'issueorigin': [{'state': item_state.property.path, 'action': self._function}]}}
'issueorigin': [{'state': state.id, 'action': self._function}]}}

return check_item, check_status, check_mindelta, check_value, _issue

Expand Down Expand Up @@ -521,8 +521,8 @@ def update(self, value):
raise NotImplementedError("Class {} doesn't implement update()".format(self.__class__.__name__))

# Complete action
# item_state: state item to read from
def complete(self, item_state, evals_items=None):
# state: state (item) to read from
def complete(self, state, evals_items=None):
raise NotImplementedError("Class {} doesn't implement complete()".format(self.__class__.__name__))

# Check if execution is possible
Expand Down Expand Up @@ -624,10 +624,10 @@ def update(self, value):
return _issue

# Complete action
# item_state: state item to read from
def complete(self, item_state, evals_items=None):
# state: state (item) to read from
def complete(self, state, evals_items=None):
self.__item, self.__status, self.__mindelta, self.__value, _issue = self.check_complete(
item_state, self.__item, self.__status, self.__mindelta, self.__value, "set", evals_items)
state, self.__item, self.__status, self.__mindelta, self.__value, "set", evals_items)
self._action_status = _issue
return _issue

Expand Down Expand Up @@ -774,8 +774,8 @@ def update(self, value):
return _issue

# Complete action
# item_state: state item to read from
def complete(self, item_state, evals_items=None):
# state: state (item) to read from
def complete(self, state, evals_items=None):
self._scheduler_name = "{}-SeByAttrDelayTimer".format(self.__byattr)
_issue = {self._name: {'issue': None, 'attribute': self.__byattr,
'issueorigin': [{'state': 'unknown', 'action': self._function}]}}
Expand Down Expand Up @@ -832,8 +832,8 @@ def update(self, value):
return _issue

# Complete action
# item_state: state item to read from
def complete(self, item_state, evals_items=None):
# state: state (item) to read from
def complete(self, state, evals_items=None):
self._scheduler_name = "{}-SeLogicDelayTimer".format(self.__logic)
_issue = {self._name: {'issue': None, 'logic': self.__logic,
'issueorigin': [{'state': 'unknown', 'action': self._function}]}}
Expand Down Expand Up @@ -907,8 +907,8 @@ def update(self, value):
return _issue

# Complete action
# item_state: state item to read from
def complete(self, item_state, evals_items=None):
# state: state (item) to read from
def complete(self, state, evals_items=None):
self._scheduler_name = "{}-SeRunDelayTimer".format(StateEngineTools.get_eval_name(self.__eval))
_issue = {self._name: {'issue': None, 'eval': StateEngineTools.get_eval_name(self.__eval),
'issueorigin': [{'state': 'unknown', 'action': self._function}]}}
Expand Down Expand Up @@ -1002,10 +1002,10 @@ def update(self, value):
return _issue

# Complete action
# item_state: state item to read from
def complete(self, item_state, evals_items=None):
# state: state (item) to read from
def complete(self, state, evals_items=None):
self.__item, self.__status, self.__mindelta, self.__value, _issue = self.check_complete(
item_state, self.__item, self.__status, self.__mindelta, self.__value, "force", evals_items)
state, self.__item, self.__status, self.__mindelta, self.__value, "force", evals_items)
self._action_status = _issue
return _issue

Expand Down Expand Up @@ -1188,8 +1188,8 @@ def update(self, value):
return _issue

# Complete action
# item_state: state item to read from
def complete(self, item_state, evals_items=None):
# state: state (item) to read from
def complete(self, state, evals_items=None):
if isinstance(self.__value, list):
item = self.__value[0].property.path
else:
Expand Down
10 changes: 5 additions & 5 deletions stateengine/StateEngineActions.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,15 +507,15 @@ def __raise_missing_parameter_error(self, parameter, param_name):
"function '{2}'!".format(parameter['action'], param_name, parameter['function']))

# Check the actions optimize and complete them
# item_state: item to read from
def complete(self, item_state, evals_items=None):
# state: state (item) to read from
def complete(self, state, evals_items=None):
_status = {}
for name in self.__actions:
try:
_status.update(self.__actions[name].complete(item_state, evals_items))
_status.update(self.__actions[name].complete(state, evals_items))
except ValueError as ex:
_status.update({name: {'issue': ex, 'issueorigin': {'state': item_state.property.path, 'action': 'unknown'}}})
raise ValueError("State '{0}', Action '{1}': {2}".format(item_state.property.path, name, ex))
_status.update({name: {'issue': ex, 'issueorigin': {'state': state.id, 'action': 'unknown'}}})
raise ValueError("State '{0}', Action '{1}': {2}".format(state.id, name, ex))
return _status

def set(self, value):
Expand Down
16 changes: 8 additions & 8 deletions stateengine/StateEngineCondition.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def __repr__(self):
"'status_eval': {}, 'value': {}".format(self.__item, self.__status, self.__eval,
self.__status_eval, self.__value)

def check_items(self, check, value=None, item_state=None):
def check_items(self, check, value=None, state=None):
item_issue, status_issue, eval_issue, status_eval_issue = None, None, None, None
item_value, status_value, eval_value, status_eval_value = None, None, None, None
if check == "attribute":
Expand All @@ -75,7 +75,7 @@ def check_items(self, check, value=None, item_state=None):
_orig_value = None
if check == "se_item" or (check == "attribute" and self.__item is None and self.__eval is None):
if value is None:
value = StateEngineTools.find_attribute(self._sh, item_state, "se_item_" + self.__name)
value = StateEngineTools.find_attribute(self._sh, state, "se_item_" + self.__name)
if isinstance(value, str):
match = re.match(r'^(.*):', value)
if value.startswith("eval:"):
Expand All @@ -95,7 +95,7 @@ def check_items(self, check, value=None, item_state=None):
if check == "attribute":
value = _orig_value
if value is None:
value = StateEngineTools.find_attribute(self._sh, item_state, "se_status_" + self.__name)
value = StateEngineTools.find_attribute(self._sh, state, "se_status_" + self.__name)
if isinstance(value, str):
match = re.match(r'^(.*):', value)
if isinstance(value, str) and value.startswith("eval:"):
Expand All @@ -114,7 +114,7 @@ def check_items(self, check, value=None, item_state=None):
status_value = value
if check == "se_eval" or (check == "attribute" and self.__eval is None):
if value is None:
value = StateEngineTools.find_attribute(self._sh, item_state, "se_eval_" + self.__name)
value = StateEngineTools.find_attribute(self._sh, state, "se_eval_" + self.__name)
if isinstance(value, str):
match = re.match(r'^(.*):', value)
if value.startswith("eval:"):
Expand All @@ -130,7 +130,7 @@ def check_items(self, check, value=None, item_state=None):
if check == "attribute":
value = _orig_value
if value is None:
value = StateEngineTools.find_attribute(self._sh, item_state, "se_status_eval_" + self.__name)
value = StateEngineTools.find_attribute(self._sh, state, "se_status_eval_" + self.__name)
if isinstance(value, str):
match = re.match(r'^(.*):', value)
if value.startswith("eval:"):
Expand Down Expand Up @@ -223,9 +223,9 @@ def get(self):
return result

# Complete condition (do some checks, cast value, min and max based on item or eval data types)
# item_state: item to read from
# state: state (item) to read from
# abitem_object: Related SeItem instance for later determination of current age and current delay
def complete(self, item_state):
def complete(self, state):
# check if it is possible to complete this condition
if self.__min.is_empty() and self.__max.is_empty() and self.__value.is_empty() \
and self.__agemin.is_empty() and self.__agemax.is_empty() \
Expand Down Expand Up @@ -285,7 +285,7 @@ def complete(self, item_state):
elif self.__name == "original_source":
self.__eval = self._abitem.get_update_original_source

self.check_items("attribute", None, item_state)
self.check_items("attribute", None, state)

# now we should have either 'item' or '(status)eval' set. If not, raise ValueError
if all(item is None for item in [self.__item, self.__status, self.__eval, self.__status_eval]):
Expand Down
13 changes: 8 additions & 5 deletions stateengine/StateEngineConditionSet.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ def update(self, item, grandparent_item):
raise ValueError("Condition {0} error: {1}".format(name, ex))

# Update item from grandparent_item
if grandparent_item is None:
return self.__unused_attributes, self.__used_attributes
for attribute in grandparent_item.conf:
func, name = StateEngineTools.partition_strip(attribute, "_")

Expand Down Expand Up @@ -146,21 +148,22 @@ def update(self, item, grandparent_item):
return self.__unused_attributes, self.__used_attributes

# Check the condition set, optimize and complete it
# item_state: item to read from
def complete(self, item_state):
# state: state (item) to read from
def complete(self, state):
conditions_to_remove = []
# try to complete conditions

for name in self.conditions:
try:
if not self.__conditions[name].complete(item_state):
if not self.__conditions[name].complete(state):
conditions_to_remove.append(name)
continue
except ValueError as ex:
self._abitem.update_attributes(self.__unused_attributes, self.__used_attributes)
self._abitem.update_issues('state', {item_state.property.path: {'issue': ex, 'issueorigin':
self._abitem.update_issues('state', {state.id: {'issue': ex, 'issueorigin':
[{'conditionset': self.name, 'condition': name}]}})
text = "State '{0}', Condition Set '{1}', Condition '{2}' Error: {3}"
raise ValueError(text.format(item_state.property.path, self.name, name, ex))
raise ValueError(text.format(state.id, self.name, name, ex))

# Remove incomplete conditions
for name in conditions_to_remove:
Expand Down
6 changes: 3 additions & 3 deletions stateengine/StateEngineConditionSets.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ def update(self, name, item, grandparent_item):
return self.__condition_sets[name].unused_attributes, self.__condition_sets[name].used_attributes

# Check the condition sets, optimize and complete them
# item_state: item to read from
def complete(self, item_state):
# state: item (item) to read from
def complete(self, state):
for name in self.__condition_sets:
self.__condition_sets[name].complete(item_state)
self.__condition_sets[name].complete(state)

# Write all condition sets to logger
def write_to_logger(self):
Expand Down
5 changes: 5 additions & 0 deletions stateengine/StateEngineItem.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

from lib.shtime import Shtime
from lib.item.item import Item
from lib.item.items import Items
import copy
import threading
import queue
Expand Down Expand Up @@ -1982,6 +1983,10 @@ def return_item(self, item_id):
if item_id is None:
_issue = "item_id is None"
return None, [_issue]
if item_id == Items.get_instance():
_issue = "'{0}' is no valid item.".format(item_id)
self.__logger.warning("{0} Check your item config!", _issue, item_id)
return None, [_issue]
if not isinstance(item_id, str):
_issue = "'{0}' is not defined as string, cannot find item.".format(item_id)
self.__logger.warning("{0} Check your item config!", _issue, item_id)
Expand Down
Loading

0 comments on commit d6f96ff

Please sign in to comment.