Fixed #72 : Exception when get_results(id=10)

Fixed #74 : Keyword parameters are no longer recognized when a concept that redefines equality is created
Fixed #118 : RecursionError: maximum recursion depth exceeded
Fixed #119 : PreventCircularReferenceEvaluator
Fixed #121 : Plural are not updated when new elements are added
Fixed #123 : BaseCache : Values in cache can be evicted before being committed
Fixed #105 : TOO_MANY_ERROR is not the relevant error when results are filtered
This commit is contained in:
2021-09-09 10:57:01 +02:00
parent 54e5681c5a
commit 945807b375
36 changed files with 503 additions and 98 deletions
@@ -1,6 +1,6 @@
import re
from dataclasses import dataclass
from typing import Set, List, Union
from typing import List, Set, Union
import core.utils
from cache.Cache import Cache
@@ -9,14 +9,14 @@ from cache.DictionaryCache import DictionaryCache
from cache.ListIfNeededCache import ListIfNeededCache
from cache.SetCache import SetCache
from core.builtin_concepts import ErrorConcept
from core.builtin_concepts_ids import BuiltinConcepts, AllBuiltinConcepts, BuiltinUnique
from core.builtin_helpers import ensure_concept, ensure_bnf
from core.concept import Concept, DEFINITION_TYPE_DEF, DEFINITION_TYPE_BNF, freeze_concept_attrs, ConceptMetadata, \
VARIABLE_PREFIX
from core.global_symbols import EVENT_CONCEPT_CREATED, NotInit, NotFound, ErrorObj, EVENT_CONCEPT_DELETED, NoFirstToken, \
EVENT_CONCEPT_MODIFIED, CONCEPT_COMPARISON_CONTEXT
from core.builtin_concepts_ids import AllBuiltinConcepts, BuiltinConcepts, BuiltinUnique
from core.builtin_helpers import ensure_bnf, ensure_concept
from core.concept import Concept, ConceptMetadata, DEFINITION_TYPE_BNF, DEFINITION_TYPE_DEF, VARIABLE_PREFIX, \
freeze_concept_attrs
from core.global_symbols import CONCEPT_COMPARISON_CONTEXT, EVENT_CONCEPT_CREATED, EVENT_CONCEPT_DELETED, \
EVENT_CONCEPT_MODIFIED, ErrorObj, NoFirstToken, NotFound, NotInit
from core.sheerka.services.sheerka_service import BaseService
from core.tokenizer import Tokenizer, TokenKind
from core.tokenizer import TokenKind, Tokenizer
from parsers.BnfNodeParser import RegExDef
from sdp.sheerkaDataProvider import SheerkaDataProviderDuplicateKeyError
@@ -133,6 +133,7 @@ class SheerkaConceptManager(BaseService):
self.sheerka.bind_service_method(self.NAME, self.get_concepts_bnf_definitions, False, visible=False)
self.sheerka.bind_service_method(self.NAME, self.clear_bnf_definition, True, visible=False)
self.sheerka.bind_service_method(self.NAME, self.set_precedence, True)
self.sheerka.bind_service_method(self.NAME, self.get_plural_concept_value, False)
register_concept_cache = self.sheerka.om.register_concept_cache
@@ -1294,3 +1295,11 @@ class SheerkaConceptManager(BaseService):
for variable in [v for v in visitor.variables if isinstance(v, ParameterVariable)]:
if variable.name not in concept.get_metadata().parameters:
concept.get_metadata().parameters.append(variable.name)
@staticmethod
def get_plural_concept_value(context, concept):
underlying_concept = concept.get_prop(BuiltinConcepts.PLURAL)
if context.sheerka.isaset(context, underlying_concept):
return context.sheerka.get_set_elements(context, underlying_concept)
return None
@@ -600,7 +600,7 @@ class SheerkaDebugManager(BaseService):
elif item_type == self.CONCEPTS_DEBUG_TYPE:
self.registered_concepts.append((service, method, item))
else:
raise NotImplementedError()
raise NotImplementedError(f"register_debug {item_type=}")
def register_debug_vars(self, service, method, item):
return self.register_debug(self.VARS_DEBUG_TYPE, service, method, item)
@@ -643,7 +643,7 @@ class SheerkaDebugManager(BaseService):
elif item_type == self.CONCEPTS_DEBUG_TYPE:
lst = self.registered_concepts
else:
raise NotImplementedError()
raise NotImplementedError(f"filter_registered_debug {item_type=}")
for registered in lst:
if service != "*" and service != registered[0]:
@@ -230,6 +230,12 @@ class SheerkaEvaluateConcept(BaseService):
:param possible_variables: concepts that must be considered as variables
:return:
"""
def get_filtered_by_prevent_circular_reference(return_values):
for ret_val in return_values:
from evaluators.PreventCircularReferenceEvaluator import PreventCircularReferenceEvaluator
if ret_val.who == PreventCircularReferenceEvaluator.NAME:
return ret_val.body.body
return None
def parse_token_concept(s):
"""
@@ -252,6 +258,7 @@ class SheerkaEvaluateConcept(BaseService):
"""
parsers_to_use = INIT_AST_QUESTION_PARSERS if p in [ConceptParts.WHERE,
ConceptParts.PRE] else INIT_AST_PARSERS
recursion_detected = False
while True:
return_value = current_context.sheerka.parse_unrecognized(current_context,
s,
@@ -262,8 +269,24 @@ class SheerkaEvaluateConcept(BaseService):
possible_variables=possible_variables)
if not return_value.status:
if current_context.preprocess:
raise ChickenAndEggException(context.sheerka.new(BuiltinConcepts.CHICKEN_AND_EGG, body={c}))
# Dealing with circular reference is not easy.
# Let's take for example 'def concept q from q ? as question(q)'
# 'q' is the name of the concept, but also the name of the parameter
# When chicken_and_egg_err is found with a concept parser (Exact, Sya, Bnf...) we must disable it
# to let a chance to the Python parser (which can handle concepts parameters)
sheerka = context.sheerka
if sheerka.has_error(context, return_value, __type="ChickenAndEggException"):
recursion_detected = True
filtered = get_filtered_by_prevent_circular_reference(return_value.body.body)
recursive_parsers = list(SheerkaEvaluateConcept.get_recursive_definitions(context, c, filtered))
if len(recursive_parsers):
desc = f"Removing parsers {recursive_parsers}"
current_context = current_context.push(context.action, context.action_context, desc=desc)
for recursive_parser in recursive_parsers:
current_context.add_preprocess(recursive_parser.name, enabled=False)
continue
elif recursion_detected:
raise ChickenAndEggException(sheerka.new(BuiltinConcepts.CHICKEN_AND_EGG, body={c}))
else:
raise FailedToCompileError([return_value.body])
@@ -529,7 +552,7 @@ class SheerkaEvaluateConcept(BaseService):
return evaluated
elif isinstance(to_resolve, Rule):
raise NotImplementedError() # how to resolve rules ?
raise NotImplementedError(f"evaluate_concept.resolve() {to_resolve=}") # how to resolve rules ?
# otherwise, execute all return values to find out what is the value
else:
@@ -772,7 +795,7 @@ class SheerkaEvaluateConcept(BaseService):
# TODO : Validate the POST condition
#
if ConceptParts.BODY in all_metadata_to_eval and not failed_to_evaluate_body:
if ConceptParts.BODY in all_metadata_to_eval and not failed_to_evaluate_body and not concept.is_dynamic():
concept.get_hints().is_evaluated = True
# # update the cache for concepts with no variables
+18 -1
View File
@@ -406,7 +406,7 @@ class SheerkaExecute(BaseService):
if isinstance(text, ParserInput):
return text.as_text()
raise NotImplementedError()
raise NotImplementedError(f"get_input_as_text({text=})")
def get_parser_input(self, text, tokens=None):
"""
@@ -835,6 +835,15 @@ class SheerkaExecute(BaseService):
:param possible_variables: concepts that must be considered as variables
:return:
"""
# def filter_for_circular_reference(return_values, concept):
# for r in return_values:
# if r.status and context.sheerka.isinstance(r.body, BuiltinConcepts.PARSER_RESULT):
# body = r.body.body[0] if isinstance(r.body.body, list) and len(r.body.body) == 1 else r.body.body
# if hasattr(body, "get_concept") and body.get_concept().id == concept.id:
# continue
# yield r
sheerka = context.sheerka
if prop:
@@ -864,6 +873,14 @@ class SheerkaExecute(BaseService):
sheerka.new(BuiltinConcepts.USER_INPUT, body=source))
res = sheerka.execute(sub_context, to_parse, PARSE_STEPS)
# # before user defined filtering, remove the return values that may lead to circular reference
# in_recursion = list(context.search(predicate=lambda c: c.action == BuiltinConcepts.EVALUATING_CONCEPT,
# get_obj=lambda c: c.action_context,
# only_first=True))
#
# if in_recursion:
# res = list(filter_for_circular_reference(res, in_recursion[0]))
if filter_func:
res = filter_func(sub_context, res)
@@ -749,7 +749,7 @@ class ReteConditionExprVisitor(GetConditionExprVisitor):
elif type(c) == NegatedCondition:
res.append(Condition(c.identifier, c.attribute, c.value))
else:
raise NotImplementedError
raise NotImplementedError("rete - negate_conditions")
else:
res.append(NegatedConjunctiveConditions(*conditions_))