Added first implementation of concepts ambiguity resolution + Jenkins file test

This commit is contained in:
2020-07-15 18:29:43 +02:00
parent b768eaa95d
commit e84b394da2
42 changed files with 1130 additions and 313 deletions
+3 -3
View File
@@ -81,7 +81,7 @@ class BaseTest:
@staticmethod
def retval(obj, who="who", status=True):
"""ret_val"""
return ReturnValueConcept.ret(who, status, obj)
return ReturnValueConcept(who, status, obj)
@staticmethod
def tretval(sheerka, obj, who="who"):
@@ -93,11 +93,11 @@ class BaseTest:
return sheerka.ret(who, True, obj)
@staticmethod
def pretval(concept, source=None, parser="parsers.name", who="some_name"):
def pretval(concept, source=None, parser="parsers.name", who="some_name", status=True):
"""ParserResult ret_val (p stands for ParserResult)"""
return ReturnValueConcept(
who,
True,
status,
ParserResultConcept(parser=parser,
source=source or concept.name,
value=concept,
+175 -23
View File
@@ -1,6 +1,7 @@
import pytest
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, ParserResultConcept
from core.concept import Concept, DoNotResolve, ConceptParts, Property, InfiniteRecursionResolved, CB, NotInit
from core.sheerka.services.SheerkaEvaluateConcept import SheerkaEvaluateConcept
from parsers.PythonParser import PythonNode
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -50,16 +51,16 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
:return:
"""
sheerka, context, concept = self.init_concepts(Concept("foo", pre=expr))
sheerka, context, concept = self.init_concepts(Concept("foo", post=expr))
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.metadata.body is None
assert evaluated.metadata.pre == expr
assert evaluated.metadata.post is None
assert evaluated.metadata.post == expr
assert evaluated.metadata.pre is None
assert evaluated.metadata.where is None
assert evaluated.get_value(ConceptParts.PRE) == expected
assert evaluated.get_value(ConceptParts.POST) == expected
assert evaluated.variables() == {}
assert not evaluated.metadata.is_evaluated
assert len(evaluated.values) == 0 if expr is None else 1
@@ -353,27 +354,34 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
assert evaluated.key == concept.init_key().key
@pytest.mark.parametrize("where_clause, expected", [
("True", True),
("False", False),
("self < 10", False),
("self < 11", True),
("a < 20", False),
("a > 19", True),
("a + self > 20", True),
@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),
])
def test_i_can_evaluate_simple_where(self, where_clause, expected):
def test_i_can_evaluate_simple_where(self, where_clause, expected, 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"),
)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept, eval_body=False)
if expected:
assert evaluated.key == concept.key
assert concept.body == expected_body
else:
assert sheerka.isinstance(evaluated, BuiltinConcepts.WHERE_CLAUSE_FAILED)
assert evaluated.body == concept
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONDITION_FAILED)
assert evaluated.body == where_clause
assert evaluated.concept == concept
assert evaluated.prop == ConceptParts.WHERE
assert concept.body == expected_body
def test_i_can_evaluate_where_when_using_other_concept(self):
sheerka, context, foo_true, foo_false = self.init_concepts(
@@ -381,20 +389,20 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
Concept("foo_false", body="False"),
)
concept = Concept("foo", where="foo_true").init_key()
concept = Concept("foo", where="foo_true")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept)
assert evaluated.key == concept.key
concept = Concept("foo", where="foo_false")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept)
assert sheerka.isinstance(evaluated, BuiltinConcepts.WHERE_CLAUSE_FAILED)
assert evaluated.body == concept
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONDITION_FAILED)
assert evaluated.body == "foo_false"
concept = Concept("foo", where="foo_false").init_key()
concept = Concept("foo", where="foo_false")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, False), concept)
assert evaluated.key == concept.key
def test_i_can_evaluate_disable_where_clause_evaluation(self):
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),
)
@@ -405,7 +413,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(context, concept)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
def test_i_can_detect_infinite_recursion_with_numeric_constant(self):
def test_i_can_detect_and_resolve_infinite_recursion_with_numeric_constant(self):
sheerka, context, one_str, one_digit = self.init_concepts(
Concept("one", body="1"),
Concept("1", body="one"),
@@ -423,7 +431,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
assert evaluated.key == one_str.key
assert evaluated.body == InfiniteRecursionResolved(1)
def test_i_can_detect_infinite_recursion_with_boolean_constant(self):
def test_i_can_detect_and_resolve_infinite_recursion_with_boolean_constant(self):
sheerka, context, true_str, true_bool = self.init_concepts(
Concept("true", body="True"),
Concept("True", body="true"),
@@ -523,3 +531,147 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(context, forty_one_thousand)
assert evaluated.body == 41000
def test_i_can_evaluate_command(self):
sheerka, context, command = self.init_concepts(Concept("command", body="a = 10"))
evaluated = sheerka.evaluate_concept(context, command)
assert evaluated.key == command.key
assert "a" not in sheerka.locals
sheerka.set_isa(context, command, sheerka.new(BuiltinConcepts.COMMAND))
evaluated = sheerka.evaluate_concept(context, sheerka.new("command"))
assert evaluated.key == command.key
assert "a" in sheerka.locals
@pytest.mark.parametrize("metadata", [
"where",
"pre",
"post",
"ret"
])
def test_i_cannot_evaluate_python_statement_in_where_pre_post_ret(self, metadata, capsys):
sheerka, context, foo = self.init_concepts("foo")
setattr(foo.metadata, metadata, "a=10; print('10')")
foo.metadata.need_validation = True
evaluated = sheerka.evaluate_concept(context, foo)
captured = capsys.readouterr()
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
error = evaluated.body
assert sheerka.isinstance(error, BuiltinConcepts.PYTHON_SECURITY_ERROR)
assert error.prop.value == metadata
assert error.body == "a=10; print('10')"
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
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
)
evaluated = sheerka.evaluate_concept(context, foo, eval_body=True)
captured = capsys.readouterr()
assert evaluated.key == foo.key
assert captured.out == "10\n"
evaluated = sheerka.evaluate_concept(context, bar)
captured = capsys.readouterr()
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
error = evaluated.body
assert sheerka.isinstance(error, BuiltinConcepts.ERROR)
assert captured.out == ""
def test_i_can_failed_a_concept_when_pre_clause_is_not_validated(self, capsys):
sheerka, context, concept = self.init_concepts(
Concept("foo", pre="in_context('foo')", body="print('10')"),
)
evaluated = sheerka.evaluate_concept(context, concept, eval_body=True)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONDITION_FAILED)
assert evaluated.body == "in_context('foo')"
assert evaluated.concept == concept
assert evaluated.prop == ConceptParts.PRE
captured = capsys.readouterr()
assert captured.out == ""
@pytest.mark.parametrize("concept, expected", [
(Concept("foo"), []),
(Concept("foo", pre="pre", post="post", ret="ret", where="where"), ["pre", "ret", "post"]),
(Concept("foo", pre="a").def_var("a"), ["variables", "pre"]),
(Concept("foo", pre="self"), ["body", "pre"]),
(Concept("foo", pre="self + a").def_var("a"), ["variables", "body", "pre"]),
(Concept("foo", pre="self + a", ret="ret").def_var("a"), ["variables", "body", "pre", "ret"]),
(Concept("foo", body="body"), []) # only if eval_body_is_set
])
def test_i_can_compute_metadata_to_eval(self, concept, expected):
sheerka, context, concept = self.init_concepts(concept)
service = sheerka.services[SheerkaEvaluateConcept.NAME]
service.initialize_concept_asts(context, concept)
assert service.compute_metadata_to_eval(context, concept) == expected
def test_i_can_compute_metadata_to_eval_for_where_and_body(self):
sheerka = self.get_sheerka()
service = sheerka.services[SheerkaEvaluateConcept.NAME]
context = self.get_context(sheerka, eval_where=True)
concept = Concept("foo", where="where")
service.initialize_concept_asts(context, concept)
assert service.compute_metadata_to_eval(context, concept) == ["where"]
concept = Concept("foo", where="where a").def_var("a")
service.initialize_concept_asts(context, concept)
assert service.compute_metadata_to_eval(context, concept) == ["variables", "where"]
concept = Concept("foo", where="where self")
service.initialize_concept_asts(context, concept)
assert service.compute_metadata_to_eval(context, concept) == ["body", "where"]
context = self.get_context(sheerka, eval_body=True)
concept = Concept("foo")
assert service.compute_metadata_to_eval(context, concept) == ["variables", "body"]
context = self.get_context(sheerka, eval_body=True)
concept = Concept("foo").def_var("a")
assert service.compute_metadata_to_eval(context, concept) == ["variables", "body"]
context = self.get_context(sheerka, eval_body=True)
concept = Concept("foo", body="body").def_var("a")
assert service.compute_metadata_to_eval(context, concept) == ["variables", "body"]
@pytest.mark.parametrize("concept, expected", [
(Concept("foo"), True),
])
def test_is_evaluated_is_correctly_set(self, concept, expected):
sheerka, context, concept = self.init_concepts(concept)
evaluated = sheerka.evaluate_concept(context, concept, eval_body=True)
assert evaluated.key == concept.key
assert concept.metadata.is_evaluated == expected
def test_i_only_compute_the_requested_metadata(self):
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
evaluated = sheerka.evaluate_concept(context, concept, metadata=['pre'])
assert evaluated.values == {"a": Property("a", NotInit), ConceptParts.PRE: Property(ConceptParts.PRE, 'pre')}
# I cannot implement value cache for now
# def test_values_when_no_variables_are_computed_only_once(self):
# sheerka, context, foo = self.init_concepts(Concept("foo", body="10"))
#
# evaluated = sheerka.evaluate_concept(context, sheerka.new("foo"), eval_body=True)
# assert evaluated.body == 10
# assert len(evaluated.compiled) > 0
#
# evaluated_2 = sheerka.evaluate_concept(context, sheerka.new("foo"), eval_body=True)
# assert evaluated_2.body == 10
# assert len(evaluated_2.compiled) == 0
+12 -2
View File
@@ -239,8 +239,6 @@ class TestSheerkaSetsManager(TestUsingMemoryBasedSheerka):
Concept("foo"),
Concept("bar"),
Concept("baz"),
create_new=True
)
sheerka.set_isa(context, foo, bar)
@@ -250,6 +248,18 @@ class TestSheerkaSetsManager(TestUsingMemoryBasedSheerka):
assert sheerka.isa(bar, baz)
assert sheerka.isa(foo, baz)
def test_i_cannot_manage_isa_transitivity_when_using_body(self):
sheerka, context, one, another_one, number = self.init_concepts(
"one",
Concept("another one", body="one"),
"number"
)
sheerka.set_isa(context, one, number)
assert sheerka.isa(one, number) # sanity
assert not sheerka.isa(another_one, number) # Correct this misbehaviour when BuiltinConcepts.IS is implemented
def test_concept_expression_recurse_id_is_updated(self):
sheerka, context, one, number, twenties = self.init_concepts(
"one",
+71
View File
@@ -3,6 +3,7 @@ import ast
import core.builtin_helpers
import pytest
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
from core.concept import Concept
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -142,3 +143,73 @@ class TestBuiltinHelpers(TestUsingMemoryBasedSheerka):
assert len(actual) == len(expected)
for i in range(len(actual)):
assert self.dump_ast(actual[i]) == self.dump_ast(expected[i])
@pytest.mark.parametrize("concepts, expected", [
([], []),
([Concept("foo", pre="True"), Concept("bar")], ["foo"]),
([Concept("foo").def_var("a"), Concept("bar")], ["bar"]),
])
def test_i_can_resolve_ambiguity_when_empty(self, concepts, expected):
context = self.get_context()
res = core.builtin_helpers.resolve_ambiguity(context, concepts)
assert [c.name for c in res] == expected
# @pytest.mark.parametrize("return_values", [
# None,
# []
# ])
# def test_i_can_resolve_simple_ambiguity_when_no_return_values(self, return_values):
# context = self.get_context()
#
# assert core.builtin_helpers.remove_ambiguity(context, return_values) == return_values
# def test_resolve_ambiguity_concepts_with_no_variable_take_precedence(self):
# context = self.get_context()
# return_values = [
# self.pretval(Concept("hello a").def_var("a", "world"), "hello word"),
# self.pretval(Concept("hello world"), "hello word"),
# # self.pretval(Concept("hello world", pre="False"), "hello word"),
# self.retval(Concept("not a parser result")),
# self.retval(Concept("status is false"), status=False),
# self.pretval(Concept("false parser result"), status=False),
# ]
#
# ret = core.builtin_helpers.remove_ambiguity(context, return_values)
# assert ret.status
# assert ret.parents == return_values
#
# filtered = ret.body
# assert context.sheerka.isinstance(ret.body, BuiltinConcepts.FILTERED)
# assert filtered.body == [
# return_values[2],
# return_values[3],
# return_values[4],
# return_values[1],
# ]
# assert filtered.iterable == return_values
# assert filtered.predicate == "remove_ambiguity(context, iterable)"
#
# def test_resolve_ambiguity_failed_pre_condition_are_discarded(self):
# context = self.get_context()
# return_values = [
# self.pretval(Concept("hello world"), "hello word"),
# self.pretval(Concept("hello world", pre="False"), "hello word"),
# ]
#
# ret = core.builtin_helpers.remove_ambiguity(context, return_values)
# filtered = ret.body
# assert context.sheerka.isinstance(ret.body, BuiltinConcepts.FILTERED)
# assert filtered.body == [
# return_values[0],
# ]
#
# def test_resolve_ambiguity_original_return_value_is_returned_when_nothing_to_filter(self):
# context = self.get_context()
# return_values = [
# self.pretval(Concept("hello a").def_var("a", "world"), "hello word"),
# self.retval(Concept("not a parser result")),
# self.retval(Concept("status is false"), status=False),
# self.pretval(Concept("false parser result"), status=False),
# ]
#
# assert core.builtin_helpers.remove_ambiguity(context, return_values) == return_values
+48 -2
View File
@@ -165,10 +165,13 @@ class EvaluatorAllReduceFooBar(EvaluatorAllWithPriority):
return ret
class EvaluatorAllSuppressFooEntry(EvaluatorAllWithPriority):
class EvaluatorAllReplaceFooEntry(EvaluatorAllWithPriority):
"""
This evaluator replaces the concept 'foo' by another one
"""
def __init__(self):
super().__init__("suppress", 100)
super().__init__("replace", 100)
def matches(self, context, return_values):
super().matches(context, return_values)
@@ -187,6 +190,30 @@ class EvaluatorAllSuppressFooEntry(EvaluatorAllWithPriority):
return None
class EvaluatorAllSuppressEntries(EvaluatorAllWithPriority):
"""
This evaluator totally removes 'foo' and 'bar' the entries from the workflow
"""
def __init__(self):
super().__init__("suppress", 100)
def matches(self, context, return_values):
super().matches(context, return_values)
to_remove = [r for r in return_values if r.body.name in ("foo", "bar")]
return len(to_remove) > 0
def eval(self, context, return_values):
super().eval(context, return_values)
to_remove = [r for r in return_values if r.body.name in ("foo", "bar")]
return context.sheerka.ret(
self.name,
True,
[],
parents=to_remove)
class EvaluatorOneDoNotModifyExecutionFlow(EvaluatorOneWithPriority):
"""
To test that when eval() returns the initial return_value, the execution flow is not modified
@@ -485,3 +512,22 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka):
# check that 'foo' is no longer in res, but 'bar' is added
assert res == [self.tretval(sheerka, Concept("bar"))]
def test_i_can_remove_return_values_from_the_execution_workflow(self):
sheerka = self.get_sheerka()
sheerka.evaluators = [EvaluatorAllSuppressEntries]
entries = [self.tretval(sheerka, Concept("foo")),
self.tretval(sheerka, Concept("bar")),
self.tretval(sheerka, Concept("baz"))]
Out.debug_out = []
res = sheerka.execute(self.get_context(sheerka), entries, [BuiltinConcepts.EVALUATION])
assert Out.debug_out == [
"__EVALUATION [0] suppress - matches - target=['foo', 'bar', 'baz']",
"__EVALUATION [0] suppress - eval - target=['foo', 'bar', 'baz']",
"__EVALUATION [1] suppress - matches - target=['baz']",
]
# check that 'foo' is no longer in res, but 'bar' is added
assert res == [self.tretval(sheerka, Concept("baz"))]
+12 -7
View File
@@ -19,7 +19,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
@staticmethod
def get_concept_part(part):
if isinstance(part, str):
node = PythonNode(part, ast.parse(part, mode="eval"))
node = PythonNode(part, ast.parse(part, mode="exec"))
return ReturnValueConcept(
who="parsers.Default",
status=True,
@@ -169,11 +169,16 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
assert from_db.compiled == {} # ast is not saved in db
def test_i_can_get_variables_from_python_node_when_long_name(self):
ret_val = self.get_concept_part("isinstance(a, str)")
@pytest.mark.parametrize("expression, name, expected", [
("isinstance(a, str)", "a b", {"a"}),
("a.location=b", "a is in b", {"a", "b"}),
("a.location=b", "'a' is in b", {"b"}),
])
def test_i_can_get_variables_from_python_node_when_long_name(self, expression, name, expected):
ret_val = self.get_concept_part(expression)
context = self.get_context()
assert AddConceptEvaluator.get_variables(context.sheerka, ret_val, ["a", "b"]) == ["a"]
assert AddConceptEvaluator.get_variables(context.sheerka, ret_val, name.split()) == expected
def test_i_can_get_variables_when_keywords(self):
sheerka, context = self.init_concepts()
@@ -182,7 +187,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
name_to_use = AddConceptEvaluator.get_name_to_use(def_concept)
concept_part = self.get_concept_part("pre")
assert AddConceptEvaluator.get_variables(context.sheerka, concept_part, name_to_use) == ["pre"]
assert AddConceptEvaluator.get_variables(context.sheerka, concept_part, name_to_use) == {"pre"}
def test_i_cannot_get_variables_from_python_node_when_name_has_only_one_token(self):
ret_val = self.get_concept_part("isinstance(a, str)")
@@ -196,14 +201,14 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
status=True,
value=ParserResultConcept(value=concept))
assert AddConceptEvaluator.get_variables(self.get_sheerka(), ret_val, []) == ["a", "b"]
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"))))
ret_val = self.get_return_value("mult (('+'|'-') add)?", parsing_expression)
assert AddConceptEvaluator.get_variables(self.get_sheerka(), ret_val, []) == ["add", "mult"]
assert AddConceptEvaluator.get_variables(self.get_sheerka(), ret_val, []) == {"add", "mult"}
def test_concept_that_references_itself_is_correctly_created(self):
context = self.get_context()
+10 -9
View File
@@ -1,8 +1,8 @@
import pytest
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
from core.concept import Concept, ConceptParts
from evaluators.ConceptEvaluator import ConceptEvaluator
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -20,11 +20,12 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
def test_i_can_evaluate_concept(self):
context = self.get_context()
context.local_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
context.local_hints.update({BuiltinConcepts.EVAL_BODY_REQUESTED, BuiltinConcepts.EVAL_WHERE_REQUESTED})
concept = Concept(name="foo",
where="True",
pre="2",
post="3").def_var("a", "4").def_var("b", "5")
pre="2 > 1",
ret="3",
post="4").def_var("a", "5").def_var("b", "6")
evaluator = ConceptEvaluator()
item = self.pretval(concept)
@@ -34,10 +35,11 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
assert result.status
assert result.value.name == "foo"
assert result.value.get_value(ConceptParts.WHERE) == True
assert result.value.get_value(ConceptParts.PRE) == 2
assert result.value.get_value(ConceptParts.POST) == 3
assert result.value.get_value("a") == 4
assert result.value.get_value("b") == 5
assert result.value.get_value(ConceptParts.PRE) == True
assert result.value.get_value(ConceptParts.RET) == 3
assert result.value.get_value(ConceptParts.POST) == 4
assert result.value.get_value("a") == 5
assert result.value.get_value("b") == 6
assert result.value.key == "foo"
assert result.parents == [item]
@@ -118,4 +120,3 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
assert not context.sheerka.is_success(error_concept) # it's indeed an error
assert result.status
assert result.value == error_concept
+3 -3
View File
@@ -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.CONCEPT_VALUE_REQUESTED)
context.global_hints.add(BuiltinConcepts.RETURN_VALUE_REQUESTED)
to_eval1 = ReturnValueConcept("some_name", True, Concept(name="2", body="to eval").auto_init())
to_eval2 = ReturnValueConcept("some_name", True, Concept(name="3", body="also to eval").auto_init())
@@ -49,12 +49,12 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
context = self.get_context()
assert not EvalEvaluator().matches(context, [return_value])
context.global_hints.add(BuiltinConcepts.CONCEPT_VALUE_REQUESTED)
context.global_hints.add(BuiltinConcepts.RETURN_VALUE_REQUESTED)
assert EvalEvaluator().matches(context, [return_value])
def test_i_can_match_depending_on_builtin_concept_processing(self):
context = self.get_context()
context.global_hints.add(BuiltinConcepts.CONCEPT_VALUE_REQUESTED)
context.global_hints.add(BuiltinConcepts.RETURN_VALUE_REQUESTED)
return_values = [ReturnValueConcept("some_name", True, Concept(name="2", body="to eval").auto_init())]
evaluator = EvalEvaluator()
@@ -45,4 +45,4 @@ class TestPrepareEvalEvaluator(TestUsingMemoryBasedSheerka):
assert res.body.body == expected
assert BuiltinConcepts.EVAL_BODY_REQUESTED in context.global_hints
assert BuiltinConcepts.CONCEPT_VALUE_REQUESTED in context.global_hints
assert BuiltinConcepts.RETURN_VALUE_REQUESTED in context.global_hints
+17 -2
View File
@@ -1,6 +1,6 @@
import pytest
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
from core.concept import Concept, CB
from core.concept import Concept, CB, NotInit
from core.sheerka.services.SheerkaExecute import ParserInput
from evaluators.PythonEvaluator import PythonEvaluator, PythonEvalError
from parsers.PythonParser import PythonNode, PythonParser
@@ -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_SUCCESS_REQUESTED)
context.local_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
@@ -224,3 +224,18 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
assert isinstance(error1.error, TypeError)
assert error1.error.args[0] == 'can only concatenate str (not "int") to str'
assert error1.concepts == {'foo': 'string'}
def test_i_do_not_include_not_initialized_variables_when_evaluating(self):
sheerka, context, foo = self.init_concepts(
Concept("foo a", pre="a == 'True'").def_var("a", "'True'").def_var("b"))
foo.set_value("b", "'Initialized!'")
context.obj = foo
assert foo.get_value("a") == NotInit
assert foo.get_value("b") == "'Initialized!'"
my_globals = {}
PythonEvaluator().update_globals_with_context(my_globals, context)
assert my_globals == {"self": foo, "b": "'Initialized!'"}
@@ -0,0 +1,74 @@
import pytest
from core.concept import Concept
from evaluators.ResolveAmbiguityEvaluator import ResolveAmbiguityEvaluator
from tests.BaseTest import BaseTest
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
pretval = BaseTest.pretval
class TestResolveAmbiguityEvaluator(TestUsingMemoryBasedSheerka):
@pytest.mark.parametrize("return_values, expected", [
([pretval(Concept("foo"), source="source"), pretval(Concept("bar"), source="source")], True),
([pretval(Concept("foo"), source="source"), pretval(Concept("bar"), source="source", status=False)], False),
([pretval(Concept("foo"), source="source1"), pretval(Concept("bar"), source="source2")], False),
])
def test_i_can_match(self, return_values, expected):
context = self.get_context()
assert ResolveAmbiguityEvaluator().matches(context, return_values) == expected
def test_i_can_manage_when_no_source(self):
context = self.get_context()
return_values = [BaseTest.retval(Concept("foo"))]
assert not ResolveAmbiguityEvaluator().matches(context, return_values)
def test_i_can_eval(self):
context = self.get_context()
return_values = [
self.pretval(Concept("hello a").def_var("a", "world"), "hello word"),
self.pretval(Concept("hello world"), "hello word"),
self.pretval(Concept("hello world", pre="False"), "hello word"),
self.retval(Concept("not a parser result")),
self.retval(Concept("status is false"), status=False),
self.pretval(Concept("false parser result"), status=False),
]
evaluator = ResolveAmbiguityEvaluator()
evaluator.matches(context, return_values)
res = evaluator.eval(context, return_values)
assert len(res) == 1
resolved = res[0]
assert resolved.who == evaluator.name
assert resolved.body == return_values[1].body
assert resolved.parents == [
return_values[0],
return_values[1],
return_values[2],
]
def test_i_can_eval_all_fail(self):
context = self.get_context()
return_values = [
self.pretval(Concept("hello world", pre="2 < 1"), "hello word"),
self.pretval(Concept("hello world", pre="False"), "hello word"),
]
evaluator = ResolveAmbiguityEvaluator()
evaluator.matches(context, return_values)
res = evaluator.eval(context, return_values)
assert len(res) == 1
resolved = res[0]
assert resolved.who == evaluator.name
assert resolved.body == []
assert resolved.parents == [
return_values[0],
return_values[1],
]
+28 -11
View File
@@ -1,7 +1,8 @@
import pytest
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, simplec, CMV, NotInit, CC
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, simplec, CMV, NotInit
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
from evaluators.OneSuccessEvaluator import OneSuccessEvaluator
from evaluators.PythonEvaluator import PythonEvalError
from parsers.BaseNodeParser import SyaAssociativity
from parsers.BnfNodeParser import Sequence, StrMatch, OrderedChoice, Optional, ConceptExpression
@@ -216,6 +217,7 @@ as:
assert evaluated.get_value("a").metadata.is_evaluated
def test_i_can_recognize_duplicate_concepts_with_same_value(self):
# when multiple result, choose the one that is the more specific (that has the less variables)
sheerka = self.get_sheerka()
self.create_and_add_in_cache_concept(sheerka, Concept(name="hello a", body="'hello ' + a"), variables=["a"])
self.create_and_add_in_cache_concept(sheerka, Concept(name="hello foo", body="'hello foo'"))
@@ -224,13 +226,14 @@ as:
res = sheerka.evaluate_user_input("hello foo")
assert len(res) == 1
assert res[0].status
assert res[0].value.body == "hello foo"
assert res[0].who == sheerka.get_evaluator_name(MultipleSameSuccessEvaluator.NAME)
assert sheerka.isinstance(res[0].body, "hello foo")
assert res[0].value.body == BuiltinConcepts.NOT_INITIALIZED
assert res[0].who == sheerka.get_evaluator_name(OneSuccessEvaluator.NAME)
def test_i_cannot_manage_duplicate_concepts_when_the_values_are_different(self):
sheerka = self.get_sheerka()
self.create_and_add_in_cache_concept(sheerka, Concept(name="hello a", body="'hello ' + a"), variables=["a"])
self.create_and_add_in_cache_concept(sheerka, Concept(name="hello foo", body="'hello foo'"))
self.create_and_add_in_cache_concept(sheerka, Concept(name="hello a", body="'hello ' + a").def_var("a"))
self.create_and_add_in_cache_concept(sheerka, Concept(name="hello b", body="'hello you ' + b").def_var("b"))
self.create_and_add_in_cache_concept(sheerka, Concept(name="foo", body="'another value'"))
res = sheerka.evaluate_user_input("hello foo")
@@ -242,7 +245,7 @@ as:
assert len(concepts) == 2
sorted_values = sorted(concepts, key=lambda x: x.value.body)
assert sorted_values[0].value.body == "hello another value"
assert sorted_values[1].value.body == "hello foo"
assert sorted_values[1].value.body == "hello you another value"
def test_i_can_manage_concepts_with_the_same_key_when_values_are_the_same(self):
sheerka = self.get_sheerka()
@@ -692,12 +695,12 @@ as:
assert len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.MULTIPLE_ERRORS)
assert str(BuiltinConcepts.WHERE_CLAUSE_FAILED) in [error.key for error in sheerka.get_error(res[0].body.body)]
assert str(BuiltinConcepts.CONDITION_FAILED) in [error.key for error in sheerka.get_error(res[0].body.body)]
res = sheerka.evaluate_user_input("eval twenty three")
assert len(res) == 1
assert not res[0].status
assert str(BuiltinConcepts.WHERE_CLAUSE_FAILED) in [error.key for error in sheerka.get_error(res[0].body.body)]
assert str(BuiltinConcepts.CONDITION_FAILED) in [error.key for error in sheerka.get_error(res[0].body.body)]
def test_i_can_manage_some_type_of_infinite_recursion(self):
sheerka = self.get_sheerka()
@@ -735,12 +738,12 @@ as:
res = sheerka.evaluate_user_input("foo baz")
assert len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.WHERE_CLAUSE_FAILED)
assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONDITION_FAILED)
res = sheerka.evaluate_user_input("eval foo baz")
assert len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.WHERE_CLAUSE_FAILED)
assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONDITION_FAILED)
res = sheerka.evaluate_user_input("foobar")
assert len(res) == 1
@@ -749,7 +752,7 @@ as:
res = sheerka.evaluate_user_input("eval foobar")
assert len(res) == 1 # error
assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.WHERE_CLAUSE_FAILED)
assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONDITION_FAILED)
@pytest.mark.skip("Not ready for that")
def test_i_can_manage_missing_variables_from_bnf_parsing(self):
@@ -998,6 +1001,20 @@ as:
assert res[0].status
assert res[0].body == 2
def test_i_can_evaluate_command(self):
init = [
"def concept command as 'Executed !'",
"set_isa(c:command:, __COMMAND)",
]
# Since command is a __COMMAND, the body is auto evaluated
# and we return the body, not the concept
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("command")
assert res[0].status
assert res[0].body == "Executed !"
class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
def test_i_can_def_several_concepts(self):
-1
View File
@@ -1,7 +1,6 @@
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, CMV
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Tokenizer
from parsers.ExactConceptParser import ExactConceptParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
+12 -4
View File
@@ -16,6 +16,14 @@ def set_full_serialization(concept):
class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
user_input_id = 0
return_value_id = 0
@classmethod
def setup(cls):
sheerka = cls().get_sheerka()
cls.user_input_id = sheerka.get_by_key("__USER_INPUT").id
cls.return_value_id = sheerka.get_by_key("__RETURN_VALUE").id
def test_i_can_encode_decode_unknown_concept_metadata(self):
sheerka = self.get_sheerka()
@@ -201,7 +209,7 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
to_string = sheerkapickle.encode(sheerka, user_input)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == user_input
assert to_string == '{"_sheerka/obj": "core.builtin_concepts.UserInputConcept", "concept/id": ["__USER_INPUT", "23"], "user_name": "my_user_name", "text": "my_text"}'
assert to_string == f'{{"_sheerka/obj": "core.builtin_concepts.UserInputConcept", "concept/id": ["__USER_INPUT", "{self.user_input_id}"], "user_name": "my_user_name", "text": "my_text"}}'
def test_i_can_encode_decode_user_input_when_tokens(self):
sheerka = self.get_sheerka()
@@ -213,7 +221,7 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
to_string = sheerkapickle.encode(sheerka, user_input)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == sheerka.new(BuiltinConcepts.USER_INPUT, body=text, user_name="my_user_name")
assert to_string == '{' + f'"_sheerka/obj": "core.builtin_concepts.UserInputConcept", "concept/id": ["__USER_INPUT", "23"], "user_name": "my_user_name", "text": "{text}"' + '}'
assert to_string == f'{{"_sheerka/obj": "core.builtin_concepts.UserInputConcept", "concept/id": ["__USER_INPUT", "{self.user_input_id}"], "user_name": "my_user_name", "text": "{text}"}}'
def test_i_can_encode_decode_return_value(self):
sheerka = self.get_sheerka()
@@ -223,7 +231,7 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
to_string = sheerkapickle.encode(sheerka, ret_val)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == ret_val
assert to_string == '{"_sheerka/obj": "core.builtin_concepts.ReturnValueConcept", "concept/id": ["__RETURN_VALUE", "28"], "who": "who", "status": true, "value": 10}'
assert to_string == f'{{"_sheerka/obj": "core.builtin_concepts.ReturnValueConcept", "concept/id": ["__RETURN_VALUE", "{self.return_value_id}"], "who": "who", "status": true, "value": 10}}'
def test_i_can_encode_decode_return_value_with_parent(self):
sheerka = self.get_sheerka()
@@ -236,7 +244,7 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == ret_val
assert decoded.parents == ret_val.parents
id_str = ', "concept/id": ["__RETURN_VALUE", "28"]'
id_str = f', "concept/id": ["__RETURN_VALUE", "{self.return_value_id}"]'
parents_str = '[{"_sheerka/obj": "core.builtin_concepts.ReturnValueConcept"' + id_str + ', "who": "parent_who", "status": true, "value": "10"}, {"_sheerka/id": 1}]'
assert to_string == '{"_sheerka/obj": "core.builtin_concepts.ReturnValueConcept"' + id_str + ', "who": "who", "status": true, "value": 10, "parents": ' + parents_str + '}'