Enhanced PythonEvaluator to accept concepts
This commit is contained in:
+104
-50
@@ -5,11 +5,14 @@ from evaluators.BaseEvaluator import OneReturnValueEvaluator
|
||||
from parsers.BaseParser import BaseParser
|
||||
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event, SheerkaDataProviderDuplicateKeyError
|
||||
import core.utils
|
||||
import core.builtin_helpers
|
||||
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
concept_evaluation_steps = [BuiltinConcepts.EVALUATION, BuiltinConcepts.AFTER_EVALUATION]
|
||||
|
||||
|
||||
class Sheerka(Concept):
|
||||
"""
|
||||
@@ -150,6 +153,12 @@ class Sheerka(Concept):
|
||||
logging.basicConfig(format=log_format, level=log_level)
|
||||
|
||||
def eval(self, text):
|
||||
"""
|
||||
Note to KSI: If you try to add execution context to this function,
|
||||
You may end in an infinite loop
|
||||
:param text:
|
||||
:return:
|
||||
"""
|
||||
evt_digest = self.sdp.save_event(Event(text))
|
||||
exec_context = ExecutionContext(self.key, evt_digest, self)
|
||||
|
||||
@@ -174,32 +183,6 @@ class Sheerka(Concept):
|
||||
|
||||
return return_values
|
||||
|
||||
def expect_one(self, context, items):
|
||||
|
||||
if not isinstance(items, list):
|
||||
items = [items]
|
||||
|
||||
if len(items) == 0:
|
||||
return self.ret(context.who, False, self.new(BuiltinConcepts.IS_EMPTY, obj=items))
|
||||
|
||||
successful_results = [item for item in items if item.status]
|
||||
number_of_successful = len(successful_results)
|
||||
total_items = len(items)
|
||||
|
||||
# remove errors when a winner is found
|
||||
if number_of_successful == 1:
|
||||
# log.debug(f"1 / {total_items} good item found.")
|
||||
return successful_results[0]
|
||||
|
||||
# too many winners, which one to choose ?
|
||||
if number_of_successful > 1:
|
||||
log.debug(f"{number_of_successful} / {total_items} good items. Too many success")
|
||||
return self.ret(context.who, False, self.new(BuiltinConcepts.TOO_MANY_SUCCESS, obj=successful_results))
|
||||
|
||||
# only errors, i cannot help you
|
||||
log.debug(f"{total_items} items. Only errors")
|
||||
return self.ret(context.who, False, self.new(BuiltinConcepts.TOO_MANY_ERRORS, obj=items))
|
||||
|
||||
def parse(self, context, text):
|
||||
result = []
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
@@ -356,6 +339,33 @@ class Sheerka(Concept):
|
||||
for prop in concept.props:
|
||||
concept.codes[prop] = self.parse(context, concept.props[prop].value)
|
||||
|
||||
# updates the code of the reference when possible
|
||||
if concept.key in self.concepts_cache:
|
||||
entry = self.concepts_cache[concept.key]
|
||||
if isinstance(entry, list):
|
||||
# TODO : manage when there are multiple entries
|
||||
pass
|
||||
else:
|
||||
self.concepts_cache[concept.key].codes = concept.codes
|
||||
|
||||
def eval_concept(self, context, concept, properties_to_eval=None):
|
||||
if len(concept.codes) == 0:
|
||||
self.add_codes_to_concept(context, concept)
|
||||
|
||||
if properties_to_eval is None:
|
||||
properties_to_eval = ["where", "pre", "post", "body", "props"]
|
||||
|
||||
for prop in properties_to_eval:
|
||||
if prop == "props":
|
||||
pass
|
||||
else:
|
||||
part_key = ConceptParts(prop)
|
||||
if concept.codes[part_key] is None:
|
||||
continue
|
||||
res = self.chain_process(context, concept.codes[part_key], concept_evaluation_steps)
|
||||
res = core.builtin_helpers.expect_one(context, res)
|
||||
setattr(concept, prop, res.value)
|
||||
|
||||
def add_in_cache(self, concept):
|
||||
"""
|
||||
Adds a concept template in cache.
|
||||
@@ -413,16 +423,37 @@ class Sheerka(Concept):
|
||||
"""
|
||||
template = self.get(concept_key)
|
||||
|
||||
def new_from_template(t, k, **kwargs_):
|
||||
# manage singleton
|
||||
if t.is_unique:
|
||||
return t
|
||||
|
||||
# otherwise, create another instance
|
||||
concept = self.builtin_cache[k]() if k in self.builtin_cache else Concept()
|
||||
concept.update_from(t)
|
||||
|
||||
# update the properties
|
||||
for k, v in kwargs_.items():
|
||||
if k in concept.props:
|
||||
concept.set_prop(k, v)
|
||||
elif hasattr(concept, k):
|
||||
setattr(concept, k, v)
|
||||
else:
|
||||
return self.new(BuiltinConcepts.UNKNOWN_PROPERTY, body=k, concept=concept)
|
||||
|
||||
# TODO : add the concept to the list of known concepts (self.instances)
|
||||
return concept
|
||||
|
||||
# manage concept not found
|
||||
if self.isinstance(template, BuiltinConcepts.UNKNOWN_CONCEPT) and \
|
||||
concept_key != BuiltinConcepts.UNKNOWN_CONCEPT:
|
||||
return template
|
||||
|
||||
if not isinstance(template, list):
|
||||
return self._new_from_template(template, concept_key, **kwargs)
|
||||
return new_from_template(template, concept_key, **kwargs)
|
||||
|
||||
# if template is a list, it means that there a multiple concepts under the same key
|
||||
concepts = [self._new_from_template(t, concept_key, **kwargs) for t in template]
|
||||
concepts = [new_from_template(t, concept_key, **kwargs) for t in template]
|
||||
return self.new(BuiltinConcepts.ENUMERATION, body=concepts)
|
||||
|
||||
def ret(self, who, status, value, message=None, parents=None):
|
||||
@@ -443,6 +474,29 @@ class Sheerka(Concept):
|
||||
message=message,
|
||||
parents=parents)
|
||||
|
||||
def value(self, obj, allow_none_body=False):
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
if not isinstance(obj, Concept):
|
||||
return obj
|
||||
|
||||
if hasattr(obj, "get_value"):
|
||||
return obj.get_value()
|
||||
|
||||
if obj.body is not None:
|
||||
return obj.body
|
||||
|
||||
return obj if allow_none_body else self.new(BuiltinConcepts.CANNOT_RESOLVE_VALUE_ERROR, body=obj)
|
||||
|
||||
def values(self, objs):
|
||||
if not (isinstance(objs, list) or
|
||||
self.isinstance(objs, BuiltinConcepts.LIST) or
|
||||
self.isinstance(objs, BuiltinConcepts.ENUMERATION)):
|
||||
objs = [objs]
|
||||
|
||||
return (self.value(obj) for obj in objs)
|
||||
|
||||
def isinstance(self, a, b):
|
||||
"""
|
||||
return true if the concept a is an instance of the concept b
|
||||
@@ -463,6 +517,27 @@ class Sheerka(Concept):
|
||||
# for example, if a is a color, it will be found the entry 'All_Colors'
|
||||
return a.key == b_key
|
||||
|
||||
def isa(self, a, b):
|
||||
"""
|
||||
return true if the concept a is a b
|
||||
Will handle when the keyword isa will be implemented
|
||||
:param a:
|
||||
:param b:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if isinstance(a, BuiltinConcepts): # common KSI error ;-)
|
||||
raise SyntaxError("Remember that the first parameter of isinstance MUST be a concept")
|
||||
|
||||
if not isinstance(a, Concept):
|
||||
return False
|
||||
|
||||
b_key = b.key if isinstance(b, Concept) else str(b)
|
||||
|
||||
# TODO : manage when a is the list of all possible b
|
||||
# for example, if a is a color, it will be found the entry 'All_Colors'
|
||||
return a.key == b_key
|
||||
|
||||
def get_evaluator_name(self, name):
|
||||
if self.evaluators_prefix is None:
|
||||
base_evaluator_class = core.utils.get_class("evaluators.BaseEvaluator.BaseEvaluator")
|
||||
@@ -486,28 +561,7 @@ class Sheerka(Concept):
|
||||
else:
|
||||
res.append(item)
|
||||
|
||||
return sorted(res, key=lambda i: i.key)
|
||||
|
||||
def _new_from_template(self, template, concept_key, **kwargs):
|
||||
# manage singleton
|
||||
if template.is_unique:
|
||||
return template
|
||||
|
||||
# otherwise, create another instance
|
||||
concept = self.builtin_cache[concept_key]() if concept_key in self.builtin_cache else Concept()
|
||||
concept.update_from(template)
|
||||
|
||||
# update the properties
|
||||
for k, v in kwargs.items():
|
||||
if k in concept.props:
|
||||
concept.set_prop(k, v)
|
||||
elif hasattr(concept, k):
|
||||
setattr(concept, k, v)
|
||||
else:
|
||||
return self.new(BuiltinConcepts.UNKNOWN_PROPERTY, body=k, concept=concept)
|
||||
|
||||
# TODO : add the concept to the list of known concepts (self.instances)
|
||||
return concept
|
||||
return sorted(res, key=lambda i: int(i.id))
|
||||
|
||||
@staticmethod
|
||||
def get_builtins_classes_as_dict():
|
||||
|
||||
Reference in New Issue
Block a user