Added first implementation of concepts ambiguity resolution + Jenkins file test
This commit is contained in:
+45
-11
@@ -1,5 +1,6 @@
|
||||
import inspect
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
|
||||
import core.builtin_helpers
|
||||
import core.utils
|
||||
@@ -22,6 +23,15 @@ BASE_NODE_PARSER_CLASS = "parsers.BaseNodeParser.BaseNodeParser"
|
||||
EXIT_COMMANDS = ("quit", "exit", "bye")
|
||||
|
||||
|
||||
@dataclass
|
||||
class SheerkaMethod:
|
||||
"""
|
||||
Wrapper to sheerka method, to indicate if it's safe to call
|
||||
"""
|
||||
method: object
|
||||
has_side_effect: bool
|
||||
|
||||
|
||||
class Sheerka(Concept):
|
||||
"""
|
||||
Main controller for the project
|
||||
@@ -55,6 +65,7 @@ class Sheerka(Concept):
|
||||
self.log.debug("Starting Sheerka.")
|
||||
|
||||
self.bnp = None # reference to the BaseNodeParser class (to compute first keyword token)
|
||||
self.return_value_concept_id = None
|
||||
|
||||
# a concept can be instantiated
|
||||
# ex: File is a concept, but File('foo.txt') is an instance
|
||||
@@ -84,10 +95,10 @@ class Sheerka(Concept):
|
||||
|
||||
self.save_execution_context = True
|
||||
|
||||
self.methods_with_context = {"test_using_context"}
|
||||
self.methods_with_context = {"test_using_context"} # only the names, the method is defined in sheerka_methods
|
||||
self.sheerka_methods = {
|
||||
"test": self.test,
|
||||
"test_using_context": self.test_using_context
|
||||
"test": SheerkaMethod(self.test, False),
|
||||
"test_using_context": SheerkaMethod(self.test_using_context, False)
|
||||
}
|
||||
self.sheerka_pipeables = {}
|
||||
|
||||
@@ -119,10 +130,11 @@ class Sheerka(Concept):
|
||||
def chicken_and_eggs(self):
|
||||
return self.cache_manager.caches[self.CONCEPTS_GRAMMARS_ENTRY].cache
|
||||
|
||||
def bind_service_method(self, bound_method, as_name=None):
|
||||
def bind_service_method(self, bound_method, has_side_effect, as_name=None):
|
||||
"""
|
||||
Bind service method to sheerka instance for ease of use ?
|
||||
:param bound_method:
|
||||
:param has_side_effect: False if the method is safe
|
||||
:param as_name:
|
||||
:return:
|
||||
"""
|
||||
@@ -132,18 +144,19 @@ 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] = bound_method
|
||||
self.sheerka_methods[as_name] = SheerkaMethod(bound_method, has_side_effect)
|
||||
|
||||
setattr(self, as_name, bound_method)
|
||||
|
||||
def add_pipeable(self, func_name, function):
|
||||
def add_pipeable(self, func_name, function, has_side_effect):
|
||||
"""
|
||||
Adds a function that can bu used with pipe '|'
|
||||
:param func_name:
|
||||
:param function:
|
||||
:param has_side_effect:
|
||||
:return:
|
||||
"""
|
||||
self.sheerka_pipeables[func_name] = function
|
||||
self.sheerka_pipeables[func_name] = SheerkaMethod(function, has_side_effect)
|
||||
|
||||
def initialize(self, root_folder: str = None, save_execution_context=True):
|
||||
"""
|
||||
@@ -292,6 +305,10 @@ class Sheerka(Concept):
|
||||
self.init_log.debug(f"'{concept.name}' concept is not found in db. Adding.")
|
||||
self.set_id_if_needed(concept, True)
|
||||
self.cache_manager.add_concept(concept)
|
||||
|
||||
if key == BuiltinConcepts.RETURN_VALUE:
|
||||
self.return_value_concept_id = concept.id
|
||||
|
||||
else:
|
||||
self.init_log.debug(f"Found concept '{from_db}' in db. Updating.")
|
||||
concept.update_from(from_db)
|
||||
@@ -595,6 +612,8 @@ class Sheerka(Concept):
|
||||
:param concept_id:
|
||||
:return:
|
||||
"""
|
||||
if concept_id is None:
|
||||
return False
|
||||
return self.cache_manager.has(self.CONCEPTS_BY_ID_ENTRY, concept_id)
|
||||
|
||||
def has_key(self, concept_key):
|
||||
@@ -652,6 +671,7 @@ class Sheerka(Concept):
|
||||
return self.new_from_template(template, concept_key, **kwargs)
|
||||
|
||||
def new_from_template(self, template, key, **kwargs):
|
||||
# core.utils.my_debug(f"Created {template}, {key=}, {kwargs=}")
|
||||
# manage singleton
|
||||
if template.metadata.is_unique:
|
||||
return template
|
||||
@@ -677,7 +697,7 @@ class Sheerka(Concept):
|
||||
return self.new(BuiltinConcepts.UNKNOWN_PROPERTY, body=k, concept=concept)
|
||||
|
||||
# TODO : add the concept to the list of known concepts (self.instances)
|
||||
concept.metadata.is_evaluated = True # because we have manually set the variables
|
||||
concept.metadata.is_evaluated = True # because we have manually set the variables
|
||||
return concept
|
||||
|
||||
def ret(self, who: str, status: bool, value, message=None, parents=None):
|
||||
@@ -690,13 +710,23 @@ class Sheerka(Concept):
|
||||
:param parents:
|
||||
:return:
|
||||
"""
|
||||
return self.new(
|
||||
BuiltinConcepts.RETURN_VALUE,
|
||||
|
||||
# 1 second saved every twenty seconds in unit tests
|
||||
return ReturnValueConcept(
|
||||
who=who,
|
||||
status=status,
|
||||
value=value,
|
||||
message=message,
|
||||
parents=parents)
|
||||
parents=parents,
|
||||
concept_id=self.return_value_concept_id
|
||||
)
|
||||
# return self.new(
|
||||
# BuiltinConcepts.RETURN_VALUE,
|
||||
# who=who,
|
||||
# status=status,
|
||||
# value=value,
|
||||
# message=message,
|
||||
# parents=parents)
|
||||
|
||||
def objvalue(self, obj, reduce_simple_list=False):
|
||||
if obj is None:
|
||||
@@ -812,6 +842,10 @@ class Sheerka(Concept):
|
||||
if isinstance(obj, ReturnValueConcept):
|
||||
return obj.status
|
||||
|
||||
# other cases ?
|
||||
# ...
|
||||
|
||||
# manage internal errors
|
||||
if isinstance(obj, Concept) and obj.metadata.is_builtin and obj.key in BuiltinErrors:
|
||||
return False
|
||||
|
||||
|
||||
@@ -14,11 +14,11 @@ class SheerkaAdmin(BaseService):
|
||||
super().__init__(sheerka)
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.caches_names)
|
||||
self.sheerka.bind_service_method(self.cache)
|
||||
self.sheerka.bind_service_method(self.restore)
|
||||
self.sheerka.bind_service_method(self.concepts)
|
||||
self.sheerka.bind_service_method(self.last_created_concept)
|
||||
self.sheerka.bind_service_method(self.caches_names, False)
|
||||
self.sheerka.bind_service_method(self.cache, False)
|
||||
self.sheerka.bind_service_method(self.restore, True)
|
||||
self.sheerka.bind_service_method(self.concepts, False)
|
||||
self.sheerka.bind_service_method(self.last_created_concept, False)
|
||||
|
||||
def caches_names(self):
|
||||
"""
|
||||
|
||||
@@ -90,10 +90,10 @@ class SheerkaComparisonManager(BaseService):
|
||||
cache = Cache()
|
||||
self.sheerka.cache_manager.register_cache(self.RESOLVED_COMPARISON_ENTRY, cache, persist=False)
|
||||
|
||||
self.sheerka.bind_service_method(self.set_is_greater_than)
|
||||
self.sheerka.bind_service_method(self.set_is_less_than)
|
||||
self.sheerka.bind_service_method(self.get_partition)
|
||||
self.sheerka.bind_service_method(self.get_concepts_weights)
|
||||
self.sheerka.bind_service_method(self.set_is_greater_than, True)
|
||||
self.sheerka.bind_service_method(self.set_is_less_than, True)
|
||||
self.sheerka.bind_service_method(self.get_partition, False)
|
||||
self.sheerka.bind_service_method(self.get_concepts_weights, False)
|
||||
|
||||
def set_is_greater_than(self, context, prop_name, concept_a, concept_b, comparison_context="#"):
|
||||
"""
|
||||
|
||||
@@ -20,7 +20,7 @@ class SheerkaCreateNewConcept(BaseService):
|
||||
self.bnp = core.utils.get_class(BASE_NODE_PARSER_CLASS) # BaseNodeParser
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.create_new_concept)
|
||||
self.sheerka.bind_service_method(self.create_new_concept, True)
|
||||
|
||||
def create_new_concept(self, context, concept: Concept):
|
||||
"""
|
||||
|
||||
@@ -21,8 +21,8 @@ class SheerkaDump(BaseService):
|
||||
super().__init__(sheerka)
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.dump_desc, "desc")
|
||||
self.sheerka.bind_service_method(self.dump_sdp, "dump_sdp")
|
||||
self.sheerka.bind_service_method(self.dump_desc, True, "desc") # because concept is evaluated
|
||||
self.sheerka.bind_service_method(self.dump_sdp, False, "dump_sdp")
|
||||
|
||||
def dump_desc(self, *concept_names, eval=False):
|
||||
first = True
|
||||
@@ -42,7 +42,7 @@ class SheerkaDump(BaseService):
|
||||
|
||||
for c in concepts:
|
||||
if eval:
|
||||
evaluated = self.sheerka.evaluate_concept(context, c)
|
||||
evaluated = self.sheerka.evaluate_concept(context, c, eval_body=eval)
|
||||
value = evaluated.body if evaluated.key == c.key else evaluated
|
||||
|
||||
if not first:
|
||||
|
||||
@@ -2,6 +2,7 @@ from core.builtin_concepts import BuiltinConcepts
|
||||
from core.builtin_helpers import expect_one, only_successful
|
||||
from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved
|
||||
from core.sheerka.services.sheerka_service import BaseService
|
||||
from core.tokenizer import Tokenizer
|
||||
from core.utils import unstr_concept
|
||||
|
||||
CONCEPT_EVALUATION_STEPS = [
|
||||
@@ -17,16 +18,23 @@ class SheerkaEvaluateConcept(BaseService):
|
||||
super().__init__(sheerka)
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.evaluate_concept)
|
||||
self.sheerka.bind_service_method(self.evaluate_concept, True)
|
||||
|
||||
@staticmethod
|
||||
def infinite_recursion_detected(context, concept):
|
||||
"""
|
||||
Browse the parents, looking for another evaluation of the same concept
|
||||
:param context:
|
||||
:param concept:
|
||||
:return:
|
||||
"""
|
||||
if concept is None:
|
||||
return False
|
||||
|
||||
parent = context.get_parent()
|
||||
while parent is not None:
|
||||
if parent.who == context.who and parent.obj == concept and parent.obj.compiled == concept.compiled:
|
||||
if parent.who == context.who and parent.action == BuiltinConcepts.EVALUATING_CONCEPT and \
|
||||
parent.obj == concept and parent.obj.compiled == concept.compiled:
|
||||
return True
|
||||
|
||||
parent = parent.get_parent()
|
||||
@@ -64,7 +72,7 @@ class SheerkaEvaluateConcept(BaseService):
|
||||
parent = context
|
||||
concepts_found = set()
|
||||
while parent and parent.obj:
|
||||
if parent.who == context.who and parent.desc == context.desc:
|
||||
if parent.who == context.who and parent.action == BuiltinConcepts.EVALUATING_CONCEPT:
|
||||
body = parent.obj.metadata.body
|
||||
try:
|
||||
return self.sheerka.ret(self.NAME, True, InfiniteRecursionResolved(eval(body)))
|
||||
@@ -180,8 +188,7 @@ class SheerkaEvaluateConcept(BaseService):
|
||||
|
||||
path = get_path(context, current_prop)
|
||||
desc = f"Evaluating {path} (concept={current_concept})"
|
||||
context.log(desc, self.NAME)
|
||||
with context.push(BuiltinConcepts.EVALUATING_CONCEPT,
|
||||
with context.push(BuiltinConcepts.EVALUATING_ATTRIBUTE,
|
||||
current_prop,
|
||||
desc=desc,
|
||||
obj=current_concept,
|
||||
@@ -191,14 +198,14 @@ class SheerkaEvaluateConcept(BaseService):
|
||||
sub_context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
|
||||
if expect_success:
|
||||
sub_context.local_hints.add(BuiltinConcepts.EVAL_SUCCESS_REQUESTED)
|
||||
sub_context.local_hints.add(BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED)
|
||||
|
||||
# when it's a concept, evaluate it
|
||||
if isinstance(to_resolve, Concept) and \
|
||||
not context.sheerka.isinstance(to_resolve, BuiltinConcepts.RETURN_VALUE):
|
||||
evaluated = self.evaluate_concept(sub_context, to_resolve)
|
||||
sub_context.add_values(return_values=evaluated)
|
||||
if evaluated.key == to_resolve.key:
|
||||
if evaluated.key == to_resolve.key: # quicker (and dirtier) than sheerka.is_success()
|
||||
return self.apply_ret(evaluated)
|
||||
else:
|
||||
error = evaluated
|
||||
@@ -253,51 +260,78 @@ class SheerkaEvaluateConcept(BaseService):
|
||||
|
||||
return res
|
||||
|
||||
def evaluate_concept(self, context, concept: Concept):
|
||||
def evaluate_concept(self, context, concept: Concept, eval_body=False, metadata=None):
|
||||
"""
|
||||
Evaluation a concept
|
||||
It means that if the where clause is True, will evaluate the body
|
||||
:param context:
|
||||
:param concept:
|
||||
:param eval_body:
|
||||
:param metadata: list of metadata to evaluate ('pre', 'post'...)
|
||||
:return: value of the evaluation or error
|
||||
"""
|
||||
|
||||
if concept.metadata.is_evaluated:
|
||||
return concept
|
||||
|
||||
self.initialize_concept_asts(context, concept)
|
||||
# I cannot use cache because of concept like 'number'.
|
||||
# They don't have variables, but their values change every time they are instanciated
|
||||
# TODO: Need to find a way to cache despite of them
|
||||
# need_body = eval_body or context.in_context(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
# if need_body and len(concept.metadata.variables) == 0 and context.sheerka.has_id(concept.id):
|
||||
# from_cache = context.sheerka.get_by_id(concept.id)
|
||||
# if from_cache.metadata.is_evaluated:
|
||||
# concept.set_value(ConceptParts.BODY, from_cache.body)
|
||||
# concept.metadata.is_evaluated = True
|
||||
# return concept
|
||||
|
||||
# to make sure of the order, it don't use ConceptParts.get_parts()
|
||||
# variables must be evaluated first, body must be evaluated before where
|
||||
all_metadata_to_eval = self.choose_metadata_to_eval(context, concept)
|
||||
desc = f"Evaluating concept {concept}"
|
||||
with context.push(BuiltinConcepts.EVALUATING_CONCEPT, concept, desc=desc, eval_body=eval_body) as sub_context:
|
||||
|
||||
for metadata_to_eval in all_metadata_to_eval:
|
||||
if metadata_to_eval == "variables":
|
||||
for var_name in (v for v in concept.variables() if v in concept.compiled):
|
||||
prop_ast = concept.compiled[var_name]
|
||||
if eval_body:
|
||||
# ask for body evaluation
|
||||
sub_context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
|
||||
if isinstance(prop_ast, list):
|
||||
# Do not send the current concept for the properties
|
||||
resolved = self.resolve_list(context, prop_ast, var_name, None, True, False)
|
||||
else:
|
||||
# Do not send the current concept for the properties
|
||||
resolved = self.resolve(context, prop_ast, var_name, None, True, False)
|
||||
# auto evaluate commands
|
||||
if context.sheerka.isa(concept, context.sheerka.new(BuiltinConcepts.COMMAND)):
|
||||
sub_context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
|
||||
if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved):
|
||||
resolved.set_value("concept", concept) # since current concept was not sent
|
||||
return resolved
|
||||
else:
|
||||
concept.set_value(var_name, resolved)
|
||||
else:
|
||||
part_key = ConceptParts(metadata_to_eval)
|
||||
self.initialize_concept_asts(sub_context, concept)
|
||||
|
||||
# do not evaluate where when the body is a set
|
||||
# Indeed, the way that the where clause is expressed is not a valid python or concept code
|
||||
if part_key == ConceptParts.WHERE and self.sheerka.isaset(context, concept.body):
|
||||
continue
|
||||
# to make sure of the order, it don't use ConceptParts.get_parts()
|
||||
# variables must be evaluated first, body must be evaluated before where
|
||||
all_metadata_to_eval = metadata or self.compute_metadata_to_eval(sub_context, concept)
|
||||
|
||||
for metadata_to_eval in all_metadata_to_eval:
|
||||
if metadata_to_eval == "variables":
|
||||
for var_name in (v for v in concept.variables() if v in concept.compiled):
|
||||
prop_ast = concept.compiled[var_name]
|
||||
|
||||
if isinstance(prop_ast, list):
|
||||
# Do not send the current concept for the properties
|
||||
resolved = self.resolve_list(sub_context, prop_ast, var_name, None, True, False)
|
||||
else:
|
||||
# Do not send the current concept for the properties
|
||||
resolved = self.resolve(sub_context, prop_ast, var_name, None, True, False)
|
||||
|
||||
if isinstance(resolved, Concept) and not sub_context.sheerka.is_success(resolved):
|
||||
resolved.set_value("concept", concept) # since current concept was not sent
|
||||
return resolved
|
||||
else:
|
||||
concept.set_value(var_name, resolved)
|
||||
else:
|
||||
part_key = ConceptParts(metadata_to_eval)
|
||||
|
||||
# do not evaluate where when the body is a set
|
||||
# Indeed, the way that the where clause is expressed is not a valid python or concept code
|
||||
if part_key == ConceptParts.WHERE and self.sheerka.isaset(sub_context, concept.body):
|
||||
continue
|
||||
|
||||
if part_key not in concept.compiled or concept.compiled[part_key] is None:
|
||||
continue
|
||||
|
||||
if part_key in concept.compiled and concept.compiled[part_key] is not None:
|
||||
metadata_ast = concept.compiled[part_key]
|
||||
|
||||
# if part_key is PRE, POST or WHERE, the concept need to be evaluated
|
||||
# if we want the predicates to be resolved => so force_eval = True
|
||||
# otherwise no need to force
|
||||
@@ -306,91 +340,111 @@ class SheerkaEvaluateConcept(BaseService):
|
||||
# when resolving predicate (where or pre), we need to make sure that PythonEvaluator
|
||||
# will try every possibilities before returning False
|
||||
expect_success = part_key in (ConceptParts.WHERE, ConceptParts.PRE)
|
||||
resolved = self.resolve(context,
|
||||
|
||||
# resolve
|
||||
resolved = self.resolve(sub_context,
|
||||
metadata_ast,
|
||||
part_key,
|
||||
concept,
|
||||
force_concept_eval,
|
||||
expect_success)
|
||||
if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved):
|
||||
|
||||
# 'FATAL' error is detected, let's stop
|
||||
if isinstance(resolved, Concept) and not sub_context.sheerka.is_success(resolved):
|
||||
return resolved
|
||||
else:
|
||||
concept.set_value(part_key, self.get_infinite_recursion_resolution(resolved) or resolved)
|
||||
|
||||
#
|
||||
# TODO : Validate the PRE condition
|
||||
#
|
||||
concept.set_value(part_key, self.get_infinite_recursion_resolution(resolved) or resolved)
|
||||
|
||||
# validate where clause
|
||||
if ConceptParts.WHERE in concept.values:
|
||||
where_value = concept.get_value(ConceptParts.WHERE)
|
||||
if not (where_value is None or self.sheerka.objvalue(where_value)):
|
||||
return self.sheerka.new(BuiltinConcepts.WHERE_CLAUSE_FAILED, body=concept)
|
||||
# validate PRE and WHERE condition
|
||||
if part_key in (ConceptParts.PRE, ConceptParts.WHERE) and not self.sheerka.objvalue(resolved):
|
||||
return self.sheerka.new(BuiltinConcepts.CONDITION_FAILED,
|
||||
body=getattr(concept.metadata, metadata_to_eval),
|
||||
concept=concept,
|
||||
prop=part_key)
|
||||
|
||||
#
|
||||
# TODO : Validate the POST condition
|
||||
#
|
||||
#
|
||||
# TODO : Validate the POST condition
|
||||
#
|
||||
|
||||
concept.init_key() # only does it if needed
|
||||
concept.metadata.is_evaluated = "body" in all_metadata_to_eval
|
||||
concept.init_key() # Necessary for old unit tests. To remove someday
|
||||
|
||||
# update the cache for concepts with no variable
|
||||
if len(concept.metadata.variables) == 0:
|
||||
self.sheerka.cache_manager.put(self.sheerka.CONCEPTS_BY_ID_ENTRY, concept.id, concept)
|
||||
if "body" in all_metadata_to_eval:
|
||||
concept.metadata.is_evaluated = True
|
||||
|
||||
return concept
|
||||
# # update the cache for concepts with no variables
|
||||
# Cannot use cache. See the comment at the beginning of this method
|
||||
# if len(concept.metadata.variables) == 0:
|
||||
# self.sheerka.cache_manager.put(self.sheerka.CONCEPTS_BY_ID_ENTRY, concept.id, concept)
|
||||
|
||||
def choose_metadata_to_eval(self, context, concept):
|
||||
if context.in_context(BuiltinConcepts.EVAL_BODY_REQUESTED):
|
||||
return ["pre", "post", "variables", "body", "where", "ret"]
|
||||
return concept
|
||||
|
||||
def compute_metadata_to_eval(self, context, concept):
|
||||
to_eval = []
|
||||
|
||||
needed, variables, body = self.get_needed_metadata(concept, ConceptParts.PRE, True, True)
|
||||
to_eval.extend(needed)
|
||||
|
||||
metadata = ["pre", "post", "ret"]
|
||||
if context.in_context(BuiltinConcepts.EVAL_WHERE_REQUESTED) or concept.metadata.need_validation:
|
||||
needed = self.needed_metadata(concept, ConceptParts.WHERE)
|
||||
for e in needed:
|
||||
if e not in metadata:
|
||||
metadata.append(e)
|
||||
if "where" not in metadata:
|
||||
metadata.append("where")
|
||||
# What are the cases where we do not need a validation ?
|
||||
# see test_sheerka_non_reg::test_i_can_evaluate_bnf_concept_with_where_clause()
|
||||
# res = sheerka.evaluate_user_input("foobar")
|
||||
needed, v, b = self.get_needed_metadata(concept, ConceptParts.WHERE, not variables, not body)
|
||||
variables |= v
|
||||
body |= b
|
||||
to_eval.extend(needed)
|
||||
|
||||
return metadata
|
||||
needed, v, b = self.get_needed_metadata(concept, ConceptParts.RET, not variables, not body)
|
||||
variables |= v
|
||||
body |= b
|
||||
to_eval.extend(needed)
|
||||
|
||||
def needed_metadata(self, concept, metadata):
|
||||
needed, v, b = self.get_needed_metadata(concept, ConceptParts.POST, not variables, not body)
|
||||
variables |= v
|
||||
body |= b
|
||||
to_eval.extend(needed)
|
||||
|
||||
if context.in_context(BuiltinConcepts.EVAL_BODY_REQUESTED):
|
||||
if not variables:
|
||||
to_eval.append('variables')
|
||||
|
||||
if not body:
|
||||
to_eval.append("body")
|
||||
|
||||
return to_eval
|
||||
|
||||
@staticmethod
|
||||
def get_needed_metadata(concept, concept_part, check_vars, check_body):
|
||||
"""
|
||||
Tries to find out if the evaluation of the body is necessary
|
||||
It's a very basic approach that will need to be improved
|
||||
Check if the concept_part has to be evaluated
|
||||
It also checks if the variables and the body need to be evaluated prior to it
|
||||
:param concept:
|
||||
:param metadata:
|
||||
:param concept_part:
|
||||
:param check_vars:
|
||||
:param check_body:
|
||||
:return:
|
||||
"""
|
||||
ret = []
|
||||
vars_needed = False
|
||||
body_needed = False
|
||||
|
||||
if metadata not in concept.compiled:
|
||||
return []
|
||||
if concept_part in concept.compiled and concept.compiled[concept_part] is not None:
|
||||
concept_part_source = getattr(concept.metadata, concept_part.value)
|
||||
|
||||
return_values = concept.compiled[metadata]
|
||||
if not isinstance(return_values, list):
|
||||
return []
|
||||
assert concept_part_source is not None
|
||||
|
||||
needed = []
|
||||
for return_value in return_values:
|
||||
if not self.sheerka.isinstance(return_value, BuiltinConcepts.RETURN_VALUE):
|
||||
continue
|
||||
tokens = [t.str_value for t in Tokenizer(concept_part_source)]
|
||||
|
||||
if not return_value.status:
|
||||
continue
|
||||
if check_vars:
|
||||
for var_name in (v[0] for v in concept.metadata.variables):
|
||||
if var_name in tokens:
|
||||
vars_needed = True
|
||||
ret.append("variables")
|
||||
break
|
||||
|
||||
if not self.sheerka.isinstance(return_value.body, BuiltinConcepts.PARSER_RESULT):
|
||||
continue
|
||||
if check_body and "self" in tokens:
|
||||
body_needed = True
|
||||
ret.append("body")
|
||||
|
||||
if not isinstance(return_value.body.source, str):
|
||||
continue
|
||||
ret.append(concept_part.value)
|
||||
|
||||
for var_name in (p[0] for p in concept.metadata.variables):
|
||||
if var_name in return_value.body.source:
|
||||
needed.append("variables")
|
||||
break
|
||||
|
||||
if "self" in return_value.body.source:
|
||||
needed.append("body")
|
||||
|
||||
return needed
|
||||
return ret, vars_needed, body_needed
|
||||
|
||||
@@ -144,7 +144,7 @@ class SheerkaExecute(BaseService):
|
||||
self.pi_cache = Cache(default=lambda key: ParserInput(key), max_size=20)
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.execute)
|
||||
self.sheerka.bind_service_method(self.execute, True)
|
||||
|
||||
self.sheerka.cache_manager.register_cache(self.PARSERS_INPUTS_ENTRY, self.pi_cache, False)
|
||||
|
||||
@@ -362,7 +362,8 @@ class SheerkaExecute(BaseService):
|
||||
if not isinstance(results, list):
|
||||
results = [results]
|
||||
for result in results:
|
||||
evaluated_items.append(result)
|
||||
if result.body:
|
||||
evaluated_items.append(result)
|
||||
to_delete.extend(result.parents)
|
||||
sub_context.add_values(return_values=results)
|
||||
else:
|
||||
|
||||
@@ -96,9 +96,9 @@ class SheerkaFilter(BaseService):
|
||||
for k, v in SheerkaFilter.__dict__.items():
|
||||
if k.startswith("pipe_"):
|
||||
if isinstance(v, staticmethod):
|
||||
self.sheerka.add_pipeable(k[5:], v.__func__)
|
||||
self.sheerka.add_pipeable(k[5:], v.__func__, True)
|
||||
else:
|
||||
self.sheerka.add_pipeable(k[5:], v.__get__(self, self.__class__))
|
||||
self.sheerka.add_pipeable(k[5:], v.__get__(self, self.__class__), True)
|
||||
|
||||
self.sheerka.cache_manager.register_cache(self.PREDICATES_ENTRY, self.cache, False, False)
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class SheerkaHistoryManager(BaseService):
|
||||
super().__init__(sheerka)
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.history)
|
||||
self.sheerka.bind_service_method(self.history, False)
|
||||
|
||||
def history(self, depth=10, start=0):
|
||||
"""
|
||||
|
||||
@@ -10,7 +10,7 @@ class SheerkaModifyConcept(BaseService):
|
||||
super().__init__(sheerka)
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.modify_concept)
|
||||
self.sheerka.bind_service_method(self.modify_concept, True)
|
||||
|
||||
def modify_concept(self, context, concept):
|
||||
old_version = self.sheerka.get_by_id(concept.id)
|
||||
|
||||
@@ -10,10 +10,10 @@ class SheerkaResultConcept(BaseService):
|
||||
self.page_size = page_size
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.get_results_by_digest)
|
||||
self.sheerka.bind_service_method(self.get_results_by_command)
|
||||
self.sheerka.bind_service_method(self.get_last_results)
|
||||
self.sheerka.bind_service_method(self.get_results)
|
||||
self.sheerka.bind_service_method(self.get_results_by_digest, True) # digest is recorded
|
||||
self.sheerka.bind_service_method(self.get_results_by_command, True) # digest is recorded
|
||||
self.sheerka.bind_service_method(self.get_last_results, True) # digest is recorded
|
||||
self.sheerka.bind_service_method(self.get_results, False)
|
||||
|
||||
def get_results_by_digest(self, context, digest, record_digest=True):
|
||||
"""
|
||||
|
||||
@@ -13,7 +13,7 @@ GROUP_PREFIX = 'All_'
|
||||
class SheerkaSetsManager(BaseService):
|
||||
NAME = "SetsManager"
|
||||
CONCEPTS_GROUPS_ENTRY = "SetsManager:Concepts_Groups"
|
||||
CONCEPTS_IN_GROUPS_ENTRY = "SetsManager:Concepts_In_Groups" # cache for get_set_elements()
|
||||
CONCEPTS_IN_GROUPS_ENTRY = "SetsManager:Concepts_In_Groups" # cache for get_set_elements()
|
||||
|
||||
def __init__(self, sheerka):
|
||||
super().__init__(sheerka)
|
||||
@@ -21,12 +21,12 @@ class SheerkaSetsManager(BaseService):
|
||||
self.concepts_in_set = Cache()
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.set_isa)
|
||||
self.sheerka.bind_service_method(self.get_set_elements)
|
||||
self.sheerka.bind_service_method(self.add_concept_to_set)
|
||||
self.sheerka.bind_service_method(self.isinset)
|
||||
self.sheerka.bind_service_method(self.isa)
|
||||
self.sheerka.bind_service_method(self.isaset)
|
||||
self.sheerka.bind_service_method(self.set_isa, True)
|
||||
self.sheerka.bind_service_method(self.get_set_elements, True) # concepts are evaluated
|
||||
self.sheerka.bind_service_method(self.add_concept_to_set, True)
|
||||
self.sheerka.bind_service_method(self.isinset, False)
|
||||
self.sheerka.bind_service_method(self.isa, False)
|
||||
self.sheerka.bind_service_method(self.isaset, True) # concept is evaluated, need to change the code
|
||||
|
||||
self.sheerka.cache_manager.register_cache(self.CONCEPTS_GROUPS_ENTRY, self.sets)
|
||||
self.sheerka.cache_manager.register_cache(self.CONCEPTS_IN_GROUPS_ENTRY, self.concepts_in_set, persist=False)
|
||||
@@ -49,6 +49,8 @@ class SheerkaSetsManager(BaseService):
|
||||
False,
|
||||
self.sheerka.new(BuiltinConcepts.CONCEPT_ALREADY_IN_SET, body=concept, concept_set=concept_set))
|
||||
|
||||
# KSI 20200709 add the concept, not its 'id' or 'key'
|
||||
# It will allow conditions handling if concept set has its WHERE or PRE set to something
|
||||
concept.add_prop(BuiltinConcepts.ISA, concept_set)
|
||||
|
||||
res = self.sheerka.modify_concept(context, concept)
|
||||
@@ -141,7 +143,7 @@ class SheerkaSetsManager(BaseService):
|
||||
if sub_concept.metadata.where:
|
||||
new_condition = self._validate_where_clause(sub_concept)
|
||||
if not new_condition:
|
||||
return self.sheerka.new(BuiltinConcepts.WHERE_CLAUSE_FAILED, body=sub_concept)
|
||||
return self.sheerka.new(BuiltinConcepts.CONDITION_FAILED, body=sub_concept)
|
||||
|
||||
# This methods sucks, but I don't have enough tools (like proper AST manipulation functions)
|
||||
# to do it properly now. It will be enhanced later
|
||||
@@ -206,7 +208,7 @@ class SheerkaSetsManager(BaseService):
|
||||
if not (isinstance(concept, Concept) and concept.id):
|
||||
return False
|
||||
|
||||
# KSI 29062020
|
||||
# KSI 20200629
|
||||
# To resolve infinite recursion between group concepts and BNF concepts
|
||||
if concept.metadata.definition_type == DEFINITION_TYPE_BNF:
|
||||
return False
|
||||
|
||||
@@ -27,11 +27,11 @@ class SheerkaVariableManager(BaseService):
|
||||
super().__init__(sheerka)
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.record)
|
||||
self.sheerka.bind_service_method(self.load)
|
||||
self.sheerka.bind_service_method(self.delete)
|
||||
self.sheerka.bind_service_method(self.set)
|
||||
self.sheerka.bind_service_method(self.get)
|
||||
self.sheerka.bind_service_method(self.record, True)
|
||||
self.sheerka.bind_service_method(self.load, False)
|
||||
self.sheerka.bind_service_method(self.delete, True)
|
||||
self.sheerka.bind_service_method(self.set, True)
|
||||
self.sheerka.bind_service_method(self.get, False)
|
||||
|
||||
cache = Cache(default=lambda k: self.sheerka.sdp.get(self.VARIABLES_ENTRY, k))
|
||||
self.sheerka.cache_manager.register_cache(self.VARIABLES_ENTRY, cache, True, True)
|
||||
|
||||
Reference in New Issue
Block a user