Refactored to use a single implementation for concept evaluation
This commit is contained in:
+39
-130
@@ -35,9 +35,12 @@ def test_i_can_match(ret_val, expected):
|
||||
assert ConceptEvaluator().matches(context, ret_val) == expected
|
||||
|
||||
|
||||
def test_concept_is_returned_when_no_body():
|
||||
def test_i_can_evaluate_concept():
|
||||
context = get_context()
|
||||
concept = Concept(name="one").init_key()
|
||||
concept = Concept(name="foo",
|
||||
where="1",
|
||||
pre="2",
|
||||
post="3").set_prop("a", "4").set_prop("b", "5")
|
||||
|
||||
evaluator = ConceptEvaluator()
|
||||
item = get_return_value(concept)
|
||||
@@ -45,13 +48,20 @@ def test_concept_is_returned_when_no_body():
|
||||
|
||||
assert result.who == evaluator.name
|
||||
assert result.status
|
||||
assert result.value == concept
|
||||
assert result.value == Concept(name="foo",
|
||||
where=1,
|
||||
pre=2,
|
||||
post=3).set_prop("a", 4).set_prop("b", 5).init_key()
|
||||
assert result.parents == [item]
|
||||
|
||||
|
||||
def test_body_is_evaluated_when_python_body():
|
||||
def test_body_is_returned_when_defined():
|
||||
context = get_context()
|
||||
concept = Concept(name="one", body="1").init_key()
|
||||
concept = Concept(name="foo",
|
||||
body="'I have a value'",
|
||||
where="1",
|
||||
pre="2",
|
||||
post="3").set_prop("a", "4").set_prop("b", "5")
|
||||
|
||||
evaluator = ConceptEvaluator()
|
||||
item = get_return_value(concept)
|
||||
@@ -59,136 +69,23 @@ def test_body_is_evaluated_when_python_body():
|
||||
|
||||
assert result.who == evaluator.name
|
||||
assert result.status
|
||||
assert result.value == 1
|
||||
assert result.value == "I have a value"
|
||||
assert result.parents == [item]
|
||||
|
||||
|
||||
def test_body_is_evaluated_when_concept_body():
|
||||
def test_i_cannot_eval_if_with_the_same_name_is_defined_in_the_context():
|
||||
# If we evaluate Concept("foo", body="a").set_prop("a", "'property_a'")
|
||||
# ConceptEvaluator will be called to resolve 'a' while we know that 'a' refers to the string 'property_a'
|
||||
|
||||
context = get_context()
|
||||
concept_one = Concept(name="one").init_key()
|
||||
context.sheerka.add_in_cache(concept_one)
|
||||
concept_un = Concept(name="un", body="one").init_key()
|
||||
context.obj = Concept("other").set_prop("foo", "'some_other_value'")
|
||||
concept = Concept(name="foo")
|
||||
|
||||
evaluator = ConceptEvaluator()
|
||||
item = get_return_value(concept_un)
|
||||
result = evaluator.eval(context, item)
|
||||
item = get_return_value(concept)
|
||||
result = ConceptEvaluator().eval(context, item)
|
||||
|
||||
assert result.who == evaluator.name
|
||||
assert result.status
|
||||
assert result.value == concept_one
|
||||
assert result.parents == [item]
|
||||
|
||||
|
||||
def test_body_is_evaluated_when_concept_body_with_a_body():
|
||||
"""
|
||||
The concept refers to another concept which has a body
|
||||
:return:
|
||||
"""
|
||||
context = get_context()
|
||||
concept_one = Concept(name="one", body="1").init_key()
|
||||
context.sheerka.add_in_cache(concept_one)
|
||||
concept_un = Concept(name="un", body="one").init_key()
|
||||
|
||||
evaluator = ConceptEvaluator()
|
||||
item = get_return_value(concept_un)
|
||||
result = evaluator.eval(context, item)
|
||||
|
||||
assert result.who == evaluator.name
|
||||
assert result.status
|
||||
assert result.value == 1
|
||||
assert result.parents == [item]
|
||||
|
||||
|
||||
def test_i_can_evaluate_longer_chains():
|
||||
context = get_context()
|
||||
context.sheerka.add_in_cache(Concept(name="a", body="'a'").init_key())
|
||||
context.sheerka.add_in_cache(Concept(name="b", body="a").init_key())
|
||||
context.sheerka.add_in_cache(Concept(name="c", body="b").init_key())
|
||||
concept_d = context.sheerka.add_in_cache(Concept(name="d", body="c").init_key())
|
||||
|
||||
evaluator = ConceptEvaluator()
|
||||
item = get_return_value(concept_d)
|
||||
result = evaluator.eval(context, item)
|
||||
|
||||
assert result.status
|
||||
assert result.value == 'a'
|
||||
|
||||
|
||||
def test_i_can_evaluate_longer_chains_2():
|
||||
context = get_context()
|
||||
concept_a = context.sheerka.add_in_cache(Concept(name="a").init_key())
|
||||
context.sheerka.add_in_cache(Concept(name="b", body="a").init_key())
|
||||
context.sheerka.add_in_cache(Concept(name="c", body="b").init_key())
|
||||
concept_d = context.sheerka.add_in_cache(Concept(name="d", body="c").init_key())
|
||||
|
||||
evaluator = ConceptEvaluator()
|
||||
item = get_return_value(concept_d)
|
||||
result = evaluator.eval(context, item)
|
||||
|
||||
assert result.status
|
||||
assert result.value == concept_a
|
||||
|
||||
|
||||
def test_i_can_recognize_concept_properties():
|
||||
"""
|
||||
The concept 'plus' has some properties.
|
||||
Let's check if they are recognized as concepts
|
||||
:return:
|
||||
"""
|
||||
context = get_context()
|
||||
concept_one = context.sheerka.add_in_cache(Concept(name="one").init_key())
|
||||
concept_two = context.sheerka.add_in_cache(Concept(name="two").init_key())
|
||||
concept_plus = context.sheerka.add_in_cache(Concept(name="a plus b")
|
||||
.set_prop("a", "one")
|
||||
.set_prop("b", "two").init_key())
|
||||
|
||||
evaluator = ConceptEvaluator()
|
||||
item = get_return_value(concept_plus)
|
||||
result = evaluator.eval(context, item)
|
||||
|
||||
assert result.status
|
||||
assert context.sheerka.isinstance(result.value, concept_plus)
|
||||
assert result.value.props["a"].value == concept_one
|
||||
assert result.value.props["b"].value == concept_two
|
||||
|
||||
|
||||
def test_i_can_recognize_concept_properties_with_body():
|
||||
"""
|
||||
The concept 'plus' has some properties.
|
||||
Let's check if they are recognized as concepts with Python code
|
||||
:return:
|
||||
"""
|
||||
context = get_context()
|
||||
context.sheerka.add_in_cache(Concept(name="one", body="1").init_key())
|
||||
context.sheerka.add_in_cache(Concept(name="two", body="2").init_key())
|
||||
concept_plus = context.sheerka.add_in_cache(Concept(name="a plus b")
|
||||
.set_prop("a", "one")
|
||||
.set_prop("b", "two").init_key())
|
||||
|
||||
evaluator = ConceptEvaluator()
|
||||
item = get_return_value(concept_plus)
|
||||
result = evaluator.eval(context, item)
|
||||
|
||||
assert result.status
|
||||
assert context.sheerka.isinstance(result.value, concept_plus)
|
||||
assert result.value.props["a"].value == 1
|
||||
assert result.value.props["b"].value == 2
|
||||
|
||||
|
||||
def test_i_can_recognize_concept_properties_with_body_when_concept_has_a_body():
|
||||
context = get_context()
|
||||
context.sheerka.add_in_cache(Concept(name="one", body="1").init_key())
|
||||
context.sheerka.add_in_cache(Concept(name="two", body="2").init_key())
|
||||
concept_plus = context.sheerka.add_in_cache(Concept(name="a plus b", body="a + b")
|
||||
.set_prop("a", "one")
|
||||
.set_prop("b", "two").init_key())
|
||||
|
||||
evaluator = ConceptEvaluator()
|
||||
item = get_return_value(concept_plus)
|
||||
result = evaluator.eval(context, item)
|
||||
|
||||
assert result.status
|
||||
assert result.value == 3
|
||||
assert not result.status
|
||||
assert context.sheerka.isinstance(result.value, BuiltinConcepts.NOT_FOR_ME)
|
||||
|
||||
|
||||
def test_i_cannot_recognize_a_concept_if_one_of_the_prop_is_unknown():
|
||||
@@ -203,7 +100,19 @@ def test_i_cannot_recognize_a_concept_if_one_of_the_prop_is_unknown():
|
||||
result = evaluator.eval(context, item)
|
||||
|
||||
assert not result.status
|
||||
assert context.sheerka.isinstance(result.value, BuiltinConcepts.PROPERTY_EVAL_ERROR)
|
||||
assert context.sheerka.isinstance(result.value, BuiltinConcepts.CONCEPT_EVAL_ERROR)
|
||||
assert result.value.property_name == "b"
|
||||
assert context.sheerka.isinstance(result.value.error, BuiltinConcepts.TOO_MANY_ERRORS)
|
||||
assert result.value.concept == concept_plus
|
||||
|
||||
|
||||
def test_that_error_concepts_are_transformed_into_errors_only_if_the_key_is_different():
|
||||
context = get_context()
|
||||
|
||||
error_concept = context.sheerka.new(BuiltinConcepts.ERROR)
|
||||
item = get_return_value(error_concept)
|
||||
result = ConceptEvaluator().eval(context, item)
|
||||
|
||||
assert not context.sheerka.is_success(error_concept) # it's indeed an error
|
||||
assert result.status
|
||||
assert result.value == error_concept
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept
|
||||
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
|
||||
from core.sheerka import Sheerka, ExecutionContext
|
||||
from core.concept import Concept
|
||||
from evaluators.PythonEvaluator import PythonEvaluator
|
||||
@@ -39,31 +39,79 @@ def test_i_can_eval(text, expected):
|
||||
assert evaluated.value == expected
|
||||
|
||||
|
||||
def test_i_can_eval_expression_with_variables():
|
||||
def test_i_can_eval_expression_that_references_concepts():
|
||||
context = get_context()
|
||||
context.sheerka.add_in_cache(Concept("foo"))
|
||||
|
||||
parsed = PythonParser().parse(context, "foo")
|
||||
evaluated = PythonEvaluator().eval(context, parsed)
|
||||
|
||||
assert evaluated.status
|
||||
assert evaluated.value == Concept("foo").init_key()
|
||||
|
||||
|
||||
def test_i_can_eval_expression_that_references_concepts_with_body():
|
||||
"""
|
||||
I can test expression with variables
|
||||
:return:
|
||||
"""
|
||||
context = get_context()
|
||||
context.sheerka.add_in_cache(Concept("foo", body="2"))
|
||||
parsed = PythonParser().parse(context, "foo + 2")
|
||||
|
||||
parsed = PythonParser().parse(context, "foo")
|
||||
evaluated = PythonEvaluator().eval(context, parsed)
|
||||
|
||||
assert evaluated.status
|
||||
assert evaluated.value == 4
|
||||
assert evaluated.value == 2
|
||||
|
||||
|
||||
def test_i_can_eval_module_with_variables():
|
||||
def test_i_can_eval_module_with_that_references_concepts():
|
||||
"""
|
||||
I can test modules with variables
|
||||
:return:
|
||||
"""
|
||||
context = get_context()
|
||||
context.sheerka.add_in_cache(Concept("foo"))
|
||||
|
||||
parsed = PythonParser().parse(context, "def a(b):\n return b\na(foo)")
|
||||
evaluated = PythonEvaluator().eval(context, parsed)
|
||||
|
||||
assert evaluated.status
|
||||
assert evaluated.value == Concept("foo").init_key()
|
||||
|
||||
|
||||
def test_i_can_eval_module_with_that_references_concepts_with_body():
|
||||
"""
|
||||
I can test modules with variables
|
||||
:return:
|
||||
"""
|
||||
context = get_context()
|
||||
context.sheerka.add_in_cache(Concept("foo", body="2"))
|
||||
parsed = PythonParser().parse(context, "def a(b):\n return b\na(foo)")
|
||||
|
||||
parsed = PythonParser().parse(context, "def a(b):\n return b\na(foo)")
|
||||
evaluated = PythonEvaluator().eval(context, parsed)
|
||||
|
||||
assert evaluated.status
|
||||
assert evaluated.value == 2
|
||||
|
||||
|
||||
def test_i_can_eval_concept_with_props():
|
||||
context = get_context()
|
||||
context.sheerka.add_in_cache(Concept("foo").set_prop("prop", "'a'"))
|
||||
|
||||
parsed = PythonParser().parse(context, "foo")
|
||||
evaluated = PythonEvaluator().eval(context, parsed)
|
||||
|
||||
assert evaluated.status
|
||||
assert evaluated.value == Concept("foo").set_prop("prop", "a").init_key() # evaluated version of foo
|
||||
|
||||
|
||||
def test_i_cannot_eval_when_body_references_unknown_concept():
|
||||
context = get_context()
|
||||
context.sheerka.add_in_cache(Concept("foo", body="bar"))
|
||||
|
||||
parsed = PythonParser().parse(context, "foo")
|
||||
evaluated = PythonEvaluator().eval(context, parsed)
|
||||
|
||||
assert not evaluated.status
|
||||
assert context.sheerka.isinstance(evaluated.value, BuiltinConcepts.ERROR)
|
||||
|
||||
@@ -46,12 +46,11 @@ def test_i_can_use_expect_when_only_errors_1():
|
||||
sheerka = get_sheerka()
|
||||
|
||||
items = [
|
||||
ReturnValueConcept("who", False, None),
|
||||
ReturnValueConcept("who", False, sheerka.new(BuiltinConcepts.ERROR)),
|
||||
]
|
||||
res = core.builtin_helpers.expect_one(get_context(sheerka), items)
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.value, BuiltinConcepts.TOO_MANY_ERRORS)
|
||||
assert res.value.body == items
|
||||
assert res.value, items[0]
|
||||
assert res.parents == items
|
||||
|
||||
|
||||
|
||||
+226
-339
@@ -30,6 +30,32 @@ def init_test():
|
||||
os.chdir(current_pwd)
|
||||
|
||||
|
||||
def get_sheerka(use_dict=True, skip_builtins_in_db=True):
|
||||
root = "mem://" if use_dict else root_folder
|
||||
sheerka = Sheerka(skip_builtins_in_db=skip_builtins_in_db)
|
||||
sheerka.initialize(root)
|
||||
|
||||
return sheerka
|
||||
|
||||
|
||||
def get_context(sheerka):
|
||||
return ExecutionContext("test", "xxx", sheerka)
|
||||
|
||||
|
||||
def get_default_concept():
|
||||
concept = Concept(
|
||||
name="a + b",
|
||||
where="isinstance(a, int) and isinstance(b, int)",
|
||||
pre="isinstance(a, int) and isinstance(b, int)",
|
||||
post="isinstance(res, int)",
|
||||
body="def func(x,y):\n return x+y\nfunc(a,b)",
|
||||
desc="specific description")
|
||||
concept.set_prop("a", "value1")
|
||||
concept.set_prop("b", "value2")
|
||||
|
||||
return concept
|
||||
|
||||
|
||||
class ConceptWithGetValue(Concept):
|
||||
def get_value(self):
|
||||
return self.get_prop("my_prop")
|
||||
@@ -260,7 +286,7 @@ def test_instances_are_different_when_asking_for_new():
|
||||
|
||||
def test_i_get_the_same_instance_when_is_unique_is_true():
|
||||
sheerka = get_sheerka()
|
||||
concept = get_unique_concept()
|
||||
concept = Concept(name="unique", is_unique=True)
|
||||
sheerka.create_new_concept(get_context(sheerka), concept)
|
||||
|
||||
new1 = sheerka.new(concept.key, a=10, b="value")
|
||||
@@ -320,389 +346,250 @@ def test_list_of_concept_is_sorted_by_id():
|
||||
assert concepts[0].id < concepts[-1].id
|
||||
|
||||
|
||||
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
#
|
||||
# E V A L U A T I O N S
|
||||
#
|
||||
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
@pytest.mark.parametrize("text, expected", [
|
||||
("1 + 1", 2),
|
||||
("sheerka.test()", 'I have access to Sheerka !')
|
||||
@pytest.mark.parametrize("body, expected", [
|
||||
(None, None),
|
||||
("", ""),
|
||||
("1", 1),
|
||||
("1+1", 2),
|
||||
("'one'", "one"),
|
||||
("'one' + 'two'", "onetwo"),
|
||||
("True", True),
|
||||
("1 > 2", False),
|
||||
])
|
||||
def test_i_can_eval_python_expressions_with_no_variable(text, expected):
|
||||
def test_i_can_evaluate_a_concept_with_simple_body(body, expected):
|
||||
sheerka = get_sheerka()
|
||||
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
concept = Concept("foo", body=body).init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value == expected
|
||||
assert evaluated.key == concept.key
|
||||
assert evaluated.body == expected
|
||||
assert evaluated.metadata.pre is None
|
||||
assert evaluated.metadata.post is None
|
||||
assert evaluated.metadata.where is None
|
||||
assert evaluated.props == {}
|
||||
assert evaluated.metadata.is_evaluated
|
||||
|
||||
|
||||
def test_i_can_eval_concept_with_python_body():
|
||||
sheerka = get_sheerka()
|
||||
concept = Concept(name="one", body="1")
|
||||
sheerka.add_in_cache(concept)
|
||||
|
||||
text = "one"
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value == 1
|
||||
|
||||
|
||||
def test_i_can_eval_concept_with_concept_body():
|
||||
sheerka = get_sheerka()
|
||||
concept_one = Concept(name="one")
|
||||
concept_un = Concept(name="un", body="one")
|
||||
sheerka.add_in_cache(concept_one)
|
||||
sheerka.add_in_cache(concept_un)
|
||||
|
||||
res = sheerka.evaluate_user_input("un")
|
||||
return_value = res[0].value
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(return_value, concept_one)
|
||||
|
||||
|
||||
def test_i_can_eval_concept_with_no_body():
|
||||
sheerka = get_sheerka()
|
||||
concept = Concept(name="one")
|
||||
sheerka.add_in_cache(concept)
|
||||
|
||||
text = "one"
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value == concept
|
||||
assert id(res[0].value) != id(concept)
|
||||
|
||||
|
||||
def test_is_unique_property_is_used_when_evaluating():
|
||||
sheerka = get_sheerka()
|
||||
concept = Concept(name="one", is_unique=True)
|
||||
sheerka.add_in_cache(concept)
|
||||
|
||||
text = "one"
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value == concept
|
||||
assert id(res[0].value) == id(concept)
|
||||
|
||||
|
||||
def test_i_can_eval_def_concept_request():
|
||||
text = """
|
||||
def concept a + b
|
||||
where isinstance(a, int) and isinstance(b, int)
|
||||
pre isinstance(a, int) and isinstance(b, int)
|
||||
post isinstance(res, int)
|
||||
as:
|
||||
def func(x,y):
|
||||
return x+y
|
||||
func(a,b)
|
||||
@pytest.mark.parametrize("expr, expected", [
|
||||
("", ""),
|
||||
("1", 1),
|
||||
("1+1", 2),
|
||||
("'one'", "one"),
|
||||
("'one' + 'two'", "onetwo"),
|
||||
("True", True),
|
||||
("1 > 2", False),
|
||||
])
|
||||
def test_i_can_evaluate_the_other_metadata(expr, expected):
|
||||
"""
|
||||
I only test WHERE, it's the same for the others
|
||||
:param expr:
|
||||
:param expected:
|
||||
:return:
|
||||
"""
|
||||
|
||||
expected = get_default_concept()
|
||||
expected.metadata.id = "1001"
|
||||
expected.metadata.desc = None
|
||||
expected.init_key()
|
||||
|
||||
sheerka = get_sheerka()
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
|
||||
concept = Concept("foo", where=expr).init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
|
||||
concept_saved = res[0].value.body
|
||||
|
||||
for prop in PROPERTIES_TO_SERIALIZE:
|
||||
assert getattr(concept_saved.metadata, prop) == getattr(expected.metadata, prop)
|
||||
|
||||
assert concept_saved.key in sheerka.concepts_cache
|
||||
assert sheerka.sdp.io.exists(
|
||||
sheerka.sdp.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, concept_saved.get_digest()))
|
||||
assert evaluated.key == concept.key
|
||||
assert evaluated.body is None
|
||||
assert evaluated.metadata.pre is None
|
||||
assert evaluated.metadata.post is None
|
||||
assert evaluated.metadata.where == expected
|
||||
assert evaluated.props == {}
|
||||
assert evaluated.metadata.is_evaluated
|
||||
|
||||
|
||||
def test_i_can_eval_def_concept_part_when_one_part_is_a_ref_of_another_concept():
|
||||
@pytest.mark.parametrize("expr, expected", [
|
||||
(None, None),
|
||||
("", ""),
|
||||
("1", 1),
|
||||
("1+1", 2),
|
||||
("'one'", "one"),
|
||||
("'one' + 'two'", "onetwo"),
|
||||
("True", True),
|
||||
("1 > 2", False),
|
||||
])
|
||||
def test_i_can_evaluate_a_concept_with_prop(expr, expected):
|
||||
sheerka = get_sheerka()
|
||||
|
||||
concept = Concept("foo").set_prop("a", expr).init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
|
||||
assert evaluated.key == concept.key
|
||||
assert evaluated.body is None
|
||||
assert evaluated.metadata.pre is None
|
||||
assert evaluated.metadata.post is None
|
||||
assert evaluated.metadata.where is None
|
||||
assert evaluated.props == {"a": Property("a", expected)}
|
||||
assert evaluated.metadata.is_evaluated
|
||||
|
||||
|
||||
def test_props_are_evaluated_before_body():
|
||||
sheerka = get_sheerka()
|
||||
|
||||
concept = Concept("foo", body="a+1").set_prop("a", "10").init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
|
||||
assert evaluated.key == concept.key
|
||||
assert evaluated.body == 11
|
||||
|
||||
|
||||
def test_i_can_evaluate_when_another_concept_is_referenced():
|
||||
sheerka = get_sheerka()
|
||||
concept_a = Concept("a")
|
||||
sheerka.add_in_cache(concept_a)
|
||||
|
||||
concept = Concept("foo", body="a").init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
|
||||
assert evaluated.key == concept.key
|
||||
assert sheerka.isinstance(evaluated.body, concept_a)
|
||||
assert id(evaluated.body) != id(concept_a)
|
||||
assert evaluated.metadata.is_evaluated
|
||||
|
||||
|
||||
def test_i_can_evaluate_when_the_referenced_concept_has_a_body():
|
||||
sheerka = get_sheerka()
|
||||
concept_a = Concept("a", body="1")
|
||||
sheerka.add_in_cache(concept_a)
|
||||
|
||||
concept = Concept("foo", body="a").init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
|
||||
assert evaluated.key == concept.key
|
||||
assert evaluated.body == 1
|
||||
assert not concept_a.metadata.is_evaluated #
|
||||
|
||||
|
||||
def test_i_can_evaluate_concept_of_concept_when_the_leaf_has_a_body():
|
||||
sheerka = get_sheerka()
|
||||
sheerka.add_in_cache(Concept(name="a", body="'a'").init_key())
|
||||
sheerka.add_in_cache(Concept(name="b", body="a").init_key())
|
||||
sheerka.add_in_cache(Concept(name="c", body="b").init_key())
|
||||
concept_d = sheerka.add_in_cache(Concept(name="d", body="c").init_key())
|
||||
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept_d)
|
||||
|
||||
assert evaluated.key == concept_d.key
|
||||
assert evaluated.body == 'a'
|
||||
|
||||
|
||||
def test_i_can_evaluate_concept_of_concept_does_not_have_a_body():
|
||||
sheerka = get_sheerka()
|
||||
concept_a = sheerka.add_in_cache(Concept(name="a").init_key())
|
||||
sheerka.add_in_cache(Concept(name="b", body="a").init_key())
|
||||
sheerka.add_in_cache(Concept(name="c", body="b").init_key())
|
||||
concept_d = sheerka.add_in_cache(Concept(name="d", body="c").init_key())
|
||||
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept_d)
|
||||
|
||||
assert evaluated.key == concept_d.key
|
||||
assert sheerka.isinstance(evaluated.body, concept_a)
|
||||
|
||||
|
||||
def test_i_can_evaluate_concept_when_properties_reference_others_concepts():
|
||||
sheerka = get_sheerka()
|
||||
concept_a = sheerka.add_in_cache(Concept(name="a").init_key())
|
||||
|
||||
concept = Concept("foo", body="a").set_prop("a", "a").init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
|
||||
assert evaluated.key == concept.key
|
||||
assert evaluated.body == concept_a
|
||||
|
||||
|
||||
def test_i_can_evaluate_concept_when_properties_reference_others_concepts_2():
|
||||
"""
|
||||
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
|
||||
Same test,
|
||||
but the name of the property and the name of the concept are different
|
||||
:return:
|
||||
"""
|
||||
sheerka = get_sheerka()
|
||||
concept_a = sheerka.add_in_cache(Concept(name="a").init_key())
|
||||
|
||||
# concept 'a plus b' is known
|
||||
concept_a_plus_b = Concept(name="a plus b").set_prop("a").set_prop("b")
|
||||
sheerka.add_in_cache(concept_a_plus_b)
|
||||
concept = Concept("foo", body="concept_a").set_prop("concept_a", "a").init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
|
||||
res = sheerka.evaluate_user_input("def concept a xx b as a plus b")
|
||||
expected = Concept(name="a xx b", body="a plus b").set_prop("a").set_prop("b").init_key()
|
||||
expected.metadata.id = "1001"
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
|
||||
|
||||
concept_saved = res[0].value.body
|
||||
|
||||
for prop in PROPERTIES_TO_SERIALIZE:
|
||||
assert getattr(concept_saved.metadata, prop) == getattr(expected.metadata, prop)
|
||||
|
||||
assert concept_saved.key in sheerka.concepts_cache
|
||||
assert sheerka.sdp.io.exists(
|
||||
sheerka.sdp.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, concept_saved.get_digest()))
|
||||
assert evaluated.key == concept.key
|
||||
assert evaluated.body == concept_a
|
||||
|
||||
|
||||
def test_i_cannot_eval_the_same_def_concept_twice():
|
||||
text = """
|
||||
def concept a + b
|
||||
where isinstance(a, int) and isinstance(b, int)
|
||||
pre isinstance(a, int) and isinstance(b, int)
|
||||
post isinstance(res, int)
|
||||
as:
|
||||
def func(x,y):
|
||||
return x+y
|
||||
func(a,b)
|
||||
"""
|
||||
|
||||
def test_i_can_evaluate_concept_when_properties_reference_others_concepts_with_body():
|
||||
sheerka = get_sheerka()
|
||||
sheerka.evaluate_user_input(text)
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
sheerka.add_in_cache(Concept(name="a", body="1").init_key())
|
||||
sheerka.add_in_cache(Concept(name="b", body="2").init_key())
|
||||
|
||||
assert len(res) == 1
|
||||
assert not res[0].status
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.CONCEPT_ALREADY_DEFINED)
|
||||
concept = Concept("foo", body="propA + propB").set_prop("propA", "a").set_prop("propB", "b").init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
|
||||
assert evaluated.key == concept.key
|
||||
assert evaluated.body == 3
|
||||
|
||||
|
||||
def test_i_can_disable_an_evaluator():
|
||||
sheerka = get_sheerka()
|
||||
concept = Concept(name="one", body="1")
|
||||
sheerka.add_in_cache(concept)
|
||||
|
||||
text = "one"
|
||||
p = next(e for e in sheerka.evaluators if e.__name__ == "PythonEvaluator")
|
||||
p.enabled = False # not that you disable the class, not the instance
|
||||
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.PARSER_RESULT)
|
||||
|
||||
p.enabled = True # put back for the remaining unit tests
|
||||
|
||||
|
||||
@pytest.mark.parametrize("text", [
|
||||
"",
|
||||
" ",
|
||||
"\n",
|
||||
])
|
||||
def test_i_can_eval_a_empty_input(text):
|
||||
def test_i_can_reference_sheerka():
|
||||
sheerka = get_sheerka()
|
||||
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
concept = Concept("foo", body="sheerka.test()").init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NOP)
|
||||
assert evaluated.key == concept.key
|
||||
assert evaluated.body == sheerka.test()
|
||||
|
||||
|
||||
def test_i_can_eval_concept_with_variable():
|
||||
def test_properties_values_takes_precedence_over_the_outside_world():
|
||||
sheerka = get_sheerka()
|
||||
concept_hello = Concept(name="hello a").set_prop("a")
|
||||
concept_foo = Concept(name="foo")
|
||||
sheerka.add_in_cache(concept_hello)
|
||||
sheerka.add_in_cache(concept_foo)
|
||||
sheerka.add_in_cache(Concept(name="a", body="'concept_a'").init_key())
|
||||
sheerka.add_in_cache(Concept(name="b", body="'concept_b'").init_key())
|
||||
|
||||
res = sheerka.evaluate_user_input("hello foo")
|
||||
return_value = res[0].value
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(return_value, concept_hello)
|
||||
assert return_value.props["a"].value == concept_foo
|
||||
concept = Concept("foo", body="a").init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
assert evaluated.key == concept.key
|
||||
assert evaluated.body == 'concept_a' # this test was already done
|
||||
|
||||
# so check this one.
|
||||
concept = Concept("foo", body="a").set_prop("a", "'property_a'").init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
assert evaluated.key == concept.key
|
||||
assert evaluated.body == 'property_a'
|
||||
|
||||
# or this one.
|
||||
concept = Concept("foo", body="a").set_prop("a", "b").init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
assert evaluated.key == concept.key
|
||||
assert evaluated.body == 'concept_b'
|
||||
|
||||
|
||||
def test_i_can_eval_concept_with_variable_and_python_as_body():
|
||||
def test_i_can_reference_sub_property_of_a_property():
|
||||
sheerka = get_sheerka()
|
||||
sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").set_prop("a"))
|
||||
sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
|
||||
sheerka.add_in_cache(Concept(name="concept_a").set_prop("subProp", "'sub_a'").init_key())
|
||||
|
||||
res = sheerka.evaluate_user_input("hello foo")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value, "hello foo"
|
||||
concept = Concept("foo", body="a.props['subProp'].value").set_prop("a", "concept_a").init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
assert evaluated.key == concept.key
|
||||
assert evaluated.body == 'sub_a'
|
||||
|
||||
|
||||
def test_i_can_eval_duplicate_concepts_with_same_value():
|
||||
def test_i_cannot_evaluate_concept_if_property_is_in_error():
|
||||
sheerka = get_sheerka()
|
||||
|
||||
sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").set_prop("a"))
|
||||
sheerka.add_in_cache(Concept(name="hello foo", body="'hello foo'"))
|
||||
sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
|
||||
|
||||
res = sheerka.evaluate_user_input("hello foo")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value, "hello foo"
|
||||
assert res[0].who == sheerka.get_evaluator_name(MultipleSameSuccessEvaluator.NAME)
|
||||
concept = Concept(name="concept_a").set_prop("subProp", "undef_concept").init_key()
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
|
||||
|
||||
|
||||
def test_i_cannot_manage_duplicate_concepts_when_the_values_are_different():
|
||||
def test_key_is_initialized_by_evaluation():
|
||||
sheerka = get_sheerka()
|
||||
|
||||
sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").set_prop("a"))
|
||||
sheerka.add_in_cache(Concept(name="hello foo", body="'hello foo'"))
|
||||
sheerka.add_in_cache(Concept(name="foo", body="'another value'"))
|
||||
concept = Concept("foo")
|
||||
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
|
||||
|
||||
res = sheerka.evaluate_user_input("hello foo")
|
||||
assert len(res) == 1
|
||||
assert not res[0].status
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.TOO_MANY_SUCCESS)
|
||||
|
||||
concepts = res[0].value.body
|
||||
assert len(concepts) == 2
|
||||
sorted_values = sorted(concepts, key=lambda x: x.value)
|
||||
assert sorted_values[0].value == "hello another value"
|
||||
assert sorted_values[1].value == "hello foo"
|
||||
assert evaluated.key == concept.init_key().key
|
||||
|
||||
|
||||
def test_i_can_manage_concepts_with_the_same_key_when_values_are_the_same():
|
||||
def test_builtin_error_concept_are_errors():
|
||||
# only test a random one, it will be the same for the others
|
||||
sheerka = get_sheerka()
|
||||
context = get_context(sheerka)
|
||||
|
||||
sheerka.create_new_concept(context, Concept(name="hello a", body="'hello ' + a").set_prop("a"))
|
||||
sheerka.create_new_concept(context, Concept(name="hello b", body="'hello ' + b").set_prop("b"))
|
||||
|
||||
res = sheerka.evaluate_user_input("hello 'foo'")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value == "hello foo"
|
||||
assert res[0].who == sheerka.get_evaluator_name(MultipleSameSuccessEvaluator.NAME)
|
||||
|
||||
|
||||
def test_i_can_create_concepts_with_python_code_as_body():
|
||||
sheerka = get_sheerka()
|
||||
context = get_context(sheerka)
|
||||
|
||||
sheerka.create_new_concept(context, Concept(name="concepts", body="sheerka.concepts()"))
|
||||
res = sheerka.evaluate_user_input("concepts")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert isinstance(res[0].value, list)
|
||||
|
||||
|
||||
def test_i_can_create_concept_with_bnf_definition():
|
||||
sheerka = get_sheerka(False, False)
|
||||
a = Concept("a")
|
||||
sheerka.add_in_cache(a)
|
||||
sheerka.concepts_definition_cache = {a: OrderedChoice("one", "two")}
|
||||
|
||||
res = sheerka.evaluate_user_input("def concept plus from bnf a ('plus' plus)?")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
|
||||
|
||||
saved_concept = sheerka.sdp.get_safe(sheerka.CONCEPTS_ENTRY, "plus")
|
||||
assert saved_concept.key == "plus"
|
||||
assert saved_concept.metadata.definition == "a ('plus' plus)?"
|
||||
assert "a" in saved_concept.props
|
||||
assert "plus" in saved_concept.props
|
||||
|
||||
saved_definitions = sheerka.sdp.get_safe(sheerka.CONCEPTS_DEFINITIONS_ENTRY)
|
||||
expected_bnf = Sequence(
|
||||
ConceptMatch("a", rule_name="a"),
|
||||
Optional(Sequence(StrMatch("plus"), ConceptMatch("plus", rule_name="plus"))))
|
||||
assert saved_definitions[saved_concept] == expected_bnf
|
||||
|
||||
new_concept = res[0].value.body
|
||||
assert new_concept.metadata.name == "plus"
|
||||
assert new_concept.metadata.definition == "a ('plus' plus)?"
|
||||
assert new_concept.bnf == expected_bnf
|
||||
assert "a" in new_concept.props
|
||||
assert "plus" in new_concept.props
|
||||
|
||||
|
||||
def test_i_can_eval_bnf_definitions():
|
||||
sheerka = get_sheerka()
|
||||
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' | 'two'")[0].body.body
|
||||
|
||||
res = sheerka.evaluate_user_input("one")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, concept_a)
|
||||
|
||||
|
||||
def test_i_can_eval_bnf_definitions_with_variables():
|
||||
sheerka = 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
|
||||
|
||||
res = sheerka.evaluate_user_input("one three")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
return_value = res[0].value
|
||||
|
||||
assert sheerka.isinstance(return_value, concept_b)
|
||||
assert return_value.props["a"] == Property("a", sheerka.new(concept_a.key, body="one"))
|
||||
|
||||
|
||||
def test_i_can_eval_bnf_definitions_from_separate_instances():
|
||||
"""
|
||||
Same test then before,
|
||||
but make sure that the BNF are correctly persisted and loaded
|
||||
"""
|
||||
sheerka = get_sheerka(False)
|
||||
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' 'two'")[0].body.body
|
||||
|
||||
res = get_sheerka(False).evaluate_user_input("one two")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, concept_a)
|
||||
|
||||
# add another bnf definition
|
||||
concept_b = sheerka.evaluate_user_input("def concept b from bnf a 'three'")[0].body.body
|
||||
|
||||
res = get_sheerka(False).evaluate_user_input("one two") # previous one still works
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, concept_a)
|
||||
|
||||
res = get_sheerka(False).evaluate_user_input("one two three") # new one works
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, concept_b)
|
||||
|
||||
|
||||
def get_sheerka(use_dict=True, skip_builtins_in_db=True):
|
||||
root = "mem://" if use_dict else root_folder
|
||||
sheerka = Sheerka(skip_builtins_in_db=skip_builtins_in_db)
|
||||
sheerka.initialize(root)
|
||||
|
||||
return sheerka
|
||||
|
||||
|
||||
def get_context(sheerka):
|
||||
return ExecutionContext("test", "xxx", sheerka)
|
||||
|
||||
|
||||
def get_default_concept():
|
||||
concept = Concept(
|
||||
name="a + b",
|
||||
where="isinstance(a, int) and isinstance(b, int)",
|
||||
pre="isinstance(a, int) and isinstance(b, int)",
|
||||
post="isinstance(res, int)",
|
||||
body="def func(x,y):\n return x+y\nfunc(a,b)",
|
||||
desc="specific description")
|
||||
concept.set_prop("a", "value1")
|
||||
concept.set_prop("b", "value2")
|
||||
|
||||
return concept
|
||||
|
||||
|
||||
def get_unique_concept():
|
||||
return Concept(name="unique", is_unique=True)
|
||||
assert not sheerka.is_success(sheerka.new(BuiltinConcepts.TOO_MANY_SUCCESS))
|
||||
|
||||
@@ -0,0 +1,408 @@
|
||||
import pytest
|
||||
import os
|
||||
from os import path
|
||||
import shutil
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept
|
||||
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, Property
|
||||
from core.sheerka import Sheerka, ExecutionContext
|
||||
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
|
||||
from parsers.ConceptLexerParser import Sequence, ZeroOrMore, StrMatch, OrderedChoice, Optional, ConceptMatch, \
|
||||
ConceptLexerParser
|
||||
from sdp.sheerkaDataProvider import SheerkaDataProvider
|
||||
|
||||
tests_root = path.abspath("../build/tests")
|
||||
root_folder = "init_folder"
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def init_test():
|
||||
if path.exists(tests_root):
|
||||
shutil.rmtree(tests_root)
|
||||
|
||||
if not path.exists(tests_root):
|
||||
os.makedirs(tests_root)
|
||||
current_pwd = os.getcwd()
|
||||
os.chdir(tests_root)
|
||||
|
||||
yield None
|
||||
|
||||
os.chdir(current_pwd)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("text, expected", [
|
||||
("1 + 1", 2),
|
||||
("sheerka.test()", 'I have access to Sheerka !')
|
||||
])
|
||||
def test_i_can_eval_python_expressions_with_no_variable(text, expected):
|
||||
sheerka = get_sheerka()
|
||||
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value == expected
|
||||
|
||||
|
||||
def test_i_can_eval_concept_with_python_body():
|
||||
sheerka = get_sheerka()
|
||||
concept = Concept(name="one", body="1")
|
||||
sheerka.add_in_cache(concept)
|
||||
|
||||
text = "one"
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value == 1
|
||||
|
||||
|
||||
def test_i_can_eval_concept_with_concept_body():
|
||||
sheerka = get_sheerka()
|
||||
concept_one = Concept(name="one")
|
||||
concept_un = Concept(name="un", body="one")
|
||||
sheerka.add_in_cache(concept_one)
|
||||
sheerka.add_in_cache(concept_un)
|
||||
|
||||
res = sheerka.evaluate_user_input("un")
|
||||
return_value = res[0].value
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(return_value, concept_one)
|
||||
|
||||
|
||||
def test_i_can_eval_concept_with_no_body():
|
||||
sheerka = get_sheerka()
|
||||
concept = Concept(name="one")
|
||||
sheerka.add_in_cache(concept)
|
||||
|
||||
text = "one"
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value == concept
|
||||
assert id(res[0].value) != id(concept)
|
||||
|
||||
|
||||
def test_is_unique_property_is_used_when_evaluating():
|
||||
sheerka = get_sheerka()
|
||||
concept = Concept(name="one", is_unique=True)
|
||||
sheerka.add_in_cache(concept)
|
||||
|
||||
text = "one"
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value == concept
|
||||
assert id(res[0].value) == id(concept)
|
||||
|
||||
|
||||
def test_i_can_eval_def_concept_request():
|
||||
text = """
|
||||
def concept a + b
|
||||
where isinstance(a, int) and isinstance(b, int)
|
||||
pre isinstance(a, int) and isinstance(b, int)
|
||||
post isinstance(res, int)
|
||||
as:
|
||||
def func(x,y):
|
||||
return x+y
|
||||
func(a,b)
|
||||
"""
|
||||
|
||||
expected = get_default_concept()
|
||||
expected.metadata.id = "1001"
|
||||
expected.metadata.desc = None
|
||||
expected.init_key()
|
||||
|
||||
sheerka = get_sheerka()
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
|
||||
|
||||
concept_saved = res[0].value.body
|
||||
|
||||
for prop in PROPERTIES_TO_SERIALIZE:
|
||||
assert getattr(concept_saved.metadata, prop) == getattr(expected.metadata, prop)
|
||||
|
||||
assert concept_saved.key in sheerka.concepts_cache
|
||||
assert sheerka.sdp.io.exists(
|
||||
sheerka.sdp.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, concept_saved.get_digest()))
|
||||
|
||||
|
||||
def test_i_can_eval_def_concept_part_when_one_part_is_a_ref_of_another_concept():
|
||||
"""
|
||||
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
|
||||
:return:
|
||||
"""
|
||||
sheerka = get_sheerka()
|
||||
|
||||
# concept 'a plus b' is known
|
||||
concept_a_plus_b = Concept(name="a plus b").set_prop("a").set_prop("b")
|
||||
sheerka.add_in_cache(concept_a_plus_b)
|
||||
|
||||
res = sheerka.evaluate_user_input("def concept a xx b as a plus b")
|
||||
expected = Concept(name="a xx b", body="a plus b").set_prop("a").set_prop("b").init_key()
|
||||
expected.metadata.id = "1001"
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
|
||||
|
||||
concept_saved = res[0].value.body
|
||||
|
||||
for prop in PROPERTIES_TO_SERIALIZE:
|
||||
assert getattr(concept_saved.metadata, prop) == getattr(expected.metadata, prop)
|
||||
|
||||
assert concept_saved.key in sheerka.concepts_cache
|
||||
assert sheerka.sdp.io.exists(
|
||||
sheerka.sdp.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, concept_saved.get_digest()))
|
||||
|
||||
|
||||
def test_i_cannot_eval_the_same_def_concept_twice():
|
||||
text = """
|
||||
def concept a + b
|
||||
where isinstance(a, int) and isinstance(b, int)
|
||||
pre isinstance(a, int) and isinstance(b, int)
|
||||
post isinstance(res, int)
|
||||
as:
|
||||
def func(x,y):
|
||||
return x+y
|
||||
func(a,b)
|
||||
"""
|
||||
|
||||
sheerka = get_sheerka()
|
||||
sheerka.evaluate_user_input(text)
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
|
||||
assert len(res) == 1
|
||||
assert not res[0].status
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.CONCEPT_ALREADY_DEFINED)
|
||||
|
||||
|
||||
def test_i_can_disable_an_evaluator():
|
||||
sheerka = get_sheerka()
|
||||
concept = Concept(name="one", body="1")
|
||||
sheerka.add_in_cache(concept)
|
||||
|
||||
text = "one"
|
||||
p = next(e for e in sheerka.evaluators if e.__name__ == "PythonEvaluator")
|
||||
p.enabled = False # not that you disable the class, not the instance
|
||||
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.PARSER_RESULT)
|
||||
|
||||
p.enabled = True # put back for the remaining unit tests
|
||||
|
||||
|
||||
@pytest.mark.parametrize("text", [
|
||||
"",
|
||||
" ",
|
||||
"\n",
|
||||
])
|
||||
def test_i_can_eval_a_empty_input(text):
|
||||
sheerka = get_sheerka()
|
||||
|
||||
res = sheerka.evaluate_user_input(text)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NOP)
|
||||
|
||||
|
||||
def test_i_can_eval_concept_with_variable():
|
||||
sheerka = get_sheerka()
|
||||
concept_hello = Concept(name="hello a").set_prop("a")
|
||||
concept_foo = Concept(name="foo")
|
||||
sheerka.add_in_cache(concept_hello)
|
||||
sheerka.add_in_cache(concept_foo)
|
||||
|
||||
res = sheerka.evaluate_user_input("hello foo")
|
||||
return_value = res[0].value
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(return_value, concept_hello)
|
||||
assert return_value.props["a"].value == concept_foo
|
||||
|
||||
|
||||
def test_i_can_eval_concept_with_variable_and_python_as_body():
|
||||
sheerka = get_sheerka()
|
||||
sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").set_prop("a"))
|
||||
sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
|
||||
|
||||
res = sheerka.evaluate_user_input("hello foo")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value, "hello foo"
|
||||
|
||||
|
||||
def test_i_can_eval_duplicate_concepts_with_same_value():
|
||||
sheerka = get_sheerka()
|
||||
|
||||
sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").set_prop("a"))
|
||||
sheerka.add_in_cache(Concept(name="hello foo", body="'hello foo'"))
|
||||
sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
|
||||
|
||||
res = sheerka.evaluate_user_input("hello foo")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value, "hello foo"
|
||||
assert res[0].who == sheerka.get_evaluator_name(MultipleSameSuccessEvaluator.NAME)
|
||||
|
||||
|
||||
def test_i_cannot_manage_duplicate_concepts_when_the_values_are_different():
|
||||
sheerka = get_sheerka()
|
||||
|
||||
sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").set_prop("a"))
|
||||
sheerka.add_in_cache(Concept(name="hello foo", body="'hello foo'"))
|
||||
sheerka.add_in_cache(Concept(name="foo", body="'another value'"))
|
||||
|
||||
res = sheerka.evaluate_user_input("hello foo")
|
||||
assert len(res) == 1
|
||||
assert not res[0].status
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.TOO_MANY_SUCCESS)
|
||||
|
||||
concepts = res[0].value.body
|
||||
assert len(concepts) == 2
|
||||
sorted_values = sorted(concepts, key=lambda x: x.value)
|
||||
assert sorted_values[0].value == "hello another value"
|
||||
assert sorted_values[1].value == "hello foo"
|
||||
|
||||
|
||||
def test_i_can_manage_concepts_with_the_same_key_when_values_are_the_same():
|
||||
sheerka = get_sheerka()
|
||||
context = get_context(sheerka)
|
||||
|
||||
sheerka.create_new_concept(context, Concept(name="hello a", body="'hello ' + a").set_prop("a"))
|
||||
sheerka.create_new_concept(context, Concept(name="hello b", body="'hello ' + b").set_prop("b"))
|
||||
|
||||
res = sheerka.evaluate_user_input("hello 'foo'")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value == "hello foo"
|
||||
assert res[0].who == sheerka.get_evaluator_name(MultipleSameSuccessEvaluator.NAME)
|
||||
|
||||
|
||||
def test_i_can_create_concepts_with_python_code_as_body():
|
||||
sheerka = get_sheerka()
|
||||
context = get_context(sheerka)
|
||||
|
||||
sheerka.create_new_concept(context, Concept(name="concepts", body="sheerka.concepts()"))
|
||||
res = sheerka.evaluate_user_input("concepts")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert isinstance(res[0].value, list)
|
||||
|
||||
|
||||
def test_i_can_create_concept_with_bnf_definition():
|
||||
sheerka = get_sheerka(False, False)
|
||||
a = Concept("a")
|
||||
sheerka.add_in_cache(a)
|
||||
sheerka.concepts_definition_cache = {a: OrderedChoice("one", "two")}
|
||||
|
||||
res = sheerka.evaluate_user_input("def concept plus from bnf a ('plus' plus)?")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
|
||||
|
||||
saved_concept = sheerka.sdp.get_safe(sheerka.CONCEPTS_ENTRY, "plus")
|
||||
assert saved_concept.key == "plus"
|
||||
assert saved_concept.metadata.definition == "a ('plus' plus)?"
|
||||
assert "a" in saved_concept.props
|
||||
assert "plus" in saved_concept.props
|
||||
|
||||
saved_definitions = sheerka.sdp.get_safe(sheerka.CONCEPTS_DEFINITIONS_ENTRY)
|
||||
expected_bnf = Sequence(
|
||||
ConceptMatch("a", rule_name="a"),
|
||||
Optional(Sequence(StrMatch("plus"), ConceptMatch("plus", rule_name="plus"))))
|
||||
assert saved_definitions[saved_concept] == expected_bnf
|
||||
|
||||
new_concept = res[0].value.body
|
||||
assert new_concept.metadata.name == "plus"
|
||||
assert new_concept.metadata.definition == "a ('plus' plus)?"
|
||||
assert new_concept.bnf == expected_bnf
|
||||
assert "a" in new_concept.props
|
||||
assert "plus" in new_concept.props
|
||||
|
||||
|
||||
def test_i_can_eval_bnf_definitions():
|
||||
sheerka = get_sheerka()
|
||||
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' | 'two'")[0].body.body
|
||||
|
||||
res = sheerka.evaluate_user_input("one")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, concept_a)
|
||||
|
||||
|
||||
def test_i_can_eval_bnf_definitions_with_variables():
|
||||
sheerka = 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
|
||||
|
||||
res = sheerka.evaluate_user_input("one three")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
return_value = res[0].value
|
||||
|
||||
assert sheerka.isinstance(return_value, concept_b)
|
||||
assert return_value.props["a"] == Property("a", sheerka.new(concept_a.key, body="one"))
|
||||
|
||||
|
||||
def test_i_can_eval_bnf_definitions_from_separate_instances():
|
||||
"""
|
||||
Same test then before,
|
||||
but make sure that the BNF are correctly persisted and loaded
|
||||
"""
|
||||
sheerka = get_sheerka(False)
|
||||
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' 'two'")[0].body.body
|
||||
|
||||
res = get_sheerka(False).evaluate_user_input("one two")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, concept_a)
|
||||
|
||||
# add another bnf definition
|
||||
concept_b = sheerka.evaluate_user_input("def concept b from bnf a 'three'")[0].body.body
|
||||
|
||||
res = get_sheerka(False).evaluate_user_input("one two") # previous one still works
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, concept_a)
|
||||
|
||||
res = get_sheerka(False).evaluate_user_input("one two three") # new one works
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].value, concept_b)
|
||||
|
||||
|
||||
def get_sheerka(use_dict=True, skip_builtins_in_db=True):
|
||||
root = "mem://" if use_dict else root_folder
|
||||
sheerka = Sheerka(skip_builtins_in_db=skip_builtins_in_db)
|
||||
sheerka.initialize(root)
|
||||
|
||||
return sheerka
|
||||
|
||||
|
||||
def get_context(sheerka):
|
||||
return ExecutionContext("test", "xxx", sheerka)
|
||||
|
||||
|
||||
def get_default_concept():
|
||||
concept = Concept(
|
||||
name="a + b",
|
||||
where="isinstance(a, int) and isinstance(b, int)",
|
||||
pre="isinstance(a, int) and isinstance(b, int)",
|
||||
post="isinstance(res, int)",
|
||||
body="def func(x,y):\n return x+y\nfunc(a,b)",
|
||||
desc="specific description")
|
||||
concept.set_prop("a", "value1")
|
||||
concept.set_prop("b", "value2")
|
||||
|
||||
return concept
|
||||
@@ -3,7 +3,7 @@ from core.tokenizer import Tokenizer, Token, TokenKind, LexerError, Keywords
|
||||
|
||||
|
||||
def test_i_can_tokenize():
|
||||
source = "+*-/{}[]() ,;:.?\n\n\r\r\r\nidentifier_0\t \t10.15 10 'string\n' \"another string\"=|&"
|
||||
source = "+*-/{}[]() ,;:.?\n\n\r\r\r\nidentifier_0\t \t10.15 10 'string\n' \"another string\"=|&<>"
|
||||
tokens = list(Tokenizer(source))
|
||||
assert tokens[0] == Token(TokenKind.PLUS, "+", 0, 1, 1)
|
||||
assert tokens[1] == Token(TokenKind.STAR, "*", 1, 1, 2)
|
||||
@@ -37,6 +37,8 @@ def test_i_can_tokenize():
|
||||
assert tokens[29] == Token(TokenKind.EQUALS, '=', 76, 6, 18)
|
||||
assert tokens[30] == Token(TokenKind.VBAR, '|', 77, 6, 19)
|
||||
assert tokens[31] == Token(TokenKind.AMPER, '&', 78, 6, 20)
|
||||
assert tokens[32] == Token(TokenKind.LESS, '<', 79, 6, 21)
|
||||
assert tokens[33] == Token(TokenKind.GREATER, '>', 80, 6, 22)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("text, expected", [
|
||||
|
||||
Reference in New Issue
Block a user