Fixed #100 : SheerkaAdmin: Add builtins() command

Fixed #99 : SheerkaQueryManager: I can manage contains predicate when filtering objects
Fixed #97 : ERROR: list indices must be integers or slices, not Concept
Fixed #96 : SequenceNodeParser: SequenceNodeParser must correctly handle concept definition
Fixed #95 : ResolveAmbiguity must not remove concepts that do not require evaluation
Fixed #94 : Concepts with the same key are lost when new ontology
Fixed #93 : Introduce BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED
Fixed #92 : ExpressionParser: Implement compile_disjunctions()
Fixed #91 : Implement get_concepts_complexity(context, concepts, concept_parts)
Fixed #90 : ResolveAmbiguity : where predicate is not used to resolve ambiguity
Fixed #89 : ResolveAmbiguityEvaluator: Concepts embedded in ConceptNode are not resolved
Fixed #88: SyaNodeParser: Parse multiple parameters when some of the are not recognized
Fixed #87: SyaNodeParser : Parse the multiple parameters
This commit is contained in:
2021-07-31 08:52:00 +02:00
parent 7dcaa9c111
commit e69745adc8
70 changed files with 1561 additions and 455 deletions
+66 -15
View File
@@ -46,6 +46,7 @@ RULES_EXECUTE_STEPS = [
# It indicate which parameter was used to recognize the concept
RECOGNIZED_BY_ID = "by_id"
RECOGNIZED_BY_NAME = "by_name"
RECOGNIZED_BY_KEY = "by_key"
@dataclass
@@ -53,9 +54,17 @@ class SheerkaMethod:
"""
Wrapper to sheerka method, to indicate if it's safe to call
"""
name: str
service: str
method: object
has_side_effect: bool
def __repr__(self):
return self.name
def __hash__(self):
return hash((self.name, self.service))
class Sheerka(Concept):
"""
@@ -111,16 +120,18 @@ class Sheerka(Concept):
self.methods_with_context = {"test_using_context"} # only the names, the method is defined in sheerka_methods
self.pipe_functions = set()
self.sheerka_methods = {
"test": SheerkaMethod(self.test, False),
"test_using_context": SheerkaMethod(self.test_using_context, False),
"test_dict": SheerkaMethod(self.test_dict, False),
"test_error": SheerkaMethod(self.test_error, False),
"is_sheerka": SheerkaMethod(self.is_sheerka, False),
"objvalue": SheerkaMethod(self.objvalue, False),
"test": SheerkaMethod("test", self.name, self.test, False),
"test_using_context": SheerkaMethod("test_using_context", self.name, self.test_using_context, False),
"test_dict": SheerkaMethod("test_dict", self.name, self.test_dict, False),
"test_error": SheerkaMethod("test_error", self.name, self.test_error, False),
"is_sheerka": SheerkaMethod("is_sheerka", self.name, self.is_sheerka, False),
"objvalue": SheerkaMethod("objvalue", self.name, self.objvalue, False),
}
self.concepts_ids = None
self._global_context_hints = set() # hints to add to every execution contexts before every execution
def __copy__(self):
return self
@@ -135,9 +146,10 @@ class Sheerka(Concept):
def root_folder(self):
return self.om.root_folder
def bind_service_method(self, bound_method, has_side_effect, as_name=None, visible=True):
def bind_service_method(self, service_name, bound_method, has_side_effect, as_name=None, visible=True):
"""
Bind service method to sheerka instance for ease of use ?
:param service_name:
:param bound_method:
:param has_side_effect: False if the method is safe
:param as_name: give another name to the method
@@ -157,7 +169,7 @@ class Sheerka(Concept):
signature = inspect.signature(bound_method)
if len(signature.parameters) > 0 and list(signature.parameters.keys())[0] == "context":
self.methods_with_context.add(as_name)
self.sheerka_methods[as_name] = SheerkaMethod(bound_method, has_side_effect)
self.sheerka_methods[as_name] = SheerkaMethod(as_name, service_name, bound_method, has_side_effect)
if is_pipe_function:
self.pipe_functions.add(as_name)
@@ -368,6 +380,9 @@ class Sheerka(Concept):
text,
desc=f"Evaluating '{text}'") as execution_context:
# adds the global context hints if any
execution_context.global_hints = self._global_context_hints.copy()
user_input = self.ret(self.name, True, self.new(BuiltinConcepts.USER_INPUT, body=text, user_name=user_name))
execution_context.add_inputs(user_input=user_input)
@@ -465,17 +480,35 @@ class Sheerka(Concept):
return None
def fast_resolve(self, key, return_new=True):
def add_recognized_by(c, _recognized_by):
c.get_hints().recognized_by = _recognized_by
def fast_resolve(self, key, return_new=True, force_instance=False):
"""
Resolve a concept, but do not use get_by_name() or get_by_id()
:param key:
:param return_new:
:param force_instance: When set, return an concept instance, not a concept definition
:return:
"""
def update_hints(c, rec_by, is_inst, is_eval):
c.get_hints().recognized_by = rec_by
c.get_hints().is_instance = is_inst
if is_eval is None:
c.get_hints().is_evaluated = len(c.get_metadata().variables) > 0
else:
c.get_hints().is_evaluated = is_eval
return c
def new_instances(concepts, _recognized_by):
def new_instances(concepts, rec_by, is_inst, is_eval):
if hasattr(concepts, "__iter__"):
return [add_recognized_by(self.new_from_template(c, c.key), _recognized_by) for c in concepts]
return [update_hints(self.new_from_template(c, c.key), rec_by, is_inst, is_eval) for c in
concepts]
return add_recognized_by(self.new_from_template(concepts, concepts.key), _recognized_by)
return update_hints(self.new_from_template(concepts, concepts.key), rec_by, is_inst, is_eval)
# ##############
# PREPROCESS
# ##############
# if the entry is a concept token, use its values.
if isinstance(key, Token):
if key.type == TokenKind.RULE: # do not recognize rules !!!
return None
@@ -484,10 +517,15 @@ class Sheerka(Concept):
elif isinstance(key, str) and key.startswith("c:"):
key = core.utils.unstr_concept(key)
# ##############
# Get the concept(s)
# ##############
if isinstance(key, tuple):
if key == (None, None):
return None
is_instance = force_instance
is_evaluated = not force_instance
if key[1]:
concept = self.om.get(self.CONCEPTS_BY_ID_ENTRY, key[1])
recognized_by = RECOGNIZED_BY_ID
@@ -495,12 +533,15 @@ class Sheerka(Concept):
concept = self.om.get(self.CONCEPTS_BY_NAME_ENTRY, key[0])
recognized_by = RECOGNIZED_BY_NAME
else:
is_instance = True
is_evaluated = None
concept = self.om.get(self.CONCEPTS_BY_NAME_ENTRY, key)
recognized_by = RECOGNIZED_BY_NAME
if concept is NotFound:
return None
return new_instances(concept, recognized_by) if return_new else concept
return new_instances(concept, recognized_by, is_instance, is_evaluated) if return_new else concept
def new(self, concept_key, **kwargs):
"""
@@ -632,6 +673,16 @@ class Sheerka(Concept):
if hasattr(service, "reset_state"):
service.reset_state()
def add_to_context(self, concept_key):
concept_key = concept_key.name if isinstance(concept_key, Concept) else concept_key
self._global_context_hints.add(concept_key)
return self.ret(self.name, True, self.new(BuiltinConcepts.SUCCESS))
def remove_fom_context(self, concept_key):
concept_key = concept_key.name if isinstance(concept_key, Concept) else concept_key
self._global_context_hints.remove(concept_key)
return self.ret(self.name, True, self.new(BuiltinConcepts.SUCCESS))
def ret(self, who: str, status: bool, value, parents=None):
"""
Creates and returns a ReturnValue concept