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
twenty isa number
def concept twenties from bnf twenty number where number < 10 as twenty + number
twenties isa number
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 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
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"
+39 -5
View File
@@ -5,12 +5,13 @@ import core.ast.nodes
from core.ast.nodes import CallNodeConcept, GenericNodeConcept
from core.ast.visitors import UnreferencedNamesVisitor
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
:param sheerka:
:param context:
:param return_values:
:return:
"""
@@ -19,13 +20,27 @@ def is_same_success(sheerka, return_values):
if not return_values[0].status:
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:]:
if not return_value.status:
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:
return False
@@ -67,7 +82,7 @@ def expect_one(context, return_values):
# too many winners, which one to choose ?
if number_of_successful > 1:
if is_same_success(sheerka, successful_results):
if is_same_success(context, successful_results):
return sheerka.ret(
context.who,
True,
@@ -218,3 +233,22 @@ def _extract_predicates(sheerka, node, variables_to_include, variables_to_exclud
predicates.append(res)
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.preprocess = None
self.logger = logger
self.extra_info = []
self.inputs = {} # what was the parameters of the execution context
self.values = {} # what was produced by the execution context
@@ -210,11 +211,11 @@ class ExecutionContext:
self.sheerka,
desc,
logger,
**_kwargs,
)
**_kwargs)
new._parent = self
new._tab = self._tab + " " * DEBUG_TAB_SIZE
new.preprocess = self.preprocess
new.extra_info.extend(self.extra_info)
self.children.append(new)
return new
@@ -1,6 +1,6 @@
from core.builtin_concepts import BuiltinConcepts
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 = [
BuiltinConcepts.BEFORE_EVALUATION,
@@ -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):
def resolve(self, context, to_resolve, current_prop, current_concept, evaluate_body):
if isinstance(to_resolve, DoNotResolve):
return to_resolve.value
@@ -137,7 +137,7 @@ class SheerkaEvaluateConcept:
# 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)
evaluated = self.evaluate_concept(sub_context, to_resolve, evaluate_body)
sub_context.add_values(return_values=evaluated)
if evaluated.key == to_resolve.key:
return evaluated
@@ -147,8 +147,11 @@ 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 = core.builtin_helpers.expect_one(context, r)
one_r = expect_one(context, r)
sub_context.add_values(return_values=one_r)
if one_r.status:
return one_r.value
@@ -161,7 +164,7 @@ class SheerkaEvaluateConcept:
concept=current_concept,
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"""
# 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)
@@ -170,7 +173,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)
return self.resolve(context, list_to_resolve, current_prop, current_concept, evaluate_body)
res = []
for to_resolve in list_to_resolve:
@@ -181,35 +184,31 @@ class SheerkaEvaluateConcept:
concept=current_concept,
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):
return r
res.append(r)
return res
def evaluate_concept(self, context, concept: Concept):
def evaluate_concept(self, context, concept: Concept, evaluate_body=False):
"""
Evaluation a concept
It means that if the where clause is True, will evaluate the body
:param context:
:param concept:
:param logger:
:param evaluate_body: If false, only evaluate body when necessary
:return: value of the evaluation or error
"""
if concept.metadata.is_evaluated:
return concept
#
# TODO : Validate the PRE condition
#
self.initialize_concept_asts(context, concept)
# 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 = ["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:
if metadata_to_eval == "props":
@@ -218,10 +217,10 @@ class SheerkaEvaluateConcept:
if isinstance(prop_ast, list):
# 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:
# 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):
resolved.set_prop("concept", concept) # since current concept was not sent
return resolved
@@ -237,12 +236,16 @@ 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)
resolved = self.resolve(context, metadata_ast, part_key, concept, evaluate_body)
if isinstance(resolved, Concept) and not context.sheerka.is_success(resolved):
return resolved
else:
concept.values[part_key] = self.get_infinite_recursion_resolution(resolved) or resolved
#
# TODO : Validate the PRE condition
#
# validate where clause
if ConceptParts.WHERE in concept.values:
where_value = concept.values[ConceptParts.WHERE]
@@ -254,5 +257,52 @@ class SheerkaEvaluateConcept:
#
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
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 = []
for item in original_items:
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)
if result is None:
debug_result.append({"input": item, "return_value": None})
@@ -108,7 +108,7 @@ 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)
evaluated = self.sheerka.evaluate_concept(sub_context, sub_concept, True)
if evaluated.key != concept.key:
return False
return _get_set_elements(context, concept, sub_concept.body)
@@ -167,7 +167,7 @@ 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)
evaluated = self.sheerka.evaluate_concept(sub_context, concept, True)
if evaluated.key != concept.key:
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:
for element_id in ids:
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)
return result
+14 -13
View File
@@ -269,7 +269,6 @@ class Sheerka(Concept):
:param execution_context:
:param return_values:
:param execution_steps:
:param logger: logger to use (if not directly called by sheerka)
:return:
"""
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
:param context:
:param concept: DefConceptNode
:param logger
:return: digest of the new concept
"""
@@ -309,7 +307,6 @@ class Sheerka(Concept):
:param context:
:param concept:
:param concept_set:
:param logger:
:return:
"""
return self.sets_handler.add_concept_to_set(context, concept, concept_set)
@@ -320,7 +317,6 @@ class Sheerka(Concept):
:param context:
:param concept:
:param concept_set:
:param logger:
:return:
"""
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)
def evaluate_concept(self, context, concept: Concept):
def evaluate_concept(self, context, concept: Concept, evaluate_body=False):
"""
Evaluation a concept
It means that if the where clause is True, will evaluate the body
:param evaluate_body:
:param context:
:param concept:
:param logger:
:param evaluate_body:
: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):
"""
@@ -393,11 +390,13 @@ class Sheerka(Concept):
if result is None:
metadata = [("key", concept_key), ("id", concept_id)] if concept_id else ("key", concept_key)
result = self._get_unknown(metadata)
self.cache_by_key[concept_key] = result
for r in (result if isinstance(result, list) else [result]):
if r.id:
self.cache_by_id[r.id] = r
# Do not put in cache_by_key or cache_by_id unknown concept
# TODO: implement an MRU cache for them
else:
self.cache_by_key[concept_key] = result
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):
return result
@@ -640,7 +639,9 @@ class Sheerka(Concept):
if line == "" or line.startswith("#"):
continue
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
except IOError:
pass
+2 -1
View File
@@ -8,6 +8,7 @@ console_handler = logging.StreamHandler(sys.stdout)
all_loggers = {}
def init_config(loggers):
if loggers is None:
return
@@ -55,7 +56,7 @@ def get_logger(logger_name):
logger.disabled = True
for e in enabled:
if logger_name.startswith("verbose." + e):
if logger_name.startswith("verbose." + e) or logger_name == e:
logger.disabled = False
return logger
+15 -2
View File
@@ -5,7 +5,7 @@ from evaluators.BaseEvaluator import 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
If ok, can execute or not the BODY
Then checks the POST conditions
@@ -15,6 +15,19 @@ 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 matches(self, context, return_value):
return return_value.status and \
@@ -36,7 +49,7 @@ class ConceptEvaluator(OneReturnValueEvaluator):
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:
# 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):
sheerka = context.sheerka
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
return True
@@ -47,5 +47,5 @@ class EvalEvaluator(AllReturnValuesEvaluator):
return sheerka.ret(
self.name,
False,
sheerka.new(BuiltinConcepts.CONCEPT_EVAL_REQUESTED),
sheerka.new(BuiltinConcepts.CONCEPT_VALUE_REQUESTED),
parents=[self.eval_requested])
@@ -49,7 +49,7 @@ class MultipleSameSuccessEvaluator(AllReturnValuesEvaluator):
for s in self.success:
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
# ######################################
+1 -1
View File
@@ -35,6 +35,6 @@ class PrepareEvalEvaluator(OneReturnValueEvaluator):
evaluation_requested = sheerka.ret(
self.name,
True, sheerka.new(BuiltinConcepts.CONCEPT_EVAL_REQUESTED))
True, sheerka.new(BuiltinConcepts.CONCEPT_VALUE_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)
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)
if evaluated.key == concept.key:
+1 -1
View File
@@ -44,7 +44,7 @@ class TooManySuccessEvaluator(AllReturnValuesEvaluator):
context.log(s, 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)
too_many_success = sheerka.new(BuiltinConcepts.TOO_MANY_SUCCESS, body=self.success)
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")})
a.preprocess = set()
a.preprocess.add("preprocess")
a.extra_info.append(BuiltinConcepts.CONCEPT_EVAL_REQUESTED)
b = a.push()
@@ -49,6 +50,7 @@ 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]
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):
sheerka = self.get_sheerka()
concept = Concept("foo", body=body)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept)
concept = Concept("foo", body=body).init_key()
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key
assert evaluated.body == expected
@@ -53,7 +53,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
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)
assert evaluated.key == concept.key
@@ -63,7 +63,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
assert evaluated.metadata.where is None
assert evaluated.get_metadata_value(ConceptParts.PRE) == expected
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
@pytest.mark.parametrize("expr, 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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept_d, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept_d, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
# 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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
if expected:
assert evaluated.key == concept.key
@@ -362,11 +362,11 @@ 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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key
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 evaluated.body == concept
@@ -379,11 +379,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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one_digit, True)
assert evaluated.key == one_digit.key
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.body == InfiniteRecursionResolved(1)
@@ -396,11 +396,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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), true_str, True)
assert evaluated.key == true_str.key
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.body == InfiniteRecursionResolved(True)
@@ -413,7 +413,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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept, True)
assert evaluated.key == concept.key
assert evaluated.body == InfiniteRecursionResolved(3)
@@ -425,19 +425,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)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), foo, True)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
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 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 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 evaluated.body == {foo, bar, baz, qux}
@@ -446,7 +446,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
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 evaluated.body == {foo}
@@ -454,7 +454,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka = self.get_sheerka()
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.body == 1
+3 -2
View File
@@ -107,7 +107,7 @@ class TestSheerkaSetsManager(TestUsingFileBasedSheerka):
def test_i_can_define_a_group_from_another_group(self):
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)
@@ -122,7 +122,8 @@ class TestSheerkaSetsManager(TestUsingFileBasedSheerka):
Concept("four", body="4"),
Concept("five", body="5"),
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)
@@ -124,6 +124,26 @@ class EvaluatorOnePreEvaluation(OneReturnValueEvaluatorForTestingPurpose):
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):
def __init__(self):
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=__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")
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):
context = self.get_context()
foo = Concept("foo", body="1")
@@ -20,6 +20,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
def test_i_can_evaluate_concept(self):
context = self.get_context()
context.extra_info.append(BuiltinConcepts.CONCEPT_EVAL_REQUESTED)
concept = Concept(name="foo",
where="True",
pre="2",
@@ -27,6 +28,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
evaluator = ConceptEvaluator()
item = self.pretval(concept)
evaluator.init_evaluator(context, [item])
result = evaluator.eval(context, item)
assert result.who == evaluator.name
@@ -42,6 +44,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)
concept = Concept(name="foo",
body="'I have a value'",
where="True",
@@ -50,6 +53,7 @@ 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
@@ -67,6 +71,7 @@ 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
@@ -90,6 +95,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.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")
@@ -97,6 +103,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
evaluator = ConceptEvaluator()
item = self.pretval(concept_plus)
evaluator.init_evaluator(context, [item])
result = evaluator.eval(context, item)
assert not result.status
+12 -12
View File
@@ -5,7 +5,7 @@ from core.concept import Concept
from evaluators.EvalEvaluator import EvalEvaluator
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):
@@ -26,7 +26,7 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
ReturnValueConcept("some_name", False, Concept(name="1", body="'not to eval'")),
to_eval1,
to_eval2,
eval_requested
value_requested
]
evaluator = EvalEvaluator()
@@ -35,16 +35,16 @@ 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, eval_requested]
assert evaluated[0].parents == [to_eval1, value_requested]
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", [
([retval(Concept("foo", body="bar")), eval_requested], True),
([retval(Concept("status is false", body="bar"), status=False), eval_requested], True),
([retval("string_value"), eval_requested], True),
([retval(Concept("no body")), eval_requested], True),
([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),
])
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, Concept(name="not to eval")),
ReturnValueConcept("some_name", False, Concept(name="1", body="not to eval")),
eval_requested
value_requested
]
evaluator = EvalEvaluator()
@@ -68,8 +68,8 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
assert evaluated == ReturnValueConcept(
"evaluators.Eval",
False,
context.sheerka.new(BuiltinConcepts.CONCEPT_EVAL_REQUESTED))
assert evaluated.parents == [eval_requested]
context.sheerka.new(BuiltinConcepts.CONCEPT_VALUE_REQUESTED))
assert evaluated.parents == [value_requested]
def test_i_can_evaluate_sets(self):
sheerka, context, foo, bar, baz, number = self.init_concepts(
@@ -79,7 +79,7 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
Concept("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.matches(context, return_values)
@@ -46,4 +46,4 @@ class TestPrepareEvalEvaluator(TestUsingMemoryBasedSheerka):
assert res[0].body.body == expected
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),
("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()
res = sheerka.evaluate_user_input(text)
@@ -24,7 +24,7 @@ class TestSheerkaNonReg(TestUsingFileBasedSheerka):
assert res[0].status
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()
concept = Concept(name="one", body="1")
sheerka.add_in_cache(concept)
@@ -33,9 +33,13 @@ class TestSheerkaNonReg(TestUsingFileBasedSheerka):
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
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()
concept_one = Concept(name="one")
concept_un = Concept(name="un", body="one")
@@ -46,9 +50,13 @@ class TestSheerkaNonReg(TestUsingFileBasedSheerka):
return_value = res[0].value
assert len(res) == 1
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()
concept = Concept(name="one")
sheerka.add_in_cache(concept)
@@ -72,7 +80,7 @@ class TestSheerkaNonReg(TestUsingFileBasedSheerka):
assert res[0].value == 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 = """
def concept a + b
where isinstance(a, int) and isinstance(b, int)
@@ -107,7 +115,7 @@ as:
assert sheerka.sdp.io.exists(
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')
are correctly detected, thanks to the source code 'a plus b' in its body
@@ -137,7 +145,7 @@ as:
assert sheerka.sdp.io.exists(
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 = """
def concept a + b
where isinstance(a, int) and isinstance(b, int)
@@ -162,7 +170,7 @@ as:
" ",
"\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()
res = sheerka.evaluate_user_input(text)
@@ -171,7 +179,7 @@ as:
assert res[0].status
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()
concept_hello = Concept(name="hello a").def_prop("a")
concept_foo = Concept(name="foo")
@@ -183,9 +191,13 @@ as:
assert len(res) == 1
assert res[0].status
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()
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'"))
@@ -194,12 +206,15 @@ as:
assert len(res) == 1
assert res[0].status
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.add_in_cache(Concept(name="hello a", body="'hello ' + a").def_prop("a"))
@@ -248,11 +263,11 @@ as:
context = self.get_context(sheerka)
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 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):
sheerka = self.get_sheerka(use_dict=False, skip_builtins_in_db=False)
@@ -284,7 +299,7 @@ as:
assert "a" 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()
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 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()
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
@@ -306,13 +321,15 @@ as:
return_value = res[0].value
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())
assert return_value.props["a"].value.metadata.is_evaluated
# sanity check
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,
but make sure that the BNF are correctly persisted and loaded
@@ -337,8 +354,10 @@ as:
assert len(res) == 1
assert res[0].status
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", [
("Simple form", [
@@ -387,7 +406,7 @@ as:
assert len(res) == 1
assert res[0].status
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")
assert len(res) == 1
@@ -430,7 +449,8 @@ as:
res = sheerka.evaluate_user_input("twenty one")
assert len(res) == 1
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")
assert len(res) == 1
@@ -472,10 +492,10 @@ as:
for exp in init:
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 res[0].status
assert res[0].body == simplec("twenties", 21)
assert res[0].body == 21
def test_i_can_mix_concept_of_concept(self):
sheerka = self.get_sheerka()
@@ -490,55 +510,55 @@ as:
for definition in definitions:
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 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 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 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 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 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 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 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 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 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 res[0].status
assert res[0].body.body == 43
assert res[0].body == 43
@pytest.mark.xfail
def test_i_can_evaluate_concept_of_concept_when_multiple_choices(self):
@@ -663,23 +683,29 @@ as:
for exp in init:
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")
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")
assert len(res) == 1 and res[0].status and res[0].body == 22
res = sheerka.evaluate_user_input("eval twenty three")
assert len(res) > 1
def test_i_can_detect_when_only_one_evaluator_is_in_error(self):
sheerka = self.get_sheerka()
sheerka.evaluate_user_input("def concept 1 as one")
res = sheerka.evaluate_user_input("1")
assert len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONCEPT_EVAL_ERROR)
# def test_i_can_detect_when_only_one_evaluator_is_in_error(self):
# sheerka = self.get_sheerka()
#
# sheerka.evaluate_user_input("def concept 1 as one")
# res = sheerka.evaluate_user_input("eval 1")
# assert len(res) == 1
# assert not res[0].status
# assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONCEPT_EVAL_ERROR)
def test_i_can_manage_some_type_of_infinite_recursion(self):
sheerka = self.get_sheerka()
@@ -696,3 +722,56 @@ 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'")
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
# 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.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)
evaluated = context.sheerka.evaluate_concept(context, return_value, True)
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)
evaluated = context.sheerka.evaluate_concept(context, return_value, True)
assert evaluated.key == return_value.key
assert evaluated.get_prop("a") == foo.init_key()
assert evaluated.get_prop("b") == 2