Fixed #29: Parsers: Implement parsing memoization

Fixed #77 : Parser: ShortTermMemoryParser should be called separately
Fixed #78 : Remove VariableNode usage
Fixed #79 : ConceptManager: Implement compile caching
Fixed #80 : SheerkaExecute : parsers_key is not correctly computed
Fixed #81 : ValidateConceptEvaluator : Validate concept's where and pre clauses right after the parsing
Fixed #82 : SheerkaIsAManager: isa() failed when the set as a body
Fixed #83 : ValidateConceptEvaluator : Support BNF and SYA Concepts
Fixed #84 : ExpressionParser: Implement the parser as a standard parser
Fixed #85 : Services: Give order to services
Fixed #86 : cannot manage smart_get_attr(the short, color)
This commit is contained in:
2021-06-07 21:14:03 +02:00
parent 1059ce25c5
commit 7dcaa9c111
92 changed files with 4263 additions and 1890 deletions
+5 -1
View File
@@ -45,7 +45,7 @@ class InitTestHelper:
c.get_metadata().definition_type = DEFINITION_TYPE_BNF
else:
raise Exception(f"Error in bnf definition '{c.get_metadata().definition}'",
self.sheerka.get_errors(res))
self.sheerka.get_errors(self.context, res))
if create_new:
self.sheerka.create_new_concept(self.context, c)
@@ -264,3 +264,7 @@ class BaseTest:
assert res[0].status, f"Error while executing '{expression}'"
return sheerka
@staticmethod
def successful_return_values(return_values):
return [ret_val for ret_val in return_values if ret_val.status]
+6 -14
View File
@@ -47,6 +47,7 @@ class TestExecutionContext(TestUsingMemoryBasedSheerka):
a.preprocess_evaluators = ["list of evaluators"]
a.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
a.global_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
a.possible_variables = {"a", "b", "c"}
b = a.push(BuiltinConcepts.EVALUATION, "sub action context", desc="sub description")
@@ -65,8 +66,9 @@ class TestExecutionContext(TestUsingMemoryBasedSheerka):
assert b.preprocess_evaluators == a.preprocess_evaluators
assert b.protected_hints == {BuiltinConcepts.EVAL_BODY_REQUESTED}
assert b.global_hints == a.global_hints
assert b.possible_variables == a.possible_variables
def test_children_i_created_when_i_push(self):
def test_children_are_created_when_i_push(self):
sheerka = self.get_sheerka()
e = ExecutionContext("who_", Event("event"), sheerka, BuiltinConcepts.NOP, None)
@@ -75,19 +77,9 @@ class TestExecutionContext(TestUsingMemoryBasedSheerka):
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")
# def test_i_can_add_variable_when_i_push(self):
# sheerka = self.get_sheerka()
#
# e = ExecutionContext("who_", Event("event"), sheerka, BuiltinConcepts.NOP, None)
# sub_e = e.push(BuiltinConcepts.NOP, None, who="a", my_new_var="new var value")
#
# assert sub_e.my_new_var == "new var value"
# with pytest.raises(AttributeError):
# assert e.my_new_var == "" # my_new_var does not exist in parent
assert (e._children[0].who, e._children[0].desc) == ("a", "I do something")
assert (e._children[1].who, e._children[1].desc) == ("b", "oups! I did a again")
assert (e._children[2].who, e._children[2].desc) == ("c", "I do something else")
def test_local_hints_are_local_and_global_hints_are_global(self):
sheerka = self.get_sheerka()
+28 -3
View File
@@ -5,7 +5,7 @@ from core.builtin_concepts import BuiltinConcepts
from core.builtin_helpers import ensure_bnf
from core.concept import PROPERTIES_TO_SERIALIZE, Concept, DEFINITION_TYPE_DEF, get_concept_attrs, \
DEFINITION_TYPE_BNF
from core.global_symbols import NotInit, NotFound, SyaAssociativity
from core.global_symbols import NotInit, NotFound, SyaAssociativity, CONCEPT_COMPARISON_CONTEXT
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager, NoModificationFound, ForbiddenAttribute, \
UnknownAttribute, CannotRemoveMeta, ValueNotFound, ConceptIsReferenced, NoFirstTokenError
from parsers.BnfNodeParser import Sequence, StrMatch, ConceptExpression, OrderedChoice, Optional, ZeroOrMore, OneOrMore, \
@@ -293,8 +293,6 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
"definition",
"definition_type",
"desc",
"is_evaluated",
"need_validation",
"full_serialization",
])
def test_i_can_modify_a_metadata_attribute(self, attr):
@@ -1422,6 +1420,33 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
res = sheerka.smart_get_attr(table_instance, size)
assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND)
def test_i_can_set_concept_precedence(self):
sheerka, context, one, two, three = self.init_concepts("one", "two", "three")
res = sheerka.set_precedence(context, one, two, three)
assert sheerka.isinstance(res, BuiltinConcepts.SUCCESS)
weights = sheerka.get_weights(BuiltinConcepts.PRECEDENCE, comparison_context=CONCEPT_COMPARISON_CONTEXT)
assert weights == {'c:one|1001:': 3, 'c:two|1002:': 2, 'c:three|1003:': 1}
def test_i_cannot_set_precedence_when_too_few_argument(self):
sheerka, context, one = self.init_concepts("one")
res = sheerka.set_precedence(context)
assert res == sheerka.err("Not enough elements")
res = sheerka.set_precedence(context, one)
assert res == sheerka.err("Not enough elements")
def test_i_cannot_set_precedence_when_error(self):
sheerka, context, one, two = self.init_concepts("one", "two")
ret = sheerka.set_precedence(context, one, two, one)
assert not ret.status
weights = sheerka.get_weights(BuiltinConcepts.PRECEDENCE, comparison_context=CONCEPT_COMPARISON_CONTEXT)
assert weights == {'c:one|1001:': 2, 'c:two|1002:': 1}
class TestSheerkaConceptManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
def test_i_can_add_several_concepts(self):
+9 -10
View File
@@ -672,16 +672,15 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
res = sheerka.inspect(context, return_values[0], values=True)
concept_debug_obj = ConceptDebugObj(return_values[0].body)
assert res.body == {
'body': concept_debug_obj,
'#type#': 'ReturnValueConcept',
'id': f'{self.return_value_id}',
'key': '__RETURN_VALUE',
'name': '__RETURN_VALUE',
'parents': [concept_debug_obj],
'status': True,
'value': concept_debug_obj,
'who': 'evaluators.OneSuccess'}
assert res.body['body'] == concept_debug_obj
assert res.body['#type#'] == 'ReturnValueConcept'
assert res.body['id'] == f'{self.return_value_id}'
assert res.body['key'] == '__RETURN_VALUE'
assert res.body['name'] == '__RETURN_VALUE'
assert isinstance(res.body['parents'], list)
assert res.body['status'] == True
assert res.body['value'] == concept_debug_obj
assert res.body['who'] == 'evaluators.OneSuccess'
# I also can print it using bag
res = sheerka.inspect(context, return_values[0], '#type#', "who", "status", "value", values=True, as_bag=True)
+154 -42
View File
@@ -5,9 +5,13 @@ from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionR
DEFINITION_TYPE_DEF
from core.global_symbols import NotInit, NotFound
from core.sheerka.services.SheerkaEvaluateConcept import SheerkaEvaluateConcept
from core.sheerka.services.SheerkaExecute import ParserInput
from core.sheerka.services.SheerkaMemory import SheerkaMemory
from parsers.BaseParser import BaseParser
from parsers.ExactConceptParser import ExactConceptParser
from parsers.ExpressionParser import ExpressionParser
from parsers.PythonParser import PythonNode, PythonParser
from parsers.SyaNodeParser import SyaNodeParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.evaluators.EvaluatorTestsUtils import pr_ret_val, python_ret_val
from tests.parsers.parsers_utils import CB, compare_with_test_object
@@ -37,7 +41,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
assert evaluated.get_metadata().post is None
assert evaluated.get_metadata().where is None
assert evaluated.variables() == {}
assert evaluated.get_metadata().is_evaluated
assert evaluated.get_hints().is_evaluated
assert len(evaluated.values()) == 0 if body is None else 1
assert "foo" in sheerka.services[SheerkaMemory.NAME].registration
@@ -70,7 +74,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
assert evaluated.get_metadata().where is None
assert evaluated.get_value(ConceptParts.POST) == expected
assert evaluated.variables() == {}
assert not evaluated.get_metadata().is_evaluated
assert not evaluated.get_hints().is_evaluated
assert len(evaluated.values) == 0 if expr is None else 1
@pytest.mark.parametrize("expr, expected", [
@@ -94,7 +98,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
assert evaluated.get_metadata().post is None
assert evaluated.get_metadata().where is None
assert evaluated.variables() == {"a": expected}
assert evaluated.get_metadata().is_evaluated
assert evaluated.get_hints().is_evaluated
def test_i_can_evaluate_when_the_body_is_the_name_of_the_concept(self):
# to prove that I can distinguish from a string
@@ -114,7 +118,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.body == "do not resolve"
assert evaluated.get_metadata().is_evaluated
assert evaluated.get_hints().is_evaluated
def test_i_can_evaluate_variable_using_do_not_resolve(self):
sheerka, context, concept = self.init_concepts(Concept("foo").def_var("a"), eval_body=True)
@@ -123,7 +127,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.get_value("a") == "do not resolve"
assert evaluated.get_metadata().is_evaluated
assert evaluated.get_hints().is_evaluated
def test_original_value_is_overridden_when_using_do_no_resolve(self):
concept = Concept("foo", body="original value").def_var("a", "original value")
@@ -135,7 +139,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
assert evaluated.body == "do not resolve"
assert evaluated.get_value("a") == "do not resolve"
assert evaluated.get_metadata().is_evaluated
assert evaluated.get_hints().is_evaluated
def test_variables_are_evaluated_before_body(self):
sheerka, context, concept = self.init_concepts(Concept("foo", body="a+1").def_var("a", "10"), eval_body=True)
@@ -153,8 +157,8 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(context, concept)
compare_with_test_object(evaluated, CB("foo", CB("a", NotInit)))
assert evaluated.get_metadata().is_evaluated
assert evaluated.body.get_metadata().is_evaluated
assert evaluated.get_hints().is_evaluated
assert evaluated.body.get_hints().is_evaluated
def test_i_can_evaluate_when_the_referenced_concept_has_a_body(self):
sheerka, context, concept_a, concept = self.init_concepts(
@@ -166,8 +170,8 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
assert evaluated.key == concept.key
compare_with_test_object(evaluated.body, CB("a", 1))
assert not concept_a.get_metadata().is_evaluated
assert evaluated.get_metadata().is_evaluated
assert not concept_a.get_hints().is_evaluated
assert evaluated.get_hints().is_evaluated
def test_i_can_evaluate_concept_of_concept_when_the_leaf_has_a_body(self):
sheerka, context, concept_a, concept_b, concept_c, concept_d = self.init_concepts(
@@ -183,7 +187,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
expected = CB("c", CB("b", CB("a", "a")))
compare_with_test_object(evaluated.body, expected)
assert sheerka.objvalue(evaluated) == 'a'
assert evaluated.get_metadata().is_evaluated
assert evaluated.get_hints().is_evaluated
def test_i_can_evaluate_concept_of_concept_does_not_have_a_body(self):
sheerka, context, concept_a, concept_b, concept_c, concept_d = self.init_concepts(
@@ -199,7 +203,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
expected = CB("c", CB("b", CB("a", NotInit)))
compare_with_test_object(evaluated.body, expected)
compare_with_test_object(sheerka.objvalue(evaluated), CB("a", NotInit))
assert evaluated.get_metadata().is_evaluated
assert evaluated.get_hints().is_evaluated
def test_i_can_evaluate_concept_when_variables_reference_others_concepts_1(self):
"""
@@ -349,7 +353,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(context, add_instance)
assert evaluated.key == add_instance.key
assert evaluated.get_metadata().is_evaluated
assert evaluated.get_hints().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):
@@ -363,7 +367,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(context, add_instance)
assert evaluated.key == add_instance.key
assert evaluated.get_metadata().is_evaluated
assert evaluated.get_hints().is_evaluated
assert sheerka.objvalue(evaluated) == 3
def test_i_can_evaluate_when_body_is_a_concept_with_its_own_variables_multiple_levels(self):
@@ -378,7 +382,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(context, inc_instance)
assert evaluated.key == inc_instance.key
assert evaluated.get_metadata().is_evaluated
assert evaluated.get_hints().is_evaluated
assert sheerka.objvalue(evaluated) == 2
def test_i_can_evaluate_a_concept_that_references_another_concept_twice(self):
@@ -556,7 +560,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
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("x is an int", body="isinstance(x, int)", pre="is_question()").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,
@@ -570,8 +574,8 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
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("x is an int", body="isinstance(x, int)", pre="is_question()").def_var("x"),
Concept("y is an integer", body="y is an int", pre="is_question()").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,
@@ -600,14 +604,15 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
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):
# The test does not work because the and condition is not correctly supported
# We need the ExpressionParser
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("x is an int", body="isinstance(x, int)", pre="is_question()").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"),
@@ -622,7 +627,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
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("x is an int", body="isinstance(x, int)", pre="is_question()").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,
@@ -685,10 +690,10 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
eval_body=True
)
for concept in (c1, c2, c3, c4):
for concept, expected in ((c1, 3), (c2, 1), (c3, 2), (c4, 3)):
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.body == InfiniteRecursionResolved(3)
assert evaluated.body == InfiniteRecursionResolved(expected)
def test_i_can_detect_infinite_recursion_when_no_constant(self):
sheerka, context, foo, bar, baz, qux = self.init_concepts(
@@ -877,26 +882,31 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(context, concept, eval_body=True)
assert evaluated.key == concept.key
assert concept.get_metadata().is_evaluated == expected
assert concept.get_hints().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'")
Concept("foo", pre="True", post="'post'", ret="'ret'", where="True", body="'body'").def_var("a", "'a'")
)
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=[ConceptParts.PRE])
assert evaluated.values() == {"a": NotInit, ConceptParts.PRE: 'pre'}
assert evaluated.values() == {"a": NotInit, ConceptParts.PRE: True}
def test_i_can_manage_ret(self):
sheerka, context, foo, bar = self.init_concepts("foo", Concept("bar", ret="foo"))
res = sheerka.evaluate_concept(context, bar)
assert res.id == bar.id
assert sheerka.isinstance(res, "bar")
res = sheerka.evaluate_concept(context, bar, eval_body=True)
assert res.id == foo.id
assert sheerka.isinstance(res, "foo")
# And the result is still the same after a second call
assert bar.get_hints().is_evaluated
res = sheerka.evaluate_concept(context, bar, eval_body=True)
assert sheerka.isinstance(res, "foo")
def test_ret_is_evaluated_only_is_body_is_requested(self):
sheerka, context, foo, bar = self.init_concepts("foo", Concept("bar", ret="__NOT_FOUND"))
@@ -930,7 +940,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
# 'def concept foo as foo'
return_values = [pr_ret_val(foo, parser="ExactConcept"), python_ret_val("foo")]
res = evaluator.get_recursive_definitions(foo, return_values)
res = evaluator.get_recursive_definitions(context, foo, return_values)
assert list(res) == [BaseParser.get_name("ExactConcept")]
@@ -941,7 +951,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
# 'def concept foo as bar'
return_values = [pr_ret_val(bar, parser="ExactConcept"), python_ret_val("foo")]
res = evaluator.get_recursive_definitions(foo, return_values)
res = evaluator.get_recursive_definitions(context, foo, return_values)
assert list(res) == []
@@ -953,18 +963,120 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
# i dunno how to construct the return value
return_values = [pr_ret_val(q, parser="ExactConcept")]
res = evaluator.get_recursive_definitions(q, return_values)
res = evaluator.get_recursive_definitions(context, q, return_values)
assert list(res) == []
# 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.get_compiled()) > 0
#
# evaluated_2 = sheerka.evaluate_concept(context, sheerka.new("foo"), eval_body=True)
# assert evaluated_2.body == 10
# assert len(evaluated_2.get_compiled()) == 0
def test_i_do_not_mess_up_use_copy_when_exact_concept(self):
sheerka, context, one, number, isa = self.init_concepts(
"one",
"number",
Concept("x is a y", body="isa(x,y)", pre="is_question()").def_var("x").def_var("y"))
evaluator = SheerkaEvaluateConcept(sheerka)
parsed_return_value = ExactConceptParser().parse(context, ParserInput("one is a number"))
concept = parsed_return_value[0].body.body
# just get the compiled
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
evaluated = evaluator.evaluate_concept(context, concept)
assert evaluated.get_compiled()["x"][0].body.body.get_hints().use_copy
assert evaluated.get_compiled()["y"][0].body.body.get_hints().use_copy
# get the body
evaluated = evaluator.evaluate_concept(context, concept, eval_body=True)
assert evaluated.get_compiled()["x"][0].body.body.get_hints().use_copy
assert evaluated.get_compiled()["y"][0].body.body.get_hints().use_copy
assert not evaluated.get_value("x").get_hints().use_copy
assert not evaluated.get_value("y").get_hints().use_copy
def test_i_do_not_mess_up_use_copy_when_expression_parser(self):
sheerka, context, one, number, isa = self.init_concepts(
"one",
"number",
Concept("x is a y", body="isa(x,y)", pre="is_question()").def_var("x").def_var("y"))
evaluator = SheerkaEvaluateConcept(sheerka)
parsed_return_value = ExpressionParser().parse(context, ParserInput("one is a number"))
concept = next(iter(parsed_return_value.body.body.compiled[0].return_value.body.body.objects.values()))
assert concept.get_compiled()["x"][0].body.body.get_hints().use_copy
assert concept.get_compiled()["y"][0].body.body.get_hints().use_copy
# get the body
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
evaluated = evaluator.evaluate_concept(context, concept, eval_body=True)
assert evaluated.get_compiled()["x"][0].body.body.get_hints().use_copy
assert evaluated.get_compiled()["y"][0].body.body.get_hints().use_copy
assert not evaluated.get_value("x").get_hints().use_copy
assert not evaluated.get_value("y").get_hints().use_copy
def test_i_do_not_evaluate_the_body_when_validation_only_is_set(self):
sheerka, context, red, shirt, a_x, red_x = self.init_concepts(
"red",
Concept("shirt", body="set_attr(self, 'body_shirt_is_evaluated', True)"),
Concept("a x", body="set_attr(x, 'body_ax_is_evaluated', True)", ret="x").def_var("x"),
Concept("red x", body="set_attr(x, 'color', 'red')", ret="x").def_var("x"),
create_new=True)
parsed_ret_val = SyaNodeParser().parse(context, ParserInput("a red shirt"))
# Sanity check for normal behaviour
to_evaluate1 = parsed_ret_val.body.body[0].concept.copy()
evaluated1 = sheerka.evaluate_concept(context, to_evaluate1, eval_body=True, validation_only=False)
assert sheerka.isinstance(evaluated1, shirt)
assert evaluated1.get_value("body_ax_is_evaluated") == True
assert evaluated1.get_value("body_shirt_is_evaluated") == True
assert evaluated1.get_value("color") == "red"
assert evaluated1.body == sheerka.new(BuiltinConcepts.SUCCESS)
# check validation_only behaviour
to_evaluate2 = parsed_ret_val.body.body[0].concept.copy()
evaluated2 = sheerka.evaluate_concept(context, to_evaluate2, eval_body=True, validation_only=True)
assert sheerka.isinstance(evaluated2, shirt)
assert evaluated2.get_value("body_ax_is_evaluated") == NotInit
assert evaluated2.get_value("body_shirt_is_evaluated") == NotInit
assert evaluated2.get_value("color") == NotInit
assert evaluated2.body == NotInit
def test_methods_with_side_effect_are_not_called_when_eval_body_is_false(self):
sheerka, context, red, shirt, a_x, red_x = self.init_concepts(
"red",
Concept("shirt", body="set_attr(self, 'body_shirt_is_evaluated', True)"),
Concept("a x", body="set_attr(x, 'body_ax_is_evaluated', True)", ret="x").def_var("x"),
Concept("red x", body="set_attr(x, 'color', 'red')", ret="x").def_var("x"),
create_new=True,
)
parsed_ret_val = SyaNodeParser().parse(context, ParserInput("a red shirt"))
to_evaluate = parsed_ret_val.body.body[0].concept
evaluated = sheerka.evaluate_concept(context, to_evaluate, eval_body=False)
assert sheerka.isinstance(evaluated, a_x)
assert "x" in evaluated.get_compiled()
assert ConceptParts.BODY in evaluated.get_compiled()
assert ConceptParts.RET in evaluated.get_compiled()
assert sheerka.isinstance(evaluated.get_compiled()["x"], red_x)
assert evaluated.get_compiled()["x"].get_compiled()["x"] == shirt # so, it's not evaluated
# sanity check
parsed_ret_val = SyaNodeParser().parse(context, ParserInput("a red shirt"))
to_evaluate = parsed_ret_val.body.body[0].concept
evaluated = sheerka.evaluate_concept(context, to_evaluate, eval_body=True)
assert sheerka.isinstance(evaluated, shirt)
assert evaluated.get_value("body_ax_is_evaluated") == True
assert evaluated.get_value("body_shirt_is_evaluated") == True
assert evaluated.get_value("color") == "red"
def test_concept_is_not_evaluated_when_method_access_error(self):
sheerka, context, foo = self.init_concepts(Concept("foo", body="set_attr(self, 'prop_name', 'prop_value')"))
evaluated = sheerka.evaluate_concept(context, foo, eval_body=True, validation_only=True)
assert sheerka.isinstance(evaluated, foo)
assert not foo.get_hints().is_evaluated
+26 -6
View File
@@ -2,14 +2,14 @@ import operator
import pytest
from core.builtin_concepts_ids import BuiltinConcepts
from core.concept import Concept, DEFINITION_TYPE_DEF
from core.rule import Rule, ACTION_TYPE_EXEC
from core.sheerka.Sheerka import RECOGNIZED_BY_ID, RECOGNIZED_BY_NAME
from core.sheerka.services.SheerkaEvaluateRules import SheerkaEvaluateRules, LOW_PRIORITY_RULES, DISABLED_RULES
from core.sheerka.services.SheerkaExecute import ParserInput
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, CompiledCondition
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, CompiledCondition, PythonConditionExprVisitor
from evaluators.PythonEvaluator import PythonEvaluator
from parsers.ExpressionParser import ExpressionParser
from parsers.PythonParser import PythonParser
from sheerkapython.python_wrapper import Expando
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -40,7 +40,7 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
DISABLED_RULES: [r7]
}
@pytest.mark.skip("Not ready for that")
@pytest.mark.skip("Rete is not ready for that")
def test_i_can_evaluate_question_concept_rules(self):
sheerka, context, concept, r1, r2, r3, r4, r5, r6, r7, r8, r9 = self.init_test().with_concepts(
Concept("x equals y", body="x == y", pre="is_question()").def_var("x").def_var("y"),
@@ -152,7 +152,7 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
there_instance = sheerka.new_from_template(there, there.key)
if recognized_by:
there_instance.set_hint(BuiltinConcepts.RECOGNIZED_BY, recognized_by)
there_instance.get_hints().recognized_by = recognized_by
ret = sheerka.ret("evaluator", True, sheerka.new(greetings, a=there_instance))
res = service.evaluate_rules(context, [rule], {"__ret": ret}, set())
assert res == {True: [rule]}
@@ -175,7 +175,7 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
my_friend_instance = sheerka.new_from_template(my_friend, my_friend.key)
if recognized_by:
my_friend_instance.set_hint(BuiltinConcepts.RECOGNIZED_BY, recognized_by)
my_friend_instance.get_hints().recognized_by = recognized_by
ret = sheerka.ret("evaluator", True, sheerka.new(greetings, a=my_friend_instance))
res = service.evaluate_rules(context, [rule], {"__ret": ret}, set())
assert res == {True: [rule]}
@@ -211,7 +211,8 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
def test_i_can_evaluate_concept_rule_with_the_same_name_when_the_second_concept_is_declared_after(self):
sheerka, context, g1, rule, g2 = self.init_test().with_concepts(
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
create_new=True).with_format_rules(Rule(predicate="recognize(__ret.body, greetings)", action="")).with_concepts(
create_new=True).with_format_rules(
Rule(predicate="recognize(__ret.body, greetings)", action="")).with_concepts(
Concept("greetings", definition="hi a", definition_type=DEFINITION_TYPE_DEF).def_var("a")).unpack()
service = sheerka.services[SheerkaEvaluateRules.NAME]
@@ -249,3 +250,22 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
assert rule in evaluate_rule_service.network.rules
assert rule.rete_net == evaluate_rule_service.network
def test_i_can_get_missing_variables_when_evaluate_conditions(self):
sheerka, context = self.init_test().unpack()
expression = "isinstance(a, int)"
parser = ExpressionParser()
ret_val = parser.parse(context, ParserInput(expression))
parsed = ret_val.body.body
visitor = PythonConditionExprVisitor(context)
conditions = visitor.get_conditions(parsed)
missing_vars = set()
service = sheerka.services[SheerkaEvaluateRules.NAME]
res = service.evaluate_conditions(context, conditions, {}, missing_vars)
assert res == []
assert missing_vars == {"a"}
+13 -1
View File
@@ -84,7 +84,19 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
assert sheerka.isinstance(error, BuiltinConcepts.NOT_A_SET)
assert error.body == one
def test_isa_and_isa_group(self):
def test_isa(self):
sheerka, context, blue, color = self.init_concepts(Concept("blue"), Concept("color"))
assert not sheerka.isa(blue, color)
sheerka.set_isa(context, blue, color)
assert sheerka.isa(blue, color)
# isa tests the id of a concept, not it's content
another_color_instance_but_with_a_body = sheerka.new(color, body="a body")
assert sheerka.isa(blue, another_color_instance_but_with_a_body)
def test_isaset(self):
sheerka, context, group, foo = self.init_concepts(Concept("group"), Concept("foo"))
assert not sheerka.isaset(context, group)
+103 -178
View File
@@ -4,28 +4,18 @@ from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept
from core.concept import Concept, DEFINITION_TYPE_DEF
from core.global_symbols import RULE_COMPARISON_CONTEXT, NotFound, EVENT_RULE_DELETED
from core.rule import Rule, ACTION_TYPE_PRINT, ACTION_TYPE_EXEC
from core.sheerka.Sheerka import RECOGNIZED_BY_ID, RECOGNIZED_BY_NAME
from core.sheerka.services.SheerkaExecute import ParserInput
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, FormatRuleActionParser, \
FormatAstRawText, FormatAstVariable, FormatAstSequence, FormatAstFunction, \
FormatRuleSyntaxError, FormatAstList, UnexpectedEof, FormatAstColor, FormatAstDict, \
FormatAstMulti, \
PythonCodeEmitter, FormatAstNode, ReteConditionExprVisitor
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, ReteConditionExprVisitor
from core.tokenizer import Token, TokenKind
from parsers.BaseParser import ErrorSink
from parsers.ExpressionParser import ExpressionParser
from parsers.FormatRuleActionParser import FormatAstNode
from sheerkarete.conditions import FilterCondition
from sheerkarete.network import ReteNetwork
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.parsers.parsers_utils import get_rete_conditions, NEGCOND, NCCOND
seq = FormatAstSequence
raw = FormatAstRawText
var = FormatAstVariable
func = FormatAstFunction
lst = FormatAstList
PYTHON_EVALUATOR_NAME = "Python"
CONCEPT_EVALUATOR_NAME = "Concept"
@@ -175,7 +165,7 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
sheerka, context = self.init_test(cache_only=False).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
rule = Rule(ACTION_TYPE_EXEC, "name", "cannot build = False", "'Hello back at you !'")
rule = Rule(action_type, "name", "cannot build = False", action)
rule.metadata.is_enabled = True # it should be disabled
rule = service.init_rule(context, rule)
@@ -209,71 +199,6 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
assert not rule.metadata.is_enabled
assert rule.compiled_action is None
@pytest.mark.parametrize("text, expected", [
("", FormatAstRawText("")),
(" ", FormatAstRawText(" ")),
(" raw text ", FormatAstRawText(" raw text ")),
("{variable}", FormatAstVariable("variable")),
("{ variable }", FormatAstVariable("variable")),
(" xy {v} z", seq([raw(" xy "), var("v"), raw(" z")])),
(r"\{variable}", FormatAstRawText("{variable}")),
(r"\\{variable}", seq([raw("\\"), var("variable")])),
(r"\\\{variable}", FormatAstRawText(r"\{variable}")),
(r"{var1}{var2}", seq([var("var1"), var("var2")])),
("func()", FormatAstFunction("func", [], {})),
("func(a, 'string value', c)", FormatAstFunction("func", ["a", "'string value'", "c"], {})),
("func(a=10, b='string value')", FormatAstFunction("func", [], {"a": "10", "b": "'string value'"})),
("func('string value'='another string value')", func("func", [], {"'string value'": "'another string value'"})),
("red(' xy {v}')", FormatAstColor("red", seq([raw(" xy "), var("v")]))),
('blue(" xy {v}")', FormatAstColor("blue", seq([raw(" xy "), var("v")]))),
('green( xy )', FormatAstColor("green", var("xy"))),
('green()', FormatAstColor("green", raw(""))),
('green("")', FormatAstColor("green", raw(""))),
("list(var_name, 2, 'children')", FormatAstList("var_name", recurse_on="children", recursion_depth=2)),
("list(var_name, recursion_depth=2, recurse_on='children')", FormatAstList("var_name",
recurse_on="children",
recursion_depth=2)),
("list(var_name, recursion_depth=2, 'children')", FormatAstList("var_name", recursion_depth=2)),
("list(var_name, 'children', recursion_depth=2)", FormatAstList("var_name", recursion_depth=2)),
("list(var_name)", FormatAstList("var_name")),
("{obj.prop1.prop2[0].prop3['value']}", FormatAstVariable("obj.prop1.prop2[0].prop3['value']")),
("[{id}]", seq([raw("["), var("id"), raw("]")])),
("{variable:format}", FormatAstVariable("variable", "format")),
("{variable:3}", FormatAstVariable("variable", "3")),
(r"\not_a_function(a={var})", seq([raw("not_a_function(a="), var("var"), raw(")")])),
("dict(var_name)", FormatAstDict("var_name")),
("dict(var_name, items_prop='props')", FormatAstDict("var_name", items_prop='props')),
("dict(var_name, debug=True)", FormatAstDict("var_name", debug=True, prefix="{", suffix="}")),
("multi(var_name)", FormatAstMulti("var_name")),
])
def test_i_can_parse_format_rule(self, text, expected):
assert FormatRuleActionParser(text).parse() == expected
@pytest.mark.parametrize("text, expected_error", [
("{", UnexpectedEof("while parsing variable", Token(TokenKind.LBRACE, "{", 0, 1, 1))),
("{var_name", UnexpectedEof("while parsing variable", Token(TokenKind.LBRACE, "{", 0, 1, 1))),
("{}", FormatRuleSyntaxError("variable name not found", None)),
("func(", UnexpectedEof("while parsing function", Token(TokenKind.IDENTIFIER, "func", 0, 1, 1))),
("func(a,b,c", UnexpectedEof("while parsing function", Token(TokenKind.IDENTIFIER, "func", 0, 1, 1))),
("func(a,,c", FormatRuleSyntaxError("no parameter found", Token(TokenKind.COMMA, ",", 7, 1, 8))),
("func(a,,c)", FormatRuleSyntaxError("no parameter found", Token(TokenKind.COMMA, ",", 7, 1, 8))),
("red(a,b)", FormatRuleSyntaxError("only one parameter supported", Token(TokenKind.IDENTIFIER, "b", 6, 1, 7))),
("red(a=b)", FormatRuleSyntaxError("keyword arguments are not supported", None)),
("red(xy {v})", FormatRuleSyntaxError("Invalid identifier", None)),
("list()", FormatRuleSyntaxError("variable name not found", None)),
("list(recursion_depth=2)", FormatRuleSyntaxError("variable name not found", None)),
("list(a,b,c,d,e)", FormatRuleSyntaxError("too many positional arguments",
Token(TokenKind.IDENTIFIER, "e", 13, 1, 14))),
("list(a, recursion_depth=hello)", FormatRuleSyntaxError("'hello' is not numeric", None)),
("list(a, recursion_depth='hello')", FormatRuleSyntaxError("'recursion_depth' must be an integer", None)),
("dict()", FormatRuleSyntaxError("variable name not found", None)),
])
def test_i_cannot_parse_invalid_format(self, text, expected_error):
parser = FormatRuleActionParser(text)
parser.parse()
assert parser.error_sink == expected_error
def test_i_can_get_rule_priorities(self):
sheerka, context, rule_true, rule_false = self.init_test().with_format_rules(("True", "True"),
("False", "False")).unpack()
@@ -337,106 +262,6 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
unresolved.metadata.id_is_unresolved = True
assert sheerka.resolve_rule(context, unresolved) == rule
@pytest.mark.parametrize("obj, expected", [
("text value", "var == 'text value'"),
("text 'value'", '''var == "text 'value'"'''),
('text "value"', """var == 'text "value"'"""),
(10, "var == 10"),
(10.01, "var == 10.01"),
])
def test_i_can_test_python_code_emitter_for_basic_types(self, obj, expected):
sheerka, context = self.init_test().unpack()
assert PythonCodeEmitter(context).recognize(obj, "var").get_text() == expected
assert PythonCodeEmitter(context, "status").recognize(obj, "var").get_text() == "status and " + expected
@pytest.mark.parametrize("recognized_by, expected", [
(RECOGNIZED_BY_ID, "isinstance(var, Concept) and var.id == '1001'"),
(RECOGNIZED_BY_NAME, "isinstance(var, Concept) and var.name == 'greetings'"),
(None, "isinstance(var, Concept) and var.key == 'hello'"),
])
def test_i_can_test_python_code_emitter_for_concepts(self, recognized_by, expected):
sheerka, context, foo = self.init_concepts(
Concept("greetings", definition="hello", definition_type=DEFINITION_TYPE_DEF))
instance = sheerka.new_from_template(foo, foo.key)
if recognized_by:
instance.set_hint(BuiltinConcepts.RECOGNIZED_BY, recognized_by)
assert PythonCodeEmitter(context).recognize(instance, "var").get_text() == expected
assert PythonCodeEmitter(context, "status").recognize(instance, "var").get_text() == "status and " + expected
def test_i_can_test_python_code_emitter_for_concepts_with_variable(self):
sheerka, context, greetings, little, foo, bar, and_concept = self.init_concepts(
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
Concept("little x").def_var("x"),
"foo",
"bar",
Concept("a and b").def_var("a").def_var("b")
)
# variable is a string
greetings_instance = sheerka.new_from_template(greetings, greetings.key, a='sheerka')
expected = "isinstance(var, Concept) and var.key == 'hello __var__0' and var.get_value('a') == 'sheerka'"
text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
assert text == expected
# variable is a concept recognized by id
foo_instance = sheerka.new_from_template(foo, foo.key)
foo_instance.set_hint(BuiltinConcepts.RECOGNIZED_BY, RECOGNIZED_BY_ID)
greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=foo_instance)
expected = """__x_00__ = var.get_value('a')
isinstance(var, Concept) and var.key == 'hello __var__0' and isinstance(__x_00__, Concept) and __x_00__.id == '1003'"""
text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
assert text == expected
# variable is a concept recognized by name
foo_instance = sheerka.new_from_template(foo, foo.key)
foo_instance.set_hint(BuiltinConcepts.RECOGNIZED_BY, RECOGNIZED_BY_NAME)
greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=foo_instance)
expected = """__x_00__ = var.get_value('a')
isinstance(var, Concept) and var.key == 'hello __var__0' and isinstance(__x_00__, Concept) and __x_00__.name == 'foo'"""
text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
assert text == expected
# variable is a concept recognized by value
foo_instance = sheerka.new_from_template(foo, foo.key)
greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=foo_instance)
expected = """__x_00__ = var.get_value('a')
isinstance(var, Concept) and var.key == 'hello __var__0' and isinstance(__x_00__, Concept) and __x_00__.key == 'foo'"""
text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
assert text == expected
# variable is a concept witch has itself some variable
foo_instance = sheerka.new_from_template(foo, foo.key)
little_instance = sheerka.new_from_template(little, little.key, x=foo_instance)
greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=little_instance)
expected = """__x_00__ = var.get_value('a')
__x_01__ = __x_00__.get_value('x')
isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
" and isinstance(__x_00__, Concept) and __x_00__.key == 'little __var__0'" + \
" and isinstance(__x_01__, Concept) and __x_01__.key == 'foo'"""
text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
assert text == expected
# concept with multiple variables (which are themselves concepts)
foo_instance = sheerka.new_from_template(foo, foo.key)
bar_instance = sheerka.new_from_template(bar, bar.key)
little_instance = sheerka.new_from_template(little, little.key, x=foo_instance)
and_instance = sheerka.new_from_template(and_concept, and_concept.key, a=bar_instance, b=little_instance)
greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=and_instance)
expected = """__x_00__ = var.get_value('a')
__x_01__ = __x_00__.get_value('a')
__x_02__ = __x_00__.get_value('b')
__x_03__ = __x_02__.get_value('x')
isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
" and isinstance(__x_00__, Concept) and __x_00__.key == '__var__0 and __var__1'" + \
" and isinstance(__x_01__, Concept) and __x_01__.key == 'bar'" + \
" and isinstance(__x_02__, Concept) and __x_02__.key == 'little __var__0'" + \
" and isinstance(__x_03__, Concept) and __x_03__.key == 'foo'"
text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
assert text == expected
def test_i_can_get_format_rules(self):
sheerka, context = self.init_test().unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
@@ -674,3 +499,103 @@ class TestSheerkaRuleManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
assert rule.compiled_conditions == expected.compiled_conditions
assert rule.priority is not None
assert rule.priority == expected.priority
# @pytest.mark.parametrize("obj, expected", [
# ("text value", "var == 'text value'"),
# ("text 'value'", '''var == "text 'value'"'''),
# ('text "value"', """var == 'text "value"'"""),
# (10, "var == 10"),
# (10.01, "var == 10.01"),
# ])
# def test_i_can_test_python_code_emitter_for_basic_types(self, obj, expected):
# sheerka, context = self.init_test().unpack()
#
# assert PythonCodeEmitter(context).recognize(obj, "var").get_text() == expected
# assert PythonCodeEmitter(context, "status").recognize(obj, "var").get_text() == "status and " + expected
#
# @pytest.mark.parametrize("recognized_by, expected", [
# (RECOGNIZED_BY_ID, "isinstance(var, Concept) and var.id == '1001'"),
# (RECOGNIZED_BY_NAME, "isinstance(var, Concept) and var.name == 'greetings'"),
# (None, "isinstance(var, Concept) and var.key == 'hello'"),
# ])
# def test_i_can_test_python_code_emitter_for_concepts(self, recognized_by, expected):
# sheerka, context, foo = self.init_concepts(
# Concept("greetings", definition="hello", definition_type=DEFINITION_TYPE_DEF))
#
# instance = sheerka.new_from_template(foo, foo.key)
# if recognized_by:
# instance.get_hints().recognized_by = recognized_by
#
# assert PythonCodeEmitter(context).recognize(instance, "var").get_text() == expected
# assert PythonCodeEmitter(context, "status").recognize(instance, "var").get_text() == "status and " + expected
#
# def test_i_can_test_python_code_emitter_for_concepts_with_variable(self):
# sheerka, context, greetings, little, foo, bar, and_concept = self.init_concepts(
# Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
# Concept("little x").def_var("x"),
# "foo",
# "bar",
# Concept("a and b").def_var("a").def_var("b")
# )
#
# # variable is a string
# greetings_instance = sheerka.new_from_template(greetings, greetings.key, a='sheerka')
# expected = "isinstance(var, Concept) and var.key == 'hello __var__0' and var.get_value('a') == 'sheerka'"
# text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
# assert text == expected
#
# # variable is a concept recognized by id
# foo_instance = sheerka.new_from_template(foo, foo.key)
# foo_instance.get_hints().recognized_by = RECOGNIZED_BY_ID
# greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=foo_instance)
# expected = """__x_00__ = var.get_value('a')
# isinstance(var, Concept) and var.key == 'hello __var__0' and isinstance(__x_00__, Concept) and __x_00__.id == '1003'"""
# text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
# assert text == expected
#
# # variable is a concept recognized by name
# foo_instance = sheerka.new_from_template(foo, foo.key)
# foo_instance.get_hints().recognized_by = RECOGNIZED_BY_NAME
# greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=foo_instance)
# expected = """__x_00__ = var.get_value('a')
# isinstance(var, Concept) and var.key == 'hello __var__0' and isinstance(__x_00__, Concept) and __x_00__.name == 'foo'"""
# text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
# assert text == expected
#
# # variable is a concept recognized by value
# foo_instance = sheerka.new_from_template(foo, foo.key)
# greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=foo_instance)
# expected = """__x_00__ = var.get_value('a')
# isinstance(var, Concept) and var.key == 'hello __var__0' and isinstance(__x_00__, Concept) and __x_00__.key == 'foo'"""
# text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
# assert text == expected
#
# # variable is a concept witch has itself some variable
# foo_instance = sheerka.new_from_template(foo, foo.key)
# little_instance = sheerka.new_from_template(little, little.key, x=foo_instance)
# greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=little_instance)
# expected = """__x_00__ = var.get_value('a')
# __x_01__ = __x_00__.get_value('x')
# isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
# " and isinstance(__x_00__, Concept) and __x_00__.key == 'little __var__0'" + \
# " and isinstance(__x_01__, Concept) and __x_01__.key == 'foo'"""
# text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
# assert text == expected
#
# # concept with multiple variables (which are themselves concepts)
# foo_instance = sheerka.new_from_template(foo, foo.key)
# bar_instance = sheerka.new_from_template(bar, bar.key)
# little_instance = sheerka.new_from_template(little, little.key, x=foo_instance)
# and_instance = sheerka.new_from_template(and_concept, and_concept.key, a=bar_instance, b=little_instance)
# greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=and_instance)
# expected = """__x_00__ = var.get_value('a')
# __x_01__ = __x_00__.get_value('a')
# __x_02__ = __x_00__.get_value('b')
# __x_03__ = __x_02__.get_value('x')
# isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
# " and isinstance(__x_00__, Concept) and __x_00__.key == '__var__0 and __var__1'" + \
# " and isinstance(__x_01__, Concept) and __x_01__.key == 'bar'" + \
# " and isinstance(__x_02__, Concept) and __x_02__.key == 'little __var__0'" + \
# " and isinstance(__x_03__, Concept) and __x_03__.key == 'foo'"
# text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
# assert text == expected
@@ -4,6 +4,7 @@ import pytest
from core.builtin_concepts import ReturnValueConcept
from core.builtin_concepts_ids import BuiltinConcepts
from core.builtin_helpers import ensure_evaluated
from core.concept import Concept, DEFINITION_TYPE_DEF
from core.rule import Rule
from core.sheerka.services.SheerkaEvaluateRules import SheerkaEvaluateRules
@@ -23,6 +24,19 @@ from tests.parsers.parsers_utils import get_rete_conditions, NEGCOND
class BaseTestSheerkaRuleManagerRulesCompilation(TestUsingMemoryBasedSheerka):
@staticmethod
def get_conditions(context, expression):
parser = ExpressionParser()
error_sink = ErrorSink()
parser_input = ParserInput(expression)
parser.reset_parser_input(parser_input, error_sink)
parsed = parser.parse_input(context, parser_input, error_sink)
visitor = PythonConditionExprVisitor(context)
conditions = visitor.get_conditions(parsed)
return conditions
@staticmethod
def check_against_rete(rule_expression, rule_conditions, objects):
"""
@@ -72,6 +86,9 @@ class BaseTestSheerkaRuleManagerRulesCompilation(TestUsingMemoryBasedSheerka):
sub_context.sheerka.add_many_to_short_term_memory(sub_context, objects)
evaluator = PythonEvaluator()
for c in condition.concepts_to_reset:
c.get_hints().is_evaluated = False
return evaluator.eval(sub_context, condition.return_value)
@classmethod
@@ -130,15 +147,7 @@ class BaseTestSheerkaRuleManagerRulesCompilation(TestUsingMemoryBasedSheerka):
expected_not_variables,
expected_objects):
sheerka = context.sheerka
parser = ExpressionParser()
error_sink = ErrorSink()
parser_input = ParserInput(expression)
parser.reset_parser_input(parser_input, error_sink)
parsed = parser.parse_input(context, parser_input, error_sink)
visitor = PythonConditionExprVisitor(context)
conditions = visitor.get_conditions(parsed)
conditions = BaseTestSheerkaRuleManagerRulesCompilation.get_conditions(context, expression)
assert len(conditions) == 1
assert isinstance(conditions[0], CompiledCondition)
@@ -312,6 +321,132 @@ class TestSheerkaRuleManagerRulesCompilationNotExists(BaseTestSheerkaRuleManager
self.check_against_python(context, expression, conditions, objects)
class TestSheerkaRuleManagerRulesCompilationSimplePython(BaseTestSheerkaRuleManagerRulesCompilation):
"""
Testing Python
True
False
10 + 5
'hello world'
a + self
a + 10
a + " world !"
a + foo
a + twenty one
a + my friend
"""
@pytest.mark.parametrize("expression, e_compiled, e_text, e_variables, e_objects, e_result", [
(
"True",
"True",
"True",
set(),
set(),
True
),
(
"False",
"False",
"False",
set(),
set(),
False
),
(
"10 + 5",
"__o_00__",
"10 + 5",
set(),
{("__o_00__", 15)},
15
),
(
"'hello world'",
"__o_00__",
"'hello world'",
set(),
{("__o_00__", 'hello world')},
'hello world'
),
(
"a + self",
"a + self",
"a + self",
{("a", 10), ("self", "foo")},
set(),
15
),
(
"a + 10",
"a + 10",
"a + 10",
{("a", 10)},
set(),
20
),
(
"a + 'world !'",
"a + 'world !'",
"a + 'world !'",
{("a", "hello ")},
set(),
"hello world !"
),
(
"a + foo",
"a + foo",
"a + foo",
{("a", 10), ("foo", "foo")},
set(),
15
),
(
"a + twenty one",
"a + __C__twenties__1004__C__",
"a + twenty one",
{("a", 10)},
{"__C__twenties__1004__C__"},
31
),
(
"a + my friend",
"a + __C__my0friend__1005__C__",
"a + my friend",
{("a", "hello ")},
{'__C__my0friend__1005__C__'},
"hello my friend"
),
])
def test_python(self, expression, e_compiled, e_text, e_variables, e_objects, e_result):
sheerka, context, foo, one, two, twenties, my_friend = self.init_concepts(
Concept("foo", body="5"),
Concept("one", body="1"),
Concept("two", body="2"),
Concept("twenties", definition="'twenty' (one|two)=n", body='20 + n').def_var("n"),
Concept("my friend", body="'my friend'"),
create_new=True
)
ensure_evaluated(context, foo, eval_body=True)
ensure_evaluated(context, my_friend, eval_body=True)
conditions = self.validate_python_test(context,
expression,
e_compiled,
e_text,
e_variables,
set(),
e_objects)
# check against SheerkaEvaluateRules
variables_mapping = {
"foo": foo,
}
namespace = self.get_testing_objects(context, e_variables, variables_mapping)
res = self.evaluate_condition(context, expression, conditions[0], namespace)
assert res.status
assert sheerka.objvalue(res) == e_result
class TestSheerkaRuleManagerRulesCompilationEquality(BaseTestSheerkaRuleManagerRulesCompilation):
"""
Testing simple equality:
@@ -321,6 +456,7 @@ class TestSheerkaRuleManagerRulesCompilationEquality(BaseTestSheerkaRuleManagerR
self == sheerka
self == BuiltinConcepts.TO_DICT
self == hello 'my friend'
a == b
"""
@pytest.mark.parametrize("expression, expected_as_list_of_str, expected_variables", [
@@ -339,7 +475,12 @@ class TestSheerkaRuleManagerRulesCompilationEquality(BaseTestSheerkaRuleManagerR
"#__x_00__|key|'hello __var__0'",
"#__x_00__|a|'my friend'"],
{("self", "hello_my_friend")}
)
),
# ("a == b",
# ["#__x_00__|__name__|'a'",
# "#__x_01__|__name__|'b'",
# "#__x_00__|__self__|#__x_01__"],
# {("a", 10), ("b", 10)}),
])
def test_rete(self, expression, expected_as_list_of_str, expected_variables):
sheerka, context, greetings = self.init_test().with_concepts(
@@ -365,23 +506,27 @@ class TestSheerkaRuleManagerRulesCompilationEquality(BaseTestSheerkaRuleManagerR
objects = self.get_testing_objects(context, expected_variables, objects_mappings)
self.check_against_rete(expression, conditions, objects)
# KSI: 2021-05-06 The last test done not produce any match because the WME (b, __self__, 10)
# is not added to memory.
@pytest.mark.parametrize("expression, expected_compiled, expected_variables, expected_objects", [
("a == 10", "a == __o_00__", {("a", 10)}, {("__o_00__", 10)}),
("__ret.status == True", "__ret.status == __o_00__", {"__ret"}, {("__o_00__", True)}),
("__ret.status == True", "__ret.status == True", {"__ret"}, set()),
("self == 'a'", "self == __o_00__", {("self", 'a')}, {("__o_00__", 'a')}),
("self == sheerka", "is_sheerka(self)", {("self", "sheerka")}, {}),
(
"self == BuiltinConcepts.TO_DICT",
"self == __o_00__",
"self == BuiltinConcepts.TO_DICT",
{("self", BuiltinConcepts.TO_DICT)},
{("__o_00__", BuiltinConcepts.TO_DICT)}
set()
),
(
"self == hello 'my friend'",
"""isinstance(self, Concept) and self.key == 'hello __var__0' and self.a == __o_01__""",
{("self", "hello_my_friend")},
{("__o_01__", "my friend")}
)
),
("a == b", "a == b", {("a", 10), ("b", 10)}, {}),
])
def test_python(self, expression, expected_compiled, expected_variables, expected_objects):
sheerka, context, greetings = self.init_test().with_concepts(
@@ -403,6 +548,176 @@ class TestSheerkaRuleManagerRulesCompilationEquality(BaseTestSheerkaRuleManagerR
self.check_against_python(context, expression, conditions, objects)
class TestSheerkaRuleManagerRulesCompilationOtherConditions(BaseTestSheerkaRuleManagerRulesCompilation):
"""
Testing other conditions than equality
a > 10
a >= 10
a < 10
a <= 10
a != 10
a > 10 and b <= 5
__ret.value > 10
10 > __ret.value
a + self > 10
a + 10 > 10
a + " world !" == "hello world !"
a + foo > 10
a + twenty one > 21
a + my friend == 'hello my friend'
10 < a + self
10 < a + 10
'hello world !' == a + ' world !'
10 < a + foo
10 > a + twenty one
'hello my friend' == a + my friend
"""
@pytest.mark.parametrize("expression, e_compiled, e_variables, e_objects, e_result", [
("a > 10", "a > __o_00__", {("a", 10)}, {("__o_00__", 10)}, False),
("a >= 10", "a >= __o_00__", {("a", 10)}, {("__o_00__", 10)}, True),
("a < 10", "a < __o_00__", {("a", 10)}, {("__o_00__", 10)}, False),
("a <= 10", "a <= __o_00__", {("a", 10)}, {("__o_00__", 10)}, True),
("a != 10", "a != __o_00__", {("a", 10)}, {("__o_00__", 10)}, False),
(
"a > 10 and b <= 5",
"a > __o_00__ and b <= __o_01__",
{("a", 11), ("b", 4)},
{("__o_00__", 10), ("__o_01__", 5)},
True
),
(
"__ret.value > 10",
"__ret.value > __o_00__",
{("__ret", 15)},
{("__o_00__", 10)},
True
),
(
"10 > __ret.value",
"__o_00__ > __ret.value",
{("__ret", 15)},
{("__o_00__", 10)},
False
),
(
"a + self > 10",
"a + self > __o_00__",
{("a", 6), ("self", "foo")},
{("__o_00__", 10)},
True
),
(
"a + 10 > 10",
"a + 10 > __o_00__",
{("a", 5)},
{("__o_00__", 10)},
True
),
(
"a + 'world !' == 'hello world !'",
"a + 'world !' == __o_00__",
{("a", "hello ")},
{("__o_00__", 'hello world !')},
True
),
(
"a + foo > 10",
"a + foo > __o_00__",
{("a", 6), ("foo", "foo")},
{("__o_00__", 10)},
True
),
(
"a + twenty one > 21",
"a + __C__twenties__1004__C__ > __o_00__",
{("a", 5)},
{"__C__twenties__1004__C__", ("__o_00__", 21)},
True
),
(
"a + my friend == 'hello my friend'",
"a + __C__my0friend__1005__C__ == __o_00__",
{("a", "hello ")},
{"__C__my0friend__1005__C__", ("__o_00__", 'hello my friend')},
True
),
(
"10 < a + self",
"__o_00__ < a + self",
{("a", 6), ("self", "foo")},
{("__o_00__", 10)},
True
),
(
"10 > a + 10",
"__o_00__ > a + 10",
{("a", 5)},
{("__o_00__", 10)},
False
),
(
"'hello world !' != a + 'world !'",
"__o_00__ != a + 'world !'",
{("a", "hello ")},
{("__o_00__", 'hello world !')},
False
),
(
"10 < a + foo",
"__o_00__ < a + foo",
{("a", 6), ("foo", "foo")},
{("__o_00__", 10)},
True
),
(
"21 > a + twenty one",
"__o_00__ > a + __C__twenties__1004__C__",
{("a", 5)},
{"__C__twenties__1004__C__", ("__o_00__", 21)},
False
),
(
"'hello my friend' == a + my friend",
"__o_00__ == a + __C__my0friend__1005__C__",
{("a", "hello ")},
{"__C__my0friend__1005__C__", ("__o_00__", 'hello my friend')},
True
),
])
def test_python(self, expression, e_compiled, e_variables, e_objects, e_result):
sheerka, context, foo, one, two, twenties, my_friend = self.init_concepts(
Concept("foo", body="5"),
Concept("one", body="1"),
Concept("two", body="2"),
Concept("twenties", definition="'twenty' (one|two)=n", body='20 + n').def_var("n"),
Concept("my friend", body="'my friend'"),
create_new=True
)
ensure_evaluated(context, foo, eval_body=True)
ensure_evaluated(context, my_friend, eval_body=True)
conditions = self.validate_python_test(context,
expression,
e_compiled,
expression,
e_variables,
set(),
e_objects)
# check against SheerkaEvaluateRules
variables_mapping = {
"foo": foo,
}
objects = self.get_testing_objects(context, e_variables, variables_mapping)
self.check_against_python(context, expression, conditions, objects, expected_result=e_result)
class TestSheerkaRuleManagerRulesCompilationFunctionsCall(BaseTestSheerkaRuleManagerRulesCompilation):
"""
Testing functions
@@ -795,6 +1110,8 @@ class TestSheerkaRuleManagerRulesCompilationEvalQuestionConcept(BaseTestSheerkaR
with long concept : the little boy is a human being
with long concept + variable : the little boy is a self
with long concept + variable : self is a human being
with a special symbol : self is a 'human'
with a special symbol : the little boy is a 'human'
"""
def test_rete(self):
@@ -826,6 +1143,16 @@ class TestSheerkaRuleManagerRulesCompilationEvalQuestionConcept(BaseTestSheerkaR
"evaluate_question(__o_00__)",
{"self"},
),
(
"self is a 'human'",
"evaluate_question(__o_00__)",
{"self"},
),
(
"the little boy is a 'human'",
"evaluate_question(__o_00__)",
set(),
),
])
def test_python(self, expression, expected_compiled, expected_variables):
sheerka, context, girl, human, little_boy, human_being, isa = self.init_test().with_concepts(
@@ -980,11 +1307,11 @@ class TestSheerkaRuleManagerRulesCompilationEvalConceptMixedWithOther(BaseTestSh
expected_objects)
# check against SheerkaEvaluateRules
variable_mapping = {
variables_mapping = {
"girl": girl,
"human being": human_being
}
testing_objects = self.get_testing_objects(context, expected_variables, variable_mapping)
testing_objects = self.get_testing_objects(context, expected_variables, variables_mapping)
self.check_against_python(context,
expression,
conditions,
@@ -1005,6 +1332,8 @@ class TestSheerkaRuleManagerRulesCompilationEvalNonQuestionConcept(BaseTestSheer
with function: func_identity(twenty two + twenty one)
with function: func_identity(twenty two plus one)
with function: func_identity(twenty two plus twenty one)
with special char : 'one' plus 'two'
with special char : twenty two plus 2
"""
def test_rete(self):
@@ -1081,6 +1410,20 @@ class TestSheerkaRuleManagerRulesCompilationEvalNonQuestionConcept(BaseTestSheer
{"__o_00__"},
43
),
(
"'one' plus 'two'",
"__o_00__",
"'one' plus 'two'",
{"__o_00__"},
'onetwo'
),
(
"twenty two plus 2",
"__o_00__",
"twenty two plus 2",
{"__o_00__"},
24
),
])
def test_python(self, expression, e_compiled, e_text, e_objects, e_result):
sheerka, context, one, two, twenties, plus = self.init_test().with_concepts(
@@ -1109,7 +1452,7 @@ class TestSheerkaRuleManagerRulesCompilationEvalNonQuestionConcept(BaseTestSheer
class TestSheerkaRuleManagerRulesCompilationMultipleSameConcept(BaseTestSheerkaRuleManagerRulesCompilation):
"""
Test when a concept returns multiple results
The compilation should fail : No need to execute a condition if we are not sure of the meaning ?
The compilation should fail : No need to execute a condition if we are not sure of the meaning
self is a bar
"""
@@ -1156,6 +1499,99 @@ class TestSheerkaRuleManagerRulesCompilationNot(BaseTestSheerkaRuleManagerRulesC
Testing not
not __ret.status == True
not recognize(__ret.body, hello sheerka)
not a cat is a pet and not bird is an animal # where x is a y is a concept
not a cat is a pet and not x > 5 # concept mixed with python
"""
pass
class TestCompiledCondition(BaseTestSheerkaRuleManagerRulesCompilation):
@pytest.mark.parametrize("expression, expected", [
("self is a 'foo'", {"x is a y"}),
("set self is a 'foo'", set()),
])
def test_i_can_get_concept_to_reset(self, expression, expected):
"""
When compiled conditions, sometimes there are concepts to reset between two usages
:param expression:
:param expected:
:return:
"""
sheerka, context, question, not_a_question = self.init_concepts(
Concept("x is a y", pre="is_question()").def_var("x").def_var("y"),
Concept("set x is a y").def_var("x").def_var("y"),
)
conditions = self.get_conditions(context, expression)
assert len(conditions) == 1
assert set(c.name for c in conditions[0].concepts_to_reset) == expected
def test_i_can_reset_concepts_when_multiple_levels(self):
"""
When compiled conditions, sometimes there are concepts to reset between two usages
:return:
"""
sheerka, context, is_instance, is_int, is_integer = self.init_concepts(
Concept("x is an instance of y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
Concept("x is a int", pre="is_question()", body="x is an instance of int").def_var("x"),
Concept("x is an integer", pre="is_question()", body="x is a int").def_var("x"),
)
expression = "self is an integer"
conditions = conditions = self.get_conditions(context, expression)
assert len(conditions) == 1
assert set(c.name for c in conditions[0].concepts_to_reset) == {"x is an instance of y",
"x is a int",
"x is an integer"}
# So I can evaluate multiple times
res = self.evaluate_condition(context, expression, conditions[0], {'self': 10})
assert res.status
assert sheerka.objvalue(res.body)
res = self.evaluate_condition(context, expression, conditions[0], {'self': "string"})
assert res.status
assert not sheerka.objvalue(res.body)
def test_i_can_reset_concepts_when_multiple_levels_and_concept_node(self):
"""
When compiled conditions, sometimes there are concepts to reset between two usages
:return:
"""
# in this example, x + 2 is an int won't be parsed as an ExactNodeConcept, but as a ConceptNode
sheerka, context, is_int, is_integer = self.init_concepts(
Concept("x is a int", pre="is_question()", body="isinstance(x, int)").def_var("x"),
Concept("x is an integer", pre="is_question()", body="x + 2 is a int").def_var("x"),
create_new=True
)
expression = "self is an integer"
conditions = self.get_conditions(context, expression)
assert len(conditions) == 1
assert set(c.name for c in conditions[0].concepts_to_reset) == {"x is a int",
"x is an integer"}
# So I can evaluate multiple times
res = self.evaluate_condition(context, expression, conditions[0], {'self': 10})
assert res.status
assert sheerka.objvalue(res.body)
res = self.evaluate_condition(context, expression, conditions[0], {'self': "string"})
assert not res.status
def test_long_name_concept_set_are_not_considered_as_variables(self):
sheerka, context, one, number = self.init_concepts(
"one",
"all numbers",
)
sheerka.set_isa(context, one, number)
expression = "all numbers < 5"
conditions = self.get_conditions(context, expression)
assert len(conditions) == 1
assert conditions[0].return_value.body.body.source == '__o_00__ < __o_01__'
+60
View File
@@ -4,6 +4,13 @@ import core.builtin_helpers
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
from core.concept import Concept
from core.global_symbols import NotInit
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Tokenizer
from evaluators.BaseEvaluator import BaseEvaluator
from evaluators.ValidateConceptEvaluator import ValidateConceptEvaluator
from parsers.BaseNodeParser import ConceptNode
from parsers.BaseParser import BaseParser
from parsers.SyaNodeParser import SyaNodeParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -162,6 +169,7 @@ class TestBuiltinHelpers(TestUsingMemoryBasedSheerka):
(" is_question ( ) ", True),
("context.in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)", True),
(" context . in_context ( BuiltinConcepts . EVAL_QUESTION_REQUESTED ) ", True),
("in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)", True),
(None, False),
("", False),
(NotInit, False),
@@ -193,6 +201,58 @@ class TestBuiltinHelpers(TestUsingMemoryBasedSheerka):
evaluated = [r for r in res if r.status][0].body
assert evaluated.body is NotInit
def test_i_can_evaluate_from_source_with_specific_evaluators(self):
sheerka, context, one = self.init_concepts(Concept("foo", body="'hello world'"))
res = core.builtin_helpers.evaluate_from_source(context, "foo", eval_body=True, evaluators=["Python"])
res = self.successful_return_values(res)
assert len(res) == 1
assert res[0].who.startswith(BaseParser.PREFIX) # Cannot evaluate concept with PythonEvaluator
res = core.builtin_helpers.evaluate_from_source(context, "foo", eval_body=True, evaluators=["Concept"])
res = self.successful_return_values(res)
assert len(res) == 1
assert res[0].who == BaseEvaluator.PREFIX + "Concept"
assert sheerka.isinstance(res[0].body.body,
BuiltinConcepts.PARSER_RESULT) # cannot eval 'hello world' without PythonEvaluator
res = core.builtin_helpers.evaluate_from_source(context, "foo", eval_body=True,
evaluators=["Concept", "Python"])
res = self.successful_return_values(res)
assert len(res) == 1
assert res[0].who == BaseEvaluator.PREFIX + "Concept"
assert res[0].body.body == "hello world"
def test_i_can_get_lexer_nodes_after_parsing_validation(self):
sheerka, context, the, foo = self.init_concepts(
Concept("the x", ret="x", where="isinstance(x, Concept)").def_var("x"),
"foo",
create_new=True)
parsed_ret_val = SyaNodeParser().parse(context, ParserInput("the foo"))
validated_ret_val = ValidateConceptEvaluator().eval(context, parsed_ret_val)
res = core.builtin_helpers.get_lexer_nodes([validated_ret_val], 0, list(Tokenizer("the foo", yield_eof=False)))
assert isinstance(res, list)
assert isinstance(res[0][0], ConceptNode)
def test_ensure_evaluated_returns_the_ret_value(self):
"""
When a concept has a RET defined, make sure to return it
:return:
"""
sheerka, context, foo, bar = self.init_concepts(
"foo",
Concept("bar", ret="foo")
)
assert core.builtin_helpers.ensure_evaluated(context, bar) == foo
# a second time, now that bar is already evaluated
assert core.builtin_helpers.ensure_evaluated(context, bar) == foo
# @pytest.mark.parametrize("return_values", [
# None,
# []
+5 -5
View File
@@ -75,7 +75,7 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
assert loaded is not None
assert sheerka.isinstance(loaded, BuiltinConcepts.UNKNOWN_CONCEPT)
assert loaded.body == {"key": "key_that_does_not_exist"}
assert loaded.get_metadata().is_evaluated
assert loaded.get_hints().is_evaluated
def test_i_cannot_get_when_id_is_not_found(self):
sheerka = self.get_sheerka()
@@ -85,7 +85,7 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
assert loaded is not None
assert sheerka.isinstance(loaded, BuiltinConcepts.UNKNOWN_CONCEPT)
assert loaded.body == {"id": "id_that_does_not_exist"}
assert loaded.get_metadata().is_evaluated
assert loaded.get_hints().is_evaluated
def test_i_can_instantiate_a_builtin_concept_when_it_has_its_own_class(self):
sheerka = self.get_sheerka()
@@ -192,15 +192,15 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
create_new=True).unpack()
sheerka.evaluate_concept(context, sheerka.get_by_id(template.id))
assert template.get_metadata().is_evaluated
assert template.get_hints().is_evaluated
assert template.body == "foo body"
new = sheerka.new(template.key)
assert not new.get_metadata().is_evaluated
assert not new.get_hints().is_evaluated
assert new.body == NotInit
new = sheerka.new((None, template.id))
assert not new.get_metadata().is_evaluated
assert not new.get_hints().is_evaluated
assert new.body == NotInit
def test_i_cannot_instantiate_an_unknown_concept(self):
+3 -3
View File
@@ -287,7 +287,7 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka):
assert groups == {20: [EvaluatorOneWithPriority20()], 15: [EvaluatorAllWithPriority15()]}
assert sorted_priorities == [20, 15]
key = BuiltinConcepts.EVALUATION + "|" + "|".join(evaluators_names)
key = (BuiltinConcepts.EVALUATION, "|".join(evaluators_names))
assert key in service.grouped_evaluators_cache
groups, sorted_priorities = service.grouped_evaluators_cache[key]
assert groups == {20: [EvaluatorOneWithPriority20()], 15: [EvaluatorAllWithPriority15()]}
@@ -343,7 +343,7 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka):
assert groups == {99: [EvaluatorAllWithPriority15(99)]}
assert sorted_priorities == [99]
key = BuiltinConcepts.EVALUATION + "|" + "|".join(evaluators_names)
key = (BuiltinConcepts.EVALUATION, "|".join(evaluators_names))
assert key not in service.grouped_evaluators_cache
def test_i_can_revert_back_evaluators_alterations(self):
@@ -570,7 +570,7 @@ class TestSheerkaExecuteEvaluators(TestUsingMemoryBasedSheerka):
# grouped evaluator is in cache
service = sheerka.services[SheerkaExecute.NAME]
assert "__EVALUATION|all_priority10" in service.grouped_evaluators_cache
assert ("__EVALUATION", "all_priority10") in service.grouped_evaluators_cache
def test_evaluators_priorities_can_be_tweaked_by_the_context(self):
sheerka, context = self.init_concepts()
+443 -21
View File
@@ -1,14 +1,38 @@
from core.builtin_concepts import ReturnValueConcept, UserInputConcept, BuiltinConcepts, ParserResultConcept
from core.sheerka.services.SheerkaExecute import ParserInput, SheerkaExecute
from parsers.BaseParser import BaseParser
import pytest
from core.builtin_concepts import ReturnValueConcept, UserInputConcept, BuiltinConcepts, ParserResultConcept
from core.concept import Concept
from core.sheerka.services.SheerkaExecute import ParserInput, SheerkaExecute, DEFAULT, PARSE_STEPS
from parsers.BaseExpressionParser import ExprNode
from parsers.BaseParser import BaseParser
from parsers.BnfNodeParser import BnfNodeParser
from parsers.SequenceNodeParser import SequenceNodeParser
from parsers.SyaNodeParser import SyaNodeParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
def get_ret_val(text, who="who"):
def get_user_input(text, who="who"):
return ReturnValueConcept(who, True, UserInputConcept(text, "user_name"))
def check_same_results(result1, result2, user_input):
assert len(result1) == len(result2)
for previous, current in zip(result1, result2):
assert current.parents == user_input
assert current.who == previous.who
assert current.status == previous.status
assert id(current.body) == id(previous.body)
def check_same_values(sheerka, context, ret_val1, ret_val2):
previous = sheerka.execute(context, ret_val1, [BuiltinConcepts.EVALUATION])
current = sheerka.execute(context, ret_val2, [BuiltinConcepts.EVALUATION])
assert len(previous) == len(current)
for p, c in zip(previous, current):
assert p == c
class BaseTestParser(BaseParser):
debug_out = []
@@ -136,12 +160,23 @@ class ListOfNoneParser(BaseTestParser):
class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
default_parsers = None
@classmethod
def setup_class(cls):
cls.default_parsers = cls().get_sheerka().parsers
@classmethod
def teardown_class(cls):
# At the end of the tests, sheerka singleton instance will be corrupted
# Ask for a new one
TestUsingMemoryBasedSheerka.sheerka = None
def reset_parsers(self, sheerka):
sheerka.parsers = self.default_parsers
service = sheerka.services[SheerkaExecute.NAME]
service.reset_registered_parsers()
def test_i_can_get_parser_when_context_is_not_altered(self):
sheerka, context = self.init_concepts()
sheerka.parsers = {
@@ -152,7 +187,7 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
service.reset_registered_parsers()
parsers_key, groups, sorted_priorities = service.get_parsers(context)
assert parsers_key == "__default"
assert parsers_key == ("__default", "__default")
assert groups == {80: [Enabled80FalseParser()], 90: [Enabled90FalseParser()]}
assert sorted_priorities == [90, 80]
@@ -171,13 +206,13 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
context.preprocess_parsers = parsers_names
parsers_key, groups, sorted_priorities = service.get_parsers(context)
assert parsers_key == "Enabled50True|Enabled70False|Disabled"
assert parsers_key == (DEFAULT, "Enabled50True|Enabled70False|Disabled")
assert groups == {50: [Enabled50TrueParser()], 70: [Enabled70FalseParser()]}
assert sorted_priorities == [70, 50] # Disabled parser does not appear
key = "|".join(parsers_names)
assert key in service.grouped_parsers_cache
groups, sorted_priorities = service.grouped_parsers_cache[key]
assert (DEFAULT, key) in service.grouped_parsers_cache
groups, sorted_priorities = service.grouped_parsers_cache[(DEFAULT, key)]
assert groups == {50: [Enabled50TrueParser], 70: [Enabled70FalseParser]}
assert sorted_priorities == [70, 50]
@@ -202,8 +237,8 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
assert groups == {80: [Enabled50TrueParser()], 70: [Enabled70FalseParser()]}
assert sorted_priorities == [80, 70] # Disabled parsers does not appear
key = "|".join(parsers_names)
assert key not in service.grouped_parsers_cache # not saved in cache
key = (DEFAULT, "|".join(parsers_names))
assert key not in service.grouped_parsers_cache # not saved in cache
def test_disabled_parsers_are_not_executed(self):
sheerka = self.get_sheerka()
@@ -214,7 +249,7 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaExecute.NAME]
service.reset_registered_parsers()
user_input = [get_ret_val("hello world")]
user_input = [get_user_input("hello world")]
BaseTestParser.debug_out = []
sheerka.execute(self.get_context(sheerka), user_input, [BuiltinConcepts.PARSING])
@@ -230,7 +265,7 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaExecute.NAME]
service.reset_registered_parsers()
user_input = [get_ret_val("hello world")]
user_input = [get_user_input("hello world")]
BaseTestParser.debug_out = []
sheerka.execute(self.get_context(sheerka), user_input, [BuiltinConcepts.PARSING])
@@ -254,7 +289,7 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaExecute.NAME]
service.reset_registered_parsers()
user_input = [get_ret_val("hello world")]
user_input = [get_user_input("hello world")]
BaseTestParser.debug_out = []
sheerka.execute(self.get_context(sheerka), user_input, [BuiltinConcepts.PARSING])
@@ -279,7 +314,7 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaExecute.NAME]
service.reset_registered_parsers()
user_input = [get_ret_val("hello world")]
user_input = [get_user_input("hello world")]
BaseTestParser.debug_out = []
sheerka.execute(self.get_context(sheerka), user_input, [BuiltinConcepts.PARSING])
@@ -310,7 +345,7 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaExecute.NAME]
service.reset_registered_parsers()
user_input = [get_ret_val("hello world")]
user_input = [get_user_input("hello world")]
BaseTestParser.debug_out = []
sheerka.execute(self.get_context(sheerka), user_input, [BuiltinConcepts.PARSING])
@@ -342,7 +377,7 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaExecute.NAME]
service.reset_registered_parsers()
user_input = [get_ret_val("hello world")]
user_input = [get_user_input("hello world")]
res = sheerka.execute(self.get_context(sheerka), user_input, [BuiltinConcepts.PARSING])
res_as_tuple = [(str(r.who)[8:], r.status, r.body.body) for r in res]
@@ -365,7 +400,7 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaExecute.NAME]
service.reset_registered_parsers()
user_input = [get_ret_val("hello world")]
user_input = [get_user_input("hello world")]
BaseTestParser.debug_out = []
res = sheerka.execute(self.get_context(sheerka), user_input, [BuiltinConcepts.PARSING])
@@ -391,7 +426,7 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaExecute.NAME]
service.reset_registered_parsers()
user_input = [get_ret_val("hello world")]
user_input = [get_user_input("hello world")]
BaseTestParser.debug_out = []
sheerka.execute(self.get_context(sheerka), user_input, [BuiltinConcepts.PARSING])
@@ -412,7 +447,7 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaExecute.NAME]
service.reset_registered_parsers()
user_input = [get_ret_val("hello world")]
user_input = [get_user_input("hello world")]
BaseTestParser.debug_out = []
res = sheerka.execute(self.get_context(sheerka), user_input, [BuiltinConcepts.PARSING])
@@ -432,7 +467,7 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
('Enabled50True', False, 'Enabled50True:Enabled80MultipleFalse:hello world_2'),
]
def test_i_can_manage_parser_with_multiple_results_and_a_sucess(self):
def test_i_can_manage_parser_with_multiple_results_and_a_success(self):
sheerka = self.get_sheerka()
sheerka.parsers = {
"Enabled80MultipleTrue": Enabled80MultipleTrueParser,
@@ -441,7 +476,7 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaExecute.NAME]
service.reset_registered_parsers()
user_input = [get_ret_val("hello world")]
user_input = [get_user_input("hello world")]
BaseTestParser.debug_out = []
res = sheerka.execute(self.get_context(sheerka), user_input, [BuiltinConcepts.PARSING])
@@ -454,3 +489,390 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
('Enabled80MultipleTrue', True, 'Enabled80MultipleTrue:hello world_1'),
('Enabled80MultipleTrue', False, 'Enabled80MultipleTrue:hello world_2'),
]
def test_parser_calls_are_put_in_cache(self):
sheerka, context = self.init_test().unpack()
service = sheerka.services[SheerkaExecute.NAME]
self.reset_parsers(sheerka)
user_input = [get_user_input("1")]
res = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
assert len(res) > 0
assert len(service.parsers_cache.cache) == 1
assert (('__default', '__default'), '1') in service.parsers_cache
def test_parser_calls_are_put_in_cache_when_question(self):
sheerka, context = self.init_test().unpack()
service = sheerka.services[SheerkaExecute.NAME]
self.reset_parsers(sheerka)
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
user_input = [get_user_input("1")]
res = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
assert len(res) > 0
assert len(service.parsers_cache.cache) == 2 # one for EVAL_QUESTION, one to compile the Python
assert ((BuiltinConcepts.EVAL_QUESTION_REQUESTED, DEFAULT), '1') in service.parsers_cache
def test_parser_calls_are_not_put_in_cache_when_preprocess_parsers(self):
sheerka, context = self.init_test().unpack()
service = sheerka.services[SheerkaExecute.NAME]
self.reset_parsers(sheerka)
context.preprocess_parsers = [SequenceNodeParser.NAME, BnfNodeParser.NAME, SyaNodeParser.NAME]
user_input = [get_user_input("1")]
res = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
expected_key = (DEFAULT, "|".join([SequenceNodeParser.NAME, BnfNodeParser.NAME, SyaNodeParser.NAME]))
assert len(res) == 3
assert len(service.parsers_cache.cache) == 1
assert (expected_key, '1') in service.parsers_cache
def test_parser_calls_are_not_put_in_cache_when_preprocess(self):
sheerka, context = self.init_test().unpack()
service = sheerka.services[SheerkaExecute.NAME]
self.reset_parsers(sheerka)
context.add_preprocess(BaseParser.PREFIX + "parser_name", some_attribute='some_value')
user_input = [get_user_input("1")]
res = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
assert len(res) > 0
assert len(service.parsers_cache.cache) == 0
def test_i_can_use_parser_memoization_on_python(self):
sheerka, context = self.init_test().unpack()
self.reset_parsers(sheerka)
user_input = [get_user_input("1 + 1")]
first_request = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
user_input_2 = [get_user_input("1 + 1")]
second_request = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
check_same_results(first_request, second_request, user_input_2)
check_same_values(sheerka, context, first_request, second_request)
@pytest.mark.parametrize("concept", {
Concept("foo"),
Concept("foo", body="1"),
})
def test_i_can_use_parser_memoization_when_exact_concept(self, concept):
sheerka, context, foo = self.init_test(eval_body=True, eval_where=True).with_concepts(concept).unpack()
self.reset_parsers(sheerka)
user_input = [get_user_input("foo")]
first_request = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
successful = [r.who for r in first_request if r.status]
assert successful == ['parsers.ExactConcept']
user_input_2 = [get_user_input("foo")]
second_request = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
check_same_results(first_request, second_request, user_input_2)
check_same_values(sheerka, context, first_request, second_request)
def test_i_can_use_parser_memoization_when_multiple_results(self):
sheerka, context, *foo = self.init_test(eval_body=True, eval_where=True).with_concepts(
Concept("foo", body="1"),
Concept("foo", body="2")).unpack()
self.reset_parsers(sheerka)
user_input = [get_user_input("foo")]
first_request = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
successful = [r.who for r in first_request if r.status]
assert successful == ['parsers.ExactConcept', 'parsers.ExactConcept']
user_input_2 = [get_user_input("foo")]
second_request = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
check_same_results(first_request, second_request, user_input_2)
check_same_values(sheerka, context, first_request, second_request)
def test_i_can_use_parser_memoization_when_bnf_node(self):
sheerka, context, *concepts = self.init_test(eval_body=True, eval_where=True).with_concepts(
Concept("one", body="1"),
Concept("two", body="2"),
Concept("twenties", definition="'twenty' (one|two)=unit", body="20 + unit").def_var("unit"),
create_new=True).unpack()
self.reset_parsers(sheerka)
user_input = [get_user_input("twenty one")]
first_request = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
successful = [r.who for r in first_request if r.status]
assert successful == ['parsers.Bnf']
user_input_2 = [get_user_input("twenty one")]
second_request = sheerka.execute(context, user_input_2, [BuiltinConcepts.PARSING])
check_same_results(first_request, second_request, user_input_2)
check_same_values(sheerka, context, first_request, second_request)
def test_i_can_use_parser_memoization_when_sequence_node(self):
sheerka, context, *concepts = self.init_test(eval_body=True, eval_where=True).with_concepts(
Concept("one", body="1"),
Concept("two", body="2"),
create_new=True).unpack()
self.reset_parsers(sheerka)
user_input = [get_user_input("one two")]
first_request = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
successful = [r.who for r in first_request if r.status]
assert successful == ['parsers.Sequence']
user_input_2 = [get_user_input("one two")]
second_request = sheerka.execute(context, user_input_2, [BuiltinConcepts.PARSING])
check_same_results(first_request, second_request, user_input_2)
check_same_values(sheerka, context, first_request, second_request)
def test_i_can_use_parser_memoization_when_sya_node(self):
sheerka, context, *concepts = self.init_test(eval_body=True, eval_where=True).with_concepts(
Concept("one", body="1"),
Concept("twenty two", body="22"),
Concept("a plus b", body="a + b").def_var("a").def_var("b"),
create_new=True).unpack()
self.reset_parsers(sheerka)
user_input = [get_user_input("one plus twenty two")]
first_request = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
successful = [r.who for r in first_request if r.status]
assert successful == ['parsers.Sya']
user_input_2 = [get_user_input("one plus twenty two")]
second_request = sheerka.execute(context, user_input_2, [BuiltinConcepts.PARSING])
check_same_results(first_request, second_request, user_input_2)
check_same_values(sheerka, context, first_request, second_request)
def test_i_can_use_parser_memoization_when_not_parser_input_from_sequence_node(self):
# In the test, 'one two' will be partially parsed by the SequenceNodeParser
# We test that the results of the UnrecognizedNodeParser and the PythonWithConceptParser
# which both do not used ParsingInput as an input (but a ParserResult)
# are added to the list of results
sheerka, context, *concepts = self.init_test(eval_body=True, eval_where=True).with_concepts(
Concept("one", body="1")).unpack()
self.reset_parsers(sheerka)
user_input = [get_user_input("one two")]
first_request = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
successful = [r.who for r in first_request if r.status]
assert successful == []
user_input_2 = [get_user_input("one two")]
second_request = sheerka.execute(context, user_input_2, [BuiltinConcepts.PARSING])
check_same_results(first_request, second_request, user_input_2)
check_same_values(sheerka, context, first_request, second_request)
def test_i_can_use_parser_memoization_when_not_parser_input_from_bnf_node(self):
# check the comment from test_i_can_use_parser_memoization_when_not_parser_input_from_sequence_node
# for more information on this test
sheerka, context, *concepts = self.init_test(eval_body=True, eval_where=True).with_concepts(
Concept("one", body="1"),
Concept("two", body="2"),
Concept("twenties", definition="'twenty' (one|two)=unit", body="20 + unit"),
create_new=True).unpack()
self.reset_parsers(sheerka)
user_input = [get_user_input("twenty two foo")]
first_request = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
successful = [r.who for r in first_request if r.status]
assert successful == []
user_input_2 = [get_user_input("twenty two foo")]
second_request = sheerka.execute(context, user_input_2, [BuiltinConcepts.PARSING])
check_same_results(first_request, second_request, user_input_2)
check_same_values(sheerka, context, first_request, second_request)
def test_i_can_use_parser_memoization_when_not_parser_input_from_sy_node(self):
# check the comment from test_i_can_use_parser_memoization_when_not_parser_input_from_sequence_node
# for more information on this test
sheerka, context, *concepts = self.init_test(eval_body=True, eval_where=True).with_concepts(
Concept("one", body="1"),
Concept("twenty two", body="22"),
Concept("a plus b", body="a + b").def_var("a").def_var("b"),
create_new=True).unpack()
self.reset_parsers(sheerka)
user_input = [get_user_input("twenty two plus one foo")]
first_request = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
successful = [r.who for r in first_request if r.status]
assert successful == []
user_input_2 = [get_user_input("twenty two plus one foo")]
second_request = sheerka.execute(context, user_input_2, [BuiltinConcepts.PARSING])
check_same_results(first_request, second_request, user_input_2)
check_same_values(sheerka, context, first_request, second_request)
def test_cache_is_reset_on_concept_creation(self):
sheerka, context, *concepts = self.init_test().with_concepts(
Concept("foo", body="1"), create_new=True).unpack()
self.reset_parsers(sheerka)
user_input = [get_user_input("foo")]
res = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
successful = [r for r in res if r.status]
assert len(successful) == 1
sheerka.create_new_concept(context, Concept("foo", body="2"))
res = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
successful = [r for r in res if r.status]
assert len(successful) == 2
def test_cache_is_reset_on_concept_deletion(self):
sheerka, context, foo1, foo2 = self.init_test().with_concepts(
Concept("foo", body="1"),
Concept("foo", body="2"),
create_new=True).unpack()
self.reset_parsers(sheerka)
user_input = [get_user_input("foo")]
res = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
successful = [r for r in res if r.status]
assert len(successful) == 2
sheerka.remove_concept(context, foo2)
res = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
successful = [r for r in res if r.status]
assert len(successful) == 1
def test_cache_is_reset_on_concept_modification(self):
sheerka, context, foo1, foo2 = self.init_test().with_concepts(
Concept("foo", body="1"),
Concept("foo", body="2"),
create_new=True).unpack()
self.reset_parsers(sheerka)
user_input = [get_user_input("foo")]
res = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
successful = [r for r in res if r.status]
assert len(successful) == 2
sheerka.modify_concept(context, foo2, to_add={'meta': {"name": "bar"}})
res = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
successful = [r for r in res if r.status]
assert len(successful) == 1
def test_i_do_not_use_short_term_memory_when_not_requested(self):
sheerka, context, foo = self.init_test().with_concepts(
Concept("foo"),
create_new=True).unpack()
self.reset_parsers(sheerka)
user_input = [get_user_input("foo")]
# put something is STM
context.add_to_short_term_memory("foo", "value")
res = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
assert len(res) == 1
assert res[0].body == "value"
# specify the parsers to use
context.preprocess_parsers = ["ExactConcept"]
res = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
assert len(res) == 1
assert res[0].body.body == foo
# I can force STM
context.preprocess_parsers = ["ExactConcept", "ShortTermMemory"] # order in not relevant for STM parser
res = sheerka.execute(context, user_input, [BuiltinConcepts.PARSING])
assert len(res) == 1
assert res[0].body == "value"
def test_i_can_compute_parsers_key(self):
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
key = SheerkaExecute.get_parsers_key(context)
assert key == (DEFAULT, DEFAULT)
context = self.get_context(sheerka)
context.add_to_private_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
key = SheerkaExecute.get_parsers_key(context)
assert key == (BuiltinConcepts.EVAL_QUESTION_REQUESTED, DEFAULT)
context = self.get_context(sheerka)
context.preprocess_parsers = ["foo", "bar", "baz"]
key = SheerkaExecute.get_parsers_key(context)
assert key == (DEFAULT, 'foo|bar|baz')
context = self.get_context(sheerka)
context.preprocess_parsers = ["foo", "bar", "baz"]
context.add_to_private_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
key = SheerkaExecute.get_parsers_key(context)
assert key == (BuiltinConcepts.EVAL_QUESTION_REQUESTED, 'foo|bar|baz')
context = self.get_context(sheerka)
context.add_preprocess(BaseParser.PREFIX + "foo", key="some_value")
key = SheerkaExecute.get_parsers_key(context)
assert key is None
context = self.get_context(sheerka)
context.add_preprocess(BaseParser.PREFIX + "foo", key="some_value")
context.add_to_private_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
key = SheerkaExecute.get_parsers_key(context)
assert key is None
context = self.get_context(sheerka)
context.add_preprocess("foo", key="some_value")
key = SheerkaExecute.get_parsers_key(context)
assert key == (DEFAULT, DEFAULT)
context = self.get_context(sheerka)
context.add_preprocess("foo", key="some_value")
context.add_to_private_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
key = SheerkaExecute.get_parsers_key(context)
assert key == (BuiltinConcepts.EVAL_QUESTION_REQUESTED, DEFAULT)
context = self.get_context(sheerka)
context.preprocess_parsers = ["foo", "bar", "baz"]
context.add_preprocess("foo", key="some_value")
key = SheerkaExecute.get_parsers_key(context)
assert key == (DEFAULT, 'foo|bar|baz')
context = self.get_context(sheerka)
context.preprocess_parsers = ["foo", "bar", "baz"]
context.add_preprocess("foo", key="some_value")
context.add_to_private_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
key = SheerkaExecute.get_parsers_key(context)
assert key == (BuiltinConcepts.EVAL_QUESTION_REQUESTED, 'foo|bar|baz')
def test_i_use_expression_parser_when_needed(self):
sheerka, context, one, number, isa_q, isa = self.init_concepts(
"one",
"number",
Concept("x is a y ", pre="is_question()").def_var("x").def_var("y"),
Concept("x is a y ").def_var("x").def_var("y"),
)
user_input = get_user_input("one is a number")
res = sheerka.execute(context, [user_input], PARSE_STEPS)
res = self.successful_return_values(res)
assert len(res) == 1
assert res[0].status
assert isinstance(res[0].body.body, Concept)
context = self.get_context(sheerka)
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
res = sheerka.execute(context, [user_input], PARSE_STEPS)
assert len(res) == 1
assert res[0].status
assert isinstance(res[0].body.body, ExprNode)
+62 -3
View File
@@ -11,53 +11,112 @@ reduced_requested = ReturnValueConcept("Sheerka", True, Concept(name=BuiltinConc
def ret_val(value="value", who="who", status=True):
"""
ReturnValueConcept
:param value:
:param who:
:param status:
:return:
"""
return ReturnValueConcept(who, status, value)
def p_ret_val(value="value", parser="parser", status=True):
"""
ReturnValueConcept from parser
:param value:
:param parser:
:param status:
:return:
"""
return ReturnValueConcept(BaseParser.get_name(parser), status, value)
def e_ret_val(value="value", evaluator="evaluator", status=True):
"""
ReturnValueConcept from evaluator
:param value:
:param evaluator:
:param status:
:return:
"""
return ReturnValueConcept(BaseEvaluator.PREFIX + evaluator, status, value)
def p_ret_val_false(value="value", parser="parser"):
"""
Failed ReturnValueConcept from parser
:param value:
:param parser:
:return:
"""
return p_ret_val(value, parser, status=False)
def p_ret_val_true(value="value", parser="parser"):
"""
Successful ReturnValueConcept from parser
:param value:
:param parser:
:return:
"""
return p_ret_val(value, parser, status=True)
def e_ret_val_false(value="value", parser="parser"):
"""
Failed ReturnValueConcept from evaluator
:param value:
:param parser:
:return:
"""
return e_ret_val(value, parser, status=False)
def e_ret_val_true(value="value", parser="parser"):
"""
Successful ReturnValueConcept from evaluator
:param value:
:param parser:
:return:
"""
return e_ret_val(value, parser, status=True)
def e_ret_val_new(key, evaluator="evaluator", status=True, **kwargs):
"""
Successful ReturnValueConcept from evaluator that returns a concept
:param key:
:param evaluator:
:param status:
:param kwargs:
:return:
"""
body = new_concept(key, **kwargs)
return e_ret_val(body, evaluator, status)
def pr_ret_val(value, parser="parser", source=None):
def pr_ret_val(value, parser="parser", source=None, status=True):
"""
ParserResult ReturnValue
eg: ReturnValue with a ParserResult
:param value:
:param parser:
:param source:
:param status:
:return:
"""
source = source or (value.name if isinstance(value, Concept) else "source")
parser_result = ParserResultConcept(BaseParser.get_name(parser), source=source, value=value)
return p_ret_val(parser_result, parser)
return p_ret_val(value=parser_result, parser=parser, status=status)
def python_ret_val(source):
"""
ReturnValueConcept with a PythonNode
:param source:
:return:
"""
python_node = PythonNode(source.strip(), ast.parse(source.strip(), f"<source>", 'eval'))
return pr_ret_val(python_node, parser="Python", source=source)
@@ -68,5 +127,5 @@ def new_concept(key, **kwargs):
to_use = "#" + k + "#" if k in ("body", "pre", "post", "ret") else k
res.set_value(to_use, v)
res.get_metadata().is_evaluated = True
res.get_hints().is_evaluated = True
return res
+2 -2
View File
@@ -47,7 +47,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
concept = Concept(name="foo",
body="'I have a value'",
where="True",
pre="2",
pre="True",
post="3").set_value("a", "4").set_value("b", "5")
evaluator = ConceptEvaluator(return_body=True)
@@ -64,7 +64,7 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
concept = Concept(name="foo",
body="'I have a value'",
where="True",
pre="2",
pre="True",
post="3").set_value("a", "4").set_value("b", "5")
evaluator = ConceptEvaluator(return_body=False) # which is the default behaviour
+3 -1
View File
@@ -204,7 +204,9 @@ class TestDefConceptEvaluator(TestUsingMemoryBasedSheerka):
assert DefConceptEvaluator.get_variables(context, concept_definition, []) == expected
def test_i_can_recognize_variables_when_referencing_other_concepts(self):
sheerka, context, isa_concept = self.init_concepts(Concept("x is an y").def_var("x").def_var("y"))
sheerka, context, isa_concept = self.init_concepts(
Concept("x is an y", pre="is_question()").def_var("x").def_var("y")
)
text = "def concept what x is y pre is_question() where x is an adjective as get_attr(x, y)"
def_ret_val = DefConceptParser().parse(context, ParserInput(text))
@@ -0,0 +1,83 @@
import pytest
from core.builtin_concepts_ids import BuiltinConcepts
from core.concept import Concept
from core.sheerka.services.SheerkaExecute import ParserInput
from evaluators.BaseEvaluator import BaseEvaluator
from evaluators.ExpressionEvaluator import ExpressionEvaluator
from parsers.BaseExpressionParser import AndNode
from parsers.ExpressionParser import ExpressionParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.evaluators.EvaluatorTestsUtils import pr_ret_val, e_ret_val_true
class TestExpressionEvaluator(TestUsingMemoryBasedSheerka):
@pytest.mark.parametrize("return_value, expected", [
(pr_ret_val(AndNode(0, 0, [])), True),
(pr_ret_val(AndNode(0, 0, []), status=False), False),
(pr_ret_val("not a ExprNode", status=True), False),
(e_ret_val_true("no parser result"), False),
])
def test_i_can_match(self, return_value, expected):
sheerka, context = self.init_concepts()
evaluator = ExpressionEvaluator()
assert evaluator.matches(context, return_value) == expected
def test_i_can_eval(self):
sheerka, context, one, number, isa = self.init_concepts(
"one",
"number",
Concept("x is a y", body="isa(x,y)", pre="is_question()").def_var("x").def_var("y"))
evaluator = ExpressionEvaluator()
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
parsed_return_value = ExpressionParser().parse(context, ParserInput("one is a number"))
# first time, it returns False
res = evaluator.eval(context, parsed_return_value)
assert res.status
assert res.who == BaseEvaluator.PREFIX + ExpressionEvaluator.NAME
assert not res.body
# second time
sheerka.set_isa(context, one, number)
parsed_return_value = ExpressionParser().parse(context, ParserInput("one is a number"))
res = evaluator.eval(context, parsed_return_value)
assert res.status
assert res.body
def test_i_do_not_mess_up_use_copy(self):
sheerka, context, one, number, isa = self.init_concepts(
"one",
"number",
Concept("x is a y", body="isa(x,y)", pre="is_question()").def_var("x").def_var("y"))
evaluator = ExpressionEvaluator()
parsed_return_value = ExpressionParser().parse(context, ParserInput("one is a number"))
concept = next(iter(parsed_return_value.body.body.compiled[0].return_value.body.body.objects.values()))
assert concept.get_compiled()["x"][0].body.body.get_hints().use_copy
assert concept.get_compiled()["y"][0].body.body.get_hints().use_copy
evaluator.eval(context, parsed_return_value)
concept = next(iter(parsed_return_value.body.body.compiled[0].return_value.body.body.objects.values()))
assert concept.get_compiled()["x"][0].body.body.get_hints().use_copy
assert concept.get_compiled()["y"][0].body.body.get_hints().use_copy
def test_i_cannot_eval_when_variables_are_missing(self):
sheerka, context, one, number, isa = self.init_concepts(
"one",
"number",
Concept("x is a y", body="isa(x,y)", pre="is_question()").def_var("x").def_var("y"))
evaluator = ExpressionEvaluator()
parsed_return_value = ExpressionParser().parse(context, ParserInput("self is a number"))
res = evaluator.eval(context, parsed_return_value)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
assert len(res.body.body) == 1
assert isinstance(res.body.body[0], NameError)
assert res.body.body[0].args == ("self",)
@@ -0,0 +1,198 @@
import pytest
from core.builtin_concepts import ParserResultConcept
from core.builtin_concepts_ids import BuiltinConcepts
from core.concept import Concept
from core.sheerka.services.SheerkaExecute import ParserInput
from evaluators.BaseEvaluator import BaseEvaluator
from evaluators.ValidateConceptEvaluator import ValidateConceptEvaluator
from parsers.BaseNodeParser import ConceptNode
from parsers.BaseParser import BaseParser
from parsers.BnfNodeParser import BnfNodeParser
from parsers.SyaNodeParser import SyaNodeParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.evaluators.EvaluatorTestsUtils import p_ret_val, pr_ret_val, ret_val
class TestValidateConceptEvaluator(TestUsingMemoryBasedSheerka):
@pytest.mark.parametrize("return_value, need_validation, expected", [
(pr_ret_val(Concept("foo", where="something"), status=True), True, True),
(pr_ret_val(Concept("foo", pre="something"), status=True), True, True),
(pr_ret_val(Concept("foo", where="something"), status=True), False, False),
(pr_ret_val(Concept("foo", pre="something"), status=True), False, False),
(pr_ret_val(Concept("foo"), status=True), True, False),
(pr_ret_val(Concept("foo"), status=True), True, False),
(pr_ret_val(Concept("foo", where=None), status=True), True, False),
(pr_ret_val(Concept("foo", pre=None), status=True), True, False),
(pr_ret_val(Concept("foo", where=""), status=True), True, False),
(pr_ret_val(Concept("foo", pre=""), status=True), True, False),
(pr_ret_val(Concept("foo", where="something"), status=False), True, False),
(pr_ret_val(Concept("foo", pre="something"), status=False), True, False),
(pr_ret_val("Not a concept", status=True), True, False),
(pr_ret_val("Not a concept", status=False), True, False),
(p_ret_val("Not a parser result", status=True), True, False),
(p_ret_val("Not a parser result", status=False), True, False),
])
def test_i_can_match(self, return_value, need_validation, expected):
sheerka, context = self.init_concepts()
evaluator = ValidateConceptEvaluator()
if (sheerka.isinstance(return_value.body, BuiltinConcepts.PARSER_RESULT) and
isinstance(return_value.body.body, Concept)):
return_value.body.body.get_hints().need_validation = need_validation
assert evaluator.matches(context, return_value) == expected
def test_i_cannot_match_when_the_return_value_is_not_a_direct_parsing_result(self):
# I match only if the return_value comes from a parser (not from an after_parsing evaluator)
sheerka, context = self.init_concepts()
concept = Concept("foo", pre="something")
parser_result = ParserResultConcept(BaseParser.get_name("parser"), source=concept.name, value=concept)
return_value = ret_val(value=parser_result, who="evaluators.something", status=True)
return_value.body.body.get_hints().need_validation = True
evaluator = ValidateConceptEvaluator()
assert not evaluator.matches(context, return_value)
@pytest.mark.parametrize("concept", [
Concept("foo", pre="False"),
Concept("foo", where="False"),
])
def test_i_can_eval_when_constraint_is_false(self, concept):
sheerka, context, foo = self.init_concepts(concept)
ret_val = pr_ret_val(foo, status=True)
res = ValidateConceptEvaluator().eval(context, ret_val)
assert not res.status
assert res.who == BaseEvaluator.PREFIX + ValidateConceptEvaluator.NAME
assert sheerka.isinstance(res.body, BuiltinConcepts.FILTERED)
assert res.body.body == foo
@pytest.mark.parametrize("concept", [
Concept("foo"),
Concept("foo", pre="True"),
Concept("foo", where="True"),
])
def test_i_can_eval_when_constraint_is_true_or_when_no_constrain(self, concept):
sheerka, context, foo = self.init_concepts(concept)
ret_val = pr_ret_val(foo, status=True)
res = ValidateConceptEvaluator().eval(context, ret_val)
assert res is None
@pytest.mark.parametrize("concept", [
Concept("foo"),
Concept("foo", pre="True"),
Concept("foo", where="True"),
])
def test_i_can_eval_when_constraint_is_true_or_when_no_constrain_use_copy(self, concept):
sheerka, context, foo = self.init_concepts(concept)
foo.get_hints().use_copy = True
ret_val = pr_ret_val(foo, status=True)
res = ValidateConceptEvaluator().eval(context, ret_val)
assert res.status
assert res.who == BaseEvaluator.PREFIX + ValidateConceptEvaluator.NAME
assert res.body.body.id == foo.id
assert not res.body.body.get_hints().use_copy
def test_i_can_eval_when_is_question(self):
sheerka, context, foo = self.init_concepts(Concept("foo", pre="is_question()"))
ret_val = pr_ret_val(foo, status=True)
res = ValidateConceptEvaluator().eval(context, ret_val)
assert not res.status
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
res = ValidateConceptEvaluator().eval(context, ret_val)
assert res is None
def test_i_can_eval_when_unknown_variables_but_no_constraint(self):
sheerka, context, foo = self.init_concepts(Concept("a plus b").def_var("a").def_var("b"))
ret_val = pr_ret_val(foo, status=True)
res = ValidateConceptEvaluator().eval(context, ret_val)
assert res is None
def test_i_can_eval_when_unknown_variables(self):
# ValidateConceptEvaluator must filter only if all the variables are known
# In this example, 'b' is not set, so the return_value must not be filtered
sheerka, context, foo = self.init_concepts(
Concept("a plus b", where="isinstance(b, int)").def_var("a", "10").def_var("b"))
ret_val = pr_ret_val(foo, status=True)
res = ValidateConceptEvaluator().eval(context, ret_val)
assert res is None
def test_i_can_eval_when_constraint_on_variable_fails(self):
sheerka, context, foo = self.init_concepts(
Concept("a plus b", where="isinstance(b, int)").def_var("a").def_var("b", "'a string'"))
ret_val = pr_ret_val(foo, status=True)
res = ValidateConceptEvaluator().eval(context, ret_val)
assert not res.status
def test_i_can_eval_bnf_concepts(self):
sheerka, context, quantify_x = self.init_concepts(
Concept("quantify x", definition="('one'|'two') x", where="x != 'one'").def_var("x"),
create_new=True)
evaluator = ValidateConceptEvaluator()
# success
ret_val = BnfNodeParser().parse(context, ParserInput("one 'two'"))
assert evaluator.matches(context, ret_val)
res = evaluator.eval(context, ret_val)
assert isinstance(res.body.body, list)
assert len(res.body.body) == 1
assert isinstance(res.body.body[0], ConceptNode)
assert res.body.body[0].concept.id == ret_val.body.body[0].concept.id
# failure
ret_val = BnfNodeParser().parse(context, ParserInput("one 'one'"))
assert evaluator.matches(context, ret_val)
res = evaluator.eval(context, ret_val)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.FILTERED)
assert res.body.body == ret_val.body.body
def test_i_can_eval_sya_concepts(self):
sheerka, context, quantify_x = self.init_concepts(
Concept("a plus b", where="a < 10").def_var("a").def_var("b"),
create_new=True)
evaluator = ValidateConceptEvaluator()
# success
ret_val = SyaNodeParser().parse(context, ParserInput("5 plus 3"))
assert evaluator.matches(context, ret_val)
res = evaluator.eval(context, ret_val)
assert isinstance(res.body.body, list)
assert len(res.body.body) == 1
assert isinstance(res.body.body[0], ConceptNode)
assert res.body.body[0].concept.id == ret_val.body.body[0].concept.id
# failure
ret_val = SyaNodeParser().parse(context, ParserInput("15 plus 3"))
assert evaluator.matches(context, ret_val)
res = evaluator.eval(context, ret_val)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.FILTERED)
assert res.body.body == ret_val.body.body
def test_i_can_manage_infinite_recursion(self):
sheerka, context, a_and_b = self.init_concepts(
Concept("a and b", where="is_question()", body="a and b").def_var("a").def_var("b"),
create_new=True)
evaluator = ValidateConceptEvaluator()
ret_val = pr_ret_val(a_and_b)
res = evaluator.eval(context, ret_val)
assert res is None # infinite recursion detected, res is None to drop the validator
+74 -32
View File
@@ -7,7 +7,6 @@ from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
from evaluators.OneSuccessEvaluator import OneSuccessEvaluator
from evaluators.PythonEvaluator import PythonEvalError
from sheerkapython.python_wrapper import MethodAccessError
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.parsers.parsers_utils import CMV, CC, compare_with_test_object, CB
@@ -211,9 +210,9 @@ as:
# sanity check
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value)
assert evaluated.body == "hello foo"
assert evaluated.get_metadata().is_evaluated
assert evaluated.get_hints().is_evaluated
compare_with_test_object(evaluated.get_value("a"), CB("foo", "foo"))
assert evaluated.get_value("a").get_metadata().is_evaluated
assert evaluated.get_value("a").get_hints().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)
@@ -296,9 +295,9 @@ as:
# sanity check
evaluated = sheerka.evaluate_concept(self.get_context(sheerka=sheerka, eval_body=True), return_value)
assert evaluated.body == "one three"
assert evaluated.get_metadata().is_evaluated
assert evaluated.get_hints().is_evaluated
assert evaluated.get_value("a") == sheerka.new(concept_a.key, body="one").init_key()
assert evaluated.get_value("a").get_metadata().is_evaluated
assert evaluated.get_value("a").get_hints().is_evaluated
@pytest.mark.parametrize("user_input", [
"def concept greetings from def hello a where a",
@@ -314,7 +313,7 @@ as:
concept_found = res[0].value
assert sheerka.isinstance(concept_found, greetings)
assert concept_found.get_value("a") == "foo"
assert concept_found.get_metadata().need_validation
assert concept_found.get_hints().need_validation
res = sheerka.evaluate_user_input("greetings")
assert len(res) == 1
@@ -322,7 +321,7 @@ as:
concept_found = res[0].value
assert sheerka.isinstance(concept_found, greetings)
assert concept_found.get_value("a") == NotInit
assert not concept_found.get_metadata().need_validation
assert not concept_found.get_hints().need_validation
@pytest.mark.parametrize("desc, definitions", [
("Simple form", [
@@ -681,14 +680,9 @@ as:
assert res[0].body == 22
res = sheerka.evaluate_user_input("twenty three")
assert len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.MULTIPLE_ERRORS)
assert sheerka.has_error(context, res, __type=BuiltinConcepts.CONDITION_FAILED)
res = sheerka.evaluate_user_input("eval twenty three")
assert len(res) == 1
assert not res[0].status
assert sheerka.has_error(context, res, __type=BuiltinConcepts.CONDITION_FAILED)
def test_i_can_manage_some_type_of_infinite_recursion(self):
@@ -725,20 +719,20 @@ as:
assert res[0].body == "hello world"
res = sheerka.evaluate_user_input("foo baz")
assert len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONDITION_FAILED)
assert sheerka.has_error(self.get_context(sheerka), res, __type=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.CONDITION_FAILED)
assert sheerka.has_error(self.get_context(sheerka), res, __type=BuiltinConcepts.CONDITION_FAILED)
res = sheerka.evaluate_user_input("foobar")
res = sheerka.evaluate_user_input("c:foobar:") # where clause must not be evaluated
assert len(res) == 1
assert res[0].status
res = sheerka.evaluate_user_input("eval foobar")
res = sheerka.evaluate_user_input("foobar") # where clause must not be evaluated
assert len(res) == 1
assert res[0].status
res = sheerka.evaluate_user_input("eval foobar") # where clause is forced
assert len(res) == 1 # error
assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONDITION_FAILED)
@@ -835,7 +829,6 @@ as:
def test_concepts_parsed_by_atom_parser_must_not_be_evaluated(self):
definitions = [
"def concept mult from a mult b as a * b",
"def concept a mult b as a * b",
]
sheerka = self.init_scenario(definitions)
@@ -844,9 +837,17 @@ as:
assert res[0].status
assert isinstance(res[0].body, Concept)
# res = sheerka.evaluate_user_input("eval a mult b")
# assert res[0].status
# assert isinstance(res[0].body, Concept)
@pytest.mark.skip("Need to be fixed")
def test_concepts_parsed_by_atom_parser_must_not_be_evaluated_2(self):
definitions = [
"def concept a mult b as a * b",
]
sheerka = self.init_scenario(definitions)
res = sheerka.evaluate_user_input("eval a mult b")
assert res[0].status
assert isinstance(res[0].body, Concept)
def test_i_can_express_comparison(self):
definitions = [
@@ -1059,8 +1060,7 @@ as:
"def concept foo",
"def concept number",
"set_isa(one, number)",
"def concept q from q ? as question(q)",
"set_auto_eval(q)",
"def concept q from q ? as question(q) auto_eval True",
"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:, 'Sya')",
]
@@ -1069,18 +1069,16 @@ as:
res = sheerka.evaluate_user_input("one is a number ?") # automatically evaluated
assert len(res) == 1
assert res[0].status
assert res[0].body == True # the body MUST be a boolean
assert isinstance(res[0].body, bool) and res[0].body # the body MUST be a boolean
res = sheerka.evaluate_user_input("foo is a number ?") # automatically evaluated
assert len(res) == 1
assert res[0].status
assert res[0].body == False # the body MUST be a boolean
assert isinstance(res[0].body, bool) and not res[0].body # the body MUST be a boolean
# x is a y is supposed to be a question. It cannot be used if not in a context of a question
res = sheerka.evaluate_user_input("one is a number")
assert len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONDITION_FAILED)
assert sheerka.has_error(self.get_context(sheerka), res, __type=BuiltinConcepts.CONDITION_FAILED)
def test_i_can_evaluate_source_code_with_concept(self):
init = [
@@ -1299,7 +1297,7 @@ as:
assert sheerka.objvalue(res[0].body.get_value("qty")) == 2
def test_i_can_implement_the_concept_and(self):
# Normally, redefining and leads to a circular ref between the concept and the python
# Normally, redefining 'and' leads to a circular ref between the concept and the python
init = [
"def concept x and y as x and y",
"set_is_lesser(__PRECEDENCE, c:x and y:, 'Sya')",
@@ -1362,3 +1360,47 @@ as:
res = sheerka.evaluate_user_input("eval foo")
assert sheerka.has_error(context, res, __type="MethodAccessError")
def test_i_can_use_function_parser_and_complex_concept(self):
init = [
"def concept the x ret x",
"def concept foo",
"def concept bar",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("smart_get_attr(the foo, bar)")
assert len(res) == 1
assert res[0].status
def test_i_can_get_smart_get_attr_for_complex_concepts(self):
init = [
"def concept q from q ? as question(q) auto_eval True",
"set_is_lesser(__PRECEDENCE, q, 'Sya')",
"def concept a x ret x where isinstance(x, Concept)",
"def concept the x ret memory(x)",
"def concept short",
"def concept color",
"def concept red",
"def concept blue",
"def concept adjective",
"set_isa(red, color)",
"set_isa(blue, color)",
"set_isa(color, adjective)",
"def concept what is the x of y pre is_question() as smart_get_attr(y, x)",
"def concept qualify x from bnf adjective x as set_attr(x, c:adjective:, adjective) ret x",
"eval a red short",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("what is the color of the short ?")
assert len(res) == 1
assert res[0].status
assert res[0].value == "red"
res = sheerka.evaluate_user_input("eval a blue short")
res = sheerka.evaluate_user_input("what is the color of the short ?")
assert len(res) == 1
assert res[0].status
assert res[0].value == "blue"
+18
View File
@@ -0,0 +1,18 @@
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestSheerkaNonRegMemory2(TestUsingMemoryBasedSheerka):
def test_i_can_select_the_correct_concept_when_ambiguity(self):
init = [
"def concept foo",
"def concept x is a y pre is_question() as isa(x,y)",
"def concept x is a foo pre is_question() as isinstance(x, foo)",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("question(foo is a foo)")
# assert len(res) == 1
# assert res[0].status
# assert res[0].value
+1 -1
View File
@@ -1,5 +1,5 @@
import pytest
from core.sheerka.services.SheerkaRuleManager import FormatAstRawText, FormatAstVariable, FormatAstVariableNotFound, \
from parsers.FormatRuleActionParser import FormatAstRawText, FormatAstVariable, FormatAstVariableNotFound, \
FormatAstSequence, FormatAstList, FormatAstDict
from out.AsStrVisitor import AsStrVisitor
+1 -1
View File
@@ -1,5 +1,5 @@
import pytest
from core.sheerka.services.SheerkaRuleManager import FormatAstRawText, FormatAstVariable, FormatAstVariableNotFound, \
from parsers.FormatRuleActionParser import FormatAstRawText, FormatAstVariable, FormatAstVariableNotFound, \
FormatAstSequence, FormatAstList, FormatAstDict
from out.ConsoleVisistor import ConsoleVisitor
+1 -1
View File
@@ -1,7 +1,7 @@
from core.builtin_concepts import BuiltinConcepts
from core.sheerka.services.SheerkaDebugManager import NullDebugLogger
from core.sheerka.services.SheerkaOut import SheerkaOut
from core.sheerka.services.SheerkaRuleManager import FormatAstList, FormatAstVariable, FormatAstDict, FormatAstMulti
from parsers.FormatRuleActionParser import FormatAstList, FormatAstVariable, FormatAstDict, FormatAstMulti
from out.DeveloperVisitor import DeveloperVisitor
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
+3 -2
View File
@@ -8,8 +8,9 @@ from core.sheerka.Sheerka import Sheerka
from core.sheerka.SheerkaOntologyManager import SheerkaOntologyManager
from core.sheerka.services.SheerkaComparisonManager import SheerkaComparisonManager
from core.sheerka.services.SheerkaOut import SheerkaOut
from core.sheerka.services.SheerkaRuleManager import FormatAstRawText, FormatAstVariable, FormatAstSequence, \
FormatAstColor, FormatAstVariableNotFound, FormatAstList, FormatAstDict, SheerkaRuleManager
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager
from parsers.FormatRuleActionParser import FormatAstRawText, FormatAstVariable, FormatAstSequence, \
FormatAstColor, FormatAstVariableNotFound, FormatAstList, FormatAstDict
from core.utils import flatten_all_children
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
+12 -13
View File
@@ -230,7 +230,7 @@ class CC:
self.exclude_body,
**compiled)
raise NotImplementedError(f"CC, {other=}")
raise Exception(f"Expecting Concept but received {other=}")
class CB:
@@ -269,7 +269,7 @@ class CB:
body = other.body
return CB(concept, body)
raise NotImplementedError(f"CB, {other=}")
raise Exception(f"Expecting Concept but received {other=}")
class CV:
@@ -310,7 +310,7 @@ class CV:
values = get_test_obj_delegate(other.values(), self.values, get_test_obj_delegate)
return CV(concept, **values)
raise NotImplementedError(f"CV, {other=}")
raise Exception(f"Expecting Concept but received {other=}")
class CMV:
@@ -361,7 +361,7 @@ class CMV:
variables = {name: value for name, value in other.get_metadata().variables}
return CMV(concept, **variables)
raise NotImplementedError(f"CMV, {other=}")
raise Exception(f"Expecting Concept but received {other=}")
class CIO:
@@ -408,7 +408,7 @@ class CIO:
if isinstance(other, Concept):
return CIO(other)
raise NotImplementedError(f"CIO, {other=}")
raise Exception(f"Expecting Concept but received {other=}")
class HelperWithPos:
@@ -496,7 +496,7 @@ class SCN(HelperWithPos):
other.start if self.start is not None else None,
other.end if self.end is not None else None)
raise NotImplementedError(f"SCN, {other=}")
raise Exception(f"Expecting SourceCodeNode but received {other=}")
class SCWC(HelperWithPos):
@@ -572,7 +572,7 @@ class SCWC(HelperWithPos):
res.end = other.end
return res
raise NotImplementedError(f"SCWC, {other=}")
raise Exception(f"Expecting SourceCodeWithConceptNode but received {other=}")
@property
def source(self):
@@ -663,7 +663,7 @@ class CN(HelperWithPos):
other.start if self.start is not None else None,
other.end if self.end is not None else None)
raise NotImplementedError(f"CN, {other=}")
raise Exception(f"Expecting ConceptNode but received {other=}")
class CNC(CN):
@@ -737,8 +737,7 @@ class CNC(CN):
other.end if self.end is not None else None,
self.exclude_body,
**compiled)
raise NotImplementedError(f"CNC, {other=}")
raise Exception(f"Expecting ConceptNode but received {other=}")
class UTN(HelperWithPos):
@@ -799,7 +798,7 @@ class UTN(HelperWithPos):
other.start,
other.end)
raise NotImplementedError(f"UTN, {other=}")
raise Exception(f"Expecting UnrecognizedTokensNode but received {other=}")
class RN(HelperWithPos):
@@ -863,7 +862,7 @@ class RN(HelperWithPos):
other.start if self.start is not None else None,
other.end if self.end is not None else None)
raise NotImplementedError(f"RN, {other=}")
raise Exception(f"Expecting RuleNode but received {other=}")
class FN:
@@ -930,7 +929,7 @@ class FN:
return FN(other.first.value, other.last.value, params)
raise NotImplementedError(f"FN, {other=}")
raise Exception(f"Expecting FunctionNode but received {other=}")
@dataclass()
+21
View File
@@ -1927,6 +1927,27 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
assert res.status
compare_with_test_object(res.value.value, expected_array)
def test_i_cannot_parse_regex_concept_mixed_with_unrecognized_sya(self):
my_map = {
"hex": self.bnf_concept("hex", RegExMatch("[a-f0-9]{8}")),
"isa": Concept("x is an y", body="isinstance(x, y)", pre="is_question()").def_var("x").def_var("y"),
"isafoo": Concept("x is an foo", body="False", pre="is_question()").def_var("x"),
"q": Concept("q ?", body="question(a)").def_var("q")
}
# I need the concept isafoo to fool SyaNodeParser when parsing the sub text 'is an hex ?'"
# The parser will try to recognize 'is an foo', will fail and will revert the result to UTN()
# It's this UTN that need to be properly handled
sheerka, context, parser = self.init_parser(my_map, init_from_sheerka=True, create_new=True)
sheerka.set_precedence(context, my_map["isa"], my_map["q"])
sheerka.set_precedence(context, my_map["isafoo"], my_map["q"])
text = "01234567 is an hexadecimal ?"
res = parser.parse(context, ParserInput(text))
assert not res.status
# @pytest.mark.parametrize("parser_input, expected", [
# ("one", [
# (True, [CNC("bnf_one", source="one", one="one", body="one")]),
+32 -36
View File
@@ -8,16 +8,18 @@ from core.concept import DEFINITION_TYPE_BNF, DEFINITION_TYPE_DEF, Concept
from core.global_symbols import NotInit
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Keywords, Tokenizer, LexerError
from parsers.BaseExpressionParser import VariableNode, ExprNode
from parsers.BaseParser import UnexpectedEofParsingError
from parsers.BnfDefinitionParser import BnfDefinitionParser
from parsers.BnfNodeParser import OrderedChoice, ConceptExpression, StrMatch, Sequence, RegExMatch, OneOrMore, \
VariableExpression
from parsers.DefConceptParser import DefConceptParser, NameNode, SyntaxErrorNode, CannotHandleParsingError
from parsers.DefConceptParser import UnexpectedTokenParsingError, DefConceptNode
from parsers.ExpressionParser import ExpressionParser
from parsers.FunctionParser import FunctionParser
from parsers.PythonParser import PythonParser, PythonNode
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.parsers.parsers_utils import compute_expected_array, SCWC, CV, compare_with_test_object
from tests.parsers.parsers_utils import compute_expected_array, SCWC, compare_with_test_object, CIO
def get_def_concept(name, where=None, pre=None, post=None, body=None, definition=None, bnf_def=None, ret=None):
@@ -26,9 +28,9 @@ def get_def_concept(name, where=None, pre=None, post=None, body=None, definition
if body:
def_concept.body = get_concept_part(body)
if where:
def_concept.where = get_concept_part(where)
def_concept.where = get_concept_part(where, use_expression=True)
if pre:
def_concept.pre = get_concept_part(pre)
def_concept.pre = get_concept_part(pre, use_expression=True)
if post:
def_concept.post = get_concept_part(post)
if ret:
@@ -46,11 +48,21 @@ def get_def_concept(name, where=None, pre=None, post=None, body=None, definition
return def_concept
def get_concept_part(part):
if isinstance(part, str):
node = PythonNode(part.strip(), ast.parse(part.strip(), mode="eval"))
def get_concept_part(part, use_expression=False):
if use_expression:
node = VariableNode(0, 0, [], part)
return ReturnValueConcept(
who="parsers.DefConcept",
who="parsers.Expression",
status=True,
value=ParserResultConcept(
source=part,
parser=ExpressionParser(),
value=node))
if isinstance(part, str):
node = PythonNode(part.lstrip(), ast.parse(part.lstrip(), mode="eval"))
return ReturnValueConcept(
who="parsers.Python",
status=True,
value=ParserResultConcept(
source=part,
@@ -61,7 +73,7 @@ def get_concept_part(part):
# node = PythonNode(part.strip(), ast.parse(part.strip(), mode="eval"))
nodes = compute_expected_array({}, part.source, [SCWC(part.first, part.last, *part.content)])
return ReturnValueConcept(
who="parsers.DefConcept",
who="parsers.Python",
status=True,
value=ParserResultConcept(
source=part.source,
@@ -70,9 +82,9 @@ def get_concept_part(part):
try_parsed=nodes[0]))
if isinstance(part, PN):
node = PythonNode(part.source.strip(), ast.parse(part.source.strip(), mode=part.mode))
node = PythonNode(part.source.lstrip(), ast.parse(part.source.lstrip(), mode=part.mode))
return ReturnValueConcept(
who="parsers.DefConcept",
who="parsers.Python",
status=True,
value=ParserResultConcept(
source=part.source,
@@ -81,7 +93,7 @@ def get_concept_part(part):
if isinstance(part, PythonNode):
return ReturnValueConcept(
who="parsers.DefConcept",
who="parsers.Python",
status=True,
value=ParserResultConcept(
source=part.source,
@@ -248,7 +260,7 @@ class TestDefConceptParser(TestUsingMemoryBasedSheerka):
assert isinstance(res.value, ParserResultConcept)
part_mapping = "body" if part == "as" else part
args = {part_mapping: get_concept_part("True")}
args = {part_mapping: "True"}
expected = get_def_concept("foo", **args)
assert node == expected
@@ -260,28 +272,6 @@ class TestDefConceptParser(TestUsingMemoryBasedSheerka):
assert not res.status
assert sheerka.isinstance(return_value, BuiltinConcepts.TOO_MANY_ERRORS)
def test_i_can_parse_complex_def_concept_statement(self):
text = """def concept a mult b
where a,b
pre isinstance(a, int) and isinstance(b, int)
as res = a * b
ret a if isinstance(a, Concept) else self
"""
sheerka, context, parser, *concepts = self.init_parser()
res = parser.parse(context, ParserInput(text))
return_value = res.value
expected_concept = get_def_concept(
name="a mult b",
where="a,b\n",
pre="isinstance(a, int) and isinstance(b, int)\n",
body=PN("res = a * b\n", "exec"),
ret="a if isinstance(a, Concept) else self\n"
)
assert res.status
assert isinstance(return_value, ParserResultConcept)
assert return_value.value == expected_concept
def test_i_can_parse_mutilines_declarations(self):
text = """
def concept add one to a as
@@ -547,7 +537,10 @@ from give me the date !
assert isinstance(res.value, ParserResultConcept)
assert isinstance(node, DefConceptNode)
assert sheerka.isinstance(node.where, BuiltinConcepts.RETURN_VALUE)
compare_with_test_object(node.where.body.body, CV(concepts[0], pre=True))
where_condition = node.where.body.body
assert isinstance(where_condition, ExprNode)
concept_found = where_condition.compiled[0].objects["__o_00__"]
compare_with_test_object(concept_found, CIO(concepts[0]))
text = "def concept foo x y pre x is a y"
res = parser.parse(context, ParserInput(text))
@@ -559,7 +552,10 @@ from give me the date !
assert isinstance(res.value, ParserResultConcept)
assert isinstance(node, DefConceptNode)
assert sheerka.isinstance(node.pre, BuiltinConcepts.RETURN_VALUE)
compare_with_test_object(node.pre.body.body, CV(concepts[0], pre=True))
pre_condition = node.pre.body.body
assert isinstance(pre_condition, ExprNode)
concept_found = pre_condition.compiled[0].objects["__o_00__"]
compare_with_test_object(concept_found, CIO(concepts[0]))
def test_i_can_parse_bnf_concept_with_regex(self):
sheerka, context, parser, number = self.init_parser("number")
+2 -1
View File
@@ -3,12 +3,13 @@ import pytest
from core.builtin_concepts_ids import BuiltinConcepts
from core.concept import Concept
from core.sheerka.services.SheerkaExecute import ParserInput
from core.sheerka.services.SheerkaRuleManager import FormatAstNode, CompiledCondition
from core.sheerka.services.SheerkaRuleManager import CompiledCondition
from core.tokenizer import Tokenizer, Keywords
from core.utils import tokens_are_matching
from parsers.BaseCustomGrammarParser import KeywordNotFound, NameNode, SyntaxErrorNode
from parsers.BaseParser import UnexpectedEofParsingError
from parsers.DefRuleParser import DefRuleParser, DefExecRuleNode, DefFormatRuleNode
from parsers.FormatRuleActionParser import FormatAstNode
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
cmap = {
+18 -18
View File
@@ -62,8 +62,8 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
assert len(results) == 1
assert results[0].status
assert concept_found == concept
assert not concept_found.get_metadata().need_validation
assert not concept_found.get_metadata().is_evaluated
assert not concept_found.get_hints().need_validation
assert not concept_found.get_hints().is_evaluated
def test_i_can_parse_concepts_defined_several_times(self):
sheerka = self.get_sheerka(singleton=True)
@@ -80,11 +80,11 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
assert results[0].status
assert results[0].value.value.name == "hello a"
assert variable_def(results[0].value.value, "a") == "world"
assert results[0].value.value.get_metadata().need_validation
assert results[0].value.value.get_hints().need_validation
assert results[1].status
assert results[1].value.value.name == "hello world"
assert not results[1].value.value.get_metadata().need_validation
assert not results[1].value.value.get_hints().need_validation
def test_i_can_parse_a_concept_with_variables(self):
sheerka = self.get_sheerka(singleton=True)
@@ -99,8 +99,8 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
concept_found = results[0].value.value
compare_with_test_object(concept_found, CMV(concept, a="10", b="5"))
assert concept_found.get_metadata().need_validation
assert not concept_found.get_metadata().is_evaluated
assert concept_found.get_hints().need_validation
assert not concept_found.get_hints().is_evaluated
def test_i_can_parse_a_concept_with_duplicate_variables(self):
sheerka = self.get_sheerka(singleton=True)
@@ -115,7 +115,7 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
concept_found = results[0].value.value
compare_with_test_object(concept_found, CMV(concept, a="10", b="5"))
assert concept_found.get_metadata().need_validation
assert concept_found.get_hints().need_validation
def test_i_can_parse_concept_when_defined_using_from_def(self):
sheerka, context, plus = self.init_concepts(
@@ -129,8 +129,8 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
assert len(results) == 1
assert results[0].status
compare_with_test_object(concept_found, CMV(plus, a="10", b="5"))
assert concept_found.get_metadata().need_validation
assert not concept_found.get_metadata().is_evaluated
assert concept_found.get_hints().need_validation
assert not concept_found.get_hints().is_evaluated
def test_i_can_parse_concept_token(self):
sheerka, context, foo = self.init_concepts("foo")
@@ -142,8 +142,8 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
assert len(results) == 1
assert results[0].status
assert concept_found == foo
assert not concept_found.get_metadata().need_validation
assert concept_found.get_metadata().is_evaluated
assert not concept_found.get_hints().need_validation
assert concept_found.get_hints().is_evaluated
def test_i_can_parse_concept_with_concept_tokens(self):
sheerka, context, one, two, plus = self.init_concepts(
@@ -159,8 +159,8 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
assert len(results) == 1
assert results[0].status
compare_with_test_object(concept_found, CMV(plus, a="c:one:", b="c:two:"))
assert concept_found.get_metadata().need_validation
assert not concept_found.get_metadata().is_evaluated
assert concept_found.get_hints().need_validation
assert not concept_found.get_hints().is_evaluated
def test_i_can_parse_when_expression_contains_keyword(self):
sheerka, context, isa, def_concept = self.init_concepts(
@@ -175,8 +175,8 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
assert len(results) == 1
assert results[0].status
compare_with_test_object(concept_found, CMV(isa, c="z"))
assert concept_found.get_metadata().need_validation
assert not concept_found.get_metadata().is_evaluated
assert concept_found.get_hints().need_validation
assert not concept_found.get_hints().is_evaluated
source = "def concept z"
results = ExactConceptParser().parse(context, ParserInput(source))
@@ -185,8 +185,8 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
assert len(results) == 1
assert results[0].status
compare_with_test_object(concept_found, CMV(def_concept, a="z"))
assert concept_found.get_metadata().need_validation
assert not concept_found.get_metadata().is_evaluated
assert concept_found.get_hints().need_validation
assert not concept_found.get_hints().is_evaluated
def test_i_can_manage_unknown_concept(self):
context = self.get_context(self.get_sheerka(singleton=True))
@@ -219,4 +219,4 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
# assert len(results) == 1
# assert results[0].status
# assert results[0].value.value == concept
# assert not results[0].value.value.get_metadata().need_validation
# assert not results[0].value.value.get_hints().need_validation
+24 -4
View File
@@ -3,8 +3,8 @@ import pytest
from core.builtin_concepts_ids import BuiltinConcepts
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Tokenizer
from parsers.BaseExpressionParser import VariableNode, ComparisonNode
from parsers.BaseParser import ErrorSink
from parsers.BaseExpressionParser import VariableNode, ComparisonNode, ExprNode
from parsers.BaseParser import ErrorSink, BaseParser
from parsers.ExpressionParser import ExpressionParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.parsers.parsers_utils import get_expr_node_from_test_node, VAR, EXPR, FN, AND, NOT, OR, GT, GTE, LT, LTE, EQ, \
@@ -71,7 +71,7 @@ class TestExpressionParser(TestUsingMemoryBasedSheerka):
"var.attr1.attr2",
"var . attr1 . attr2",
])
def test_i_can_parse_variable(self, expression):
def test_i_can_parse_input_variable(self, expression):
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
parsed = parser.parse_input(context, parser_input, error_sink)
@@ -80,7 +80,7 @@ class TestExpressionParser(TestUsingMemoryBasedSheerka):
assert parsed.name == "var"
assert parsed.attributes == ["attr1", "attr2"]
def test_i_can_parse_sub_tokens(self):
def test_i_can_parse_input_sub_tokens(self):
sheerka, context, parser = self.init_parser()
expression = "do not care var1 + var2 do not care either"
@@ -105,3 +105,23 @@ class TestExpressionParser(TestUsingMemoryBasedSheerka):
new_source = ComparisonNode.rebuild_source("new_var", parsed.comp, parsed.right.get_source())
assert new_source == expected
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_compile(self):
sheerka, context, parser = self.init_parser()
text = ParserInput("a > b and c < d")
res = parser.parse(context, text)
assert res.who == BaseParser.PREFIX + ExpressionParser.NAME
assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.PARSER_RESULT)
assert isinstance(res.body.body, ExprNode)
assert res.body.body.compiled is not None
@@ -0,0 +1,81 @@
import pytest
from core.tokenizer import Token, TokenKind
from parsers.FormatRuleActionParser import FormatAstSequence, FormatAstRawText, FormatAstVariable, FormatAstFunction, \
FormatAstList, FormatAstColor, FormatAstDict, FormatAstMulti, FormatRuleActionParser, UnexpectedEof, \
FormatRuleSyntaxError
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
seq = FormatAstSequence
raw = FormatAstRawText
var = FormatAstVariable
func = FormatAstFunction
lst = FormatAstList
class TestFormatRuleActionParser(TestUsingMemoryBasedSheerka):
@pytest.mark.parametrize("text, expected", [
("", FormatAstRawText("")),
(" ", FormatAstRawText(" ")),
(" raw text ", FormatAstRawText(" raw text ")),
("{variable}", FormatAstVariable("variable")),
("{ variable }", FormatAstVariable("variable")),
(" xy {v} z", seq([raw(" xy "), var("v"), raw(" z")])),
(r"\{variable}", FormatAstRawText("{variable}")),
(r"\\{variable}", seq([raw("\\"), var("variable")])),
(r"\\\{variable}", FormatAstRawText(r"\{variable}")),
(r"{var1}{var2}", seq([var("var1"), var("var2")])),
("func()", FormatAstFunction("func", [], {})),
("func(a, 'string value', c)", FormatAstFunction("func", ["a", "'string value'", "c"], {})),
("func(a=10, b='string value')", FormatAstFunction("func", [], {"a": "10", "b": "'string value'"})),
("func('string value'='another string value')", func("func", [], {"'string value'": "'another string value'"})),
("red(' xy {v}')", FormatAstColor("red", seq([raw(" xy "), var("v")]))),
('blue(" xy {v}")', FormatAstColor("blue", seq([raw(" xy "), var("v")]))),
('green( xy )', FormatAstColor("green", var("xy"))),
('green()', FormatAstColor("green", raw(""))),
('green("")', FormatAstColor("green", raw(""))),
("list(var_name, 2, 'children')", FormatAstList("var_name", recurse_on="children", recursion_depth=2)),
("list(var_name, recursion_depth=2, recurse_on='children')", FormatAstList("var_name",
recurse_on="children",
recursion_depth=2)),
("list(var_name, recursion_depth=2, 'children')", FormatAstList("var_name", recursion_depth=2)),
("list(var_name, 'children', recursion_depth=2)", FormatAstList("var_name", recursion_depth=2)),
("list(var_name)", FormatAstList("var_name")),
("{obj.prop1.prop2[0].prop3['value']}", FormatAstVariable("obj.prop1.prop2[0].prop3['value']")),
("[{id}]", seq([raw("["), var("id"), raw("]")])),
("{variable:format}", FormatAstVariable("variable", "format")),
("{variable:3}", FormatAstVariable("variable", "3")),
(r"\not_a_function(a={var})", seq([raw("not_a_function(a="), var("var"), raw(")")])),
("dict(var_name)", FormatAstDict("var_name")),
("dict(var_name, items_prop='props')", FormatAstDict("var_name", items_prop='props')),
("dict(var_name, debug=True)", FormatAstDict("var_name", debug=True, prefix="{", suffix="}")),
("multi(var_name)", FormatAstMulti("var_name")),
])
def test_i_can_parse_format_rule(self, text, expected):
assert FormatRuleActionParser(text).parse() == expected
@pytest.mark.parametrize("text, expected_error", [
("{", UnexpectedEof("while parsing variable", Token(TokenKind.LBRACE, "{", 0, 1, 1))),
("{var_name", UnexpectedEof("while parsing variable", Token(TokenKind.LBRACE, "{", 0, 1, 1))),
("{}", FormatRuleSyntaxError("variable name not found", None)),
("func(", UnexpectedEof("while parsing function", Token(TokenKind.IDENTIFIER, "func", 0, 1, 1))),
("func(a,b,c", UnexpectedEof("while parsing function", Token(TokenKind.IDENTIFIER, "func", 0, 1, 1))),
("func(a,,c", FormatRuleSyntaxError("no parameter found", Token(TokenKind.COMMA, ",", 7, 1, 8))),
("func(a,,c)", FormatRuleSyntaxError("no parameter found", Token(TokenKind.COMMA, ",", 7, 1, 8))),
("red(a,b)", FormatRuleSyntaxError("only one parameter supported", Token(TokenKind.IDENTIFIER, "b", 6, 1, 7))),
("red(a=b)", FormatRuleSyntaxError("keyword arguments are not supported", None)),
("red(xy {v})", FormatRuleSyntaxError("Invalid identifier", None)),
("list()", FormatRuleSyntaxError("variable name not found", None)),
("list(recursion_depth=2)", FormatRuleSyntaxError("variable name not found", None)),
("list(a,b,c,d,e)", FormatRuleSyntaxError("too many positional arguments",
Token(TokenKind.IDENTIFIER, "e", 13, 1, 14))),
("list(a, recursion_depth=hello)", FormatRuleSyntaxError("'hello' is not numeric", None)),
("list(a, recursion_depth='hello')", FormatRuleSyntaxError("'recursion_depth' must be an integer", None)),
("dict()", FormatRuleSyntaxError("variable name not found", None)),
])
def test_i_cannot_parse_invalid_format(self, text, expected_error):
parser = FormatRuleActionParser(text)
parser.parse()
assert parser.error_sink == expected_error
+281 -287
View File
@@ -1,21 +1,15 @@
import ast
import pytest
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept
from core.concept import Concept, DoNotResolve
from core.rule import Rule
from core.builtin_concepts import BuiltinConcepts
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import TokenKind
from parsers.BaseExpressionParser import TrueifyVisitor, IsAQuestionVisitor, AndNode, LeftPartNotFoundError, \
from parsers.BaseExpressionParser import TrueifyVisitor, IsAQuestionVisitor, LeftPartNotFoundError, \
ParenthesisMismatchError
from parsers.BaseParser import UnexpectedEofParsingError, UnexpectedTokenParsingError
from parsers.LogicalOperatorParser import LogicalOperatorParser
from parsers.PythonParser import PythonNode
from sheerkarete.network import ReteNetwork
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.parsers.parsers_utils import compute_expected_array, resolve_test_concept, EXPR, OR, AND, NOT, \
get_expr_node_from_test_node, get_rete_conditions, CMV, CNC, CC, compare_with_test_object
from tests.parsers.parsers_utils import EXPR, OR, AND, NOT, \
get_expr_node_from_test_node
class TestLogicalOperatorParser(TestUsingMemoryBasedSheerka):
@@ -181,281 +175,281 @@ class TestLogicalOperatorParser(TestUsingMemoryBasedSheerka):
assert IsAQuestionVisitor().visit(expr_node) == expected
@pytest.mark.parametrize("expression, expected", [
("foo", "foo"),
("one two", "one two"),
("foo is a bar", CMV("is a", x='foo', y='bar')),
("one two is a bar", [CNC("is a", "one two is a bar", x="one two", y="bar")]),
("foo is an foo bar",
[CNC("is an", "foo is an foo bar", x=DoNotResolve(value='foo'), exclude_body=True)]),
])
def test_i_can_get_compiled_expr_from_simple_concepts_expressions(self, expression, expected):
concepts_map = {
"foo": Concept("foo"),
"bar": Concept("bar"),
"one two": Concept("one two"),
"is a": Concept("x is a y").def_var("x").def_var("y"),
"is an": Concept("x is an y", definition="('foo'|'bar')=x 'is an' 'foo bar'").def_var("x"),
}
sheerka, context, *concepts = self.init_test().with_concepts(*concepts_map.values(), create_new=True).unpack()
# @pytest.mark.parametrize("expression, expected", [
# ("foo", "foo"),
# ("one two", "one two"),
# ("foo is a bar", CMV("is a", x='foo', y='bar')),
# ("one two is a bar", [CNC("is a", "one two is a bar", x="one two", y="bar")]),
# ("foo is an foo bar",
# [CNC("is an", "foo is an foo bar", x=DoNotResolve(value='foo'), exclude_body=True)]),
# ])
# def test_i_can_get_compiled_expr_from_simple_concepts_expressions(self, expression, expected):
# concepts_map = {
# "foo": Concept("foo"),
# "bar": Concept("bar"),
# "one two": Concept("one two"),
# "is a": Concept("x is a y").def_var("x").def_var("y"),
# "is an": Concept("x is an y", definition="('foo'|'bar')=x 'is an' 'foo bar'").def_var("x"),
# }
# sheerka, context, *concepts = self.init_test().with_concepts(*concepts_map.values(), create_new=True).unpack()
#
# parser = LogicalOperatorParser()
# expr_node = parser.parse(context, ParserInput(expression)).body.body
# return_values, _ = parser.compile_conjunctions(context, [expr_node], "test")
#
# assert len(return_values) == 1
# ret = return_values[0]
#
# if isinstance(expected, list):
# expected_nodes = compute_expected_array(concepts_map, expression, expected)
# compare_with_test_object(ret.body.body, expected_nodes)
# else:
# expected_concept = resolve_test_concept(concepts_map, expected)
# compare_with_test_object(ret.body.body, expected_concept)
parser = LogicalOperatorParser()
expr_node = parser.parse(context, ParserInput(expression)).body.body
return_values, _ = parser.compile_conjunctions(context, [expr_node], "test")
assert len(return_values) == 1
ret = return_values[0]
if isinstance(expected, list):
expected_nodes = compute_expected_array(concepts_map, expression, expected)
compare_with_test_object(ret.body.body, expected_nodes)
else:
expected_concept = resolve_test_concept(concepts_map, expected)
compare_with_test_object(ret.body.body, expected_concept)
@pytest.mark.parametrize("expression", [
"a == 5",
"foo > 5",
"func() == 5",
"not a == 5",
"not foo > 5",
"not func() == 5",
"isinstance(a, int)",
"func()",
"not isinstance(a, int)",
"not func()"
])
def test_i_can_get_compiled_expr_from_simple_python_expressions(self, expression):
sheerka, context, = self.init_test().unpack()
parser = LogicalOperatorParser()
expr_node = parser.parse(context, ParserInput(expression)).body.body
return_values, _ = parser.compile_conjunctions(context, [expr_node], "test")
assert len(return_values) == 1
ret = return_values[0]
assert ret.status
python_node = ret.body.body.get_python_node()
_ast = ast.parse(expression, mode="eval")
expected_python_node = PythonNode(expression, _ast)
assert python_node == expected_python_node
@pytest.mark.parametrize("expression", [
"a and not b",
"not b and a",
"__ret and not __ret.status",
])
def test_i_can_compile_negative_conjunctions_when_pure_python(self, expression):
sheerka, context, *concepts = self.init_concepts("foo")
parser = LogicalOperatorParser()
expr_node = parser.parse(context, ParserInput(expression)).body.body
return_values, _ = parser.compile_conjunctions(context, expr_node.parts, "test")
ast_ = ast.parse(expression, "<source>", 'eval')
expected_python_node = PythonNode(expression, ast_)
assert len(return_values) == 1
ret = return_values[0]
assert sheerka.objvalue(ret) == expected_python_node
@pytest.mark.parametrize("expression, text_to_compile", [
("foo bar == 5", "__C__foo0bar__1001__C__ == 5"),
("not foo bar == 5", "not __C__foo0bar__1001__C__ == 5"),
])
def test_i_can_get_compiled_expr_from_python_and_concept(self, expression, text_to_compile):
sheerka, context, *concepts = self.init_test().with_concepts(Concept("foo bar"), create_new=True).unpack()
parser = LogicalOperatorParser()
expr_node = parser.parse(context, ParserInput(expression)).body.body
return_values, _ = parser.compile_conjunctions(context, [expr_node], "test")
assert len(return_values) == 1
ret = return_values[0]
assert ret.status
python_node = ret.body.body.get_python_node()
_ast = ast.parse(text_to_compile, mode="eval")
expected_python_node = PythonNode(text_to_compile, _ast, expression)
assert python_node == expected_python_node
def test_i_can_get_compiled_expr_from__mix_of_concepts_and_python(self):
sheerka, context, animal, cat, dog, pet, is_a, is_an = self.init_test().with_concepts(
Concept("animal"),
Concept("a cat"),
Concept("dog"),
Concept("pet"),
Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
Concept("x is an y", pre="is_question()", definition="('cat'|'bird')=x 'is an' animal").def_var("x"),
create_new=True
).unpack()
parser = LogicalOperatorParser()
expression = "not a cat is a pet and not bird is an animal and not x > 5 and not dog is a pet"
expr_node = parser.parse(context, ParserInput(expression)).body.body
return_values, _ = parser.compile_conjunctions(context, expr_node.parts, "test")
to_compile = 'not __C__00var0000is0a000var001__1005__C__'
to_compile += ' and not __C__00var0000is0an0y__1006__C__'
to_compile += ' and not x > 5'
to_compile += ' and not __C__00var0000is0a000var001__1005_1__C__'
ast_ = ast.parse(to_compile, "<source>", 'eval')
expected_python_node = PythonNode(to_compile, ast_, expression)
assert len(return_values) == 1
ret = return_values[0]
python_node = ret.body.body
assert python_node == expected_python_node
compare_with_test_object(python_node.objects, {
"__C__00var0000is0a000var001__1005__C__": CC(is_a, x=cat, y=pet),
"__C__00var0000is0an0y__1006__C__": CC(is_an, exclude_body=True, x=DoNotResolve("bird"), animal=animal),
"__C__00var0000is0a000var001__1005_1__C__": CMV(is_a, x="dog", y="pet"),
})
def test_i_can_get_compiled_expr_from_mix(self):
sheerka, context, animal, cat, dog, pet, is_a, is_an = self.init_test().with_concepts(
Concept("animal"),
Concept("a cat"),
Concept("dog"),
Concept("pet"),
Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
Concept("x is an y", pre="is_question()", definition="('cat'|'bird')=x 'is an' animal").def_var("x"),
create_new=True
).unpack()
expression = "a cat is a pet and bird is an animal and x > 5 and dog is a pet"
parser = LogicalOperatorParser()
expr_node = parser.parse(context, ParserInput(expression)).body.body
return_values, _ = parser.compile_conjunctions(context, expr_node.parts, "test")
assert len(return_values) == 1
ret = return_values[0]
to_compile = '__C__00var0000is0a000var001__1005__C__ and __C__00var0000is0an0y__1006__C__ and x > 5 and __C__00var0000is0a000var001__1005_1__C__'
ast_ = ast.parse(to_compile, "<source>", 'eval')
expected_python_node = PythonNode(to_compile, ast_, expression)
python_node = ret.body.body
assert python_node == expected_python_node
compare_with_test_object(python_node.objects, {
"__C__00var0000is0a000var001__1005__C__": CC(is_a, x=cat, y=pet),
"__C__00var0000is0an0y__1006__C__": CC(is_an, exclude_body=True, x=DoNotResolve("bird"), animal=animal),
"__C__00var0000is0a000var001__1005_1__C__": CMV(is_a, x="dog", y="pet"),
})
def test_i_can_get_compiled_expr_when_multiple_choices(self):
sheerka, context, *concepts = self.init_test().with_concepts(
Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
Concept("x is a y", pre="is_question()", body="isa(x, y)").def_var("x").def_var("y"),
create_new=True
).unpack()
parser = LogicalOperatorParser()
expression = "a is a b"
expr_node = parser.parse(context, ParserInput(expression)).body.body
return_values, _ = parser.compile_conjunctions(context, [expr_node], "test")
assert len(return_values) == 2
ret = return_values[0]
compare_with_test_object(sheerka.objvalue(ret)[0].concept, CMV(concepts[0], x="a", y="b"))
ret = return_values[1]
compare_with_test_object(sheerka.objvalue(ret)[0].concept, CMV(concepts[1], x="a", y="b"))
def test_i_can_get_compiled_expr_from_mix_when_multiple_choices(self):
sheerka, context, *concepts = self.init_test().with_concepts(
Concept("animal"),
Concept("a cat"),
Concept("dog"),
Concept("pet"),
Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
Concept("x is a y", pre="is_question()", body="isa(x, y)").def_var("x").def_var("y"),
Concept("x is an y", pre="is_question()", definition="('cat'|'bird')=x 'is an' animal").def_var("x"),
create_new=True
).unpack()
expression = "a cat is a pet and bird is an animal and x > 5 and dog is a pet"
parser = LogicalOperatorParser()
expr_node = parser.parse(context, ParserInput(expression)).body.body
return_values, _ = parser.compile_conjunctions(context, expr_node.parts, "test")
assert len(return_values) == 4
trimmed_source = "a cat is a pet and bird is an animal and x > 5 and dog is a pet"
current_ret = return_values[0]
python_source = "__C__00var0000is0a000var001__1005__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1005_1__C__"
ast_ = ast.parse(python_source, "<source>", 'eval')
resolved_expected = PythonNode(python_source, ast_, trimmed_source)
assert sheerka.objvalue(current_ret) == resolved_expected
current_ret = return_values[1]
assert sheerka.isinstance(current_ret, BuiltinConcepts.RETURN_VALUE)
python_source = "__C__00var0000is0a000var001__1005__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1006__C__"
ast_ = ast.parse(python_source, "<source>", 'eval')
resolved_expected = PythonNode(python_source, ast_, trimmed_source)
assert sheerka.objvalue(current_ret) == resolved_expected
current_ret = return_values[2]
assert sheerka.isinstance(current_ret, BuiltinConcepts.RETURN_VALUE)
python_source = "__C__00var0000is0a000var001__1006__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1005__C__"
ast_ = ast.parse(python_source, "<source>", 'eval')
resolved_expected = PythonNode(python_source, ast_, trimmed_source)
assert sheerka.objvalue(current_ret) == resolved_expected
current_ret = return_values[3]
python_source = "__C__00var0000is0a000var001__1006__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1006_1__C__"
ast_ = ast.parse(python_source, "<source>", 'eval')
resolved_expected = PythonNode(python_source, ast_, trimmed_source)
assert sheerka.objvalue(current_ret) == resolved_expected
@pytest.mark.skip
@pytest.mark.parametrize("expression, expected_conditions, test_obj", [
(
"__ret",
["#__x_00__|__name__|'__ret'"],
ReturnValueConcept("Test", True, None)
),
(
"__ret.status == True",
["#__x_00__|__name__|'__ret'", "#__x_00__|status|True"],
ReturnValueConcept("Test", True, None)
),
(
"__ret.status",
["#__x_00__|__name__|'__ret'", "#__x_00__|status|True"],
ReturnValueConcept("Test", True, None)
),
(
"__ret and __ret.status",
["#__x_00__|__name__|'__ret'", "#__x_00__|status|True"],
ReturnValueConcept("Test", True, None)
),
])
def test_i_can_get_rete_condition_from_python(self, expression, expected_conditions, test_obj):
sheerka, context, = self.init_test().unpack()
expected_full_condition = get_rete_conditions(*expected_conditions)
parser = LogicalOperatorParser()
expr_node = parser.parse(context, ParserInput(expression)).body.body
nodes = expr_node.parts if isinstance(expr_node, AndNode) else [expr_node]
_, rete_disjunctions = parser.compile_conjunctions(context, nodes, "test")
assert len(rete_disjunctions) == 1
assert rete_disjunctions == [expected_full_condition]
# check against a Rete network
network = ReteNetwork()
rule = Rule("test", expression, None)
rule.metadata.id = 9999
rule.metadata.is_compiled = True
rule.metadata.is_enabled = True
rule.rete_disjunctions = rete_disjunctions
network.add_rule(rule)
network.add_obj("__ret", test_obj)
matches = list(network.matches)
assert len(matches) > 0
# @pytest.mark.parametrize("expression", [
# "a == 5",
# "foo > 5",
# "func() == 5",
# "not a == 5",
# "not foo > 5",
# "not func() == 5",
# "isinstance(a, int)",
# "func()",
# "not isinstance(a, int)",
# "not func()"
# ])
# def test_i_can_get_compiled_expr_from_simple_python_expressions(self, expression):
# sheerka, context, = self.init_test().unpack()
#
# parser = LogicalOperatorParser()
# expr_node = parser.parse(context, ParserInput(expression)).body.body
# return_values, _ = parser.compile_conjunctions(context, [expr_node], "test")
#
# assert len(return_values) == 1
# ret = return_values[0]
#
# assert ret.status
# python_node = ret.body.body.get_python_node()
# _ast = ast.parse(expression, mode="eval")
# expected_python_node = PythonNode(expression, _ast)
# assert python_node == expected_python_node
#
# @pytest.mark.parametrize("expression", [
# "a and not b",
# "not b and a",
# "__ret and not __ret.status",
# ])
# def test_i_can_compile_negative_conjunctions_when_pure_python(self, expression):
# sheerka, context, *concepts = self.init_concepts("foo")
#
# parser = LogicalOperatorParser()
# expr_node = parser.parse(context, ParserInput(expression)).body.body
# return_values, _ = parser.compile_conjunctions(context, expr_node.parts, "test")
#
# ast_ = ast.parse(expression, "<source>", 'eval')
# expected_python_node = PythonNode(expression, ast_)
#
# assert len(return_values) == 1
# ret = return_values[0]
#
# assert sheerka.objvalue(ret) == expected_python_node
#
# @pytest.mark.parametrize("expression, text_to_compile", [
# ("foo bar == 5", "__C__foo0bar__1001__C__ == 5"),
# ("not foo bar == 5", "not __C__foo0bar__1001__C__ == 5"),
# ])
# def test_i_can_get_compiled_expr_from_python_and_concept(self, expression, text_to_compile):
# sheerka, context, *concepts = self.init_test().with_concepts(Concept("foo bar"), create_new=True).unpack()
#
# parser = LogicalOperatorParser()
# expr_node = parser.parse(context, ParserInput(expression)).body.body
# return_values, _ = parser.compile_conjunctions(context, [expr_node], "test")
#
# assert len(return_values) == 1
# ret = return_values[0]
#
# assert ret.status
# python_node = ret.body.body.get_python_node()
# _ast = ast.parse(text_to_compile, mode="eval")
# expected_python_node = PythonNode(text_to_compile, _ast, expression)
# assert python_node == expected_python_node
#
# def test_i_can_get_compiled_expr_from__mix_of_concepts_and_python(self):
# sheerka, context, animal, cat, dog, pet, is_a, is_an = self.init_test().with_concepts(
# Concept("animal"),
# Concept("a cat"),
# Concept("dog"),
# Concept("pet"),
# Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
# Concept("x is an y", pre="is_question()", definition="('cat'|'bird')=x 'is an' animal").def_var("x"),
# create_new=True
# ).unpack()
#
# parser = LogicalOperatorParser()
# expression = "not a cat is a pet and not bird is an animal and not x > 5 and not dog is a pet"
# expr_node = parser.parse(context, ParserInput(expression)).body.body
# return_values, _ = parser.compile_conjunctions(context, expr_node.parts, "test")
#
# to_compile = 'not __C__00var0000is0a000var001__1005__C__'
# to_compile += ' and not __C__00var0000is0an0y__1006__C__'
# to_compile += ' and not x > 5'
# to_compile += ' and not __C__00var0000is0a000var001__1005_1__C__'
# ast_ = ast.parse(to_compile, "<source>", 'eval')
# expected_python_node = PythonNode(to_compile, ast_, expression)
#
# assert len(return_values) == 1
# ret = return_values[0]
# python_node = ret.body.body
# assert python_node == expected_python_node
# compare_with_test_object(python_node.objects, {
# "__C__00var0000is0a000var001__1005__C__": CC(is_a, x=cat, y=pet),
# "__C__00var0000is0an0y__1006__C__": CC(is_an, exclude_body=True, x=DoNotResolve("bird"), animal=animal),
# "__C__00var0000is0a000var001__1005_1__C__": CMV(is_a, x="dog", y="pet"),
# })
#
# def test_i_can_get_compiled_expr_from_mix(self):
# sheerka, context, animal, cat, dog, pet, is_a, is_an = self.init_test().with_concepts(
# Concept("animal"),
# Concept("a cat"),
# Concept("dog"),
# Concept("pet"),
# Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
# Concept("x is an y", pre="is_question()", definition="('cat'|'bird')=x 'is an' animal").def_var("x"),
# create_new=True
# ).unpack()
#
# expression = "a cat is a pet and bird is an animal and x > 5 and dog is a pet"
# parser = LogicalOperatorParser()
# expr_node = parser.parse(context, ParserInput(expression)).body.body
# return_values, _ = parser.compile_conjunctions(context, expr_node.parts, "test")
#
# assert len(return_values) == 1
# ret = return_values[0]
#
# to_compile = '__C__00var0000is0a000var001__1005__C__ and __C__00var0000is0an0y__1006__C__ and x > 5 and __C__00var0000is0a000var001__1005_1__C__'
# ast_ = ast.parse(to_compile, "<source>", 'eval')
# expected_python_node = PythonNode(to_compile, ast_, expression)
#
# python_node = ret.body.body
# assert python_node == expected_python_node
# compare_with_test_object(python_node.objects, {
# "__C__00var0000is0a000var001__1005__C__": CC(is_a, x=cat, y=pet),
# "__C__00var0000is0an0y__1006__C__": CC(is_an, exclude_body=True, x=DoNotResolve("bird"), animal=animal),
# "__C__00var0000is0a000var001__1005_1__C__": CMV(is_a, x="dog", y="pet"),
# })
#
# def test_i_can_get_compiled_expr_when_multiple_choices(self):
# sheerka, context, *concepts = self.init_test().with_concepts(
# Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
# Concept("x is a y", pre="is_question()", body="isa(x, y)").def_var("x").def_var("y"),
# create_new=True
# ).unpack()
#
# parser = LogicalOperatorParser()
# expression = "a is a b"
# expr_node = parser.parse(context, ParserInput(expression)).body.body
# return_values, _ = parser.compile_conjunctions(context, [expr_node], "test")
#
# assert len(return_values) == 2
#
# ret = return_values[0]
# compare_with_test_object(sheerka.objvalue(ret)[0].concept, CMV(concepts[0], x="a", y="b"))
#
# ret = return_values[1]
# compare_with_test_object(sheerka.objvalue(ret)[0].concept, CMV(concepts[1], x="a", y="b"))
#
# def test_i_can_get_compiled_expr_from_mix_when_multiple_choices(self):
# sheerka, context, *concepts = self.init_test().with_concepts(
# Concept("animal"),
# Concept("a cat"),
# Concept("dog"),
# Concept("pet"),
# Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
# Concept("x is a y", pre="is_question()", body="isa(x, y)").def_var("x").def_var("y"),
# Concept("x is an y", pre="is_question()", definition="('cat'|'bird')=x 'is an' animal").def_var("x"),
# create_new=True
# ).unpack()
#
# expression = "a cat is a pet and bird is an animal and x > 5 and dog is a pet"
# parser = LogicalOperatorParser()
# expr_node = parser.parse(context, ParserInput(expression)).body.body
# return_values, _ = parser.compile_conjunctions(context, expr_node.parts, "test")
#
# assert len(return_values) == 4
# trimmed_source = "a cat is a pet and bird is an animal and x > 5 and dog is a pet"
#
# current_ret = return_values[0]
# python_source = "__C__00var0000is0a000var001__1005__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1005_1__C__"
# ast_ = ast.parse(python_source, "<source>", 'eval')
# resolved_expected = PythonNode(python_source, ast_, trimmed_source)
# assert sheerka.objvalue(current_ret) == resolved_expected
#
# current_ret = return_values[1]
# assert sheerka.isinstance(current_ret, BuiltinConcepts.RETURN_VALUE)
# python_source = "__C__00var0000is0a000var001__1005__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1006__C__"
# ast_ = ast.parse(python_source, "<source>", 'eval')
# resolved_expected = PythonNode(python_source, ast_, trimmed_source)
# assert sheerka.objvalue(current_ret) == resolved_expected
#
# current_ret = return_values[2]
# assert sheerka.isinstance(current_ret, BuiltinConcepts.RETURN_VALUE)
# python_source = "__C__00var0000is0a000var001__1006__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1005__C__"
# ast_ = ast.parse(python_source, "<source>", 'eval')
# resolved_expected = PythonNode(python_source, ast_, trimmed_source)
# assert sheerka.objvalue(current_ret) == resolved_expected
#
# current_ret = return_values[3]
# python_source = "__C__00var0000is0a000var001__1006__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1006_1__C__"
# ast_ = ast.parse(python_source, "<source>", 'eval')
# resolved_expected = PythonNode(python_source, ast_, trimmed_source)
# assert sheerka.objvalue(current_ret) == resolved_expected
#
# @pytest.mark.skip
# @pytest.mark.parametrize("expression, expected_conditions, test_obj", [
# (
# "__ret",
# ["#__x_00__|__name__|'__ret'"],
# ReturnValueConcept("Test", True, None)
# ),
# (
# "__ret.status == True",
# ["#__x_00__|__name__|'__ret'", "#__x_00__|status|True"],
# ReturnValueConcept("Test", True, None)
# ),
# (
# "__ret.status",
# ["#__x_00__|__name__|'__ret'", "#__x_00__|status|True"],
# ReturnValueConcept("Test", True, None)
# ),
# (
# "__ret and __ret.status",
# ["#__x_00__|__name__|'__ret'", "#__x_00__|status|True"],
# ReturnValueConcept("Test", True, None)
# ),
# ])
# def test_i_can_get_rete_condition_from_python(self, expression, expected_conditions, test_obj):
# sheerka, context, = self.init_test().unpack()
# expected_full_condition = get_rete_conditions(*expected_conditions)
#
# parser = LogicalOperatorParser()
# expr_node = parser.parse(context, ParserInput(expression)).body.body
#
# nodes = expr_node.parts if isinstance(expr_node, AndNode) else [expr_node]
# _, rete_disjunctions = parser.compile_conjunctions(context, nodes, "test")
#
# assert len(rete_disjunctions) == 1
# assert rete_disjunctions == [expected_full_condition]
#
# # check against a Rete network
# network = ReteNetwork()
# rule = Rule("test", expression, None)
# rule.metadata.id = 9999
# rule.metadata.is_compiled = True
# rule.metadata.is_enabled = True
# rule.rete_disjunctions = rete_disjunctions
# network.add_rule(rule)
#
# network.add_obj("__ret", test_obj)
# matches = list(network.matches)
# assert len(matches) > 0
@@ -9,8 +9,10 @@ from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Token, TokenKind, Tokenizer
from core.var_ref import VariableRef
from parsers.BaseNodeParser import ConceptNode, UnrecognizedTokensNode, RuleNode, VariableNode
from parsers.BnfNodeParser import BnfNodeParser
from parsers.PythonParser import PythonNode
from parsers.PythonWithConceptsParser import PythonWithConceptsParser
from parsers.SequenceNodeParser import SequenceNodeParser
from parsers.UnrecognizedNodeParser import UnrecognizedNodeParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.parsers.parsers_utils import get_source_code_node
@@ -226,3 +228,39 @@ class TestPythonWithConceptsParser(TestUsingMemoryBasedSheerka):
assert result_python_node.ast_str == PythonNode.get_dump(expected_ast)
assert result_python_node.original_source == "not foo == 1 and bar < 1"
assert result_python_node.objects == {"__C__foo__C__": foo, "__C__bar__C__": bar}
def test_can_parse_after_unrecognized_bnf(self):
sheerka, context, one, two, twenties = self.init_concepts(
Concept("one", body="1"),
Concept("two", body="2"),
Concept("twenties", definition="'twenty' (one|two)=n", body='20 + n').def_var("n"),
create_new=True
)
bnf_parser_ret_val = BnfNodeParser().parse(context, ParserInput("a + twenty one"))
unrec_node_ret_val = UnrecognizedNodeParser().parse(context, bnf_parser_ret_val.body)
parser = PythonWithConceptsParser()
result = parser.parse(context, unrec_node_ret_val.body)
assert result.status
python_node = result.body.body
assert isinstance(python_node, PythonNode)
assert python_node.source == 'a + __C__twenties__1003__C__'
assert "__C__twenties__1003__C__" in python_node.objects
def test_i_cannot_parse_unrecognized_sequence(self):
sheerka, context, one, two, twenties = self.init_concepts(
Concept("one", body="1"),
Concept("two", body="2"),
Concept("twenties", definition="'twenty' (one|two)=n", body='20 + n').def_var("n"),
create_new=True
)
sequence_parser_ret_val = SequenceNodeParser().parse(context, ParserInput("a + twenty one"))
unrec_node_ret_val = UnrecognizedNodeParser().parse(context, sequence_parser_ret_val.body)
parser = PythonWithConceptsParser()
result = parser.parse(context, unrec_node_ret_val.body)
assert not result.status
+27 -5
View File
@@ -9,7 +9,7 @@ from tests.parsers.parsers_utils import compute_expected_array, CN, CNC, SCN, ge
UTN
class TestAtomsParser(TestUsingMemoryBasedSheerka):
class TestSequenceNodeParser(TestUsingMemoryBasedSheerka):
def init_parser(self, my_map, create_new=False, singleton=True, use_sheerka=False):
sheerka, context, *updated_concepts = self.init_test().with_concepts(
*my_map.values(),
@@ -283,8 +283,8 @@ class TestAtomsParser(TestUsingMemoryBasedSheerka):
@pytest.mark.parametrize("text, expected", [
("hello foo bar",
[
(True, [CNC("hello1", "hello foo ", a="foo "), "bar"]),
(True, [CNC("hello2", "hello foo ", b="foo "), "bar"]),
("a", [CN("hello1", "hello foo "), "bar"]),
("b", [CN("hello2", "hello foo "), "bar"]),
]),
])
def test_i_can_parse_when_unrecognized_yield_multiple_values(self, text, expected):
@@ -303,11 +303,12 @@ class TestAtomsParser(TestUsingMemoryBasedSheerka):
wrapper = res.body
lexer_nodes = res.body.body
assert res.status == expected[0]
assert res.status
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
expected_array = compute_expected_array(concepts_map, text, expected[1])
transformed_nodes = get_test_obj(lexer_nodes, expected_array)
assert transformed_nodes == expected_array
assert lexer_nodes[0].concept.get_metadata().variables == [(expected[0], "foo ")]
@pytest.mark.parametrize("text, expected", [
("1 + twenty one", [SCN("1 + twenty "), "one"]),
@@ -352,7 +353,7 @@ class TestAtomsParser(TestUsingMemoryBasedSheerka):
lexer_nodes = res.body.body
assert res.status
assert lexer_nodes[0].concept.get_metadata().is_evaluated == expected_is_evaluated
assert lexer_nodes[0].concept.get_hints().is_evaluated == expected_is_evaluated
def test_the_parser_always_return_a_new_instance_of_the_concept(self):
concepts_map = {
@@ -383,3 +384,24 @@ class TestAtomsParser(TestUsingMemoryBasedSheerka):
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.NOT_FOR_ME)
@pytest.mark.parametrize("text", [
"foo",
"foo bar",
"long concept",
"unrecognized foo",
"bar unrecognized",
])
def test_i_correctly_set_up_use_copy(self, text):
concepts_map = {
"foo": Concept("foo"),
"bar": Concept("bar"),
"long concept": Concept("long concept"),
}
sheerka, context, parser = self.init_parser(concepts_map)
res = parser.parse(context, ParserInput(text))
for node in res.body.body:
if hasattr(node, "concept"):
assert node.concept.get_hints().use_copy
+32 -44
View File
@@ -7,7 +7,6 @@ from core.global_symbols import CONCEPT_COMPARISON_CONTEXT
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Tokenizer
from core.utils import NextIdManager
from parsers.BaseNodeParser import UnrecognizedTokensNode
from parsers.PythonParser import PythonNode
from parsers.SyaNodeParser import SyaNodeParser, SyaConceptParserHelper, SyaAssociativity, \
NoneAssociativeSequenceError, TooManyParametersFoundError, InFixToPostFix, ParenthesisMismatchError
@@ -1081,29 +1080,6 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
assert isinstance(concept_plus_b[0].body.body, PythonNode)
assert concept_suffixed_a == cmap["two"]
@pytest.mark.parametrize("text, expected_status, expected_result", [
("f1(one prefixed) plus f2(suffixed two)", False, [
CNC("plus",
a=SCWC("f1(", ")", CNC("prefixed", a="one")),
b=SCWC("f2(", (")", 1), CNC("suffixed", a="two")))
]),
("one is a concept", True, [CNC("is a concept", c="one")]),
("a is a concept", False, [CNC("is a concept", c=UTN("a"))]),
])
def test_i_can_parse_when_one_result(self, text, expected_status, expected_result):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, ParserInput(text))
wrapper = res.body
lexer_nodes = res.body.body
expected_array = compute_expected_array(cmap, text, expected_result)
assert res.status == expected_status
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
transformed_nodes = get_test_obj(lexer_nodes, expected_array)
assert transformed_nodes == expected_array
@pytest.mark.parametrize("text", [
"function(suffixed one)",
"function(one plus two mult three)",
@@ -1144,8 +1120,6 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
("one plus two a long other b", [CNC("plus", a="one", b="two"), UTN(" a long other b")]),
("one plus two a long infixed", [CNC("plus", a="one", b="two"), UTN(" a long infixed")]),
("one plus two a long", [CNC("plus", a="one", b="two"), UTN(" a long")]),
("one ? a long infixed : two", [CNC("?", a="one", b=UTN("a long infixed"), c="two")]),
("one ? a long infix : two", [CNC("?", a="one", b=UTN("a long infix"), c="two")]),
])
def test_i_can_almost_parse_when_one_part_is_recognized_but_not_the_rest(self, text, expected_result):
"""
@@ -1195,31 +1169,25 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
assert transformed_nodes == expected_array
# assert lexer_nodes == expected_array
@pytest.mark.parametrize("text, expected_concept, expected_unrecognized", [
("x$!# prefixed", "prefixed", ["a"]),
("suffixed x$!#", "suffixed", ["a"]),
("one infix x$!#", "infix", ["b"]),
("x$!# infix one", "infix", ["a"]),
("x$!# infix z$!#", "infix", ["a", "b"]),
@pytest.mark.parametrize("text, expected_error", [
("x$!# prefixed", "Cannot parse 'x$!#'"),
("suffixed x$!#", "Cannot parse 'x$!#'"),
("one infix x$!#", "Cannot parse 'x$!#'"),
("x$!# infix one", "Cannot parse 'x$!#'"),
("x$!# infix z$!#", ["Cannot parse 'z$!#'", "Cannot parse 'x$!#'"]),
("suffixed alpha beta", "Cannot parse 'alpha beta'"),
("alpha beta prefixed", "Cannot parse 'alpha beta'"),
("one plus alpha beta", "Cannot parse 'alpha beta'"),
])
def test_i_cannot_parse_when_unrecognized(self, text, expected_concept, expected_unrecognized):
def test_i_cannot_parse_when_unrecognized(self, text, expected_error):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, ParserInput(text))
wrapper = res.body
lexer_nodes = res.body.body
expected_end = len(list(Tokenizer(text))) - 2
assert not res.status
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
expected_array = [CN(cmap[expected_concept], text, 0, expected_end)]
transformed_nodes = get_test_obj(lexer_nodes, expected_array)
assert transformed_nodes == expected_array
# assert lexer_nodes == [CN(cmap[expected_concept], text, 0, expected_end)]
concept_found = lexer_nodes[0].concept
for unrecognized in expected_unrecognized:
assert isinstance(concept_found.get_compiled()[unrecognized], UnrecognizedTokensNode)
assert sheerka.isinstance(wrapper, BuiltinConcepts.ERROR)
assert wrapper.body == expected_error
@pytest.mark.parametrize("text, expected", [
("x$!# suffixed one", [UTN("x$!# ", 0, 4), CN("suffixed __var__0", "suffixed one", 5, 7)]),
@@ -1364,6 +1332,26 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
compare_with_test_object(lexer_nodes, [CN(cmap["suffixed"], text, 0, 6)])
def test_i_correctly_set_up_use_copy(self):
my_map = {
"shirt": Concept("shirt"),
"a x": Concept("a x", ret="x").def_var("x"),
"red x": Concept("red x", ret="x").def_var("x"),
}
sheerka, context, parser = self.init_parser(my_map)
res = parser.parse(context, ParserInput("a red shirt"))
concept_found = res.body.body[0].concept
assert concept_found.get_hints().use_copy
concept_found_x = concept_found.get_compiled()["x"]
assert concept_found_x.get_hints().use_copy
concept_found_x_x = concept_found_x.get_compiled()["x"]
assert concept_found_x_x.get_hints().use_copy
class TestFileBaseSyaNodeParser(TestUsingFileBasedSheerka):
def test_i_can_parse_after_restart(self):
+3 -3
View File
@@ -363,7 +363,7 @@ class TestUnrecognizedNodeParser(TestUsingMemoryBasedSheerka):
assert parser_result.source == expression
assert len(actual_nodes) == 1
assert actual_nodes[0].nodes[
0].concept.get_metadata().is_evaluated # 'a plus b' is recognized as concept definition
0].concept.get_hints().is_evaluated # 'a plus b' is recognized as concept definition
def test_i_can_parse_unrecognized_source_code_with_concept_node_when_var_in_short_term_memory(self):
sheerka, context, parser = self.init_parser()
@@ -373,7 +373,7 @@ class TestUnrecognizedNodeParser(TestUsingMemoryBasedSheerka):
nodes = get_input_nodes_from(concepts_map, expression, source_code_concepts)
parser_input = ParserResultConcept("parsers.xxx", source=expression, value=nodes)
context.add_to_short_term_memory("a", 1)
context.add_to_short_term_memory("a", 1) # -> a plus b is now an instance of the concept
res = parser.parse(context, parser_input)
parser_result = res.body
actual_nodes = res.body.body
@@ -382,7 +382,7 @@ class TestUnrecognizedNodeParser(TestUsingMemoryBasedSheerka):
assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT)
assert parser_result.source == expression
assert len(actual_nodes) == 1
assert not actual_nodes[0].nodes[0].concept.get_metadata().is_evaluated # 'a plus b' need to be evaluated
assert not actual_nodes[0].nodes[0].concept.get_hints().is_evaluated # 'a plus b' need to be evaluated
def test_i_can_parse_unrecognized_sya_concept_that_references_source_code(self):
sheerka, context, parser = self.init_parser()
+27
View File
@@ -1,3 +1,5 @@
import pytest
from sheerkarete.common import WME, V
from sheerkarete.conditions import NotEqualsCondition, AndConditions, Condition, NegatedCondition, \
NegatedConjunctiveConditions, FilterCondition, BindCondition
@@ -27,6 +29,31 @@ class TestReteConditions(TestUsingMemoryBasedSheerka):
network.remove_wme(wme)
assert len(list(network.matches)) == 0
@pytest.mark.skip("Comparison between variables need to be implemented.")
def test_i_can_test_condition_between_variables(self):
network = ReteNetwork()
conditions = [Condition(V("x"), "__name__", "x"),
Condition(V("y"), "__name__", "y"),
Condition(V("x"), "__self__", V("y"))],
rule = RuleForTestingRete(AndConditions(conditions))
network.add_rule(rule)
assert len(list(network.matches)) == 0
wme_x = WME("x", "__self__", "10")
wme_y = WME("y", "__self__", "10")
network.add_wme(wme_x)
network.add_wme(wme_y)
matches = list(network.matches)
assert len(matches) == 1
assert matches[0].pnode.rules == [rule]
assert matches[0].token.wmes == [wme_x, wme_y]
# remove wme
network.remove_wme(wme_x)
assert len(list(network.matches)) == 0
def test_i_can_manage_not_equals_condition(self):
network = ReteNetwork()
+14
View File
@@ -88,6 +88,20 @@ class TestReteNetwork(TestUsingMemoryBasedSheerka):
"fact_name.value.body": ["sub_value"],
}
def test_i_can_update_conditions_attributes_when_value_is_a_variable(self):
network = ReteNetwork()
conditions = [Condition(V("x"), "__name__", "x"),
Condition(V("y"), "__name__", "y"),
Condition(V("x"), "__self__", V("y"))]
rule = RuleForTestingRete(AndConditions(conditions))
network.add_rule(rule)
assert network.attributes_by_id == {
"x": ["__name__", "__self__"],
"y": ["__name__", "__self__"],
}
def test_adding_obj_when_no_rule_has_no_effect(self):
network = ReteNetwork()
ret = ReturnValueConcept("test", True, "value")