Concepts bodies are now evaluated on demand

This commit is contained in:
2020-02-27 10:48:45 +01:00
parent 7cd94e888f
commit ef31a4807d
25 changed files with 468 additions and 172 deletions
+8 -1
View File
@@ -40,6 +40,13 @@ eighteen isa number
nineteen isa number nineteen isa number
twenty isa number twenty isa number
def concept twenties from bnf twenty number where number < 10 as twenty + number def concept twenties from bnf twenty number where number < 10 as twenty + number
twenties isa number
def concept thirty as 30 def concept thirty as 30
def concept thirties from bnf thirty number where number < 10 as thirty + number
thirties isa number
def concept forty as 40 def concept forty as 40
def concept forties from bnf forty number where number < 10 as forty + number
forties isa number
def concept fifty as 50
def concept fifties from bnf fifty number where number < 10 as fifty + number
fifties isa number
+1
View File
@@ -53,6 +53,7 @@ class BuiltinConcepts(Enum):
WHERE_CLAUSE_FAILED = "where clause failed" # failed to validate where clause during evaluation WHERE_CLAUSE_FAILED = "where clause failed" # failed to validate where clause during evaluation
CHICKEN_AND_EGG = "chicken and egg" # infinite recursion when declaring concept 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 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" NODE = "node"
GENERIC_NODE = "generic node" GENERIC_NODE = "generic node"
+39 -5
View File
@@ -5,12 +5,13 @@ import core.ast.nodes
from core.ast.nodes import CallNodeConcept, GenericNodeConcept from core.ast.nodes import CallNodeConcept, GenericNodeConcept
from core.ast.visitors import UnreferencedNamesVisitor from core.ast.visitors import UnreferencedNamesVisitor
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
def is_same_success(sheerka, return_values): def is_same_success(context, return_values):
""" """
Returns True if all returns values are successful and have the same value Returns True if all returns values are successful and have the same value
:param sheerka: :param context:
:param return_values: :param return_values:
:return: :return:
""" """
@@ -19,13 +20,27 @@ def is_same_success(sheerka, return_values):
if not return_values[0].status: if not return_values[0].status:
return False return False
reference = sheerka.value(return_values[0].value) 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])
for return_value in return_values[1:]: for return_value in return_values[1:]:
if not return_value.status: if not return_value.status:
return False return False
actual = sheerka.value(return_value.value) if isinstance(return_value.body, Concept):
evaluated = context.sheerka.evaluate_concept(context, return_value.body, True)
if evaluated.key != return_value.body.key:
return False
actual = context.sheerka.value(evaluated)
else:
actual = context.sheerka.value(return_value)
if actual != reference: if actual != reference:
return False return False
@@ -67,7 +82,7 @@ def expect_one(context, return_values):
# too many winners, which one to choose ? # too many winners, which one to choose ?
if number_of_successful > 1: if number_of_successful > 1:
if is_same_success(sheerka, successful_results): if is_same_success(context, successful_results):
return sheerka.ret( return sheerka.ret(
context.who, context.who,
True, True,
@@ -218,3 +233,22 @@ def _extract_predicates(sheerka, node, variables_to_include, variables_to_exclud
predicates.append(res) predicates.append(res)
return predicates return predicates
def add_to_ret_val(sheerka, context, return_values, concept_key):
concept = sheerka.new(concept_key)
ret_val = sheerka.ret(context.who, True, concept)
return_values.append(ret_val)
return return_values
def remove_from_ret_val(sheerka, return_values, concept_key):
to_remove = []
for ret_val in return_values:
if ret_val.status and sheerka.isinstance(ret_val.body, concept_key):
to_remove.append(ret_val)
for item in to_remove:
return_values.remove(item)
return return_values
+3 -2
View File
@@ -60,6 +60,7 @@ class ExecutionContext:
self.children = [] self.children = []
self.preprocess = None self.preprocess = None
self.logger = logger self.logger = logger
self.extra_info = []
self.inputs = {} # what was the parameters of the execution context self.inputs = {} # what was the parameters of the execution context
self.values = {} # what was produced by the execution context self.values = {} # what was produced by the execution context
@@ -210,11 +211,11 @@ class ExecutionContext:
self.sheerka, self.sheerka,
desc, desc,
logger, logger,
**_kwargs, **_kwargs)
)
new._parent = self new._parent = self
new._tab = self._tab + " " * DEBUG_TAB_SIZE new._tab = self._tab + " " * DEBUG_TAB_SIZE
new.preprocess = self.preprocess new.preprocess = self.preprocess
new.extra_info.extend(self.extra_info)
self.children.append(new) self.children.append(new)
return new return new
@@ -1,6 +1,6 @@
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved
import core.builtin_helpers from core.builtin_helpers import add_to_ret_val, remove_from_ret_val, expect_one
CONCEPT_EVALUATION_STEPS = [ CONCEPT_EVALUATION_STEPS = [
BuiltinConcepts.BEFORE_EVALUATION, BuiltinConcepts.BEFORE_EVALUATION,
@@ -118,7 +118,7 @@ class SheerkaEvaluateConcept:
else: else:
self.sheerka.cache_by_key[concept.key].compiled = concept.compiled self.sheerka.cache_by_key[concept.key].compiled = concept.compiled
def resolve(self, context, to_resolve, current_prop, current_concept): def resolve(self, context, to_resolve, current_prop, current_concept, evaluate_body):
if isinstance(to_resolve, DoNotResolve): if isinstance(to_resolve, DoNotResolve):
return to_resolve.value return to_resolve.value
@@ -137,7 +137,7 @@ class SheerkaEvaluateConcept:
# when it's a concept, evaluate it # when it's a concept, evaluate it
if isinstance(to_resolve, Concept) and \ if isinstance(to_resolve, Concept) and \
not context.sheerka.isinstance(to_resolve, BuiltinConcepts.RETURN_VALUE): not context.sheerka.isinstance(to_resolve, BuiltinConcepts.RETURN_VALUE):
evaluated = self.evaluate_concept(sub_context, to_resolve) evaluated = self.evaluate_concept(sub_context, to_resolve, evaluate_body)
sub_context.add_values(return_values=evaluated) sub_context.add_values(return_values=evaluated)
if evaluated.key == to_resolve.key: if evaluated.key == to_resolve.key:
return evaluated return evaluated
@@ -147,8 +147,11 @@ class SheerkaEvaluateConcept:
# otherwise, execute all return values to find out what is the value # otherwise, execute all return values to find out what is the value
else: else:
use_copy = [r for r in to_resolve] if hasattr(to_resolve, "__iter__") else to_resolve 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) r = self.sheerka.execute(sub_context, use_copy, CONCEPT_EVALUATION_STEPS)
one_r = core.builtin_helpers.expect_one(context, r)
one_r = expect_one(context, r)
sub_context.add_values(return_values=one_r) sub_context.add_values(return_values=one_r)
if one_r.status: if one_r.status:
return one_r.value return one_r.value
@@ -161,7 +164,7 @@ class SheerkaEvaluateConcept:
concept=current_concept, concept=current_concept,
property_name=current_prop) property_name=current_prop)
def resolve_list(self, context, list_to_resolve, current_prop, current_concept): def resolve_list(self, context, list_to_resolve, current_prop, current_concept, evaluate_body):
"""When dealing with a list, there are two possibilities""" """When dealing with a list, there are two possibilities"""
# It may be a list of ReturnValueConcept to execute (always the case for metadata) # 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) # or a list of single values (may be the case for properties)
@@ -170,7 +173,7 @@ class SheerkaEvaluateConcept:
return [] return []
if self.sheerka.isinstance(list_to_resolve[0], BuiltinConcepts.RETURN_VALUE): if self.sheerka.isinstance(list_to_resolve[0], BuiltinConcepts.RETURN_VALUE):
return self.resolve(context, list_to_resolve, current_prop, current_concept) return self.resolve(context, list_to_resolve, current_prop, current_concept, evaluate_body)
res = [] res = []
for to_resolve in list_to_resolve: for to_resolve in list_to_resolve:
@@ -181,35 +184,31 @@ class SheerkaEvaluateConcept:
concept=current_concept, concept=current_concept,
property_name=current_prop) property_name=current_prop)
r = self.resolve(context, to_resolve, current_prop, current_concept) r = self.resolve(context, to_resolve, current_prop, current_concept, evaluate_body)
if self.sheerka.isinstance(r, BuiltinConcepts.CONCEPT_EVAL_ERROR): if self.sheerka.isinstance(r, BuiltinConcepts.CONCEPT_EVAL_ERROR):
return r return r
res.append(r) res.append(r)
return res return res
def evaluate_concept(self, context, concept: Concept): def evaluate_concept(self, context, concept: Concept, evaluate_body=False):
""" """
Evaluation a concept Evaluation a concept
It means that if the where clause is True, will evaluate the body It means that if the where clause is True, will evaluate the body
:param context: :param context:
:param concept: :param concept:
:param logger: :param evaluate_body: If false, only evaluate body when necessary
:return: value of the evaluation or error :return: value of the evaluation or error
""" """
if concept.metadata.is_evaluated: if concept.metadata.is_evaluated:
return concept return concept
#
# TODO : Validate the PRE condition
#
self.initialize_concept_asts(context, concept) self.initialize_concept_asts(context, concept)
# to make sure of the order, it don't use ConceptParts.get_parts() # to make sure of the order, it don't use ConceptParts.get_parts()
# props must be evaluated first, body must be evaluated before where # props must be evaluated first, body must be evaluated before where
all_metadata_to_eval = ["pre", "post", "props", "body", "where"] all_metadata_to_eval = self.choose_metadata_to_eval(concept, evaluate_body)
for metadata_to_eval in all_metadata_to_eval: for metadata_to_eval in all_metadata_to_eval:
if metadata_to_eval == "props": if metadata_to_eval == "props":
@@ -218,10 +217,10 @@ class SheerkaEvaluateConcept:
if isinstance(prop_ast, list): if isinstance(prop_ast, list):
# Do not send the current concept for the properties # Do not send the current concept for the properties
resolved = self.resolve_list(context, prop_ast, prop_name, None) resolved = self.resolve_list(context, prop_ast, prop_name, None, True)
else: else:
# Do not send the current concept for the properties # Do not send the current concept for the properties
resolved = self.resolve(context, prop_ast, prop_name, None) resolved = self.resolve(context, prop_ast, prop_name, None, True)
if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved): if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved):
resolved.set_prop("concept", concept) # since current concept was not sent resolved.set_prop("concept", concept) # since current concept was not sent
return resolved return resolved
@@ -237,12 +236,16 @@ class SheerkaEvaluateConcept:
if part_key in concept.compiled and concept.compiled[part_key] is not None: if part_key in concept.compiled and concept.compiled[part_key] is not None:
metadata_ast = concept.compiled[part_key] metadata_ast = concept.compiled[part_key]
resolved = self.resolve(context, metadata_ast, part_key, concept) resolved = self.resolve(context, metadata_ast, part_key, concept, evaluate_body)
if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved): if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved):
return resolved return resolved
else: else:
concept.values[part_key] = self.get_infinite_recursion_resolution(resolved) or resolved concept.values[part_key] = self.get_infinite_recursion_resolution(resolved) or resolved
#
# TODO : Validate the PRE condition
#
# validate where clause # validate where clause
if ConceptParts.WHERE in concept.values: if ConceptParts.WHERE in concept.values:
where_value = concept.values[ConceptParts.WHERE] where_value = concept.values[ConceptParts.WHERE]
@@ -254,5 +257,52 @@ class SheerkaEvaluateConcept:
# #
concept.init_key() # only does it if needed concept.init_key() # only does it if needed
concept.metadata.is_evaluated = True concept.metadata.is_evaluated = "body" in all_metadata_to_eval
return concept return concept
def choose_metadata_to_eval(self, concept, evaluate_body):
if evaluate_body:
return ["pre", "post", "props", "body", "where"]
metadata = ["pre", "post"] + self.needed_metadata(concept) + ["where"]
return metadata
def needed_metadata(self, concept):
"""
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:
:return:
"""
needed = []
for metadata in (ConceptParts.PRE, ConceptParts.POST, ConceptParts.WHERE):
if metadata not in concept.compiled:
continue
return_values = concept.compiled[metadata]
if not isinstance(return_values, list):
continue
for return_value in return_values:
if not self.sheerka.isinstance(return_value, BuiltinConcepts.RETURN_VALUE):
continue
if not return_value.status:
continue
if not self.sheerka.isinstance(return_value.body, BuiltinConcepts.PARSER_RESULT):
continue
if not isinstance(return_value.body.source, str):
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 "self" in return_value.body.source:
needed.append("body")
return needed
@@ -150,6 +150,11 @@ class SheerkaExecute:
debug_result = [] debug_result = []
for item in original_items: for item in original_items:
if evaluator.matches(sub_context, item): if evaluator.matches(sub_context, item):
# init the evaluator is possible
if hasattr(evaluator, "init_evaluator") and not evaluator.is_initialized:
evaluator.init_evaluator(sub_context, original_items)
result = evaluator.eval(sub_context, item) result = evaluator.eval(sub_context, item)
if result is None: if result is None:
debug_result.append({"input": item, "return_value": None}) debug_result.append({"input": item, "return_value": None})
@@ -108,7 +108,7 @@ class SheerkaSetsManager:
# it may be a concept that references a set # it may be a concept that references a set
if not sub_concept.metadata.is_evaluated: if not sub_concept.metadata.is_evaluated:
with context.push(desc=f"Evaluating concept {sub_concept}") as sub_context: with context.push(desc=f"Evaluating concept {sub_concept}") as sub_context:
evaluated = self.sheerka.evaluate_concept(sub_context, sub_concept) evaluated = self.sheerka.evaluate_concept(sub_context, sub_concept, True)
if evaluated.key != concept.key: if evaluated.key != concept.key:
return False return False
return _get_set_elements(context, concept, sub_concept.body) return _get_set_elements(context, concept, sub_concept.body)
@@ -167,7 +167,7 @@ class SheerkaSetsManager:
# it may be a concept that references a set # it may be a concept that references a set
if not concept.metadata.is_evaluated: if not concept.metadata.is_evaluated:
with context.push(desc=f"Evaluating concept {concept}") as sub_context: with context.push(desc=f"Evaluating concept {concept}") as sub_context:
evaluated = self.sheerka.evaluate_concept(sub_context, concept) evaluated = self.sheerka.evaluate_concept(sub_context, concept, True)
if evaluated.key != concept.key: if evaluated.key != concept.key:
return False return False
@@ -218,7 +218,7 @@ for x in xx__concepts__xx:
with context.push(desc=f"Evaluating concepts of a set") as sub_context: with context.push(desc=f"Evaluating concepts of a set") as sub_context:
for element_id in ids: for element_id in ids:
concept = self.sheerka.get_by_id(element_id) concept = self.sheerka.get_by_id(element_id)
evaluated = self.sheerka.evaluate_concept(context, concept) evaluated = self.sheerka.evaluate_concept(sub_context, concept, True)
result.append(evaluated) result.append(evaluated)
return result return result
+14 -13
View File
@@ -269,7 +269,6 @@ class Sheerka(Concept):
:param execution_context: :param execution_context:
:param return_values: :param return_values:
:param execution_steps: :param execution_steps:
:param logger: logger to use (if not directly called by sheerka)
:return: :return:
""" """
return self.execute_handler.execute(execution_context, return_values, execution_steps) return self.execute_handler.execute(execution_context, return_values, execution_steps)
@@ -294,7 +293,6 @@ class Sheerka(Concept):
Adds a new concept to the system Adds a new concept to the system
:param context: :param context:
:param concept: DefConceptNode :param concept: DefConceptNode
:param logger
:return: digest of the new concept :return: digest of the new concept
""" """
@@ -309,7 +307,6 @@ class Sheerka(Concept):
:param context: :param context:
:param concept: :param concept:
:param concept_set: :param concept_set:
:param logger:
:return: :return:
""" """
return self.sets_handler.add_concept_to_set(context, concept, concept_set) return self.sets_handler.add_concept_to_set(context, concept, concept_set)
@@ -320,7 +317,6 @@ class Sheerka(Concept):
:param context: :param context:
:param concept: :param concept:
:param concept_set: :param concept_set:
:param logger:
:return: :return:
""" """
return self.sets_handler.set_isa(context, concept, concept_set) return self.sets_handler.set_isa(context, concept, concept_set)
@@ -336,16 +332,17 @@ class Sheerka(Concept):
return self.sets_handler.get_set_elements(context, concept) return self.sets_handler.get_set_elements(context, concept)
def evaluate_concept(self, context, concept: Concept): def evaluate_concept(self, context, concept: Concept, evaluate_body=False):
""" """
Evaluation a concept Evaluation a concept
It means that if the where clause is True, will evaluate the body It means that if the where clause is True, will evaluate the body
:param evaluate_body:
:param context: :param context:
:param concept: :param concept:
:param logger: :param evaluate_body:
:return: value of the evaluation or error :return: value of the evaluation or error
""" """
return self.evaluate_concept_handler.evaluate_concept(context, concept) return self.evaluate_concept_handler.evaluate_concept(context, concept, evaluate_body)
def add_in_cache(self, concept: Concept): def add_in_cache(self, concept: Concept):
""" """
@@ -393,11 +390,13 @@ class Sheerka(Concept):
if result is None: if result is None:
metadata = [("key", concept_key), ("id", concept_id)] if concept_id else ("key", concept_key) metadata = [("key", concept_key), ("id", concept_id)] if concept_id else ("key", concept_key)
result = self._get_unknown(metadata) result = self._get_unknown(metadata)
# Do not put in cache_by_key or cache_by_id unknown concept
self.cache_by_key[concept_key] = result # TODO: implement an MRU cache for them
for r in (result if isinstance(result, list) else [result]): else:
if r.id: self.cache_by_key[concept_key] = result
self.cache_by_id[r.id] = r for r in (result if isinstance(result, list) else [result]):
if r.id:
self.cache_by_id[r.id] = r
if not (isinstance(result, list) and concept_id): if not (isinstance(result, list) and concept_id):
return result return result
@@ -640,7 +639,9 @@ class Sheerka(Concept):
if line == "" or line.startswith("#"): if line == "" or line.startswith("#"):
continue continue
self.log.info(line) self.log.info(line)
self.evaluate_user_input(line) res = self.evaluate_user_input(line)
if len(res) > 1 or not res[0].status:
self.log.error("Error detected !")
self.during_restore = False self.during_restore = False
except IOError: except IOError:
pass pass
+2 -1
View File
@@ -8,6 +8,7 @@ console_handler = logging.StreamHandler(sys.stdout)
all_loggers = {} all_loggers = {}
def init_config(loggers): def init_config(loggers):
if loggers is None: if loggers is None:
return return
@@ -55,7 +56,7 @@ def get_logger(logger_name):
logger.disabled = True logger.disabled = True
for e in enabled: for e in enabled:
if logger_name.startswith("verbose." + e): if logger_name.startswith("verbose." + e) or logger_name == e:
logger.disabled = False logger.disabled = False
return logger return logger
+15 -2
View File
@@ -5,7 +5,7 @@ from evaluators.BaseEvaluator import OneReturnValueEvaluator
class ConceptEvaluator(OneReturnValueEvaluator): class ConceptEvaluator(OneReturnValueEvaluator):
""" """
The concept evaluatuor is the main class that know what to do with a concept The concept evaluator is the main class that know what to do with a concept
It verifies the PRE It verifies the PRE
If ok, can execute or not the BODY If ok, can execute or not the BODY
Then checks the POST conditions Then checks the POST conditions
@@ -15,6 +15,19 @@ class ConceptEvaluator(OneReturnValueEvaluator):
def __init__(self, return_body=False): def __init__(self, return_body=False):
super().__init__(self.NAME, [BuiltinConcepts.EVALUATION], 50) super().__init__(self.NAME, [BuiltinConcepts.EVALUATION], 50)
self.return_body = return_body 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 matches(self, context, return_value): def matches(self, context, return_value):
return return_value.status and \ return return_value.status and \
@@ -36,7 +49,7 @@ class ConceptEvaluator(OneReturnValueEvaluator):
return sheerka.ret(self.name, True, value, parents=[return_value]) return sheerka.ret(self.name, True, value, parents=[return_value])
evaluated = sheerka.evaluate_concept(context, concept) evaluated = sheerka.evaluate_concept(context, concept, self.evaluate_body)
if evaluated.key != concept.key: if evaluated.key != concept.key:
# evaluated.key != concept.key means that we have transformed the concept # evaluated.key != concept.key means that we have transformed the concept
+2 -2
View File
@@ -17,7 +17,7 @@ class EvalEvaluator(AllReturnValuesEvaluator):
def matches(self, context, return_values): def matches(self, context, return_values):
sheerka = context.sheerka sheerka = context.sheerka
for ret in return_values: for ret in return_values:
if ret.status and sheerka.isinstance(ret.body, BuiltinConcepts.CONCEPT_EVAL_REQUESTED): if ret.status and sheerka.isinstance(ret.body, BuiltinConcepts.CONCEPT_VALUE_REQUESTED):
self.eval_requested = ret self.eval_requested = ret
return True return True
@@ -47,5 +47,5 @@ class EvalEvaluator(AllReturnValuesEvaluator):
return sheerka.ret( return sheerka.ret(
self.name, self.name,
False, False,
sheerka.new(BuiltinConcepts.CONCEPT_EVAL_REQUESTED), sheerka.new(BuiltinConcepts.CONCEPT_VALUE_REQUESTED),
parents=[self.eval_requested]) parents=[self.eval_requested])
@@ -49,7 +49,7 @@ class MultipleSameSuccessEvaluator(AllReturnValuesEvaluator):
for s in self.success: for s in self.success:
context.log(f"{s}", who=self) context.log(f"{s}", who=self)
if not core.builtin_helpers.is_same_success(sheerka, self.success): if not core.builtin_helpers.is_same_success(context, self.success):
return None return None
# ###################################### # ######################################
+1 -1
View File
@@ -35,6 +35,6 @@ class PrepareEvalEvaluator(OneReturnValueEvaluator):
evaluation_requested = sheerka.ret( evaluation_requested = sheerka.ret(
self.name, self.name,
True, sheerka.new(BuiltinConcepts.CONCEPT_EVAL_REQUESTED)) True, sheerka.new(BuiltinConcepts.CONCEPT_VALUE_REQUESTED))
return [new_text_to_parse, evaluation_requested] return [new_text_to_parse, evaluation_requested]
+1 -1
View File
@@ -112,7 +112,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
context.log(f"Evaluating '{concept}'", self.name) context.log(f"Evaluating '{concept}'", self.name)
with context.push(self.name, desc=f"Evaluating '{concept}'", obj=concept) as sub_context: with context.push(self.name, desc=f"Evaluating '{concept}'", obj=concept) as sub_context:
evaluated = context.sheerka.evaluate_concept(sub_context, concept) evaluated = context.sheerka.evaluate_concept(sub_context, concept, True)
sub_context.add_values(return_values=evaluated) sub_context.add_values(return_values=evaluated)
if evaluated.key == concept.key: if evaluated.key == concept.key:
+1 -1
View File
@@ -44,7 +44,7 @@ class TooManySuccessEvaluator(AllReturnValuesEvaluator):
context.log(s, self.name) context.log(s, self.name)
context.log(f"value={sheerka.value(s.value)}", self.name) context.log(f"value={sheerka.value(s.value)}", self.name)
if not core.builtin_helpers.is_same_success(sheerka, self.success): if not core.builtin_helpers.is_same_success(context, self.success):
context.log(f"Values are different. Raising {BuiltinConcepts.TOO_MANY_SUCCESS}.", self.name) context.log(f"Values are different. Raising {BuiltinConcepts.TOO_MANY_SUCCESS}.", self.name)
too_many_success = sheerka.new(BuiltinConcepts.TOO_MANY_SUCCESS, body=self.success) too_many_success = sheerka.new(BuiltinConcepts.TOO_MANY_SUCCESS, body=self.success)
return sheerka.ret(self.name, False, too_many_success, parents=self.eaten) return sheerka.ret(self.name, False, too_many_success, parents=self.eaten)
+2
View File
@@ -34,6 +34,7 @@ def test_i_can_push():
concepts={"bar": Concept("bar")}) concepts={"bar": Concept("bar")})
a.preprocess = set() a.preprocess = set()
a.preprocess.add("preprocess") a.preprocess.add("preprocess")
a.extra_info.append(BuiltinConcepts.CONCEPT_EVAL_REQUESTED)
b = a.push() b = a.push()
@@ -49,6 +50,7 @@ def test_i_can_push():
assert b.id == a.id + 1 assert b.id == a.id + 1
assert b._tab == a._tab + " " assert b._tab == a._tab + " "
assert b.preprocess == a.preprocess assert b.preprocess == a.preprocess
assert b.extra_info == [BuiltinConcepts.CONCEPT_EVAL_REQUESTED]
def test_children_i_created_when_i_push(): def test_children_i_created_when_i_push():
+42 -42
View File
@@ -21,8 +21,8 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
def test_i_can_evaluate_a_concept_with_simple_body(self, body, expected): def test_i_can_evaluate_a_concept_with_simple_body(self, body, expected):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept = Concept("foo", body=body) concept = Concept("foo", body=body).init_key()
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == expected assert evaluated.body == expected
@@ -53,7 +53,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept = Concept("foo", pre=expr) concept = Concept("foo", pre=expr).init_key()
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated.key == concept.key
@@ -63,7 +63,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
assert evaluated.metadata.where is None assert evaluated.metadata.where is None
assert evaluated.get_metadata_value(ConceptParts.PRE) == expected assert evaluated.get_metadata_value(ConceptParts.PRE) == expected
assert evaluated.props == {} assert evaluated.props == {}
assert evaluated.metadata.is_evaluated assert not evaluated.metadata.is_evaluated
assert len(evaluated.values) == 0 if expr is None else 1 assert len(evaluated.values) == 0 if expr is None else 1
@pytest.mark.parametrize("expr, expected", [ @pytest.mark.parametrize("expr, expected", [
@@ -80,7 +80,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept = Concept("foo").def_prop("a", expr) concept = Concept("foo").def_prop("a", expr)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.metadata.pre is None assert evaluated.metadata.pre is None
@@ -95,7 +95,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
concept = Concept("foo") concept = Concept("foo")
concept.compiled[ConceptParts.BODY] = DoNotResolve("do not resolve") concept.compiled[ConceptParts.BODY] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.body == "do not resolve" assert evaluated.body == "do not resolve"
assert evaluated.metadata.is_evaluated assert evaluated.metadata.is_evaluated
@@ -105,7 +105,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
concept = Concept("foo").def_prop("a") concept = Concept("foo").def_prop("a")
concept.compiled["a"] = DoNotResolve("do not resolve") concept.compiled["a"] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.get_prop("a") == "do not resolve" assert evaluated.get_prop("a") == "do not resolve"
assert evaluated.metadata.is_evaluated assert evaluated.metadata.is_evaluated
@@ -116,7 +116,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
concept.compiled["a"] = DoNotResolve("do not resolve") concept.compiled["a"] = DoNotResolve("do not resolve")
concept.compiled[ConceptParts.BODY] = DoNotResolve("do not resolve") concept.compiled[ConceptParts.BODY] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.body == "do not resolve" assert evaluated.body == "do not resolve"
assert evaluated.get_prop("a") == "do not resolve" assert evaluated.get_prop("a") == "do not resolve"
@@ -126,7 +126,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept = Concept("foo", body="a+1").def_prop("a", "10").init_key() concept = Concept("foo", body="a+1").def_prop("a", "10").init_key()
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == 11 assert evaluated.body == 11
@@ -137,7 +137,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka.add_in_cache(concept_a) sheerka.add_in_cache(concept_a)
concept = Concept("foo", body="a").init_key() concept = Concept("foo", body="a").init_key()
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated == simplec("foo", simplec("a", None)) assert evaluated == simplec("foo", simplec("a", None))
assert id(evaluated.body) != id(concept_a) assert id(evaluated.body) != id(concept_a)
@@ -150,7 +150,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka.add_in_cache(concept_a) sheerka.add_in_cache(concept_a)
concept = Concept("foo", body="a") concept = Concept("foo", body="a")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == simplec("a", 1) assert evaluated.body == simplec("a", 1)
@@ -164,7 +164,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka.add_in_cache(Concept(name="c", body="b")) sheerka.add_in_cache(Concept(name="c", body="b"))
concept_d = sheerka.add_in_cache(Concept(name="d", body="c")) concept_d = sheerka.add_in_cache(Concept(name="d", body="c"))
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept_d) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept_d, True)
assert evaluated.key == concept_d.key assert evaluated.key == concept_d.key
expected = simplec("c", simplec("b", simplec("a", "a"))) expected = simplec("c", simplec("b", simplec("a", "a")))
@@ -179,7 +179,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka.add_in_cache(Concept(name="c", body="b")) sheerka.add_in_cache(Concept(name="c", body="b"))
concept_d = sheerka.add_in_cache(Concept(name="d", body="c")) concept_d = sheerka.add_in_cache(Concept(name="d", body="c"))
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept_d) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept_d, True)
assert evaluated.key == concept_d.key assert evaluated.key == concept_d.key
expected = simplec("c", simplec("b", simplec("a", None))) 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_a = sheerka.add_in_cache(Concept(name="a").init_key())
concept = Concept("foo", body="a").def_prop("a", "a").init_key() concept = Concept("foo", body="a").def_prop("a", "a").init_key()
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
# first prop a is evaluated to concept_a # first prop a is evaluated to concept_a
# then body is evaluated to prop a -> 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_a = sheerka.add_in_cache(Concept(name="a"))
concept = Concept("foo", body="concept_a").def_prop("concept_a", "a") concept = Concept("foo", body="concept_a").def_prop("concept_a", "a")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == concept_a assert evaluated.body == concept_a
@@ -220,7 +220,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka.add_in_cache(Concept(name="b", body="2")) sheerka.add_in_cache(Concept(name="b", body="2"))
concept = Concept("foo", body="propA + propB").def_prop("propA", "a").def_prop("propB", "b") concept = Concept("foo", body="propA + propB").def_prop("propA", "a").def_prop("propB", "b")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == 3 assert evaluated.body == 3
@@ -231,7 +231,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
concept = Concept("foo").def_prop("a") concept = Concept("foo").def_prop("a")
concept.compiled["a"] = concept_a concept.compiled["a"] = concept_a
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.get_prop("a") == simplec("a", "a") assert evaluated.get_prop("a") == simplec("a", "a")
@@ -242,7 +242,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
concept = Concept("to_eval").def_prop("prop") concept = Concept("to_eval").def_prop("prop")
concept.compiled["prop"] = [foo, DoNotResolve("1")] concept.compiled["prop"] = [foo, DoNotResolve("1")]
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
props = evaluated.get_prop("prop") props = evaluated.get_prop("prop")
assert len(props) == 2 assert len(props) == 2
@@ -257,20 +257,20 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
concept = Concept("to_eval").def_prop("prop") concept = Concept("to_eval").def_prop("prop")
concept.compiled["prop"] = [ReturnValueConcept("who", True, parser_result)] concept.compiled["prop"] = [ReturnValueConcept("who", True, parser_result)]
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.get_prop("prop") == 2 assert evaluated.get_prop("prop") == 2
# also works when only one return value # also works when only one return value
concept = Concept("to_eval").def_prop("prop") concept = Concept("to_eval").def_prop("prop")
concept.compiled["prop"] = ReturnValueConcept("who", True, parser_result) concept.compiled["prop"] = ReturnValueConcept("who", True, parser_result)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.get_prop("prop") == 2 assert evaluated.get_prop("prop") == 2
def test_i_can_reference_sheerka(self): def test_i_can_reference_sheerka(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept = Concept("foo", body="sheerka.test()").init_key() concept = Concept("foo", body="sheerka.test()").init_key()
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == sheerka.test() assert evaluated.body == sheerka.test()
@@ -281,19 +281,19 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka.add_in_cache(Concept(name="b", body="'concept_b'")) sheerka.add_in_cache(Concept(name="b", body="'concept_b'"))
concept = Concept("foo", body="a") concept = Concept("foo", body="a")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == simplec("a", "concept_a") # this test was already done assert evaluated.body == simplec("a", "concept_a") # this test was already done
# so check this one. # so check this one.
concept = Concept("foo", body="a").def_prop("a", "'property_a'") concept = Concept("foo", body="a").def_prop("a", "'property_a'")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == 'property_a' assert evaluated.body == 'property_a'
# or this one. # or this one.
concept = Concept("foo", body="a").def_prop("a", "b") concept = Concept("foo", body="a").def_prop("a", "b")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == simplec(name="b", body="concept_b") 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'")) sheerka.add_in_cache(Concept(name="b", body="'concept_b'"))
concept = Concept("foo", body="a + b").def_prop("a", "'prop_a'").init_key() concept = Concept("foo", body="a + b").def_prop("a", "'prop_a'").init_key()
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == 'prop_aconcept_b' 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'")) 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") concept = Concept("foo", body="a.props['subProp'].value").def_prop("a", "concept_a")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated == simplec(concept.key, "sub_a") assert evaluated == simplec(concept.key, "sub_a")
def test_i_cannot_evaluate_concept_if_property_is_in_error(self): def test_i_cannot_evaluate_concept_if_property_is_in_error(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept = Concept(name="concept_a").def_prop("subProp", "undef_concept") concept = Concept(name="concept_a").def_prop("subProp", "undef_concept")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR) assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
def test_key_is_initialized_by_evaluation(self): def test_key_is_initialized_by_evaluation(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept = Concept("foo") concept = Concept("foo")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.init_key().key 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") concept = Concept("foo", body="10", where=where_clause).def_prop("a", "20")
sheerka.add_in_cache(concept) sheerka.add_in_cache(concept)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
if expected: if expected:
assert evaluated.key == concept.key assert evaluated.key == concept.key
@@ -362,11 +362,11 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka.add_in_cache(foo_true) sheerka.add_in_cache(foo_true)
concept = Concept("foo", where="foo_true").init_key() concept = Concept("foo", where="foo_true").init_key()
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key assert evaluated.key == concept.key
concept = Concept("foo", where="foo_false") concept = Concept("foo", where="foo_false")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert sheerka.isinstance(evaluated, BuiltinConcepts.WHERE_CLAUSE_FAILED) assert sheerka.isinstance(evaluated, BuiltinConcepts.WHERE_CLAUSE_FAILED)
assert evaluated.body == concept assert evaluated.body == concept
@@ -379,11 +379,11 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka.add_in_cache(one_str) sheerka.add_in_cache(one_str)
sheerka.add_in_cache(one_digit) sheerka.add_in_cache(one_digit)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one_digit) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one_digit, True)
assert evaluated.key == one_digit.key assert evaluated.key == one_digit.key
assert evaluated.body == InfiniteRecursionResolved(1) assert evaluated.body == InfiniteRecursionResolved(1)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one_str) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one_str, True)
assert evaluated.key == one_str.key assert evaluated.key == one_str.key
assert evaluated.body == InfiniteRecursionResolved(1) assert evaluated.body == InfiniteRecursionResolved(1)
@@ -396,11 +396,11 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka.add_in_cache(true_str) sheerka.add_in_cache(true_str)
sheerka.add_in_cache(true_bool) sheerka.add_in_cache(true_bool)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), true_str) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), true_str, True)
assert evaluated.key == true_str.key assert evaluated.key == true_str.key
assert evaluated.body == InfiniteRecursionResolved(True) assert evaluated.body == InfiniteRecursionResolved(True)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), true_bool) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), true_bool, True)
assert evaluated.key == true_bool.key assert evaluated.key == true_bool.key
assert evaluated.body == InfiniteRecursionResolved(True) assert evaluated.body == InfiniteRecursionResolved(True)
@@ -413,7 +413,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
c4 = sheerka.add_in_cache(Concept("3", body="one")) c4 = sheerka.add_in_cache(Concept("3", body="one"))
for concept in (c1, c2, c3, c4): for concept in (c1, c2, c3, c4):
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == InfiniteRecursionResolved(3) assert evaluated.body == InfiniteRecursionResolved(3)
@@ -425,19 +425,19 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
baz = sheerka.add_in_cache(Concept("baz", body="qux")) baz = sheerka.add_in_cache(Concept("baz", body="qux"))
qux = sheerka.add_in_cache(Concept("qux", body="foo")) qux = sheerka.add_in_cache(Concept("qux", body="foo"))
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), foo) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), foo, True)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG) assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo, bar, baz, qux} assert evaluated.body == {foo, bar, baz, qux}
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), bar) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), bar, True)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG) assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo, bar, baz, qux} assert evaluated.body == {foo, bar, baz, qux}
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), baz) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), baz, True)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG) assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo, bar, baz, qux} assert evaluated.body == {foo, bar, baz, qux}
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), qux) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), qux, True)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG) assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo, bar, baz, qux} assert evaluated.body == {foo, bar, baz, qux}
@@ -446,7 +446,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
foo = sheerka.add_in_cache(Concept("foo", body="foo")) foo = sheerka.add_in_cache(Concept("foo", body="foo"))
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), foo) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), foo, True)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG) assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo} assert evaluated.body == {foo}
@@ -454,7 +454,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
one = Concept("1", body="1") one = Concept("1", body="1")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one, True)
assert evaluated.key == one.key assert evaluated.key == one.key
assert evaluated.body == 1 assert evaluated.body == 1
+3 -2
View File
@@ -107,7 +107,7 @@ class TestSheerkaSetsManager(TestUsingFileBasedSheerka):
def test_i_can_define_a_group_from_another_group(self): def test_i_can_define_a_group_from_another_group(self):
sheerka, context, foo, bar, group1, group2 = self.init_concepts( sheerka, context, foo, bar, group1, group2 = self.init_concepts(
Concept("foo"), Concept("bar"), Concept("group1"), Concept("group2", body="group1")) "foo", "bar", "group1", Concept("group2", body="group1"))
sheerka.sets_handler.add_concepts_to_set(context, [foo, bar], group1) sheerka.sets_handler.add_concepts_to_set(context, [foo, bar], group1)
@@ -122,7 +122,8 @@ class TestSheerkaSetsManager(TestUsingFileBasedSheerka):
Concept("four", body="4"), Concept("four", body="4"),
Concept("five", body="5"), Concept("five", body="5"),
Concept("number"), Concept("number"),
Concept("sub_number", body="number", where="number < 4") Concept("sub_number", body="number", where="number < 4"),
create_new=True
) )
sheerka.sets_handler.add_concepts_to_set(context, [one, two, three, four, five], number) sheerka.sets_handler.add_concepts_to_set(context, [one, two, three, four, five], number)
@@ -124,6 +124,26 @@ class EvaluatorOnePreEvaluation(OneReturnValueEvaluatorForTestingPurpose):
super().__init__("preEval", [BuiltinConcepts.BEFORE_EVALUATION], 10) super().__init__("preEval", [BuiltinConcepts.BEFORE_EVALUATION], 10)
class EvaluatorOneInitializationOnce(OneReturnValueEvaluatorForTestingPurpose):
def __init__(self):
super().__init__("init_once", [BuiltinConcepts.EVALUATION], 10)
self.is_initialized = False
def init_evaluator(self, context, return_values):
self.out_all("init_evaluator", self.name, context, return_values)
self.is_initialized = True
class EvaluatorOneInitializationMultiple(OneReturnValueEvaluatorForTestingPurpose):
def __init__(self):
super().__init__("init_multiple", [BuiltinConcepts.EVALUATION], 10)
self.is_initialized = False
def init_evaluator(self, context, return_values):
self.out_all("init_evaluator", self.name, context, return_values)
# self.is_initialized = True
class EvaluatorOneMultiSteps(OneReturnValueEvaluatorForTestingPurpose): class EvaluatorOneMultiSteps(OneReturnValueEvaluatorForTestingPurpose):
def __init__(self): def __init__(self):
super().__init__("multiStep", [BuiltinConcepts.EVALUATION, BuiltinConcepts.BEFORE_EVALUATION], 10) super().__init__("multiStep", [BuiltinConcepts.EVALUATION, BuiltinConcepts.BEFORE_EVALUATION], 10)
@@ -373,3 +393,52 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka):
'__EVALUATION [1] modifyFoo - matches - target=bar', '__EVALUATION [1] modifyFoo - matches - target=bar',
'__EVALUATION [1] modifyFoo - matches - target=__EVALUATION' '__EVALUATION [1] modifyFoo - matches - target=__EVALUATION'
] ]
def test_i_can_initialize_evaluator_if_initialize_evaluator_is_defined(self):
sheerka, context, foo, bar, baz = self.init_concepts("foo", "bar", "baz")
sheerka.evaluators = [EvaluatorOneInitializationOnce]
entries = [
self.tretval(sheerka, foo),
self.tretval(sheerka, bar),
self.tretval(sheerka, baz)
]
Out.debug_out = []
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 - 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):
sheerka, context, foo, bar, baz = self.init_concepts("foo", "bar", "baz")
sheerka.evaluators = [EvaluatorOneInitializationMultiple]
entries = [
self.tretval(sheerka, foo),
self.tretval(sheerka, bar),
self.tretval(sheerka, baz)
]
Out.debug_out = []
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 - 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 - 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 - 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'
]
@@ -66,6 +66,31 @@ class TestAddConceptInSetEvaluator(TestUsingMemoryBasedSheerka):
foo_from_sheerka = context.sheerka.get("foo") foo_from_sheerka = context.sheerka.get("foo")
assert foo_from_sheerka.get_prop(BuiltinConcepts.ISA) == [bar] assert foo_from_sheerka.get_prop(BuiltinConcepts.ISA) == [bar]
def test_i_can_add_bnf_concept_to_a_set_of_concept(self):
"""
This test is the reason why I have started the whole eval on demand stuff
Sheerka tries to evaluate the body but it can (as a and b are not defined)
So 'foo' cannot be put is set
:return:
"""
sheerka, context, foo, bar = self.init_concepts(
Concept("foo", definition="a plus b", body="a + b").def_prop("a").def_prop("b"),
"bar",
create_new=True)
ret_val = get_ret_val("foo", "bar")
res = AddConceptInSetEvaluator().eval(context, ret_val)
foo = sheerka.new("foo") # reload it
assert res.status
assert context.sheerka.isinstance(res.value, BuiltinConcepts.SUCCESS)
assert context.sheerka.isaset(context, bar)
assert context.sheerka.isinset(foo, bar)
assert context.sheerka.isa(foo, bar)
foo_from_sheerka = context.sheerka.get("foo")
assert foo_from_sheerka.get_prop(BuiltinConcepts.ISA) == [bar]
def test_i_can_add_concept_with_a_body_to_a_set_of_concept(self): def test_i_can_add_concept_with_a_body_to_a_set_of_concept(self):
context = self.get_context() context = self.get_context()
foo = Concept("foo", body="1") foo = Concept("foo", body="1")
@@ -20,6 +20,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
def test_i_can_evaluate_concept(self): def test_i_can_evaluate_concept(self):
context = self.get_context() context = self.get_context()
context.extra_info.append(BuiltinConcepts.CONCEPT_EVAL_REQUESTED)
concept = Concept(name="foo", concept = Concept(name="foo",
where="True", where="True",
pre="2", pre="2",
@@ -27,6 +28,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
evaluator = ConceptEvaluator() evaluator = ConceptEvaluator()
item = self.pretval(concept) item = self.pretval(concept)
evaluator.init_evaluator(context, [item])
result = evaluator.eval(context, item) result = evaluator.eval(context, item)
assert result.who == evaluator.name assert result.who == evaluator.name
@@ -42,6 +44,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
def test_body_is_returned_when_defined_and_requested(self): def test_body_is_returned_when_defined_and_requested(self):
context = self.get_context() context = self.get_context()
context.extra_info.append(BuiltinConcepts.CONCEPT_EVAL_REQUESTED)
concept = Concept(name="foo", concept = Concept(name="foo",
body="'I have a value'", body="'I have a value'",
where="True", where="True",
@@ -50,6 +53,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
evaluator = ConceptEvaluator(return_body=True) evaluator = ConceptEvaluator(return_body=True)
item = self.pretval(concept) item = self.pretval(concept)
evaluator.init_evaluator(context, [item])
result = evaluator.eval(context, item) result = evaluator.eval(context, item)
assert result.who == evaluator.name assert result.who == evaluator.name
@@ -67,6 +71,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
evaluator = ConceptEvaluator(return_body=False) # which is the default behaviour evaluator = ConceptEvaluator(return_body=False) # which is the default behaviour
item = self.pretval(concept) item = self.pretval(concept)
evaluator.init_evaluator(context, [item])
result = evaluator.eval(context, item) result = evaluator.eval(context, item)
assert result.who == evaluator.name assert result.who == evaluator.name
@@ -90,6 +95,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
def test_i_cannot_recognize_a_concept_if_one_of_the_prop_is_unknown(self): def test_i_cannot_recognize_a_concept_if_one_of_the_prop_is_unknown(self):
context = self.get_context() context = self.get_context()
context.extra_info.append(BuiltinConcepts.CONCEPT_EVAL_REQUESTED)
context.sheerka.add_in_cache(Concept(name="one").init_key()) context.sheerka.add_in_cache(Concept(name="one").init_key())
concept_plus = context.sheerka.add_in_cache(Concept(name="a plus b") concept_plus = context.sheerka.add_in_cache(Concept(name="a plus b")
.def_prop("a", "one") .def_prop("a", "one")
@@ -97,6 +103,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
evaluator = ConceptEvaluator() evaluator = ConceptEvaluator()
item = self.pretval(concept_plus) item = self.pretval(concept_plus)
evaluator.init_evaluator(context, [item])
result = evaluator.eval(context, item) result = evaluator.eval(context, item)
assert not result.status assert not result.status
+12 -12
View File
@@ -5,7 +5,7 @@ from core.concept import Concept
from evaluators.EvalEvaluator import EvalEvaluator from evaluators.EvalEvaluator import EvalEvaluator
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
eval_requested = ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.CONCEPT_EVAL_REQUESTED)) value_requested = ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.CONCEPT_VALUE_REQUESTED))
def retval(obj, who="who", status=True): def retval(obj, who="who", status=True):
@@ -26,7 +26,7 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
ReturnValueConcept("some_name", False, Concept(name="1", body="'not to eval'")), ReturnValueConcept("some_name", False, Concept(name="1", body="'not to eval'")),
to_eval1, to_eval1,
to_eval2, to_eval2,
eval_requested value_requested
] ]
evaluator = EvalEvaluator() evaluator = EvalEvaluator()
@@ -35,16 +35,16 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
evaluated = evaluator.eval(context, return_values) evaluated = evaluator.eval(context, return_values)
assert len(evaluated) == 2 assert len(evaluated) == 2
assert evaluated[0].value == to_eval1.body.body assert evaluated[0].value == to_eval1.body.body
assert evaluated[0].parents == [to_eval1, eval_requested] assert evaluated[0].parents == [to_eval1, value_requested]
assert evaluated[1].value == to_eval2.body.body assert evaluated[1].value == to_eval2.body.body
assert evaluated[1].parents == [to_eval2, eval_requested] assert evaluated[1].parents == [to_eval2, value_requested]
@pytest.mark.parametrize("return_values, expected", [ @pytest.mark.parametrize("return_values, expected", [
([retval(Concept("foo", body="bar")), eval_requested], True), ([retval(Concept("foo", body="bar")), value_requested], True),
([retval(Concept("status is false", body="bar"), status=False), eval_requested], True), ([retval(Concept("status is false", body="bar"), status=False), value_requested], True),
([retval("string_value"), eval_requested], True), ([retval("string_value"), value_requested], True),
([retval(Concept("no body")), eval_requested], True), ([retval(Concept("no body")), value_requested], True),
([retval(Concept("eval requested missing", body="bar"))], False), ([retval(Concept("eval requested missing", body="bar"))], False),
]) ])
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_values, expected):
@@ -58,7 +58,7 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
ReturnValueConcept("some_name", True, "not to eval"), ReturnValueConcept("some_name", True, "not to eval"),
ReturnValueConcept("some_name", True, Concept(name="not to eval")), ReturnValueConcept("some_name", True, Concept(name="not to eval")),
ReturnValueConcept("some_name", False, Concept(name="1", body="not to eval")), ReturnValueConcept("some_name", False, Concept(name="1", body="not to eval")),
eval_requested value_requested
] ]
evaluator = EvalEvaluator() evaluator = EvalEvaluator()
@@ -68,8 +68,8 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
assert evaluated == ReturnValueConcept( assert evaluated == ReturnValueConcept(
"evaluators.Eval", "evaluators.Eval",
False, False,
context.sheerka.new(BuiltinConcepts.CONCEPT_EVAL_REQUESTED)) context.sheerka.new(BuiltinConcepts.CONCEPT_VALUE_REQUESTED))
assert evaluated.parents == [eval_requested] assert evaluated.parents == [value_requested]
def test_i_can_evaluate_sets(self): def test_i_can_evaluate_sets(self):
sheerka, context, foo, bar, baz, number = self.init_concepts( sheerka, context, foo, bar, baz, number = self.init_concepts(
@@ -79,7 +79,7 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
Concept("number")) Concept("number"))
sheerka.sets_handler.add_concepts_to_set(context, [foo, bar, baz], number) sheerka.sets_handler.add_concepts_to_set(context, [foo, bar, baz], number)
return_values = [retval(number), eval_requested] return_values = [retval(number), value_requested]
evaluator = EvalEvaluator() evaluator = EvalEvaluator()
evaluator.matches(context, return_values) evaluator.matches(context, return_values)
@@ -46,4 +46,4 @@ class TestPrepareEvalEvaluator(TestUsingMemoryBasedSheerka):
assert res[0].body.body == expected assert res[0].body.body == expected
assert res[1].status assert res[1].status
assert sheerka.isinstance(res[1].body, BuiltinConcepts.CONCEPT_EVAL_REQUESTED) assert sheerka.isinstance(res[1].body, BuiltinConcepts.CONCEPT_VALUE_REQUESTED)
+140 -61
View File
@@ -15,7 +15,7 @@ class TestSheerkaNonReg(TestUsingFileBasedSheerka):
("1 + 1", 2), ("1 + 1", 2),
("sheerka.test()", 'I have access to Sheerka !') ("sheerka.test()", 'I have access to Sheerka !')
]) ])
def test_i_can_eval_python_expressions_with_no_variable(self, text, expected): def test_i_can_evaluate_python_expressions_with_no_variable(self, text, expected):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
res = sheerka.evaluate_user_input(text) res = sheerka.evaluate_user_input(text)
@@ -24,7 +24,7 @@ class TestSheerkaNonReg(TestUsingFileBasedSheerka):
assert res[0].status assert res[0].status
assert res[0].value == expected assert res[0].value == expected
def test_i_can_eval_concept_with_python_body(self): def test_i_can_recognize_concept_with_python_body(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept = Concept(name="one", body="1") concept = Concept(name="one", body="1")
sheerka.add_in_cache(concept) sheerka.add_in_cache(concept)
@@ -33,9 +33,13 @@ class TestSheerkaNonReg(TestUsingFileBasedSheerka):
res = sheerka.evaluate_user_input(text) res = sheerka.evaluate_user_input(text)
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].value == simplec("one", 1) # by default, the concept is returned assert res[0].value == concept
def test_i_can_eval_concept_with_concept_body(self): # sanity check
evaluated = sheerka.evaluate_concept(self.get_context(), res[0].value, True)
assert evaluated == simplec("one", 1)
def test_i_can_recognize_concept_with_concept_body(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept_one = Concept(name="one") concept_one = Concept(name="one")
concept_un = Concept(name="un", body="one") concept_un = Concept(name="un", body="one")
@@ -46,9 +50,13 @@ class TestSheerkaNonReg(TestUsingFileBasedSheerka):
return_value = res[0].value return_value = res[0].value
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert return_value == simplec("un", simplec("one", None)) assert return_value == concept_un
def test_i_can_eval_concept_with_no_body(self): # sanity check
evaluated = sheerka.evaluate_concept(self.get_context(), return_value, True)
assert evaluated == simplec("un", simplec("one", None))
def test_i_can_recognize_concept_with_no_body(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept = Concept(name="one") concept = Concept(name="one")
sheerka.add_in_cache(concept) sheerka.add_in_cache(concept)
@@ -72,7 +80,7 @@ class TestSheerkaNonReg(TestUsingFileBasedSheerka):
assert res[0].value == concept assert res[0].value == concept
assert id(res[0].value) == id(concept) assert id(res[0].value) == id(concept)
def test_i_can_eval_def_concept_request(self): def test_i_can_evaluate_def_concept_request(self):
text = """ text = """
def concept a + b def concept a + b
where isinstance(a, int) and isinstance(b, int) where isinstance(a, int) and isinstance(b, int)
@@ -107,7 +115,7 @@ as:
assert sheerka.sdp.io.exists( assert sheerka.sdp.io.exists(
sheerka.sdp.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, concept_saved.get_origin())) sheerka.sdp.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, concept_saved.get_origin()))
def test_i_can_eval_def_concept_part_when_one_part_is_a_ref_of_another_concept(self): def test_i_can_evaluate_def_concept_part_when_one_part_is_a_ref_of_another_concept(self):
""" """
In this test, we test that the properties of 'concept a xx b' (which are 'a' and 'b') In this test, we test that the properties of 'concept a xx b' (which are 'a' and 'b')
are correctly detected, thanks to the source code 'a plus b' in its body are correctly detected, thanks to the source code 'a plus b' in its body
@@ -137,7 +145,7 @@ as:
assert sheerka.sdp.io.exists( assert sheerka.sdp.io.exists(
sheerka.sdp.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, concept_saved.get_origin())) sheerka.sdp.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, concept_saved.get_origin()))
def test_i_cannot_eval_the_same_def_concept_twice(self): def test_i_cannot_evaluate_the_same_def_concept_twice(self):
text = """ text = """
def concept a + b def concept a + b
where isinstance(a, int) and isinstance(b, int) where isinstance(a, int) and isinstance(b, int)
@@ -162,7 +170,7 @@ as:
" ", " ",
"\n", "\n",
]) ])
def test_i_can_eval_a_empty_input(self, text): def test_i_can_recognize_a_empty_input(self, text):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
res = sheerka.evaluate_user_input(text) res = sheerka.evaluate_user_input(text)
@@ -171,7 +179,7 @@ as:
assert res[0].status assert res[0].status
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NOP) assert sheerka.isinstance(res[0].value, BuiltinConcepts.NOP)
def test_i_can_eval_concept_with_variable(self): def test_i_can_recognize_concept_with_variable(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept_hello = Concept(name="hello a").def_prop("a") concept_hello = Concept(name="hello a").def_prop("a")
concept_foo = Concept(name="foo") concept_foo = Concept(name="foo")
@@ -183,9 +191,13 @@ as:
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert sheerka.isinstance(return_value, concept_hello) assert sheerka.isinstance(return_value, concept_hello)
assert return_value.props["a"].value == concept_foo assert return_value.metadata.props[0] == ('a', "foo")
def test_i_can_eval_concept_with_variable_and_python_as_body(self): # sanity check
evaluated = sheerka.evaluate_concept(self.get_context(), return_value, True)
assert evaluated.props["a"].value == concept_foo
def test_i_can_recognize_concept_with_variable_and_python_as_body(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
hello_a = sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").def_prop("a")) hello_a = sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").def_prop("a"))
sheerka.add_in_cache(Concept(name="foo", body="'foo'")) sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
@@ -194,12 +206,15 @@ as:
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert sheerka.isinstance(res[0].value, hello_a) assert sheerka.isinstance(res[0].value, hello_a)
assert res[0].value.body == "hello foo"
assert res[0].value.metadata.is_evaluated
assert res[0].value.props["a"].value == simplec("foo", "foo")
assert res[0].value.props["a"].value.metadata.is_evaluated
def test_i_can_eval_duplicate_concepts_with_same_value(self): # sanity check
evaluated = sheerka.evaluate_concept(self.get_context(), res[0].value, True)
assert evaluated.body == "hello foo"
assert evaluated.metadata.is_evaluated
assert evaluated.props["a"].value == simplec("foo", "foo")
assert evaluated.props["a"].value.metadata.is_evaluated
def test_i_can_recognize_duplicate_concepts_with_same_value(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").def_prop("a")) sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").def_prop("a"))
@@ -248,11 +263,11 @@ as:
context = self.get_context(sheerka) context = self.get_context(sheerka)
sheerka.create_new_concept(context, Concept(name="concepts", body="sheerka.concepts()")) sheerka.create_new_concept(context, Concept(name="concepts", body="sheerka.concepts()"))
res = sheerka.evaluate_user_input("concepts") res = sheerka.evaluate_user_input("eval concepts")
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert isinstance(res[0].value.body, list) assert isinstance(res[0].value, list)
def test_i_can_create_concept_with_bnf_definition(self): def test_i_can_create_concept_with_bnf_definition(self):
sheerka = self.get_sheerka(use_dict=False, skip_builtins_in_db=False) sheerka = self.get_sheerka(use_dict=False, skip_builtins_in_db=False)
@@ -284,7 +299,7 @@ as:
assert "a" in new_concept.props assert "a" in new_concept.props
assert "plus" in new_concept.props assert "plus" in new_concept.props
def test_i_can_eval_bnf_definitions(self): def test_i_can_recognize_bnf_definitions(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' | 'two'")[0].body.body concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' | 'two'")[0].body.body
@@ -294,7 +309,7 @@ as:
assert res[0].status assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a) assert sheerka.isinstance(res[0].value, concept_a)
def test_i_can_eval_bnf_definitions_with_variables(self): def test_i_can_recognize_bnf_definitions_with_variables(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' | 'two'")[0].body.body concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' | 'two'")[0].body.body
concept_b = sheerka.evaluate_user_input("def concept b from bnf a 'three'")[0].body.body concept_b = sheerka.evaluate_user_input("def concept b from bnf a 'three'")[0].body.body
@@ -306,13 +321,15 @@ as:
return_value = res[0].value return_value = res[0].value
assert sheerka.isinstance(return_value, concept_b) assert sheerka.isinstance(return_value, concept_b)
assert return_value.body == "one three"
assert return_value.metadata.is_evaluated
assert return_value.props["a"] == Property("a", sheerka.new(concept_a.key, body="one").init_key()) # sanity check
assert return_value.props["a"].value.metadata.is_evaluated evaluated = sheerka.evaluate_concept(self.get_context(), return_value, True)
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())
assert evaluated.props["a"].value.metadata.is_evaluated
def test_i_can_eval_bnf_definitions_from_separate_instances(self): def test_i_can_recognize_bnf_definitions_from_separate_instances(self):
""" """
Same test then before, Same test then before,
but make sure that the BNF are correctly persisted and loaded but make sure that the BNF are correctly persisted and loaded
@@ -337,8 +354,10 @@ as:
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert sheerka.isinstance(res[0].value, concept_b) assert sheerka.isinstance(res[0].value, concept_b)
assert res[0].value.body == "one two three"
assert res[0].value.props["a"] == Property("a", sheerka.new(concept_a.key, body="one two").init_key()) evaluated = sheerka.evaluate_concept(self.get_context(), res[0].value, True)
assert evaluated.body == "one two three"
assert evaluated.props["a"] == Property("a", sheerka.new(concept_a.key, body="one two").init_key())
@pytest.mark.parametrize("desc, definitions", [ @pytest.mark.parametrize("desc, definitions", [
("Simple form", [ ("Simple form", [
@@ -387,7 +406,7 @@ as:
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert sheerka.isinstance(res[0].body, "twenties") assert sheerka.isinstance(res[0].body, "twenties")
assert res[0].body.body == 21 assert sheerka.evaluate_concept(self.get_context(), res[0].body, True).body == 21
res = sheerka.evaluate_user_input("twenty one + 1") res = sheerka.evaluate_user_input("twenty one + 1")
assert len(res) == 1 assert len(res) == 1
@@ -430,7 +449,8 @@ as:
res = sheerka.evaluate_user_input("twenty one") res = sheerka.evaluate_user_input("twenty one")
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].body == simplec("twenties", 21) assert sheerka.isinstance(res[0].body, "twenties")
assert sheerka.evaluate_concept(self.get_context(), res[0].value, True).body == 21
res = sheerka.evaluate_user_input("twenty one + 1") res = sheerka.evaluate_user_input("twenty one + 1")
assert len(res) == 1 assert len(res) == 1
@@ -472,10 +492,10 @@ as:
for exp in init: for exp in init:
sheerka.evaluate_user_input(exp) sheerka.evaluate_user_input(exp)
res = sheerka.evaluate_user_input("twenty one") res = sheerka.evaluate_user_input("eval twenty one")
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].body == simplec("twenties", 21) assert res[0].body == 21
def test_i_can_mix_concept_of_concept(self): def test_i_can_mix_concept_of_concept(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
@@ -490,55 +510,55 @@ as:
for definition in definitions: for definition in definitions:
sheerka.evaluate_user_input(definition) sheerka.evaluate_user_input(definition)
res = sheerka.evaluate_user_input("1 plus 2") res = sheerka.evaluate_user_input("eval 1 plus 2")
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].body.body == 3 assert res[0].body == 3
res = sheerka.evaluate_user_input("1 plus one") res = sheerka.evaluate_user_input("eval 1 plus one")
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].body.body == 2 assert res[0].body == 2
res = sheerka.evaluate_user_input("1 + 1 plus 1") res = sheerka.evaluate_user_input("eval 1 + 1 plus 1")
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].body.body == 3 assert res[0].body == 3
res = sheerka.evaluate_user_input("1 plus twenty one") res = sheerka.evaluate_user_input("eval 1 plus twenty one")
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].body.body == 22 assert res[0].body == 22
res = sheerka.evaluate_user_input("one plus 1") res = sheerka.evaluate_user_input("eval one plus 1")
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].body.body == 2 assert res[0].body == 2
res = sheerka.evaluate_user_input("one plus two") res = sheerka.evaluate_user_input("eval one plus two")
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].body.body == 3 assert res[0].body == 3
res = sheerka.evaluate_user_input("one plus twenty one") res = sheerka.evaluate_user_input("eval one plus twenty one")
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].body.body == 22 assert res[0].body == 22
res = sheerka.evaluate_user_input("twenty one plus 1") res = sheerka.evaluate_user_input("eval twenty one plus 1")
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].body.body == 22 assert res[0].body == 22
res = sheerka.evaluate_user_input("twenty one plus one") res = sheerka.evaluate_user_input("eval twenty one plus one")
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].body.body == 22 assert res[0].body == 22
res = sheerka.evaluate_user_input("twenty one plus twenty two") res = sheerka.evaluate_user_input("eval twenty one plus twenty two")
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].body.body == 43 assert res[0].body == 43
@pytest.mark.xfail @pytest.mark.xfail
def test_i_can_evaluate_concept_of_concept_when_multiple_choices(self): def test_i_can_evaluate_concept_of_concept_when_multiple_choices(self):
@@ -663,23 +683,29 @@ as:
for exp in init: for exp in init:
sheerka.evaluate_user_input(exp) sheerka.evaluate_user_input(exp)
res = sheerka.evaluate_user_input("twenty one")
assert len(res) == 1 and res[0].status and sheerka.isinstance(res[0].body, "twenties")
res = sheerka.evaluate_user_input("eval twenty one") res = sheerka.evaluate_user_input("eval twenty one")
assert len(res) == 1 and res[0].status and res[0].body == 21 assert len(res) == 1 and res[0].status and res[0].body == 21
res = sheerka.evaluate_user_input("twenty two")
assert len(res) == 1 and res[0].status and sheerka.isinstance(res[0].body, "twenties")
res = sheerka.evaluate_user_input("eval twenty two") res = sheerka.evaluate_user_input("eval twenty two")
assert len(res) == 1 and res[0].status and res[0].body == 22 assert len(res) == 1 and res[0].status and res[0].body == 22
res = sheerka.evaluate_user_input("eval twenty three") res = sheerka.evaluate_user_input("eval twenty three")
assert len(res) > 1 assert len(res) > 1
def test_i_can_detect_when_only_one_evaluator_is_in_error(self): # def test_i_can_detect_when_only_one_evaluator_is_in_error(self):
sheerka = self.get_sheerka() # sheerka = self.get_sheerka()
#
sheerka.evaluate_user_input("def concept 1 as one") # sheerka.evaluate_user_input("def concept 1 as one")
res = sheerka.evaluate_user_input("1") # res = sheerka.evaluate_user_input("eval 1")
assert len(res) == 1 # assert len(res) == 1
assert not res[0].status # assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONCEPT_EVAL_ERROR) # assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONCEPT_EVAL_ERROR)
def test_i_can_manage_some_type_of_infinite_recursion(self): def test_i_can_manage_some_type_of_infinite_recursion(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
@@ -696,3 +722,56 @@ as:
assert res[0].status assert res[0].status
assert res[0].body == 2 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'")
sheerka.evaluate_user_input("def concept b as 'hello world'")
sheerka.evaluate_user_input("def concept foobar from bnf 'foo' a where a=='bar' as b")
res = sheerka.evaluate_user_input("foo bar")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, "foobar")
assert res[0].body.body is None
res = sheerka.evaluate_user_input("eval foo bar")
assert len(res) == 1
assert res[0].status
assert res[0].body.body == "hello world"
res = sheerka.evaluate_user_input("foo baz")
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 foo baz")
assert len(res) > 1
# 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
def test_i_can_say_than_bnf_concept_isa_another_concept(self):
sheerka = self.get_sheerka()
sheerka.evaluate_user_input("def concept number")
sheerka.evaluate_user_input("def concept one as 1")
sheerka.evaluate_user_input("def concept two as 2")
sheerka.evaluate_user_input("def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit")
res = sheerka.evaluate_user_input("twenties isa number")
assert len(res) == 1
assert res[0].status
twenties = sheerka.get("twenties")
number = sheerka.get("number")
assert sheerka.isa(twenties, number)
@@ -93,7 +93,7 @@ class TestConceptsWithConceptsParser(TestUsingMemoryBasedSheerka):
assert return_value.compiled["b"] == bar assert return_value.compiled["b"] == bar
# sanity check, I can evaluate the result # sanity check, I can evaluate the result
evaluated = context.sheerka.evaluate_concept(context, return_value) evaluated = context.sheerka.evaluate_concept(context, return_value, True)
assert evaluated.key == return_value.key assert evaluated.key == return_value.key
assert evaluated.get_prop("a") == foo.init_key() assert evaluated.get_prop("a") == foo.init_key()
assert evaluated.get_prop("b") == bar.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)] assert return_value.compiled["b"] == [ReturnValueConcept(parser.name, True, right_parser_result)]
# sanity check, I can evaluate the result # sanity check, I can evaluate the result
evaluated = context.sheerka.evaluate_concept(context, return_value) evaluated = context.sheerka.evaluate_concept(context, return_value, True)
assert evaluated.key == return_value.key assert evaluated.key == return_value.key
assert evaluated.get_prop("a") == 2 assert evaluated.get_prop("a") == 2
assert evaluated.get_prop("b") == 4 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)] assert return_value.compiled["b"] == [ReturnValueConcept(parser.name, True, code_parser_result)]
# sanity check, I can evaluate the result # sanity check, I can evaluate the result
evaluated = context.sheerka.evaluate_concept(context, return_value) evaluated = context.sheerka.evaluate_concept(context, return_value, True)
assert evaluated.key == return_value.key assert evaluated.key == return_value.key
assert evaluated.get_prop("a") == foo.init_key() assert evaluated.get_prop("a") == foo.init_key()
assert evaluated.get_prop("b") == 2 assert evaluated.get_prop("b") == 2