Managing concept properties in ConceptEvaluator
This commit is contained in:
@@ -23,9 +23,13 @@ class BuiltinConcepts(Enum):
|
||||
INVALID_RETURN_VALUE = 14 # the return value of an evaluator is not correct
|
||||
BEFORE_PARSING = 15 # activated before evaluation by the parsers
|
||||
PARSING = 16 # activated during the parsing. It contains the text to parse
|
||||
AFTER_PARSING = 17 # activated when the parsing process seems to be finished
|
||||
CONCEPT_ALREADY_DEFINED = 18 # when you try to add the same concept twice
|
||||
NOP = 19 # no operation concept. Does nothing
|
||||
AFTER_PARSING = 17 # after parsing
|
||||
BEFORE_EVALUATION = 18 # before evalution
|
||||
EVALUATION = 19 # activated when the parsing process seems to be finished
|
||||
AFTER_EVALUATION = 20 # activated when the parsing process seems to be finished
|
||||
CONCEPT_ALREADY_DEFINED = 21 # when you try to add the same concept twice
|
||||
NOP = 22 # no operation concept. Does nothing
|
||||
PROPERTY_EVAL_ERROR = 23
|
||||
|
||||
|
||||
"""
|
||||
@@ -198,11 +202,34 @@ class BeforeParsingConcept(Concept):
|
||||
super().__init__(BuiltinConcepts.BEFORE_PARSING, True, True, BuiltinConcepts.BEFORE_PARSING)
|
||||
|
||||
|
||||
class ParsingConcept(Concept):
|
||||
class EvaluationConcept(Concept):
|
||||
def __init__(self):
|
||||
super().__init__(BuiltinConcepts.PARSING, True, True, BuiltinConcepts.PARSING)
|
||||
super().__init__(BuiltinConcepts.EVALUATION, True, True, BuiltinConcepts.EVALUATION)
|
||||
|
||||
|
||||
class AfterParsingConcept(Concept):
|
||||
class AfterEvaluationConcept(Concept):
|
||||
def __init__(self):
|
||||
super().__init__(BuiltinConcepts.AFTER_PARSING, True, True, BuiltinConcepts.AFTER_PARSING)
|
||||
super().__init__(BuiltinConcepts.AFTER_EVALUATION, True, True, BuiltinConcepts.AFTER_EVALUATION)
|
||||
|
||||
|
||||
class PropertyEvalError(Concept):
|
||||
def __init__(self, property_name=None, concept=None, error=None):
|
||||
super().__init__(BuiltinConcepts.PROPERTY_EVAL_ERROR, True, False, BuiltinConcepts.PROPERTY_EVAL_ERROR)
|
||||
self.set_prop("concept", concept)
|
||||
self.set_prop("error", error)
|
||||
self.body = property_name
|
||||
|
||||
def __repr__(self):
|
||||
return f"PropertyEvalError(property={self.property_name}, concept={self.concept}), error={self.error})"
|
||||
|
||||
@property
|
||||
def concept(self):
|
||||
return self.props["concept"].value
|
||||
|
||||
@property
|
||||
def error(self):
|
||||
return self.props["error"].value
|
||||
|
||||
@property
|
||||
def property_name(self):
|
||||
return self.body
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ class Concept:
|
||||
# check the attributes
|
||||
for prop in self.props_to_serialize:
|
||||
if getattr(self, prop) != getattr(other, prop):
|
||||
print(prop)
|
||||
# print(prop) # use full to know which id does not match
|
||||
return False
|
||||
|
||||
# check the props (Concept variables)
|
||||
|
||||
+59
-22
@@ -150,19 +150,24 @@ class Sheerka(Concept):
|
||||
evt_digest = self.sdp.save_event(Event(text))
|
||||
exec_context = ExecutionContext(self.key, evt_digest, self)
|
||||
|
||||
before_parsing = self.ret(self.eval.__name__, True, self.new(BuiltinConcepts.BEFORE_PARSING))
|
||||
# Before parsing
|
||||
before_parsing = self.new(BuiltinConcepts.BEFORE_PARSING)
|
||||
return_values = self.process(exec_context, [], [before_parsing])
|
||||
return_values = core.utils.remove_from_list(return_values, [before_parsing])
|
||||
return_values = core.utils.remove_from_list(return_values, lambda x: x.value == before_parsing)
|
||||
|
||||
# parse
|
||||
parsing_results = self.parse(exec_context, text)
|
||||
return_values.extend(parsing_results)
|
||||
processing_parsing = self.ret(self.eval.__name__, True, self.new(BuiltinConcepts.PARSING))
|
||||
return_values = self.process(exec_context, return_values, [processing_parsing])
|
||||
return_values = core.utils.remove_from_list(return_values, [processing_parsing])
|
||||
|
||||
after_parsing = self.ret(self.eval.__name__, True, self.new(BuiltinConcepts.AFTER_PARSING))
|
||||
return_values = self.process(exec_context, return_values, [after_parsing])
|
||||
return_values = core.utils.remove_from_list(return_values, [after_parsing])
|
||||
# evaluate
|
||||
evaluating = self.new(BuiltinConcepts.EVALUATION)
|
||||
return_values = self.process(exec_context, return_values, [evaluating])
|
||||
return_values = core.utils.remove_from_list(return_values, lambda x: x.value == evaluating)
|
||||
|
||||
# post evaluation
|
||||
after_evaluation = self.new(BuiltinConcepts.AFTER_EVALUATION)
|
||||
return_values = self.process(exec_context, return_values, [after_evaluation])
|
||||
return_values = core.utils.remove_from_list(return_values, lambda x: x.value == after_evaluation)
|
||||
|
||||
return return_values
|
||||
|
||||
@@ -207,17 +212,17 @@ class Sheerka(Concept):
|
||||
result.append(res)
|
||||
return result
|
||||
|
||||
def process(self, context, return_values, contextual_concepts=None):
|
||||
contextual_concepts_values = [c.value for c in contextual_concepts] if contextual_concepts else []
|
||||
log.debug(f"Processing parsing result. context concept={contextual_concepts_values}")
|
||||
def process(self, context, return_values, initial_concepts=None):
|
||||
log.debug(f"Processing parsing result. context concept={initial_concepts}")
|
||||
|
||||
# return_values must be a list
|
||||
if not isinstance(return_values, list):
|
||||
return_values = [return_values]
|
||||
|
||||
# adds contextual concepts
|
||||
if contextual_concepts:
|
||||
return_values.extend(contextual_concepts)
|
||||
if initial_concepts:
|
||||
for concept in initial_concepts:
|
||||
return_values.append(self.ret(context.who, True, concept))
|
||||
|
||||
# group the evaluators by priority and sort them
|
||||
# The first one to be applied will be the one with the highest priority
|
||||
@@ -261,6 +266,8 @@ class Sheerka(Concept):
|
||||
else:
|
||||
if evaluator.matches(context, original_items):
|
||||
results = evaluator.eval(context, original_items)
|
||||
if results is None:
|
||||
continue
|
||||
if not isinstance(results, list):
|
||||
results = [results]
|
||||
for result in results:
|
||||
@@ -277,6 +284,24 @@ class Sheerka(Concept):
|
||||
|
||||
return return_values
|
||||
|
||||
def chain_process(self, context, return_values, initial_concepts):
|
||||
"""
|
||||
Executes process for all initial contexts
|
||||
:param context:
|
||||
:param return_values:
|
||||
:param initial_concepts:
|
||||
:return:
|
||||
"""
|
||||
for concept in initial_concepts:
|
||||
if isinstance(concept, BuiltinConcepts):
|
||||
concept = self.new(BuiltinConcepts)
|
||||
|
||||
init = [self.ret(context.who, True, concept)]
|
||||
return_values = self.process(context, return_values, [init])
|
||||
return_values = core.utils.remove_from_list(return_values, lambda x: x.value == init)
|
||||
|
||||
return return_values
|
||||
|
||||
def create_new_concept(self, context, concept):
|
||||
"""
|
||||
Adds a new concept to the system
|
||||
@@ -319,13 +344,14 @@ class Sheerka(Concept):
|
||||
for part_key in ConceptParts:
|
||||
source = getattr(concept, part_key.value)
|
||||
if source is None or not isinstance(source, str) or source == "":
|
||||
|
||||
# the only sources that I am sure to parse are strings
|
||||
# I refuse empty strings for performance, I don't want to handle useless NOPConcepts
|
||||
continue
|
||||
else:
|
||||
concept.codes[part_key] = self.parse(context, source)
|
||||
|
||||
ret_val = self.expect_one(context, self.parse(context, source))
|
||||
concept.codes[part_key] = ret_val
|
||||
for prop in concept.props:
|
||||
concept.codes[prop] = self.parse(context, concept.props[prop].value)
|
||||
|
||||
def add_in_cache(self, concept):
|
||||
"""
|
||||
@@ -334,7 +360,16 @@ class Sheerka(Concept):
|
||||
:param concept:
|
||||
:return:
|
||||
"""
|
||||
|
||||
# sanity check
|
||||
if concept.key is None:
|
||||
concept.init_key()
|
||||
|
||||
if concept.key is None:
|
||||
raise KeyError()
|
||||
|
||||
self.concepts_cache[concept.key] = concept
|
||||
return concept
|
||||
|
||||
def get(self, concept_key):
|
||||
"""
|
||||
@@ -455,7 +490,7 @@ class Sheerka(Concept):
|
||||
base_class = core.utils.get_class("parsers.BaseParser.BaseParser")
|
||||
|
||||
for c in core.utils.get_classes_recursive("parsers"):
|
||||
#if issubclass(c, base_class) and c != base_class:
|
||||
# if issubclass(c, base_class) and c != base_class:
|
||||
res.append(c)
|
||||
|
||||
return res
|
||||
@@ -470,9 +505,11 @@ class ExecutionContext:
|
||||
"""
|
||||
To keep track of the execution of a request
|
||||
"""
|
||||
who: object
|
||||
event_digest: str
|
||||
sheerka: Sheerka
|
||||
who: object # who is asking
|
||||
event_digest: str # what was the (original) trigger
|
||||
sheerka: Sheerka # sheerka
|
||||
desc: str = None # human description of what is going on
|
||||
obj: Concept = None # what is the subject of the execution context (if known)
|
||||
|
||||
def push(self, who):
|
||||
return ExecutionContext(who, self.event_digest, self.sheerka)
|
||||
def push(self, who, desc=None, obj=None):
|
||||
return ExecutionContext(who, self.event_digest, self.sheerka, desc=desc, obj=obj)
|
||||
|
||||
+8
-4
@@ -106,7 +106,6 @@ def get_classes_from_package(package_name):
|
||||
|
||||
|
||||
def get_sub_classes(package_name, base_class_name):
|
||||
|
||||
pkg = __import__(package_name)
|
||||
prefix = pkg.__name__ + "."
|
||||
for (module_loader, name, ispkg) in pkgutil.iter_modules(pkg.__path__, prefix):
|
||||
@@ -123,8 +122,13 @@ def remove_from_list(lst, to_remove):
|
||||
:param to_remove:
|
||||
:return:
|
||||
"""
|
||||
for item in to_remove:
|
||||
if item in lst:
|
||||
lst.remove(item)
|
||||
|
||||
flagged = []
|
||||
for item in lst:
|
||||
if to_remove(item):
|
||||
flagged.append(item)
|
||||
|
||||
for item in flagged:
|
||||
lst.remove(item)
|
||||
|
||||
return lst
|
||||
|
||||
Reference in New Issue
Block a user