First implementation of questions management

This commit is contained in:
2020-08-14 08:16:33 +02:00
parent e84b394da2
commit 351c16f946
47 changed files with 1582 additions and 400 deletions
+11 -2
View File
@@ -15,9 +15,9 @@ class BaseTest:
def get_context(self, sheerka=None, eval_body=False, eval_where=False):
context = ExecutionContext("test", Event(), sheerka or self.get_sheerka(), BuiltinConcepts.TESTING, None)
if eval_body:
context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
if eval_where:
context.local_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
return context
@@ -78,6 +78,15 @@ class BaseTest:
return sheerka, context, *result
@staticmethod
def get_concept_instance(sheerka, concept, **kwargs):
instance = sheerka.new(concept.key if isinstance(concept, Concept) else concept)
for i, var in enumerate(instance.metadata.variables):
if var[0] in kwargs:
instance.metadata.variables[i] = (var[0], kwargs[var[0]])
return instance
@staticmethod
def retval(obj, who="who", status=True):
"""ret_val"""
+10 -10
View File
@@ -35,7 +35,7 @@ def test_i_can_push():
concepts={"bar": Concept("bar")})
a.preprocess = set()
a.preprocess.add("preprocess")
a.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
a.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
a.global_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
b = a.push(BuiltinConcepts.EVALUATION, "sub action context", desc="sub description")
@@ -54,7 +54,7 @@ def test_i_can_push():
assert b.id == a.id + 1
assert b._tab == a._tab + " "
assert b.preprocess == a.preprocess
assert b.local_hints == {BuiltinConcepts.EVAL_BODY_REQUESTED}
assert b.protected_hints == {BuiltinConcepts.EVAL_BODY_REQUESTED}
assert b.global_hints == a.global_hints
@@ -64,10 +64,10 @@ def test_children_i_created_when_i_push():
e.push(BuiltinConcepts.NOP, None, who="b", desc="oups! I did a again")
e.push(BuiltinConcepts.NOP, None, who="c", desc="I do something else")
assert len(e.children) == 3
assert e.children[0].who, e.children[0].who == ("a", "I do something")
assert e.children[1].who, e.children[1].who == ("b", "oups! I did a again")
assert e.children[2].who, e.children[2].who == ("c", "I do something else")
assert len(e._children) == 3
assert e._children[0].who, e._children[0].who == ("a", "I do something")
assert e._children[1].who, e._children[1].who == ("b", "oups! I did a again")
assert e._children[2].who, e._children[2].who == ("c", "I do something else")
def test_i_can_add_variable_when_i_push():
@@ -81,17 +81,17 @@ def test_i_can_add_variable_when_i_push():
def test_local_hints_are_local_and_global_hints_are_global():
a = ExecutionContext("foo", Event("event_1"), "fake_sheerka", BuiltinConcepts.NOP, None)
a.local_hints.add("local hint 1")
a.protected_hints.add("local hint 1")
a.global_hints.add("global hint 1")
b = a.push(BuiltinConcepts.NOP, None)
b.local_hints.add("local hint 2")
b.protected_hints.add("local hint 2")
b.global_hints.add("global hint 2")
assert a.local_hints == {"local hint 1"}
assert a.protected_hints == {"local hint 1"}
assert a.global_hints == {"global hint 1", "global hint 2"}
assert b.local_hints == {"local hint 1", "local hint 2"}
assert b.protected_hints == {"local hint 1", "local hint 2"}
assert b.global_hints == {"global hint 1", "global hint 2"}
+180 -14
View File
@@ -284,6 +284,49 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept)
assert evaluated.get_value("prop") == 2
def test_i_can_evaluate_when_body_is_a_concept_with_its_own_variables(self):
sheerka, context, plus, add = self.init_concepts(
Concept("a plus b", body="a + b").def_var("a").def_var("b"),
Concept("add a b", body="a plus b").def_var("a").def_var("b"),
eval_body=True)
add_instance = self.get_concept_instance(sheerka, add, a="1", b="2")
evaluated = sheerka.evaluate_concept(context, add_instance)
assert evaluated.key == add_instance.key
assert evaluated.metadata.is_evaluated
assert sheerka.objvalue(evaluated) == 3
def test_i_can_evaluate_when_body_is_a_concept_with_its_own_variables_and_different_names(self):
sheerka, context, plus, add = self.init_concepts(
Concept("a plus b", body="a + b").def_var("a").def_var("b"),
Concept("add x y", body="x plus y").def_var("x").def_var("y"),
eval_body=True)
add_instance = self.get_concept_instance(sheerka, add, x="1", y="2")
evaluated = sheerka.evaluate_concept(context, add_instance)
assert evaluated.key == add_instance.key
assert evaluated.metadata.is_evaluated
assert sheerka.objvalue(evaluated) == 3
def test_i_can_evaluate_when_body_is_a_concept_with_its_own_variables_multiple_levels(self):
sheerka, context, plus, add, inc = self.init_concepts(
Concept("a plus b", body="a + b").def_var("a").def_var("b"),
Concept("add x y", body="x plus y").def_var("x").def_var("y"),
Concept("inc number", body="add number 1").def_var("number"),
eval_body=True)
inc_instance = self.get_concept_instance(sheerka, inc, number="1")
evaluated = sheerka.evaluate_concept(context, inc_instance)
assert evaluated.key == inc_instance.key
assert evaluated.metadata.is_evaluated
assert sheerka.objvalue(evaluated) == 2
def test_i_can_reference_sheerka(self):
sheerka = self.get_sheerka()
@@ -354,21 +397,24 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
assert evaluated.key == concept.init_key().key
@pytest.mark.parametrize("where_clause, expected, expected_body", [
("True", True, BuiltinConcepts.NOT_INITIALIZED),
("False", False, BuiltinConcepts.NOT_INITIALIZED),
("self < 10", False, 10),
("self < 11", True, 10),
("a < 20", False, BuiltinConcepts.NOT_INITIALIZED),
("a > 19", True, BuiltinConcepts.NOT_INITIALIZED),
("a + self > 20", True, 10),
@pytest.mark.parametrize("where_clause, expected, expected_prop, expected_body", [
("True", True, None, BuiltinConcepts.NOT_INITIALIZED),
("False", False, ConceptParts.WHERE, BuiltinConcepts.NOT_INITIALIZED),
("self < 10", False, ConceptParts.WHERE, 10),
("self < 11", True, None, 10),
("a < 20", False, "a", BuiltinConcepts.NOT_INITIALIZED),
("a > 19", True, None, BuiltinConcepts.NOT_INITIALIZED),
("a + self > 20", True, None, 10),
("a + self < 20", False, ConceptParts.WHERE, 10),
])
def test_i_can_evaluate_simple_where(self, where_clause, expected, expected_body):
def test_i_can_evaluate_simple_where(self, where_clause, expected, expected_prop, expected_body):
# We check that the WHERE condition is correctly evaluated
# We also check that the body is evaluated only when it's mandatory
sheerka, context, concept = self.init_concepts(
Concept("foo", body="10", where=where_clause).def_var("a", "20"),
eval_body=False, # to check when the evaluation is forced
eval_where=True,
)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept, eval_body=False)
@@ -380,7 +426,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONDITION_FAILED)
assert evaluated.body == where_clause
assert evaluated.concept == concept
assert evaluated.prop == ConceptParts.WHERE
assert evaluated.prop == expected_prop
assert concept.body == expected_body
def test_i_can_evaluate_where_when_using_other_concept(self):
@@ -402,6 +448,116 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, False), concept)
assert evaluated.key == concept.key
def test_i_can_apply_intermediate_where_condition_using_python(self):
sheerka, context, one_1, one_str, plus = self.init_concepts(
Concept("one", body="1"),
Concept("one", body="'one'"),
Concept("a plus b", body="a + b", where="isinstance(a, int)").def_var("a", "one").def_var("b", "2"),
eval_body=True,
eval_where=True,
)
evaluated = sheerka.evaluate_concept(context, plus)
assert evaluated.key == plus.key
assert evaluated.body == 3
def test_i_can_apply_intermediate_where_condition_when_multiple_variables_using_python(self):
sheerka, context, one_1, one_str, two_2, two_str, plus = self.init_concepts(
Concept("one", body="1"),
Concept("one", body="'one'"),
Concept("two", body="2"),
Concept("two", body="'two'"),
Concept("a plus b",
body="a + b",
where="isinstance(a, int) and isinstance(b, int)").def_var("a", "one").def_var("b", "two"),
eval_body=True,
eval_where=True,
)
evaluated = sheerka.evaluate_concept(context, plus)
assert evaluated.key == plus.key
assert evaluated.body == 3
def test_i_can_apply_intermediate_where_condition_using_other_concepts(self):
sheerka, context, one_1, one_str, is_an_int, plus = self.init_concepts(
Concept("one", body="1"),
Concept("one", body="'one'"),
Concept("x is an int", body="isinstance(x, int)").def_var("x"),
Concept("a plus b", body="a + b", where="a is an int").def_var("a", "one").def_var("b", "2"),
eval_body=True,
eval_where=True,
)
evaluated = sheerka.evaluate_concept(context, plus)
assert evaluated.key == plus.key
assert evaluated.body == 3
def test_i_can_apply_intermediate_where_condition_when_multiple_levels(self):
sheerka, context, one_1, one_str, is_an_int, is_an_integer, plus = self.init_concepts(
Concept("one", body="1"),
Concept("one", body="'one'"),
Concept("x is an int", body="isinstance(x, int)").def_var("x"),
Concept("y is an integer", body="y is an int").def_var("y"),
Concept("a plus b", body="a + b", where="a is an integer").def_var("a", "one").def_var("b", "2"),
eval_body=True,
eval_where=True,
)
evaluated = sheerka.evaluate_concept(context, plus)
assert evaluated.key == plus.key
assert evaluated.body == 3
def test_i_can_apply_intermediate_where_condition_choosing_the_correct_where_concept(self):
# in this test, there are two where conditions with the same name
# We need to use the 'PRE' condition to select the correct one
sheerka, context, one_1, one_str, is_an_int, is_an_integer, plus = self.init_concepts(
Concept("one", body="1"),
Concept("one", body="'one'"),
Concept("x is an int",
body="isinstance(x, int)",
pre="in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)").def_var("x"),
Concept("x is an int", body="False").def_var("x"),
Concept("a plus b", body="a + b", where="a is an int").def_var("a", "one").def_var("b", "2"),
eval_body=True,
eval_where=True,
)
evaluated = sheerka.evaluate_concept(context, plus)
assert evaluated.key == plus.key
assert evaluated.body == 3
@pytest.mark.skip("Not ready for that")
def test_i_can_apply_intermediate_where_condition_when_multiple_variables(self):
sheerka, context, one_1, one_str, two_2, two_str, is_an_int, plus = self.init_concepts(
Concept("one", body="1"),
Concept("one", body="'one'"),
Concept("two", body="2"),
Concept("two", body="'two'"),
Concept("x is an int", body="isinstance(x, int)").def_var("x"),
Concept("a plus b",
body="a + b",
where="a is an int and isinstance(b, int)").def_var("a", "one").def_var("b", "two"),
eval_body=True,
eval_where=True,
)
evaluated = sheerka.evaluate_concept(context, plus)
assert evaluated.key == plus.key
assert evaluated.body == 3
def test_i_cannot_evaluate_when_intermediate_where_condition_fails(self):
sheerka, context, one_1, is_an_int, plus = self.init_concepts(
Concept("one", body="'one'"),
Concept("x is an int", body="isinstance(x, int)").def_var("x"),
Concept("a plus b", body="a + b", where="a is an int").def_var("a", "one").def_var("b", "2"),
eval_body=True,
eval_where=True,
)
evaluated = sheerka.evaluate_concept(context, plus)
assert evaluated.key == BuiltinConcepts.CONDITION_FAILED
assert evaluated.body == "a is an int"
def test_i_can_enable_disable_where_clause_evaluation(self):
sheerka, context, concept = self.init_concepts(
Concept("foo", body="10", where="a > 10").def_var("a", None),
@@ -409,7 +565,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
context.local_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
evaluated = sheerka.evaluate_concept(context, concept)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
@@ -495,6 +651,16 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo}
# def test_i_can_detect_auto_recursion_when_evaluating_another_concept(self):
# sheerka, context, one_1, one_str, plus = self.init_concepts(
# Concept("one", body="1"),
# Concept("one", body="one"),
# Concept("a plus b", body="a + b", where="isinstance(a, int)").def_var("a", "one").def_var("b", "2")
# )
#
# evaluated = sheerka.evaluate_concept(context, plus, eval_body=True)
# sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
def test_i_can_manage_auto_recursion_when_constant(self):
sheerka = self.get_sheerka()
@@ -566,7 +732,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
assert captured.out == ""
def test_python_builtin_function_are_forbidden_in_where_pre_post_ret(self, capsys):
# I do the test only for PRE, as it will be the same for the other CounceptPart
# I do the test only for PRE, as it will be the same for the other ConceptPart
sheerka, context, foo, bar = self.init_concepts(
Concept("foo", body="print('10')"), # print will be executed
Concept("bar", pre="print('10')"), # print won't be executed
@@ -658,8 +824,8 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
sheerka, context, concept = self.init_concepts(
Concept("foo", pre="'pre'", post="'post'", ret="'ret'", where="'where'", body="'body'").def_var("a", "'a'")
)
context.local_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED) # to prove that we do not care
context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) # to prove that we do not care
context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED) # to prove that we do not care
context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) # to prove that we do not care
evaluated = sheerka.evaluate_concept(context, concept, metadata=['pre'])
assert evaluated.values == {"a": Property("a", NotInit), ConceptParts.PRE: Property(ConceptParts.PRE, 'pre')}
+3 -3
View File
@@ -197,11 +197,11 @@ class TestSheerkaFilter(TestUsingMemoryBasedSheerka):
assert len(res) == 2
format_instructions = res[0].get_prop(BuiltinConcepts.FORMAT_INSTRUCTIONS)
assert isinstance(format_instructions, FormatInstructions)
assert format_instructions.recursive_props["children"] == 10
assert format_instructions.recursive_props["_children"] == 10
format_instructions = res[1].get_prop(BuiltinConcepts.FORMAT_INSTRUCTIONS)
assert isinstance(format_instructions, FormatInstructions)
assert format_instructions.recursive_props["children"] == 10
assert format_instructions.recursive_props["_children"] == 10
res = lst | Pipe(SheerkaFilter.pipe_recurse)(15, "other_prop")
res = list(res)
@@ -209,7 +209,7 @@ class TestSheerkaFilter(TestUsingMemoryBasedSheerka):
assert len(res) == 2
format_instructions = res[0].get_prop(BuiltinConcepts.FORMAT_INSTRUCTIONS)
assert isinstance(format_instructions, FormatInstructions)
assert format_instructions.recursive_props["children"] == 10
assert format_instructions.recursive_props["_children"] == 10
assert format_instructions.recursive_props["other_prop"] == 15
def test_i_can_inspect_obj(self):
+52
View File
@@ -0,0 +1,52 @@
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from core.sheerka.ExecutionContext import ExecutionContext
from core.sheerka.services.SheerkaShortTermMemory import SheerkaShortTermMemory
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestSheerkaShortTermMemory(TestUsingMemoryBasedSheerka):
def test_i_can_add_to_global_short_term_memory(self):
sheerka = self.get_sheerka()
service = sheerka.services[SheerkaShortTermMemory.NAME]
foo = Concept("foo")
sheerka.add_to_short_term_memory(None, "a", foo)
assert service.objects.copy() == {":a": foo}
assert id(sheerka.get_from_short_term_memory(None, "a")) == id(foo)
def test_i_can_add_context_short_term_memory(self):
sheerka, context = self.init_concepts()
service = sheerka.services[SheerkaShortTermMemory.NAME]
foo = Concept("foo")
sheerka.add_to_short_term_memory(context, "a", foo)
context_id = ExecutionContext.ids[context.event.get_digest()]
assert service.objects.copy() == {f"{context_id}:a": foo}
assert id(sheerka.get_from_short_term_memory(context, "a")) == id(foo)
assert sheerka.get_from_short_term_memory(None, "a") is None
def test_i_can_get_obj_from_parents(self):
sheerka, context = self.init_concepts()
service = sheerka.services[SheerkaShortTermMemory.NAME]
foo = Concept("foo")
sheerka.add_to_short_term_memory(None, "a", foo)
with context.push(BuiltinConcepts.TESTING, None) as sub_context:
assert service.objects.copy() == {":a": foo}
assert id(sheerka.get_from_short_term_memory(sub_context, "a")) == id(foo)
assert id(sheerka.get_from_short_term_memory(context, "a")) == id(foo)
assert id(sheerka.get_from_short_term_memory(None, "a")) == id(foo)
def test_entry_are_removed_on_context_exit(self):
sheerka, context = self.init_concepts()
with context.push(BuiltinConcepts.TESTING, None) as sub_context:
foo = Concept("foo")
sheerka.add_to_short_term_memory(sub_context, "a", foo)
assert id(sheerka.get_from_short_term_memory(sub_context, "a")) == id(foo)
assert sheerka.get_from_short_term_memory(sub_context, "a") is None
+11 -10
View File
@@ -242,16 +242,17 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
assert sheerka.isinstance(new.concept, concept)
@pytest.mark.parametrize("concept, reduce_simple_list, expected", [
(None, False, None),
(3.14, False, 3.14),
("foo", False, "foo"),
(True, False, True),
(Concept("name", body="foo"), False, "foo"),
(Concept("name"), False, Concept("name")),
(ConceptWithGetObjValue("name").set_value("my_prop", "my_value"), False, "my_value"),
(ReturnValueConcept(value="return_value"), False, "return_value"),
(ReturnValueConcept(value=Concept(key=BuiltinConcepts.USER_INPUT, body="text"), status=True), False, "text"),
(ReturnValueConcept(value=UserInputConcept("text"), status=True), False, "text"),
# (None, False, None),
# (3.14, False, 3.14),
# ("foo", False, "foo"),
# (True, False, True),
# (Concept("name", body="foo"), False, "foo"),
# (Concept("name"), False, Concept("name")),
# (ConceptWithGetObjValue("name").set_value("my_prop", "my_value"), False, "my_value"),
# (ReturnValueConcept(value="return_value"), False, "return_value"),
# (ReturnValueConcept(value=Concept(key=BuiltinConcepts.USER_INPUT, body="text"), status=True), False, "text"),
# (ReturnValueConcept(value=UserInputConcept("text"), status=True), False, "text"),
(ReturnValueConcept(value=Concept("foo", body=False).auto_init(), status=True), False, False),
(Concept("name", body=["foo", "bar"]), False, ["foo", "bar"]),
(Concept("name", body=["foo"]), True, "foo"),
(Concept("name", body=Concept("foo")), False, Concept("foo")),
+1 -1
View File
@@ -210,7 +210,7 @@ class EvaluatorAllSuppressEntries(EvaluatorAllWithPriority):
return context.sheerka.ret(
self.name,
True,
[],
BuiltinConcepts.NO_RESULT,
parents=to_remove)
+15 -8
View File
@@ -114,6 +114,21 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
assert created_concept.metadata.definition == "hello a"
assert created_concept.metadata.definition_type == "bnf"
def test_i_can_add_concept_with_the_correct_variables_when_referencing_other_concepts(self):
context = self.get_context()
def_concept_return_value = self.get_def_concept(
name="x plus y",
where=self.pretval(Concept("u is a v").def_var("u").def_var("v"), source="x is a number"),
body=self.pretval(Concept("add a b").def_var("a").def_var("b"), source="add x y"),)
evaluated = AddConceptEvaluator().eval(context, def_concept_return_value)
assert evaluated.status
assert context.sheerka.isinstance(evaluated.body, BuiltinConcepts.NEW_CONCEPT)
created_concept = evaluated.body.body
assert created_concept.metadata.variables == [("x", None), ("y", None)]
def test_that_the_source_is_correctly_set_for_concept_with_simple_definition(self):
context = self.get_context()
def_concept_return_value = self.get_def_concept(
@@ -195,14 +210,6 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
assert AddConceptEvaluator.get_variables(context.sheerka, ret_val, ["a"]) == []
def test_i_can_get_variables_from_another_concept(self):
concept = Concept("hello").def_var("a").def_var("b")
ret_val = ReturnValueConcept(who="some_parser",
status=True,
value=ParserResultConcept(value=concept))
assert AddConceptEvaluator.get_variables(self.get_sheerka(), ret_val, []) == {"a", "b"}
def test_i_can_get_variables_from_definition(self):
parsing_expression = Sequence(ConceptExpression('mult'),
ZeroOrMore(Sequence(StrMatch("+"), ConceptExpression("add"))))
+3 -3
View File
@@ -20,7 +20,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
def test_i_can_evaluate_concept(self):
context = self.get_context()
context.local_hints.update({BuiltinConcepts.EVAL_BODY_REQUESTED, BuiltinConcepts.EVAL_WHERE_REQUESTED})
context.protected_hints.update({BuiltinConcepts.EVAL_BODY_REQUESTED, BuiltinConcepts.EVAL_WHERE_REQUESTED})
concept = Concept(name="foo",
where="True",
pre="2 > 1",
@@ -45,7 +45,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
def test_body_is_returned_when_defined_and_requested(self):
context = self.get_context()
context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
concept = Concept(name="foo",
body="'I have a value'",
where="True",
@@ -94,7 +94,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
def test_i_cannot_recognize_a_concept_if_one_of_the_prop_is_unknown(self):
context = self.get_context()
context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
context.sheerka.add_in_cache(Concept(name="one").init_key())
concept_plus = context.sheerka.add_in_cache(Concept(name="a plus b")
.def_var("a", "one")
+10 -10
View File
@@ -2,7 +2,7 @@ import pytest
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
from core.concept import Concept
from core.sheerka.services.SheerkaSetsManager import SheerkaSetsManager
from evaluators.EvalEvaluator import EvalEvaluator
from evaluators.ReturnBodyEvaluator import ReturnBodyEvaluator
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -15,7 +15,7 @@ def retval(obj, who="who", status=True):
class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
def test_i_can_match_and_eval(self):
context = self.get_context()
context.global_hints.add(BuiltinConcepts.RETURN_VALUE_REQUESTED)
context.global_hints.add(BuiltinConcepts.RETURN_BODY_REQUESTED)
to_eval1 = ReturnValueConcept("some_name", True, Concept(name="2", body="to eval").auto_init())
to_eval2 = ReturnValueConcept("some_name", True, Concept(name="3", body="also to eval").auto_init())
@@ -28,7 +28,7 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
to_eval2,
]
evaluator = EvalEvaluator()
evaluator = ReturnBodyEvaluator()
assert evaluator.matches(context, return_values)
evaluated = evaluator.eval(context, return_values)
@@ -47,16 +47,16 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
])
def test_i_cannot_match_if_eval_request_is_not_present(self, return_value):
context = self.get_context()
assert not EvalEvaluator().matches(context, [return_value])
assert not ReturnBodyEvaluator().matches(context, [return_value])
context.global_hints.add(BuiltinConcepts.RETURN_VALUE_REQUESTED)
assert EvalEvaluator().matches(context, [return_value])
context.global_hints.add(BuiltinConcepts.RETURN_BODY_REQUESTED)
assert ReturnBodyEvaluator().matches(context, [return_value])
def test_i_can_match_depending_on_builtin_concept_processing(self):
context = self.get_context()
context.global_hints.add(BuiltinConcepts.RETURN_VALUE_REQUESTED)
context.global_hints.add(BuiltinConcepts.RETURN_BODY_REQUESTED)
return_values = [ReturnValueConcept("some_name", True, Concept(name="2", body="to eval").auto_init())]
evaluator = EvalEvaluator()
evaluator = ReturnBodyEvaluator()
# i match when no BuiltinConcepts.PROCESSING is found
assert evaluator.matches(context, return_values)
@@ -80,7 +80,7 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
ReturnValueConcept("some_name", False, Concept(name="1", body="not to eval")), # no evaluated body
]
evaluated = EvalEvaluator().eval(context, return_values)
evaluated = ReturnBodyEvaluator().eval(context, return_values)
assert evaluated is None
def test_i_can_evaluate_sets(self):
@@ -92,7 +92,7 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
sets_handler = sheerka.services[SheerkaSetsManager.NAME]
sets_handler.add_concepts_to_set(context, [foo, bar, baz], number)
evaluated = EvalEvaluator().eval(context, [retval(number)])
evaluated = ReturnBodyEvaluator().eval(context, [retval(number)])
assert len(evaluated) == 1
assert evaluated[0].status
@@ -2,14 +2,14 @@ import pytest
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept
from core.concept import Concept
from evaluators.PrepareEvalEvaluator import PrepareEvalEvaluator
from evaluators.PrepareEvalBodyEvaluator import PrepareEvalBodyEvaluator
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
r = ReturnValueConcept
class TestPrepareEvalEvaluator(TestUsingMemoryBasedSheerka):
class TestPrepareEvalBodyEvaluator(TestUsingMemoryBasedSheerka):
@pytest.mark.parametrize("ret_val, expected", [
(r("name", True, UserInputConcept("eval 1 + 1")), True),
@@ -26,7 +26,7 @@ class TestPrepareEvalEvaluator(TestUsingMemoryBasedSheerka):
])
def test_i_can_match(self, ret_val, expected):
context = self.get_context()
assert PrepareEvalEvaluator().matches(context, ret_val) == expected
assert PrepareEvalBodyEvaluator().matches(context, ret_val) == expected
@pytest.mark.parametrize("ret_val, expected", [
(r("name", True, UserInputConcept("eval 1 + 1")), "1 + 1"),
@@ -36,7 +36,7 @@ class TestPrepareEvalEvaluator(TestUsingMemoryBasedSheerka):
context = self.get_context()
sheerka = context.sheerka
prepare_evaluator = PrepareEvalEvaluator()
prepare_evaluator = PrepareEvalBodyEvaluator()
prepare_evaluator.matches(context, ret_val)
res = prepare_evaluator.eval(context, ret_val)
@@ -44,5 +44,6 @@ class TestPrepareEvalEvaluator(TestUsingMemoryBasedSheerka):
assert sheerka.isinstance(res.body, BuiltinConcepts.USER_INPUT)
assert res.body.body == expected
assert BuiltinConcepts.EVAL_BODY_REQUESTED in context.global_hints
assert BuiltinConcepts.RETURN_VALUE_REQUESTED in context.global_hints
assert BuiltinConcepts.EVAL_BODY_REQUESTED in context.protected_hints
assert BuiltinConcepts.EVAL_WHERE_REQUESTED in context.protected_hints
assert BuiltinConcepts.RETURN_BODY_REQUESTED in context.protected_hints
@@ -0,0 +1,49 @@
import pytest
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept
from core.concept import Concept
from evaluators.PrepareEvalQuestionEvaluator import PrepareEvalQuestionEvaluator
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
r = ReturnValueConcept
class TestPrepareEvalQuestionEvaluator(TestUsingMemoryBasedSheerka):
@pytest.mark.parametrize("ret_val, expected", [
(r("name", True, UserInputConcept("question(1 + 1)")), True),
(r("name", True, UserInputConcept(" question(1 + 1) ")), True),
(r("name", True, UserInputConcept("question()")), False),
(r("name", True, UserInputConcept("1+1")), False),
(r("name", True, UserInputConcept("")), False),
(r("name", True, UserInputConcept("question(")), False),
(r("name", True, UserInputConcept(")")), False),
(r("name", True, UserInputConcept([])), False),
(r("name", True, Concept("foo")), False),
(r("name", True, "not a concept"), False),
(r("name", False, UserInputConcept("question(1 + 1)")), False),
])
def test_i_can_match(self, ret_val, expected):
context = self.get_context()
assert PrepareEvalQuestionEvaluator().matches(context, ret_val) == expected
@pytest.mark.parametrize("ret_val, expected", [
(r("name", True, UserInputConcept("question(1 + 1)")), "1 + 1"),
(r("name", True, UserInputConcept(" question( 1 + 1 ) ")), "1 + 1"),
])
def test_i_can_eval(self, ret_val, expected):
context = self.get_context()
sheerka = context.sheerka
prepare_evaluator = PrepareEvalQuestionEvaluator()
prepare_evaluator.matches(context, ret_val)
res = prepare_evaluator.eval(context, ret_val)
assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.USER_INPUT)
assert res.body.body == expected
assert BuiltinConcepts.EVAL_QUESTION_REQUESTED in context.protected_hints
assert BuiltinConcepts.EVAL_BODY_REQUESTED in context.protected_hints
assert BuiltinConcepts.RETURN_BODY_REQUESTED in context.protected_hints
+1 -1
View File
@@ -137,7 +137,7 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
assert evaluated.status
assert not evaluated.value # the first test is between Concept(foo) and int(2)
context.local_hints.add(BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED)
context.protected_hints.add(BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED)
evaluated = python_evaluator.eval(context, parsed)
assert evaluated.status
assert evaluated.value # we test until we compare foo.body and 2
@@ -1,4 +1,5 @@
import pytest
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from evaluators.ResolveAmbiguityEvaluator import ResolveAmbiguityEvaluator
@@ -67,8 +68,26 @@ class TestResolveAmbiguityEvaluator(TestUsingMemoryBasedSheerka):
resolved = res[0]
assert resolved.who == evaluator.name
assert resolved.body == []
assert resolved.body == BuiltinConcepts.NO_RESULT
assert resolved.parents == [
return_values[0],
return_values[1],
]
def test_i_can_eval_all_pass(self):
"""
If they all pass, that means that no concept was reduced
-> We need to act like resolve ambiguity was not called
:return:
"""
context = self.get_context()
return_values = [
self.pretval(Concept("hello world 1"), "hello word"),
self.pretval(Concept("hello world 2"), "hello word"),
]
evaluator = ResolveAmbiguityEvaluator()
evaluator.matches(context, return_values)
res = evaluator.eval(context, return_values)
assert res is None
+76
View File
@@ -1015,6 +1015,82 @@ as:
assert res[0].status
assert res[0].body == "Executed !"
def test_i_can_manage_question(self):
init = [
"def concept one",
"def concept foo",
"def concept number",
"one isa number",
"def concept x is a y as isa(x,y) pre in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)",
"def concept x is a y as set_isa(x,y)",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("question(one is a number)") # automatically evaluated
assert len(res) == 1
assert res[0].status
assert res[0].body
res = sheerka.evaluate_user_input("question(foo is a number)") # automatically evaluated
assert len(res) == 1
assert res[0].status
assert not res[0].body
def test_where_clause_implicitly_infer_to_question(self):
init = [
"def concept one as 1",
"def concept number",
"one isa number",
"def concept one as 10", # to make sure that it won't be rejected because of the cast
"def concept x is a y as isa(x,y) pre in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)",
"def concept x is a y as set_isa(x,y)",
]
# Explanations
# There are two concepts 'one'. The first one is tagged as a number while the second one is not
# So the first one should be picked.
# the second concept 'one' 's value is an integer, to make sure that it won't be rejected because of its type
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("def concept x plus y where x is a number as x + y")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.NEW_CONCEPT)
# Let's check that the concept is correctly understood
res = sheerka.evaluate_user_input("eval one plus 2")
assert len(res) == 1
assert res[0].status
assert res[0].body == 3 # it means that the first 'one' was chosen
def test_i_can_manage_concept_that_refers_to_question(self):
init = [
"def concept one",
"def concept foo",
"def concept number",
"one isa number",
"def concept q from q ? as question(q)",
"def concept is_a from x is a y as isa(x,y) pre in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)",
"set_is_greater_than(BuiltinConcepts.PRECEDENCE, c:is_a:, c:q:)"
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("one is a number ?") # automatically evaluated
assert len(res) == 1
assert res[0].status
assert res[0].body
res = sheerka.evaluate_user_input("foo is a number ?") # automatically evaluated
assert len(res) == 1
assert res[0].status
assert not res[0].body
# Sanity, when there is only one 'is a' concept. It's chosen regardless of the PRE condition
res = sheerka.evaluate_user_input("one is a number")
assert len(res) == 1
assert res[0].status
assert res[0].body
class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
def test_i_can_def_several_concepts(self):
+35 -3
View File
@@ -3,7 +3,7 @@ from dataclasses import dataclass
import pytest
from core.builtin_concepts import ParserResultConcept, BuiltinConcepts, ReturnValueConcept
from core.concept import DEFINITION_TYPE_BNF, DEFINITION_TYPE_DEF
from core.concept import DEFINITION_TYPE_BNF, DEFINITION_TYPE_DEF, Concept, CV
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Keywords, Tokenizer, LexerError
from parsers.BnfNodeParser import OrderedChoice, ConceptExpression, StrMatch
@@ -87,9 +87,9 @@ class PN:
class TestDefaultParser(TestUsingMemoryBasedSheerka):
def init_parser(self, *concepts):
sheerka, concept, *updated = self.init_concepts(*concepts, singleton=True)
sheerka, context, *updated = self.init_concepts(*concepts, singleton=True)
parser = DefaultParser()
return sheerka, concept, parser, *updated
return sheerka, context, parser, *updated
@pytest.mark.parametrize("text, expected", [
("def concept hello", get_def_concept(name="hello")),
@@ -313,6 +313,38 @@ def concept add one to a as
assert isinstance(res.value, ParserResultConcept)
assert node == expected
def test_i_can_parse_when_ambiguity_in_where_pre_clause(self):
sheerka, context, parser, *concepts = self.init_parser(
Concept("x is a y", pre="in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)"),
Concept("x is a y")
)
text = "def concept foo x y where x is a y"
res = parser.parse(context, ParserInput(text))
expected_body = self.pretval(CV(concepts[0], pre=True), source="x is a y", who="parsers.Default",
parser="parsers.ExactConcept")
expected = get_def_concept("foo x y", where=expected_body)
node = res.value.value
assert res.status
assert res.who == parser.name
assert res.value.source == text
assert isinstance(res.value, ParserResultConcept)
assert node == expected
text = "def concept foo x y pre x is a y"
res = parser.parse(context, ParserInput(text))
expected_body = self.pretval(CV(concepts[0], pre=True), source="x is a y", who="parsers.Default",
parser="parsers.ExactConcept")
expected = get_def_concept("foo x y", pre=expected_body)
node = res.value.value
assert res.status
assert res.who == parser.name
assert res.value.source == text
assert isinstance(res.value, ParserResultConcept)
assert node == expected
def test_i_can_detect_not_for_me(self):
text = "hello world"
sheerka, context, parser = self.init_parser()
+108 -1
View File
@@ -1,9 +1,13 @@
from dataclasses import dataclass
import pytest
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept
from core.concept import Concept
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Tokenizer, TokenKind
from parsers.BaseParser import UnexpectedEof, UnexpectedTokenErrorNode
from parsers.ExpressionParser import PropertyEqualsNode, PropertyEqualsSequenceNode, PropertyContainsNode, AndNode, \
OrNode, NotNode, LambdaNode, IsaNode
OrNode, NotNode, LambdaNode, IsaNode, NameExprNode, ExpressionParser, LeftPartNotFoundError, TrueifyVisitor
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -16,8 +20,93 @@ class Obj:
parent: object = None
def n(value):
return NameExprNode(Tokenizer(value, yield_eof=False))
class TestExpressionParser(TestUsingMemoryBasedSheerka):
def init_parser(self):
sheerka, context = self.init_concepts()
parser = ExpressionParser()
return sheerka, context, parser
@pytest.mark.parametrize("expression, expected", [
("one complicated expression", n("one complicated expression")),
("function_call(a,b,c)", n("function_call(a,b,c)")),
("one expression or another expression", OrNode(n("one expression"), n("another expression"))),
("one expression and another expression", AndNode(n("one expression"), n("another expression"))),
("one or two or three", OrNode(n("one"), n("two"), n("three"))),
("one and two and three", AndNode(n("one"), n("two"), n("three"))),
("one or two and three", OrNode(n("one"), AndNode(n("two"), n("three")))),
("one and two or three", OrNode(AndNode(n("one"), n("two")), n("three"))),
("one and (two or three)", AndNode(n("one"), OrNode(n("two"), n("three")))),
])
def test_i_can_parse_expression(self, expression, expected):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, ParserInput(expression))
wrapper = res.body
expressions = res.body.body
assert res.status
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
assert expressions == expected
@pytest.mark.parametrize("expression, expected_errors", [
("one or", [UnexpectedEof("When parsing 'or'")]),
("one and", [UnexpectedEof("When parsing 'and'")]),
("and one", [LeftPartNotFoundError()]),
("or one", [LeftPartNotFoundError()]),
("or", [LeftPartNotFoundError(), UnexpectedEof("When parsing 'or'")]),
("and", [LeftPartNotFoundError(), UnexpectedEof("When parsing 'and'")]),
])
def test_i_can_detect_error(self, expression, expected_errors):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, ParserInput(expression))
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
assert res.body.body == expected_errors
def test_i_can_detect_unbalanced_parenthesis(self):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, ParserInput("("))
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
assert isinstance(res.body.body[0], UnexpectedTokenErrorNode)
assert res.body.body[0].token.type == TokenKind.EOF
assert res.body.body[0].expected_tokens == [TokenKind.RPAR]
res = parser.parse(context, ParserInput(")"))
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
assert isinstance(res.body.body[0], UnexpectedTokenErrorNode)
assert res.body.body[0].token.type == TokenKind.RPAR
assert res.body.body[0].expected_tokens == []
res = parser.parse(context, ParserInput("one and two)"))
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
assert isinstance(res.body.body[0], UnexpectedTokenErrorNode)
assert res.body.body[0].token.type == TokenKind.RPAR
assert res.body.body[0].expected_tokens == []
res = parser.parse(context, ParserInput("one and two)"))
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
assert isinstance(res.body.body[0], UnexpectedTokenErrorNode)
assert res.body.body[0].token.type == TokenKind.RPAR
assert res.body.body[0].expected_tokens == []
def test_i_can_detect_empty_expression(self):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, ParserInput(""))
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.IS_EMPTY)
def test_i_can_test_property_equals(self):
node = PropertyEqualsNode("prop_a", "good value")
@@ -101,3 +190,21 @@ class TestExpressionParser(TestUsingMemoryBasedSheerka):
assert concept_node2.eval(Concept("foo").init_key())
assert not concept_node2.eval(Obj)
assert not concept_node2.eval(Concept())
@pytest.mark.parametrize("expression, to_trueify, to_skip, expected", [
("a", ["b"], ["a"], "a"),
("b", ["b"], ["a"], "True"),
("a and b", ["b"], ["a"], "a and True"),
("b or a", ["b"], ["a"], "True or a"),
("isinstance(b, str)", ["b"], ["a"], "True"),
("isinstance(b, str) or instance(a, str)", ["b"], ["a"], "True or instance(a, str)"),
("a and b or c", ["b", "c"], ["a"], "a and True or True"),
("a + b or a + c", ["b", "c"], ["a"], "a + b or a + c"),
])
def test_i_can_trueify(self, expression, to_trueify, to_skip, expected):
sheerka, context, parser = self.init_parser()
expr_node = parser.parse(context, ParserInput(expression)).body.body
translated_node = TrueifyVisitor(to_trueify, to_skip).visit(expr_node)
assert str(translated_node) == expected
@@ -0,0 +1,69 @@
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from core.sheerka.services.SheerkaExecute import ParserInput
from parsers.ShortTermMemoryParser import ShortTermMemoryParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestShortTermMemoryParser(TestUsingMemoryBasedSheerka):
def init_parser(self):
sheerka, context = self.init_concepts()
parser = ShortTermMemoryParser()
return sheerka, context, parser
def test_i_cannot_parse_empty_string(self):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, ParserInput(""))
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.IS_EMPTY)
def test_i_can_get_concept_from_sheerka(self):
sheerka, context, parser = self.init_parser()
foo = Concept("foo")
sheerka.add_to_short_term_memory(None, "test", foo)
res = parser.parse(context, ParserInput("test"))
assert res.status
assert id(res.body) == id(foo)
def test_i_can_get_concept_from_the_context(self):
sheerka, context, parser = self.init_parser()
foo = Concept("foo")
sheerka.add_to_short_term_memory(context, "test", foo)
res = parser.parse(context, ParserInput("test"))
assert res.status
assert id(res.body) == id(foo)
def test_i_can_get_concept_from_parent_context(self):
sheerka, context, parser = self.init_parser()
foo = Concept("foo")
sheerka.add_to_short_term_memory(context, "test", foo)
with context.push(BuiltinConcepts.TESTING, None) as sub_context:
res = parser.parse(sub_context, ParserInput("test"))
assert res.status
assert id(res.body) == id(foo)
def test_i_cannot_get_concept_when_no_concept_in_memory(self):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, ParserInput("test"))
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.NOT_FOUND)
assert res.body.body == "test"
def test_parser_can_only_be_called_with_parser_input(self):
sheerka, context, parser = self.init_parser()
assert parser.parse(context, "not_a_parser_input") is None
+4 -4
View File
@@ -279,14 +279,14 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
def test_i_can_encode_decode_execution_context(self):
sheerka = self.get_sheerka()
context = ExecutionContext("who", Event("xxx"), sheerka, BuiltinConcepts.NOP, None, "my desc")
c = Concept("foo").def_var("a")
context = ExecutionContext("who", Event("xxx"), sheerka, BuiltinConcepts.EVALUATE_CONCEPT, c, "my desc")
input_list = [ReturnValueConcept("who", True, 10), ReturnValueConcept("who2", False, 20)]
context.inputs = {"a": input_list, "b": set_full_serialization(Concept("foo"))}
context.values = {"c": input_list, "d": set_full_serialization(Concept("bar"))}
context.obj = set_full_serialization(Concept("baz"))
context.push(BuiltinConcepts.NOP, None, who="who3", desc="sub_child1")
context.push(BuiltinConcepts.NOP, None, who="who4", desc="sub_child2")
context.push(BuiltinConcepts.EVALUATING_CONCEPT, c, who="who3", desc="sub_child1")
context.push(BuiltinConcepts.EVALUATING_ATTRIBUTE, "a", who="who4", desc="sub_child2")
to_string = sheerkapickle.encode(sheerka, context)
decoded = sheerkapickle.decode(sheerka, to_string)