Files
Sheerka/src/core/ExecutionContext.py
T

220 lines
6.0 KiB
Python

from __future__ import annotations
import time
from core.Event import Event
class ContextActions:
TESTING = "Testing"
INIT_SHEERKA = "Init Sheerka"
EVALUATE_USER_INPUT = "Evaluate user input"
EVALUATING_STEP = "Evaluating step"
EVALUATING_ITERATION = "Evaluating iteration"
BEFORE_PARSING = "Before parsing"
PARSING = "Parsing"
AFTER_PARSING = "After parsing"
BEFORE_EVALUATION = "Before evaluation"
EVALUATION = "Evaluation"
AFTER_EVALUATION = "After Evaluation"
EVALUATING_CONCEPT = "Evaluating concept"
BUILD_CONCEPT = "Building all attributes"
BUILD_CONCEPT_ATTR = "Building one attribute"
EVAL_CONCEPT = "Evaluating all attributes"
EVAL_CONCEPT_ATTR = "Evaluating one attribute"
class ContextHint:
REDUCE_CONCEPTS = "Reduce Concepts" # to tell the process to only keep the meaningful results
EXPRESSION_ONLY_REQUESTED = "Expression Only"
ids = {} # keep track of the next execution context id, for a given event id
def get_next_id(event_digest):
"""
For a given event, give the next id
:param event_digest:
:type event_digest:
:return:
:rtype:
"""
if event_digest in ids:
ids[event_digest] += 1
else:
ids[event_digest] = 0
return ids[event_digest]
class ExecutionContext:
"""
To keep track of the execution of a request
Note that the protected hints are working correctly only if the hint is added BEFORE the creation of the child
"""
def __init__(self,
who: str,
event: Event,
sheerka,
action: ContextActions,
action_context: object,
desc: str = None,
logger=None,
global_hints=None,
protected_hints=None,
parent: ExecutionContext = None):
self._id = get_next_id(event.get_digest())
self._parent = parent
self._children = []
self._start = 0 # when the execution starts (to measure elapsed time)
self._stop = 0 # when the execution stops (to measure elapses time)
self._logger = logger
self.who = who # who is asking
self.event = event # what was the (original) trigger
self.sheerka = sheerka # sheerka
self.action = action
self.action_context = action_context
self.desc = desc # human description of what is going on
self.private_hints = set()
self.protected_hints = set() if protected_hints is None else protected_hints.copy()
self.global_hints = set() if global_hints is None else global_hints
self.inputs = {} # what were the parameters of the execution context
self.values = {} # what was produced by the execution context
def __repr__(self):
msg = f"ExecutionContext(who={self.who}, id={self._id}, action={self.action}, context={self.action_context}"
if self.desc:
msg += f", desc='{self.desc}'"
msg += ")"
return msg
def __eq__(self, other):
if id(self) == id(other):
return True
if not isinstance(other, ExecutionContext):
return False
return self.long_id == other.long_id
def __hash__(self):
return hash(self.long_id)
@property
def long_id(self):
return f"{self.event.get_digest()}:{self._id}"
@property
def medium_id(self):
return f"{self.event.get_digest()[:8]}:{self._id}"
@property
def id(self):
return self._id
@property
def elapsed(self):
if self._start == 0:
return 0
return (self._stop if self._stop > 0 else time.time_ns()) - self._start
@property
def elapsed_str(self):
nano_sec = self.elapsed
dt = nano_sec / 1e6
return f"{dt} ms" if dt < 1000 else f"{dt / 1000} s"
def add_inputs(self, **kwargs):
"""
When entering stacking an ExecutionContext, list of variable that are worth to trace
:param kwargs:
:type kwargs:
:return:
:rtype:
"""
self.inputs.update(kwargs)
return self
def add_values(self, **kwargs):
"""
When popping from an ExecutionContext, list of variable that are worth to trace
:param kwargs:
:type kwargs:
:return:
:rtype:
"""
self.values.update(kwargs)
return self
def push(self,
who: str,
action: ContextActions,
action_context: object,
desc: str = None,
logger=None):
child = ExecutionContext(
who,
self.event,
self.sheerka,
action,
action_context,
desc,
logger or self._logger,
self.global_hints,
self.protected_hints,
self
)
self._children.append(child)
return child
def get_parent(self):
return self._parent
def get_children(self, level=-1):
"""
recursively look for children
:return:
:rtype:
"""
for child in self._children:
yield child
if level != 1:
yield from child.get_children(level - 1)
def get_parents(self, level=-1):
"""
recursively look for parent
:return:
:rtype:
"""
if level == 0 or self._parent is None:
return
yield self._parent
yield from self._parent.get_parents(level - 1)
def in_context(self, hint: ContextHint):
return hint in self.protected_hints or \
hint in self.global_hints or \
hint in self.private_hints
def get_from_short_term_memory(self, key):
return self.sheerka.get_from_short_term_memory(self, key)
def log(self, message: str, who: str = None):
"""Send debug information to logger"""
pass
def __enter__(self):
self._start = time.time_ns()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self._stop = time.time_ns()