From 1bde97b5e35384065b40f8aea5aad7a8f0872d03 Mon Sep 17 00:00:00 2001 From: Kodjo Sossouvi Date: Mon, 9 Mar 2020 12:23:53 +0100 Subject: [PATCH] Concept validation must be requested --- _concepts.txt | 21 +++- src/core/builtin_concepts.py | 9 +- src/core/builtin_helpers.py | 44 +++++---- src/core/concept.py | 1 + src/core/sheerka/ExecutionContext.py | 18 +++- src/core/sheerka/Services/SheerkaDump.py | 3 +- .../Services/SheerkaEvaluateConcept.py | 83 +++++++++------- src/core/sheerka/Services/SheerkaExecute.py | 21 +--- .../sheerka/Services/SheerkaSetsManager.py | 9 +- src/core/sheerka/Sheerka.py | 7 +- src/evaluators/ConceptEvaluator.py | 24 +++-- src/evaluators/EvalEvaluator.py | 23 +---- src/evaluators/PrepareEvalEvaluator.py | 7 +- src/evaluators/PythonEvaluator.py | 3 +- src/parsers/ConceptLexerParser.py | 1 + src/parsers/ExactConceptParser.py | 5 +- tests/BaseTest.py | 12 ++- tests/core/test_ExecutionContext.py | 32 +++++- tests/core/test_SheerkaEvaluateConcept.py | 98 +++++++++++-------- tests/core/test_sheerka_call_evaluators.py | 54 +++------- tests/evaluators/test_ConceptEvaluator.py | 10 +- tests/evaluators/test_EvalEvaluator.py | 50 ++++------ tests/evaluators/test_PrepareEvalEvaluator.py | 11 +-- tests/non_reg/test_sheerka_non_reg.py | 41 ++++---- tests/parsers/test_ConceptLexerParser.py | 22 +++++ .../test_ConceptsWithConceptsParser.py | 6 +- tests/parsers/test_ExactConceptParser.py | 11 ++- 27 files changed, 346 insertions(+), 280 deletions(-) diff --git a/_concepts.txt b/_concepts.txt index 420d0df..5c96c53 100644 --- a/_concepts.txt +++ b/_concepts.txt @@ -42,11 +42,30 @@ twenty isa number def concept twenties from bnf twenty number where number < 10 as twenty + number twenties isa number def concept thirty as 30 +thirty isa number def concept thirties from bnf thirty number where number < 10 as thirty + number thirties isa number def concept forty as 40 +forty isa number def concept forties from bnf forty number where number < 10 as forty + number forties isa number def concept fifty as 50 +fifty isa number def concept fifties from bnf fifty number where number < 10 as fifty + number -fifties isa number \ No newline at end of file +fifties isa number +def concept sixty as 60 +sixty isa number +def concept sixties from bnf sixty number where number < 10 as sixty + number +sixties isa number +def concept seventy as 70 +seventy isa number +def concept seventies from bnf seventy number where number < 10 as seventy + number +seventies isa number +def concept eighty as 80 +eighty isa number +def concept eighties from bnf eighty number where number < 10 as eighty + number +eighties isa number +def concept ninety as 90 +ninety isa number +def concept nineties from bnf ninety number where number < 10 as ninety + number +nineties isa number diff --git a/src/core/builtin_concepts.py b/src/core/builtin_concepts.py index d400ec5..4399afa 100644 --- a/src/core/builtin_concepts.py +++ b/src/core/builtin_concepts.py @@ -47,13 +47,14 @@ class BuiltinConcepts(Enum): LIST = "list" # represents a list CONCEPT_ALREADY_IN_SET = "concept already in set" EVALUATOR_PRE_PROCESS = "evaluator pre process" # used modify / tweak behaviour of evaluators - CONCEPT_EVAL_REQUESTED = "concept eval requested" + EVAL_BODY_REQUESTED = "eval body requested" # to evaluate the body + EVAL_WHERE_REQUESTED = "eval where requested" # to evaluate the where clause + CONCEPT_VALUE_REQUESTED = "concept value requested" # returns the body of the concept instead of the concept itself REDUCE_REQUESTED = "reduce requested" # remove meaningless error when possible NOT_A_SET = "not a set" # the concept has no entry in sets WHERE_CLAUSE_FAILED = "where clause failed" # failed to validate where clause during evaluation CHICKEN_AND_EGG = "chicken and egg" # infinite recursion when declaring concept ISA = "is a" # builtin concept to express that a concept is an instance of another one - CONCEPT_VALUE_REQUESTED = "concept value requested" # returns the body of the concept instead of the concept itself NODE = "node" GENERIC_NODE = "generic node" @@ -78,7 +79,7 @@ BuiltinUnique = [ BuiltinConcepts.AFTER_RENDERING, BuiltinConcepts.SUCCESS, BuiltinConcepts.NOP, - BuiltinConcepts.CONCEPT_EVAL_REQUESTED, + BuiltinConcepts.EVAL_BODY_REQUESTED, BuiltinConcepts.REDUCE_REQUESTED, ] @@ -248,7 +249,7 @@ class ParserResultConcept(Concept): Result of a parsing """ - def __init__(self, parser=None, source=None, value=None, try_parsed=None): + def __init__(self, parser=None, source=None, value=None, try_parsed=None, validate_concept=None): super().__init__(BuiltinConcepts.PARSER_RESULT, True, False, BuiltinConcepts.PARSER_RESULT) self.set_metadata_value(ConceptParts.BODY, value) self.set_prop("parser", parser) diff --git a/src/core/builtin_helpers.py b/src/core/builtin_helpers.py index ab2dadd..c89972e 100644 --- a/src/core/builtin_helpers.py +++ b/src/core/builtin_helpers.py @@ -17,32 +17,34 @@ def is_same_success(context, return_values): """ assert isinstance(return_values, list) - if not return_values[0].status: - return False + def _get_value(ret_val): + if not ret_val.status: + raise Exception("Status is false") - if isinstance(return_values[0].body, Concept): - evaluated = context.sheerka.evaluate_concept(context, return_values[0].body, True) - if evaluated.key != return_values[0].body.key: - return False - reference = context.sheerka.value(evaluated) - else: - reference = context.sheerka.value(return_values[0]) + if isinstance(ret_val.body, Concept): + if not ret_val.body.metadata.is_evaluated: + with context.push(desc=f"Evaluating concept '{ret_val.body}'") as sub_context: + sub_context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) + evaluated = context.sheerka.evaluate_concept(sub_context, ret_val.body) + if evaluated.key != ret_val.body.key: + raise Exception("Failed to evaluate evaluate") + return context.sheerka.value(evaluated) + else: + return context.sheerka.value(ret_val.body) + else: + return context.sheerka.value(ret_val) - for return_value in return_values[1:]: - if not return_value.status: - return False + try: + reference = _get_value(return_values[0]) - if isinstance(return_value.body, Concept): - evaluated = context.sheerka.evaluate_concept(context, return_value.body, True) - if evaluated.key != return_value.body.key: + for return_value in return_values[1:]: + actual = _get_value(return_value) + if actual != reference: return False - actual = context.sheerka.value(evaluated) - else: - actual = context.sheerka.value(return_value) - - if actual != reference: - return False + except Exception as ex: + context.log_error(ex) + return False return True diff --git a/src/core/concept.py b/src/core/concept.py index 921310c..14f70b3 100644 --- a/src/core/concept.py +++ b/src/core/concept.py @@ -48,6 +48,7 @@ class ConceptMetadata: id: str # unique identifier for a concept. The id will never be modified (but the key can) props: list # list properties, with their default values is_evaluated: bool = False # True is the concept is evaluated by sheerka.eval_concept() + need_validation = False # True if the properties of the concept need to be validated full_serialization: bool = False # If True, the full object will be serialized, rather than just the diff diff --git a/src/core/sheerka/ExecutionContext.py b/src/core/sheerka/ExecutionContext.py index f8aeb29..48094f3 100644 --- a/src/core/sheerka/ExecutionContext.py +++ b/src/core/sheerka/ExecutionContext.py @@ -21,8 +21,6 @@ PROPERTIES_TO_SERIALIZE = ("_id", "concepts") - - class ExecutionContext: """ To keep track of the execution of a request @@ -44,6 +42,7 @@ class ExecutionContext: sheerka, desc: str = None, logger=None, + global_hints=None, **kwargs): self._parent = None @@ -60,7 +59,8 @@ class ExecutionContext: self.children = [] self.preprocess = None self.logger = logger - self.extra_info = [] + self.local_hints = set() + self.global_hints = set() if global_hints is None else global_hints self.inputs = {} # what was the parameters of the execution context self.values = {} # what was produced by the execution context @@ -211,11 +211,12 @@ class ExecutionContext: self.sheerka, desc, logger, + self.global_hints, **_kwargs) new._parent = self new._tab = self._tab + " " * DEBUG_TAB_SIZE new.preprocess = self.preprocess - new.extra_info.extend(self.extra_info) + new.local_hints.update(self.local_hints) self.children.append(new) return new @@ -247,6 +248,15 @@ class ExecutionContext: def get_parent(self): return self._parent + def in_context(self, concept_key): + if concept_key in self.local_hints: + return True + + if concept_key in self.global_hints: + return True + + return False + @staticmethod def return_value_to_str(r): value = str(r.value) diff --git a/src/core/sheerka/Services/SheerkaDump.py b/src/core/sheerka/Services/SheerkaDump.py index 43f51ca..810b891 100644 --- a/src/core/sheerka/Services/SheerkaDump.py +++ b/src/core/sheerka/Services/SheerkaDump.py @@ -53,9 +53,10 @@ class SheerkaDump: if not first: self.sheerka.log.info("") self.sheerka.log.info(f"name : {c.name}") - self.sheerka.log.info(f"bnf : {c.metadata.definition}") self.sheerka.log.info(f"key : {c.key}") + self.sheerka.log.info(f"bnf : {c.metadata.definition}") self.sheerka.log.info(f"body : {c.metadata.body}") + self.sheerka.log.info(f"where : {c.metadata.where}") if eval: self.sheerka.log.info(f"value : {value}") for p in c.props: diff --git a/src/core/sheerka/Services/SheerkaEvaluateConcept.py b/src/core/sheerka/Services/SheerkaEvaluateConcept.py index b023224..2c02947 100644 --- a/src/core/sheerka/Services/SheerkaEvaluateConcept.py +++ b/src/core/sheerka/Services/SheerkaEvaluateConcept.py @@ -118,7 +118,7 @@ class SheerkaEvaluateConcept: else: self.sheerka.cache_by_key[concept.key].compiled = concept.compiled - def resolve(self, context, to_resolve, current_prop, current_concept, evaluate_body): + def resolve(self, context, to_resolve, current_prop, current_concept, force_evaluation): if isinstance(to_resolve, DoNotResolve): return to_resolve.value @@ -134,10 +134,13 @@ class SheerkaEvaluateConcept: context.log(desc, self.logger_name) with context.push(desc=desc, obj=current_concept) as sub_context: + if force_evaluation: + sub_context.local_hints.add(BuiltinConcepts.EVAL_BODY_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, evaluate_body) + evaluated = self.evaluate_concept(sub_context, to_resolve) sub_context.add_values(return_values=evaluated) if evaluated.key == to_resolve.key: return evaluated @@ -147,8 +150,6 @@ class SheerkaEvaluateConcept: # otherwise, execute all return values to find out what is the value else: use_copy = [r for r in to_resolve] if hasattr(to_resolve, "__iter__") else to_resolve - if evaluate_body: - sub_context.extra_info.append(BuiltinConcepts.CONCEPT_EVAL_REQUESTED) r = self.sheerka.execute(sub_context, use_copy, CONCEPT_EVALUATION_STEPS) one_r = expect_one(context, r) @@ -164,7 +165,7 @@ class SheerkaEvaluateConcept: concept=current_concept, property_name=current_prop) - def resolve_list(self, context, list_to_resolve, current_prop, current_concept, evaluate_body): + def resolve_list(self, context, list_to_resolve, current_prop, current_concept, force_evaluation): """When dealing with a list, there are two possibilities""" # It may be a list of ReturnValueConcept to execute (always the case for metadata) # or a list of single values (may be the case for properties) @@ -173,7 +174,7 @@ class SheerkaEvaluateConcept: return [] if self.sheerka.isinstance(list_to_resolve[0], BuiltinConcepts.RETURN_VALUE): - return self.resolve(context, list_to_resolve, current_prop, current_concept, evaluate_body) + return self.resolve(context, list_to_resolve, current_prop, current_concept, force_evaluation) res = [] for to_resolve in list_to_resolve: @@ -184,14 +185,14 @@ class SheerkaEvaluateConcept: concept=current_concept, property_name=current_prop) - r = self.resolve(context, to_resolve, current_prop, current_concept, evaluate_body) + r = self.resolve(context, to_resolve, current_prop, current_concept, force_evaluation) if self.sheerka.isinstance(r, BuiltinConcepts.CONCEPT_EVAL_ERROR): return r res.append(r) return res - def evaluate_concept(self, context, concept: Concept, evaluate_body=False): + def evaluate_concept(self, context, concept: Concept): """ Evaluation a concept It means that if the where clause is True, will evaluate the body @@ -208,7 +209,7 @@ class SheerkaEvaluateConcept: # to make sure of the order, it don't use ConceptParts.get_parts() # props must be evaluated first, body must be evaluated before where - all_metadata_to_eval = self.choose_metadata_to_eval(concept, evaluate_body) + all_metadata_to_eval = self.choose_metadata_to_eval(context, concept) for metadata_to_eval in all_metadata_to_eval: if metadata_to_eval == "props": @@ -221,6 +222,7 @@ class SheerkaEvaluateConcept: else: # Do not send the current concept for the properties resolved = self.resolve(context, prop_ast, prop_name, None, True) + if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved): resolved.set_prop("concept", concept) # since current concept was not sent return resolved @@ -236,7 +238,10 @@ class SheerkaEvaluateConcept: if part_key in concept.compiled and concept.compiled[part_key] is not None: metadata_ast = concept.compiled[part_key] - resolved = self.resolve(context, metadata_ast, part_key, concept, evaluate_body) + # if part_key is PRE, POST or WHERE, the concepts need to be evaluated + # otherwise the predicates cannot be resolved + force_concept_eval = False if part_key == ConceptParts.BODY else True + resolved = self.resolve(context, metadata_ast, part_key, concept, force_concept_eval) if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved): return resolved else: @@ -260,49 +265,57 @@ class SheerkaEvaluateConcept: concept.metadata.is_evaluated = "body" in all_metadata_to_eval return concept - def choose_metadata_to_eval(self, concept, evaluate_body): - if evaluate_body: + def choose_metadata_to_eval(self, context, concept): + if context.in_context(BuiltinConcepts.EVAL_BODY_REQUESTED): return ["pre", "post", "props", "body", "where"] - metadata = ["pre", "post"] + self.needed_metadata(concept) + ["where"] + metadata = ["pre", "post"] + 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") + return metadata - def needed_metadata(self, concept): + def needed_metadata(self, concept, metadata): """ Tries to find out if the evaluation of the body is necessary It's a very basic approach that will need to be improved :param concept: + :param metadata: :return: """ + if metadata not in concept.compiled: + return [] + + return_values = concept.compiled[metadata] + if not isinstance(return_values, list): + return [] + needed = [] - - for metadata in (ConceptParts.PRE, ConceptParts.POST, ConceptParts.WHERE): - if metadata not in concept.compiled: + for return_value in return_values: + if not self.sheerka.isinstance(return_value, BuiltinConcepts.RETURN_VALUE): continue - return_values = concept.compiled[metadata] - if not isinstance(return_values, list): + if not return_value.status: continue - for return_value in return_values: - if not self.sheerka.isinstance(return_value, BuiltinConcepts.RETURN_VALUE): - continue + if not self.sheerka.isinstance(return_value.body, BuiltinConcepts.PARSER_RESULT): + continue - if not return_value.status: - continue + if not isinstance(return_value.body.source, str): + continue - if not self.sheerka.isinstance(return_value.body, BuiltinConcepts.PARSER_RESULT): - continue + for prop_name in (p[0] for p in concept.metadata.props): + if prop_name in return_value.body.source: + needed.append("props") + break - if not isinstance(return_value.body.source, str): - continue + if "self" in return_value.body.source: + needed.append("body") - for prop_name in (p[0] for p in concept.metadata.props): - if prop_name in return_value.body.source: - needed.append("props") - break - - if "self" in return_value.body.source: - needed.append("body") return needed diff --git a/src/core/sheerka/Services/SheerkaExecute.py b/src/core/sheerka/Services/SheerkaExecute.py index 71b9a27..9f0deb3 100644 --- a/src/core/sheerka/Services/SheerkaExecute.py +++ b/src/core/sheerka/Services/SheerkaExecute.py @@ -90,27 +90,12 @@ class SheerkaExecute: result = core.utils.remove_list_from_list(result, user_inputs) return result - def call_evaluators(self, execution_context, return_values, process_step, evaluation_context=None): + def call_evaluators(self, execution_context, return_values, process_step): # return_values must be a list if not isinstance(return_values, list): return_values = [return_values] - # Evaluation context are contexts that may modify the behaviour of the execution - # For example, a concept to indicate that the value is not wanted - # Or a concept to indicate that we want the letter form of the response - # But first, they need to be transformed into return values - if evaluation_context is None: - evaluation_return_values = [] - else: - evaluation_return_values = [self.sheerka.ret(execution_context.who, True, c) for c in evaluation_context] - - # add the current step as part as the evaluation context - evaluation_return_values.append(self.sheerka.ret(execution_context.who, True, self.sheerka.new(process_step))) - - # the pool of return values are the mix - return_values.extend(evaluation_return_values) - # group the evaluators by priority and sort them # The first one to be applied will be the one with the highest priority grouped_evaluators = {} @@ -203,8 +188,6 @@ class SheerkaExecute: # inc the iteration and continue iteration += 1 - # remove all evaluation context that are not reduced - return_values = core.utils.remove_list_from_list(return_values, evaluation_return_values) return return_values def execute(self, execution_context, return_values, execution_steps): @@ -223,7 +206,7 @@ class SheerkaExecute: if step == BuiltinConcepts.PARSING: return_values = self.call_parsers(sub_context, return_values) else: - return_values = self.call_evaluators(sub_context, return_values, step, None) + return_values = self.call_evaluators(sub_context, return_values, step) if copy != return_values: sub_context.log_result(return_values) diff --git a/src/core/sheerka/Services/SheerkaSetsManager.py b/src/core/sheerka/Services/SheerkaSetsManager.py index bb03fa6..84fd182 100644 --- a/src/core/sheerka/Services/SheerkaSetsManager.py +++ b/src/core/sheerka/Services/SheerkaSetsManager.py @@ -108,7 +108,8 @@ class SheerkaSetsManager: # it may be a concept that references a set if not sub_concept.metadata.is_evaluated: with context.push(desc=f"Evaluating concept {sub_concept}") as sub_context: - evaluated = self.sheerka.evaluate_concept(sub_context, sub_concept, True) + sub_context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) + evaluated = self.sheerka.evaluate_concept(sub_context, sub_concept) if evaluated.key != concept.key: return False return _get_set_elements(context, concept, sub_concept.body) @@ -167,7 +168,8 @@ class SheerkaSetsManager: # it may be a concept that references a set if not concept.metadata.is_evaluated: with context.push(desc=f"Evaluating concept {concept}") as sub_context: - evaluated = self.sheerka.evaluate_concept(sub_context, concept, True) + sub_context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) + evaluated = self.sheerka.evaluate_concept(sub_context, concept) if evaluated.key != concept.key: return False @@ -216,9 +218,10 @@ for x in xx__concepts__xx: result = [] with context.push(desc=f"Evaluating concepts of a set") as sub_context: + sub_context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) for element_id in ids: concept = self.sheerka.get_by_id(element_id) - evaluated = self.sheerka.evaluate_concept(sub_context, concept, True) + evaluated = self.sheerka.evaluate_concept(sub_context, concept) result.append(evaluated) return result diff --git a/src/core/sheerka/Sheerka.py b/src/core/sheerka/Sheerka.py index c344bbb..3eb3758 100644 --- a/src/core/sheerka/Sheerka.py +++ b/src/core/sheerka/Sheerka.py @@ -239,6 +239,7 @@ class Sheerka(Concept): with ExecutionContext(self.key, event, self, f"Evaluating '{text}'", self.log) as execution_context: user_input = self.ret(self.name, True, self.new(BuiltinConcepts.USER_INPUT, body=text, user_name=user_name)) reduce_requested = self.ret(self.name, True, self.new(BuiltinConcepts.REDUCE_REQUESTED)) + #execution_context.local_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED) steps = [ BuiltinConcepts.BEFORE_PARSING, @@ -332,17 +333,15 @@ class Sheerka(Concept): return self.sets_handler.get_set_elements(context, concept) - def evaluate_concept(self, context, concept: Concept, evaluate_body=False): + def evaluate_concept(self, context, concept: Concept): """ Evaluation a concept It means that if the where clause is True, will evaluate the body - :param evaluate_body: :param context: :param concept: - :param evaluate_body: :return: value of the evaluation or error """ - return self.evaluate_concept_handler.evaluate_concept(context, concept, evaluate_body) + return self.evaluate_concept_handler.evaluate_concept(context, concept) def add_in_cache(self, concept: Concept): """ diff --git a/src/evaluators/ConceptEvaluator.py b/src/evaluators/ConceptEvaluator.py index 48154f0..046a862 100644 --- a/src/evaluators/ConceptEvaluator.py +++ b/src/evaluators/ConceptEvaluator.py @@ -15,19 +15,17 @@ class ConceptEvaluator(OneReturnValueEvaluator): def __init__(self, return_body=False): super().__init__(self.NAME, [BuiltinConcepts.EVALUATION], 50) self.return_body = return_body - self.evaluate_body = False - self.is_initialized = False - def init_evaluator(self, context, return_values): - if BuiltinConcepts.CONCEPT_EVAL_REQUESTED in context.extra_info: - self.evaluate_body = True - - for r in return_values: - if r.status and context.sheerka.isinstance(r.body, BuiltinConcepts.CONCEPT_VALUE_REQUESTED): - self.evaluate_body = True - break - - self.is_initialized = True + # def init_evaluator(self, context, return_values): + # if BuiltinConcepts.EVAL_BODY_REQUESTED in context.local_hints: + # self.evaluate_body = True + # + # for r in return_values: + # if r.status and context.sheerka.isinstance(r.body, BuiltinConcepts.CONCEPT_VALUE_REQUESTED): + # self.evaluate_body = True + # break + # + # self.is_initialized = True def matches(self, context, return_value): return return_value.status and \ @@ -49,7 +47,7 @@ class ConceptEvaluator(OneReturnValueEvaluator): return sheerka.ret(self.name, True, value, parents=[return_value]) - evaluated = sheerka.evaluate_concept(context, concept, self.evaluate_body) + evaluated = sheerka.evaluate_concept(context, concept) if evaluated.key != concept.key: # evaluated.key != concept.key means that we have transformed the concept diff --git a/src/evaluators/EvalEvaluator.py b/src/evaluators/EvalEvaluator.py index 6ab3041..07f9099 100644 --- a/src/evaluators/EvalEvaluator.py +++ b/src/evaluators/EvalEvaluator.py @@ -12,16 +12,9 @@ class EvalEvaluator(AllReturnValuesEvaluator): def __init__(self): super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 80) - self.eval_requested = None def matches(self, context, return_values): - sheerka = context.sheerka - for ret in return_values: - if ret.status and sheerka.isinstance(ret.body, BuiltinConcepts.CONCEPT_VALUE_REQUESTED): - self.eval_requested = ret - return True - - return False + return context.in_context(BuiltinConcepts.CONCEPT_VALUE_REQUESTED) def eval(self, context, return_values): sheerka = context.sheerka @@ -30,22 +23,16 @@ class EvalEvaluator(AllReturnValuesEvaluator): for ret_val in return_values: if ret_val.status and isinstance(ret_val.body, Concept) and ret_val.body.body: context.log(f"Evaluating {ret_val.body}", who=self) - result.append(sheerka.ret(self.name, True, ret_val.body.body, parents=[ret_val, self.eval_requested])) + result.append(sheerka.ret(self.name, True, ret_val.body.body, parents=[ret_val])) elif ret_val.status and sheerka.isaset(context, ret_val.body): context.log(f"Evaluating set {ret_val.body}", who=self) result.append(sheerka.ret( self.name, True, sheerka.get_set_elements(context, ret_val.body), - parents=[ret_val, self.eval_requested])) + parents=[ret_val])) if len(result) > 0: return result - else: - # suppress the successful BuiltinConcepts.CONCEPT_EVAL_REQUESTED - # status of CONCEPT_EVAL_REQUESTED is now set to False - return sheerka.ret( - self.name, - False, - sheerka.new(BuiltinConcepts.CONCEPT_VALUE_REQUESTED), - parents=[self.eval_requested]) + + return None diff --git a/src/evaluators/PrepareEvalEvaluator.py b/src/evaluators/PrepareEvalEvaluator.py index 4c5867f..614c42f 100644 --- a/src/evaluators/PrepareEvalEvaluator.py +++ b/src/evaluators/PrepareEvalEvaluator.py @@ -33,8 +33,7 @@ class PrepareEvalEvaluator(OneReturnValueEvaluator): self.name, True, sheerka.new(BuiltinConcepts.USER_INPUT, body=self.text[5:], user_name=context.event.user)) - evaluation_requested = sheerka.ret( - self.name, - True, sheerka.new(BuiltinConcepts.CONCEPT_VALUE_REQUESTED)) + context.global_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) + context.global_hints.add(BuiltinConcepts.CONCEPT_VALUE_REQUESTED) - return [new_text_to_parse, evaluation_requested] + return new_text_to_parse diff --git a/src/evaluators/PythonEvaluator.py b/src/evaluators/PythonEvaluator.py index 6a456de..19fa13f 100644 --- a/src/evaluators/PythonEvaluator.py +++ b/src/evaluators/PythonEvaluator.py @@ -112,7 +112,8 @@ class PythonEvaluator(OneReturnValueEvaluator): context.log(f"Evaluating '{concept}'", self.name) with context.push(self.name, desc=f"Evaluating '{concept}'", obj=concept) as sub_context: - evaluated = context.sheerka.evaluate_concept(sub_context, concept, True) + sub_context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) + evaluated = context.sheerka.evaluate_concept(sub_context, concept) sub_context.add_values(return_values=evaluated) if evaluated.key == concept.key: diff --git a/src/parsers/ConceptLexerParser.py b/src/parsers/ConceptLexerParser.py index 32db674..f43a2a8 100644 --- a/src/parsers/ConceptLexerParser.py +++ b/src/parsers/ConceptLexerParser.py @@ -944,6 +944,7 @@ class ConceptLexerParser(BaseParser): if _underlying.parsing_expression.rule_name: value = _get_underlying_value(_underlying) _add_prop(_concept, _underlying.parsing_expression.rule_name, value) + _concept.metadata.need_validation = True if isinstance(_underlying, NonTerminalNode): for child in _underlying.children: diff --git a/src/parsers/ExactConceptParser.py b/src/parsers/ExactConceptParser.py index f1cd108..66e1bb8 100644 --- a/src/parsers/ExactConceptParser.py +++ b/src/parsers/ExactConceptParser.py @@ -41,21 +41,22 @@ class ExactConceptParser(BaseParser): for combination in self.combinations(words): concept_key = " ".join(combination) - result = sheerka.new(concept_key) + result = sheerka.new(concept_key) # use new(), not get() because we need a new instance if sheerka.isinstance(result, BuiltinConcepts.UNKNOWN_CONCEPT): continue - # concepts = result.body if sheerka.isinstance(result, BuiltinConcepts.ENUMERATION) else [result] concepts = result if isinstance(result, list) else [result] for concept in concepts: context.log(f"Recognized concept {concept}.", self.name) # update the properties if needed + need_validation = False for i, token in enumerate(combination): if token.startswith(VARIABLE_PREFIX): index = int(token[len(VARIABLE_PREFIX):]) concept.def_prop_by_index(index, words[i]) + concept.metadata.need_validation = True if self.verbose_log.isEnabledFor(logging.DEBUG): prop_name = list(concept.props.keys())[index] context.log( diff --git a/tests/BaseTest.py b/tests/BaseTest.py index 59ec4d9..bc95606 100644 --- a/tests/BaseTest.py +++ b/tests/BaseTest.py @@ -1,6 +1,6 @@ import ast -from core.builtin_concepts import ReturnValueConcept, ParserResultConcept +from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts from core.concept import Concept from core.sheerka.ExecutionContext import ExecutionContext from parsers.BnfParser import BnfParser @@ -11,8 +11,14 @@ class BaseTest: def get_sheerka(self, **kwargs): pass - def get_context(self, sheerka=None): - return ExecutionContext("test", Event(), sheerka or self.get_sheerka()) + def get_context(self, sheerka=None, eval_body=False, eval_where=False): + context = ExecutionContext("test", Event(), sheerka or self.get_sheerka()) + if eval_body: + context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) + if eval_where: + context.local_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED) + + return context def get_default_concept(self): concept = Concept( diff --git a/tests/core/test_ExecutionContext.py b/tests/core/test_ExecutionContext.py index 40c7845..6b69353 100644 --- a/tests/core/test_ExecutionContext.py +++ b/tests/core/test_ExecutionContext.py @@ -34,7 +34,8 @@ def test_i_can_push(): concepts={"bar": Concept("bar")}) a.preprocess = set() a.preprocess.add("preprocess") - a.extra_info.append(BuiltinConcepts.CONCEPT_EVAL_REQUESTED) + a.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) + a.global_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) b = a.push() @@ -50,7 +51,8 @@ def test_i_can_push(): assert b.id == a.id + 1 assert b._tab == a._tab + " " assert b.preprocess == a.preprocess - assert b.extra_info == [BuiltinConcepts.CONCEPT_EVAL_REQUESTED] + assert b.local_hints == {BuiltinConcepts.EVAL_BODY_REQUESTED} + assert b.global_hints == a.global_hints def test_children_i_created_when_i_push(): @@ -72,3 +74,29 @@ def test_i_can_add_variable_when_i_push(): assert sub_e.my_new_var == "new var value" with pytest.raises(AttributeError): assert e.my_new_var == "" # my_new_var does not exist in parent + + +def test_local_hints_are_local_and_global_hints_are_global(): + a = ExecutionContext("foo", Event("event_1"), "fake_sheerka") + a.local_hints.add("local hint 1") + a.global_hints.add("global hint 1") + + b = a.push() + b.local_hints.add("local hint 2") + b.global_hints.add("global hint 2") + + assert a.local_hints == {"local hint 1"} + assert a.global_hints == {"global hint 1", "global hint 2"} + + assert b.local_hints == {"local hint 1", "local hint 2"} + assert b.global_hints == {"global hint 1", "global hint 2"} + + +def test_global_hits_are_global_even_when_empty(): + a = ExecutionContext("foo", Event("event_1"), "fake_sheerka") + + b = a.push() + b.global_hints.add("global hint 2") + + assert a.global_hints == {"global hint 2"} + assert b.global_hints == {"global hint 2"} diff --git a/tests/core/test_SheerkaEvaluateConcept.py b/tests/core/test_SheerkaEvaluateConcept.py index 4df84cb..927d88d 100644 --- a/tests/core/test_SheerkaEvaluateConcept.py +++ b/tests/core/test_SheerkaEvaluateConcept.py @@ -22,7 +22,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka = self.get_sheerka() concept = Concept("foo", body=body).init_key() - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.key == concept.key assert evaluated.body == expected @@ -80,7 +80,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka = self.get_sheerka() concept = Concept("foo").def_prop("a", expr) - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka,True), concept) assert evaluated.key == concept.key assert evaluated.metadata.pre is None @@ -95,7 +95,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): concept = Concept("foo") concept.compiled[ConceptParts.BODY] = DoNotResolve("do not resolve") - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.body == "do not resolve" assert evaluated.metadata.is_evaluated @@ -105,7 +105,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): concept = Concept("foo").def_prop("a") concept.compiled["a"] = DoNotResolve("do not resolve") - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.get_prop("a") == "do not resolve" assert evaluated.metadata.is_evaluated @@ -116,7 +116,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): concept.compiled["a"] = DoNotResolve("do not resolve") concept.compiled[ConceptParts.BODY] = DoNotResolve("do not resolve") - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.body == "do not resolve" assert evaluated.get_prop("a") == "do not resolve" @@ -126,7 +126,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka = self.get_sheerka() concept = Concept("foo", body="a+1").def_prop("a", "10").init_key() - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.key == concept.key assert evaluated.body == 11 @@ -137,7 +137,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka.add_in_cache(concept_a) concept = Concept("foo", body="a").init_key() - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated == simplec("foo", simplec("a", None)) assert id(evaluated.body) != id(concept_a) @@ -150,7 +150,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka.add_in_cache(concept_a) concept = Concept("foo", body="a") - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.key == concept.key assert evaluated.body == simplec("a", 1) @@ -164,7 +164,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka.add_in_cache(Concept(name="c", body="b")) concept_d = sheerka.add_in_cache(Concept(name="d", body="c")) - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept_d, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept_d) assert evaluated.key == concept_d.key expected = simplec("c", simplec("b", simplec("a", "a"))) @@ -179,7 +179,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka.add_in_cache(Concept(name="c", body="b")) concept_d = sheerka.add_in_cache(Concept(name="d", body="c")) - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept_d, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept_d) assert evaluated.key == concept_d.key expected = simplec("c", simplec("b", simplec("a", None))) @@ -192,7 +192,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): concept_a = sheerka.add_in_cache(Concept(name="a").init_key()) concept = Concept("foo", body="a").def_prop("a", "a").init_key() - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) # first prop a is evaluated to concept_a # then body is evaluated to prop a -> concept_a @@ -209,7 +209,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): concept_a = sheerka.add_in_cache(Concept(name="a")) concept = Concept("foo", body="concept_a").def_prop("concept_a", "a") - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.key == concept.key assert evaluated.body == concept_a @@ -220,7 +220,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka.add_in_cache(Concept(name="b", body="2")) concept = Concept("foo", body="propA + propB").def_prop("propA", "a").def_prop("propB", "b") - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.key == concept.key assert evaluated.body == 3 @@ -231,7 +231,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): concept = Concept("foo").def_prop("a") concept.compiled["a"] = concept_a - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.key == concept.key assert evaluated.get_prop("a") == simplec("a", "a") @@ -242,7 +242,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): concept = Concept("to_eval").def_prop("prop") concept.compiled["prop"] = [foo, DoNotResolve("1")] - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) props = evaluated.get_prop("prop") assert len(props) == 2 @@ -257,20 +257,20 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): concept = Concept("to_eval").def_prop("prop") concept.compiled["prop"] = [ReturnValueConcept("who", True, parser_result)] - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.get_prop("prop") == 2 # also works when only one return value concept = Concept("to_eval").def_prop("prop") concept.compiled["prop"] = ReturnValueConcept("who", True, parser_result) - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.get_prop("prop") == 2 def test_i_can_reference_sheerka(self): sheerka = self.get_sheerka() concept = Concept("foo", body="sheerka.test()").init_key() - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.key == concept.key assert evaluated.body == sheerka.test() @@ -281,19 +281,19 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka.add_in_cache(Concept(name="b", body="'concept_b'")) concept = Concept("foo", body="a") - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.key == concept.key assert evaluated.body == simplec("a", "concept_a") # this test was already done # so check this one. concept = Concept("foo", body="a").def_prop("a", "'property_a'") - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.key == concept.key assert evaluated.body == 'property_a' # or this one. concept = Concept("foo", body="a").def_prop("a", "b") - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.key == concept.key assert evaluated.body == simplec(name="b", body="concept_b") @@ -303,7 +303,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka.add_in_cache(Concept(name="b", body="'concept_b'")) concept = Concept("foo", body="a + b").def_prop("a", "'prop_a'").init_key() - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.key == concept.key assert evaluated.body == 'prop_aconcept_b' @@ -312,21 +312,21 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka.add_in_cache(Concept(name="concept_a").def_prop("subProp", "'sub_a'")) concept = Concept("foo", body="a.props['subProp'].value").def_prop("a", "concept_a") - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated == simplec(concept.key, "sub_a") def test_i_cannot_evaluate_concept_if_property_is_in_error(self): sheerka = self.get_sheerka() concept = Concept(name="concept_a").def_prop("subProp", "undef_concept") - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR) def test_key_is_initialized_by_evaluation(self): sheerka = self.get_sheerka() concept = Concept("foo") - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.key == concept.init_key().key @@ -345,7 +345,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): concept = Concept("foo", body="10", where=where_clause).def_prop("a", "20") sheerka.add_in_cache(concept) - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept) if expected: assert evaluated.key == concept.key @@ -362,14 +362,32 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka.add_in_cache(foo_true) concept = Concept("foo", where="foo_true").init_key() - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept) assert evaluated.key == concept.key concept = Concept("foo", where="foo_false") - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept) assert sheerka.isinstance(evaluated, BuiltinConcepts.WHERE_CLAUSE_FAILED) assert evaluated.body == concept + concept = Concept("foo", where="foo_false").init_key() + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, False), concept) + assert evaluated.key == concept.key + + def test_i_can_evaluate_disable_where_clause_evaluation(self): + sheerka = self.get_sheerka() + + concept = Concept("foo", body="10", where="a > 10").def_prop("a", None) + sheerka.add_in_cache(concept) + + context = self.get_context(sheerka) + evaluated = sheerka.evaluate_concept(context, concept) + assert evaluated.key == concept.key + + context.local_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED) + evaluated = sheerka.evaluate_concept(context, concept) + assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR) + def test_i_can_detect_infinite_recursion_with_numeric_constant(self): sheerka = self.get_sheerka() @@ -379,11 +397,11 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka.add_in_cache(one_str) sheerka.add_in_cache(one_digit) - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one_digit, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), one_digit) assert evaluated.key == one_digit.key assert evaluated.body == InfiniteRecursionResolved(1) - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one_str, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), one_str) assert evaluated.key == one_str.key assert evaluated.body == InfiniteRecursionResolved(1) @@ -396,11 +414,11 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka.add_in_cache(true_str) sheerka.add_in_cache(true_bool) - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), true_str, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), true_str) assert evaluated.key == true_str.key assert evaluated.body == InfiniteRecursionResolved(True) - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), true_bool, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), true_bool) assert evaluated.key == true_bool.key assert evaluated.body == InfiniteRecursionResolved(True) @@ -413,7 +431,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): c4 = sheerka.add_in_cache(Concept("3", body="one")) for concept in (c1, c2, c3, c4): - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) assert evaluated.key == concept.key assert evaluated.body == InfiniteRecursionResolved(3) @@ -425,19 +443,19 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): baz = sheerka.add_in_cache(Concept("baz", body="qux")) qux = sheerka.add_in_cache(Concept("qux", body="foo")) - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), foo, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), foo) assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG) assert evaluated.body == {foo, bar, baz, qux} - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), bar, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), bar) assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG) assert evaluated.body == {foo, bar, baz, qux} - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), baz, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), baz) assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG) assert evaluated.body == {foo, bar, baz, qux} - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), qux, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), qux) assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG) assert evaluated.body == {foo, bar, baz, qux} @@ -446,7 +464,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): foo = sheerka.add_in_cache(Concept("foo", body="foo")) - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), foo, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), foo) assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG) assert evaluated.body == {foo} @@ -454,7 +472,9 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): sheerka = self.get_sheerka() one = Concept("1", body="1") - evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one, True) + evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), one) assert evaluated.key == one.key assert evaluated.body == 1 + + diff --git a/tests/core/test_sheerka_call_evaluators.py b/tests/core/test_sheerka_call_evaluators.py index 3d27ba5..5aa7369 100644 --- a/tests/core/test_sheerka_call_evaluators.py +++ b/tests/core/test_sheerka_call_evaluators.py @@ -249,22 +249,16 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka): assert Out.debug_out == [ '__EVALUATION [0] priority20 - matches - target=foo', '__EVALUATION [0] priority20 - eval - target=foo', - '__EVALUATION [0] priority20 - matches - target=__EVALUATION', - '__EVALUATION [0] priority20 - eval - target=__EVALUATION', - "__EVALUATION [0] all_priority20 - matches - target=['foo', '__EVALUATION']", - "__EVALUATION [0] all_priority20 - eval - target=['foo', '__EVALUATION']", - "__EVALUATION [0] all_priority15 - matches - target=['foo', '__EVALUATION']", - "__EVALUATION [0] all_priority15 - eval - target=['foo', '__EVALUATION']", + "__EVALUATION [0] all_priority20 - matches - target=['foo']", + "__EVALUATION [0] all_priority20 - eval - target=['foo']", + "__EVALUATION [0] all_priority15 - matches - target=['foo']", + "__EVALUATION [0] all_priority15 - eval - target=['foo']", '__EVALUATION [0] priority15 - matches - target=foo', '__EVALUATION [0] priority15 - eval - target=foo', - '__EVALUATION [0] priority15 - matches - target=__EVALUATION', - '__EVALUATION [0] priority15 - eval - target=__EVALUATION', - "__EVALUATION [0] all_priority10 - matches - target=['foo', '__EVALUATION']", - "__EVALUATION [0] all_priority10 - eval - target=['foo', '__EVALUATION']", + "__EVALUATION [0] all_priority10 - matches - target=['foo']", + "__EVALUATION [0] all_priority10 - eval - target=['foo']", '__EVALUATION [0] priority10 - matches - target=foo', '__EVALUATION [0] priority10 - eval - target=foo', - '__EVALUATION [0] priority10 - matches - target=__EVALUATION', - '__EVALUATION [0] priority10 - eval - target=__EVALUATION' ] def test_that_predicate_is_checked_before_evaluation_for_one_return(self): @@ -279,10 +273,8 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka): '__EVALUATION [0] modifyFoo - matches - target=foo', '__EVALUATION [0] modifyFoo - eval - target=foo', '__EVALUATION [0] modifyFoo - matches - target=baz', - '__EVALUATION [0] modifyFoo - matches - target=__EVALUATION', '__EVALUATION [1] modifyFoo - matches - target=bar', '__EVALUATION [1] modifyFoo - matches - target=baz', - '__EVALUATION [1] modifyFoo - matches - target=__EVALUATION' ] def test_that_predicate_is_checked_before_evaluation_for_all_return(self): @@ -293,8 +285,8 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka): Out.debug_out = [] sheerka.execute(self.get_context(sheerka), entries, [BuiltinConcepts.EVALUATION]) assert Out.debug_out == [ - "__EVALUATION [0] all_reduce_foobar - matches - target=['foo', 'bar', '__EVALUATION']", - "__EVALUATION [0] all_reduce_foobar - eval - target=['foo', 'bar', '__EVALUATION']", + "__EVALUATION [0] all_reduce_foobar - matches - target=['foo', 'bar']", + "__EVALUATION [0] all_reduce_foobar - eval - target=['foo', 'bar']", "__EVALUATION [1] all_reduce_foobar - matches - target=['__SUCCESS']" ] @@ -302,7 +294,7 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka): Out.debug_out = [] sheerka.execute(self.get_context(sheerka), entries, [BuiltinConcepts.EVALUATION]) assert Out.debug_out == [ - "__EVALUATION [0] all_reduce_foobar - matches - target=['foo', '__EVALUATION']" + "__EVALUATION [0] all_reduce_foobar - matches - target=['foo']" ] def test_evaluation_continue_until_no_more_modification(self): @@ -317,23 +309,17 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka): '__EVALUATION [0] modifyFoo - matches - target=foo', '__EVALUATION [0] modifyFoo - eval - target=foo', '__EVALUATION [0] modifyFoo - matches - target=baz', - '__EVALUATION [0] modifyFoo - matches - target=__EVALUATION', '__EVALUATION [0] modifyBar - matches - target=foo', '__EVALUATION [0] modifyBar - matches - target=baz', - '__EVALUATION [0] modifyBar - matches - target=__EVALUATION', '__EVALUATION [1] modifyFoo - matches - target=bar', '__EVALUATION [1] modifyFoo - matches - target=baz', - '__EVALUATION [1] modifyFoo - matches - target=__EVALUATION', '__EVALUATION [1] modifyBar - matches - target=bar', '__EVALUATION [1] modifyBar - eval - target=bar', '__EVALUATION [1] modifyBar - matches - target=baz', - '__EVALUATION [1] modifyBar - matches - target=__EVALUATION', '__EVALUATION [2] modifyFoo - matches - target=baz', '__EVALUATION [2] modifyFoo - matches - target=baz', - '__EVALUATION [2] modifyFoo - matches - target=__EVALUATION', '__EVALUATION [2] modifyBar - matches - target=baz', '__EVALUATION [2] modifyBar - matches - target=baz', - '__EVALUATION [2] modifyBar - matches - target=__EVALUATION' ] def test_evaluation_steps_are_respected(self): @@ -347,8 +333,7 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka): assert Out.debug_out == [ '__BEFORE_EVALUATION [0] preEval - matches - target=foo', '__BEFORE_EVALUATION [0] preEval - eval - target=foo', - '__BEFORE_EVALUATION [0] preEval - matches - target=__BEFORE_EVALUATION', - '__BEFORE_EVALUATION [0] preEval - eval - target=__BEFORE_EVALUATION'] + ] def test_evaluation_multi_steps_are_respected(self): sheerka = self.get_sheerka() @@ -362,12 +347,8 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka): assert Out.debug_out == [ '__BEFORE_EVALUATION [0] multiStep - matches - target=foo', '__BEFORE_EVALUATION [0] multiStep - eval - target=foo', - '__BEFORE_EVALUATION [0] multiStep - matches - target=__BEFORE_EVALUATION', - '__BEFORE_EVALUATION [0] multiStep - eval - target=__BEFORE_EVALUATION', '__EVALUATION [0] multiStep - matches - target=foo', '__EVALUATION [0] multiStep - eval - target=foo', - '__EVALUATION [0] multiStep - matches - target=__EVALUATION', - '__EVALUATION [0] multiStep - eval - target=__EVALUATION' ] def test_evaluators_can_be_pre_processed(self): @@ -389,9 +370,7 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka): assert Out.debug_out == [ '__EVALUATION [0] modifyFoo - matches - target=foo', '__EVALUATION [0] modifyFoo - eval - target=foo', - '__EVALUATION [0] modifyFoo - matches - target=__EVALUATION', '__EVALUATION [1] modifyFoo - matches - target=bar', - '__EVALUATION [1] modifyFoo - matches - target=__EVALUATION' ] def test_i_can_initialize_evaluator_if_initialize_evaluator_is_defined(self): @@ -407,14 +386,12 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka): sheerka.execute(context, entries, [BuiltinConcepts.EVALUATION]) assert Out.debug_out == [ '__EVALUATION [0] init_once - matches - target=foo', - "__EVALUATION [0] init_once - init_evaluator - target=['foo', 'bar', 'baz', '__EVALUATION']", + "__EVALUATION [0] init_once - init_evaluator - target=['foo', 'bar', 'baz']", '__EVALUATION [0] init_once - eval - target=foo', '__EVALUATION [0] init_once - matches - target=bar', '__EVALUATION [0] init_once - eval - target=bar', '__EVALUATION [0] init_once - matches - target=baz', '__EVALUATION [0] init_once - eval - target=baz', - '__EVALUATION [0] init_once - matches - target=__EVALUATION', - '__EVALUATION [0] init_once - eval - target=__EVALUATION' ] def test_i_can_initialize_evaluators_multiple_times(self): @@ -430,15 +407,12 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka): sheerka.execute(context, entries, [BuiltinConcepts.EVALUATION]) assert Out.debug_out == [ '__EVALUATION [0] init_multiple - matches - target=foo', - "__EVALUATION [0] init_multiple - init_evaluator - target=['foo', 'bar', 'baz', '__EVALUATION']", + "__EVALUATION [0] init_multiple - init_evaluator - target=['foo', 'bar', 'baz']", '__EVALUATION [0] init_multiple - eval - target=foo', '__EVALUATION [0] init_multiple - matches - target=bar', - "__EVALUATION [0] init_multiple - init_evaluator - target=['foo', 'bar', 'baz', '__EVALUATION']", + "__EVALUATION [0] init_multiple - init_evaluator - target=['foo', 'bar', 'baz']", '__EVALUATION [0] init_multiple - eval - target=bar', '__EVALUATION [0] init_multiple - matches - target=baz', - "__EVALUATION [0] init_multiple - init_evaluator - target=['foo', 'bar', 'baz', '__EVALUATION']", + "__EVALUATION [0] init_multiple - init_evaluator - target=['foo', 'bar', 'baz']", '__EVALUATION [0] init_multiple - eval - target=baz', - '__EVALUATION [0] init_multiple - matches - target=__EVALUATION', - "__EVALUATION [0] init_multiple - init_evaluator - target=['foo', 'bar', 'baz', '__EVALUATION']", - '__EVALUATION [0] init_multiple - eval - target=__EVALUATION' ] diff --git a/tests/evaluators/test_ConceptEvaluator.py b/tests/evaluators/test_ConceptEvaluator.py index f762828..68a1688 100644 --- a/tests/evaluators/test_ConceptEvaluator.py +++ b/tests/evaluators/test_ConceptEvaluator.py @@ -20,7 +20,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka): def test_i_can_evaluate_concept(self): context = self.get_context() - context.extra_info.append(BuiltinConcepts.CONCEPT_EVAL_REQUESTED) + context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) concept = Concept(name="foo", where="True", pre="2", @@ -28,7 +28,6 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka): evaluator = ConceptEvaluator() item = self.pretval(concept) - evaluator.init_evaluator(context, [item]) result = evaluator.eval(context, item) assert result.who == evaluator.name @@ -44,7 +43,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka): def test_body_is_returned_when_defined_and_requested(self): context = self.get_context() - context.extra_info.append(BuiltinConcepts.CONCEPT_EVAL_REQUESTED) + context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) concept = Concept(name="foo", body="'I have a value'", where="True", @@ -53,7 +52,6 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka): evaluator = ConceptEvaluator(return_body=True) item = self.pretval(concept) - evaluator.init_evaluator(context, [item]) result = evaluator.eval(context, item) assert result.who == evaluator.name @@ -71,7 +69,6 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka): evaluator = ConceptEvaluator(return_body=False) # which is the default behaviour item = self.pretval(concept) - evaluator.init_evaluator(context, [item]) result = evaluator.eval(context, item) assert result.who == evaluator.name @@ -95,7 +92,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka): def test_i_cannot_recognize_a_concept_if_one_of_the_prop_is_unknown(self): context = self.get_context() - context.extra_info.append(BuiltinConcepts.CONCEPT_EVAL_REQUESTED) + context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) context.sheerka.add_in_cache(Concept(name="one").init_key()) concept_plus = context.sheerka.add_in_cache(Concept(name="a plus b") .def_prop("a", "one") @@ -103,7 +100,6 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka): evaluator = ConceptEvaluator() item = self.pretval(concept_plus) - evaluator.init_evaluator(context, [item]) result = evaluator.eval(context, item) assert not result.status diff --git a/tests/evaluators/test_EvalEvaluator.py b/tests/evaluators/test_EvalEvaluator.py index dbcbb71..e586fb1 100644 --- a/tests/evaluators/test_EvalEvaluator.py +++ b/tests/evaluators/test_EvalEvaluator.py @@ -5,8 +5,6 @@ from core.concept import Concept from evaluators.EvalEvaluator import EvalEvaluator from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka -value_requested = ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.CONCEPT_VALUE_REQUESTED)) - def retval(obj, who="who", status=True): """ret_val""" @@ -16,6 +14,7 @@ def retval(obj, who="who", status=True): class TestEvalEvaluator(TestUsingMemoryBasedSheerka): def test_i_can_match_and_eval(self): context = self.get_context() + context.global_hints.add(BuiltinConcepts.CONCEPT_VALUE_REQUESTED) to_eval1 = ReturnValueConcept("some_name", True, Concept(name="2", body="to eval").auto_init()) to_eval2 = ReturnValueConcept("some_name", True, Concept(name="3", body="also to eval").auto_init()) @@ -26,7 +25,6 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka): ReturnValueConcept("some_name", False, Concept(name="1", body="'not to eval'")), to_eval1, to_eval2, - value_requested ] evaluator = EvalEvaluator() @@ -35,41 +33,35 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka): evaluated = evaluator.eval(context, return_values) assert len(evaluated) == 2 assert evaluated[0].value == to_eval1.body.body - assert evaluated[0].parents == [to_eval1, value_requested] + assert evaluated[0].parents == [to_eval1] assert evaluated[1].value == to_eval2.body.body - assert evaluated[1].parents == [to_eval2, value_requested] + assert evaluated[1].parents == [to_eval2] - @pytest.mark.parametrize("return_values, expected", [ - ([retval(Concept("foo", body="bar")), value_requested], True), - ([retval(Concept("status is false", body="bar"), status=False), value_requested], True), - ([retval("string_value"), value_requested], True), - ([retval(Concept("no body")), value_requested], True), - ([retval(Concept("eval requested missing", body="bar"))], False), + @pytest.mark.parametrize("return_value", [ + retval(Concept("foo", body="bar")), + retval(Concept("status is false", body="bar"), status=False), + retval("string_value"), + retval(Concept("no body")), ]) - def test_i_cannot_match_if_eval_request_is_not_present(self, return_values, expected): + def test_i_cannot_match_if_eval_request_is_not_present(self, return_value): context = self.get_context() - assert EvalEvaluator().matches(context, return_values) == expected + assert not EvalEvaluator().matches(context, [return_value]) + + context.global_hints.add(BuiltinConcepts.CONCEPT_VALUE_REQUESTED) + assert EvalEvaluator().matches(context, [return_value]) def test_concept_eval_requested_is_reduced_when_nothing_to_reduce(self): context = self.get_context() return_values = [ - ReturnValueConcept("some_name", True, "not to eval"), - ReturnValueConcept("some_name", True, Concept(name="not to eval")), - ReturnValueConcept("some_name", False, Concept(name="1", body="not to eval")), - value_requested + ReturnValueConcept("some_name", True, "not to eval"), # not a concept + ReturnValueConcept("some_name", True, Concept(name="not to eval")), # no body + ReturnValueConcept("some_name", False, Concept(name="1", body="not to eval")), # no evaluated body ] - evaluator = EvalEvaluator() - assert evaluator.matches(context, return_values) - - evaluated = evaluator.eval(context, return_values) - assert evaluated == ReturnValueConcept( - "evaluators.Eval", - False, - context.sheerka.new(BuiltinConcepts.CONCEPT_VALUE_REQUESTED)) - assert evaluated.parents == [value_requested] + evaluated = EvalEvaluator().eval(context, return_values) + assert evaluated is None def test_i_can_evaluate_sets(self): sheerka, context, foo, bar, baz, number = self.init_concepts( @@ -79,11 +71,7 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka): Concept("number")) sheerka.sets_handler.add_concepts_to_set(context, [foo, bar, baz], number) - return_values = [retval(number), value_requested] - - evaluator = EvalEvaluator() - evaluator.matches(context, return_values) - evaluated = evaluator.eval(context, return_values) + evaluated = EvalEvaluator().eval(context, [retval(number)]) assert len(evaluated) == 1 assert evaluated[0].status diff --git a/tests/evaluators/test_PrepareEvalEvaluator.py b/tests/evaluators/test_PrepareEvalEvaluator.py index b72db4b..b82d1d2 100644 --- a/tests/evaluators/test_PrepareEvalEvaluator.py +++ b/tests/evaluators/test_PrepareEvalEvaluator.py @@ -40,10 +40,9 @@ class TestPrepareEvalEvaluator(TestUsingMemoryBasedSheerka): prepare_evaluator.matches(context, ret_val) res = prepare_evaluator.eval(context, ret_val) - assert len(res) == 2 - assert res[0].status - assert sheerka.isinstance(res[0].body, BuiltinConcepts.USER_INPUT) - assert res[0].body.body == expected + assert res.status + assert sheerka.isinstance(res.body, BuiltinConcepts.USER_INPUT) + assert res.body.body == expected - assert res[1].status - assert sheerka.isinstance(res[1].body, BuiltinConcepts.CONCEPT_VALUE_REQUESTED) + assert BuiltinConcepts.EVAL_BODY_REQUESTED in context.global_hints + assert BuiltinConcepts.CONCEPT_VALUE_REQUESTED in context.global_hints diff --git a/tests/non_reg/test_sheerka_non_reg.py b/tests/non_reg/test_sheerka_non_reg.py index 304ce18..8c52009 100644 --- a/tests/non_reg/test_sheerka_non_reg.py +++ b/tests/non_reg/test_sheerka_non_reg.py @@ -36,7 +36,7 @@ class TestSheerkaNonReg(TestUsingFileBasedSheerka): assert res[0].value == concept # sanity check - evaluated = sheerka.evaluate_concept(self.get_context(), res[0].value, True) + evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value) assert evaluated == simplec("one", 1) def test_i_can_recognize_concept_with_concept_body(self): @@ -53,7 +53,7 @@ class TestSheerkaNonReg(TestUsingFileBasedSheerka): assert return_value == concept_un # sanity check - evaluated = sheerka.evaluate_concept(self.get_context(), return_value, True) + evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), return_value) assert evaluated == simplec("un", simplec("one", None)) def test_i_can_recognize_concept_with_no_body(self): @@ -194,7 +194,7 @@ as: assert return_value.metadata.props[0] == ('a', "foo") # sanity check - evaluated = sheerka.evaluate_concept(self.get_context(), return_value, True) + evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), return_value) assert evaluated.props["a"].value == concept_foo def test_i_can_recognize_concept_with_variable_and_python_as_body(self): @@ -208,7 +208,7 @@ as: assert sheerka.isinstance(res[0].value, hello_a) # sanity check - evaluated = sheerka.evaluate_concept(self.get_context(), res[0].value, True) + evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value) assert evaluated.body == "hello foo" assert evaluated.metadata.is_evaluated assert evaluated.props["a"].value == simplec("foo", "foo") @@ -323,7 +323,7 @@ as: assert sheerka.isinstance(return_value, concept_b) # sanity check - evaluated = sheerka.evaluate_concept(self.get_context(), return_value, True) + evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), return_value) assert evaluated.body == "one three" assert evaluated.metadata.is_evaluated assert evaluated.props["a"] == Property("a", sheerka.new(concept_a.key, body="one").init_key()) @@ -355,7 +355,7 @@ as: assert res[0].status assert sheerka.isinstance(res[0].value, concept_b) - evaluated = sheerka.evaluate_concept(self.get_context(), res[0].value, True) + evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value) assert evaluated.body == "one two three" assert evaluated.props["a"] == Property("a", sheerka.new(concept_a.key, body="one two").init_key()) @@ -406,7 +406,7 @@ as: assert len(res) == 1 assert res[0].status assert sheerka.isinstance(res[0].body, "twenties") - assert sheerka.evaluate_concept(self.get_context(), res[0].body, True).body == 21 + assert sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].body).body == 21 res = sheerka.evaluate_user_input("twenty one + 1") assert len(res) == 1 @@ -450,7 +450,7 @@ as: assert len(res) == 1 assert res[0].status assert sheerka.isinstance(res[0].body, "twenties") - assert sheerka.evaluate_concept(self.get_context(), res[0].value, True).body == 21 + assert sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value).body == 21 res = sheerka.evaluate_user_input("twenty one + 1") assert len(res) == 1 @@ -695,8 +695,15 @@ as: res = sheerka.evaluate_user_input("eval twenty two") assert len(res) == 1 and res[0].status and res[0].body == 22 + res = sheerka.evaluate_user_input("twenty three") + assert len(res) == 1 + assert not res[0].status + assert sheerka.isinstance(res[0].body, BuiltinConcepts.WHERE_CLAUSE_FAILED) + res = sheerka.evaluate_user_input("eval twenty three") - assert len(res) > 1 + assert len(res) == 1 + assert not res[0].status + assert sheerka.isinstance(res[0].body, BuiltinConcepts.WHERE_CLAUSE_FAILED) # def test_i_can_detect_when_only_one_evaluator_is_in_error(self): # sheerka = self.get_sheerka() @@ -722,10 +729,7 @@ as: assert res[0].status assert res[0].body == 2 - @pytest.mark.xfail def test_i_can_evaluate_bnf_concept_with_where_clause(self): - - sheerka = self.get_sheerka() sheerka.evaluate_user_input("def concept a from bnf 'bar' | 'baz'") @@ -741,7 +745,7 @@ as: res = sheerka.evaluate_user_input("eval foo bar") assert len(res) == 1 assert res[0].status - assert res[0].body.body == "hello world" + assert res[0].body == "hello world" res = sheerka.evaluate_user_input("foo baz") assert len(res) == 1 @@ -749,17 +753,18 @@ as: assert sheerka.isinstance(res[0].body, BuiltinConcepts.WHERE_CLAUSE_FAILED) res = sheerka.evaluate_user_input("eval foo baz") - assert len(res) > 1 + assert len(res) == 1 + assert not res[0].status + assert sheerka.isinstance(res[0].body, BuiltinConcepts.WHERE_CLAUSE_FAILED) - # The following test fails - # the Where clause is evaluated while it should not res = sheerka.evaluate_user_input("foobar") assert len(res) == 1 assert res[0].status res = sheerka.evaluate_user_input("eval foobar") - assert len(res) > 1 # error - assert res[0].status + assert len(res) == 1 # error + assert not res[0].status + assert sheerka.isinstance(res[0].body, BuiltinConcepts.WHERE_CLAUSE_FAILED) def test_i_can_say_than_bnf_concept_isa_another_concept(self): sheerka = self.get_sheerka() diff --git a/tests/parsers/test_ConceptLexerParser.py b/tests/parsers/test_ConceptLexerParser.py index a393cf7..19afc2e 100644 --- a/tests/parsers/test_ConceptLexerParser.py +++ b/tests/parsers/test_ConceptLexerParser.py @@ -1225,6 +1225,28 @@ class TestConceptLexerParser(TestUsingMemoryBasedSheerka): OneOrMore(ConceptExpression(baz, rule_name="baz")), rule_name="oc"), rule_name="s") assert parse_res.value.value == expected + def test_i_concept_validation_is_not_set_when_no_variables(self): + foo = Concept(name="foo") + grammar = {foo: "foo"} + + context, res, wrapper, return_value = self.execute([foo], grammar, "foo") + assert not return_value[0].concept.metadata.need_validation + + def test_i_concept_validation_is_set_when_unnamed_variables_are_found(self): + foo = Concept(name="foo") + grammar = {foo: Sequence("foo", OrderedChoice("a", "b"))} + + context, res, wrapper, return_value = self.execute([foo], grammar, "foo a") + assert not return_value[0].concept.metadata.need_validation + + def test_i_concept_validation_is_set_when_named_variables_are_found(self): + foo = Concept(name="foo") + grammar = {foo: Sequence("foo", OrderedChoice("a", "b", rule_name="var"))} + + context, res, wrapper, return_value = self.execute([foo], grammar, "foo a") + assert return_value[0].concept.metadata.need_validation + + # # def test_i_can_parse_basic_arithmetic_operations_and_resolve_properties(self): # context = self.get_context() diff --git a/tests/parsers/test_ConceptsWithConceptsParser.py b/tests/parsers/test_ConceptsWithConceptsParser.py index a5cfd44..17fd1ea 100644 --- a/tests/parsers/test_ConceptsWithConceptsParser.py +++ b/tests/parsers/test_ConceptsWithConceptsParser.py @@ -93,7 +93,7 @@ class TestConceptsWithConceptsParser(TestUsingMemoryBasedSheerka): assert return_value.compiled["b"] == bar # sanity check, I can evaluate the result - evaluated = context.sheerka.evaluate_concept(context, return_value, True) + evaluated = context.sheerka.evaluate_concept(self.get_context(context.sheerka, True), return_value) assert evaluated.key == return_value.key assert evaluated.get_prop("a") == foo.init_key() assert evaluated.get_prop("b") == bar.init_key() @@ -116,7 +116,7 @@ class TestConceptsWithConceptsParser(TestUsingMemoryBasedSheerka): assert return_value.compiled["b"] == [ReturnValueConcept(parser.name, True, right_parser_result)] # sanity check, I can evaluate the result - evaluated = context.sheerka.evaluate_concept(context, return_value, True) + evaluated = context.sheerka.evaluate_concept(self.get_context(context.sheerka, True), return_value) assert evaluated.key == return_value.key assert evaluated.get_prop("a") == 2 assert evaluated.get_prop("b") == 4 @@ -139,7 +139,7 @@ class TestConceptsWithConceptsParser(TestUsingMemoryBasedSheerka): assert return_value.compiled["b"] == [ReturnValueConcept(parser.name, True, code_parser_result)] # sanity check, I can evaluate the result - evaluated = context.sheerka.evaluate_concept(context, return_value, True) + evaluated = context.sheerka.evaluate_concept(self.get_context(context.sheerka, True), return_value) assert evaluated.key == return_value.key assert evaluated.get_prop("a") == foo.init_key() assert evaluated.get_prop("b") == 2 diff --git a/tests/parsers/test_ExactConceptParser.py b/tests/parsers/test_ExactConceptParser.py index 8547077..c893720 100644 --- a/tests/parsers/test_ExactConceptParser.py +++ b/tests/parsers/test_ExactConceptParser.py @@ -56,10 +56,12 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka): source = "hello world" results = ExactConceptParser().parse(context, source) + concept_found = results[0].value.value assert len(results) == 1 assert results[0].status - assert results[0].value.value == concept + assert concept_found == concept + assert not concept_found.metadata.need_validation def test_i_can_recognize_concepts_defined_several_times(self): context = self.get_context() @@ -75,9 +77,11 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka): assert results[0].status assert results[0].value.value.name == "hello a" assert metadata_prop(results[0].value.value, "a") == "world" + assert results[0].value.value.metadata.need_validation assert results[1].status assert results[1].value.value.name == "hello world" + assert not results[1].value.value.metadata.need_validation def test_i_can_recognize_a_concept_with_variables(self): context = self.get_context() @@ -88,10 +92,12 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka): assert len(results) == 1 assert results[0].status + concept_found = results[0].value.value assert concept_found.key == concept.key assert metadata_prop(concept_found, "a") == "10" assert metadata_prop(concept_found, "b") == "5" + assert concept_found.metadata.need_validation def test_i_can_recognize_a_concept_with_duplicate_variables(self): context = self.get_context() @@ -102,10 +108,12 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka): assert len(results) == 1 assert results[0].status + concept_found = results[0].value.value assert concept_found.key == concept.key assert metadata_prop(concept_found, "a") == "10" assert metadata_prop(concept_found, "b") == "5" + assert concept_found.metadata.need_validation def test_i_can_manage_unknown_concept(self): context = self.get_context() @@ -136,3 +144,4 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka): assert len(results) == 1 assert results[0].status assert results[0].value.value == concept + assert not results[0].value.value.metadata.need_validation