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:
+5
-1
@@ -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]
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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__'
|
||||
|
||||
@@ -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,
|
||||
# []
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -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,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,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,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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")]),
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user