import ast import pytest from core.builtin_concepts import ReturnValueConcept from core.builtin_concepts_ids import BuiltinConcepts from core.concept import Concept, DEFINITION_TYPE_DEF from core.rule import Rule from core.sheerka.services.SheerkaEvaluateRules import SheerkaEvaluateRules from core.sheerka.services.SheerkaExecute import ParserInput from core.sheerka.services.SheerkaRuleManager import CompiledCondition, ReteConditionExprVisitor from core.sheerka.services.sheerka_service import FailedToCompileError from evaluators.PythonEvaluator import PythonEvaluator from parsers.BaseParser import ErrorSink from parsers.ExpressionParser import ExpressionParser from parsers.PythonParser import PythonNode from sheerkapython.ExprToConditions import ExprToConditionsVisitor from sheerkarete.network import ReteNetwork from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.core.test_SheerkaRuleManager import PYTHON_EVALUATOR_NAME from tests.parsers.parsers_utils import NEGCOND, get_rete_conditions 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 = ExprToConditionsVisitor(context) conditions = visitor.get_conditions(parsed) return conditions @staticmethod def check_against_rete(rule_expression, rule_conditions, objects): """ :param rule_expression: :param rule_conditions: :param objects: list of tuple(name, obj) :return: """ # check against a Rete network network = ReteNetwork() rule = Rule("test", rule_expression, None) rule.metadata.id = 9999 rule.metadata.is_compiled = True rule.metadata.is_enabled = True rule.rete_disjunctions = rule_conditions network.add_rule(rule) for name, value in objects.items(): network.add_obj(name, value) matches = list(network.matches) assert len(matches) == 1 @staticmethod def check_against_python(context, rule_expression, rule_conditions, objects, expected_result=True): bag = {} for name, value in objects.items(): bag[name] = value evaluate_rules_service = context.sheerka.services[SheerkaEvaluateRules.NAME] rule = Rule(name="test", predicate=rule_expression) rule.compiled_conditions = rule_conditions rule.metadata.is_enabled = True rule.metadata.is_compiled = True evaluation = evaluate_rules_service.evaluate_rules(context, [rule], bag, set()) assert expected_result in evaluation and len(evaluation[expected_result]) == 1 @staticmethod def evaluate_condition(context, expression, condition, objects): with context.push("Testing conditions SheerkaRuleManagerRulesCompilation", expression) as sub_context: sub_context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) sub_context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED) sub_context.protected_hints.add(BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED) sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED) 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 def get_testing_objects(cls, context, objects_names, objects_mappings=None): if objects_names is None: return {} result = {} for name in objects_names: if isinstance(name, tuple): name, value = name if value == "sheerka": value = context.sheerka else: value = None if objects_mappings and value in objects_mappings: value = objects_mappings[value] if name == "__ret": return_value = ReturnValueConcept("Test", True, value) result["__ret"] = return_value elif name == "__ret.status": return_value = ReturnValueConcept("Test", True, value) result["__ret.status"] = return_value.status elif name == "body": return_value = ReturnValueConcept("Test", True, value) result["body"] = return_value.body elif name == "a_string": result["a_string"] = value or "hello world!" elif name == "an_int": result["an_int"] = value or 10 else: result[name] = value return result @staticmethod def get_variables_names_from_expected_variables(expected_variables): return {v[0] if isinstance(v, tuple) else v for v in expected_variables} @staticmethod def func_true(*args, **kwargs): return True @staticmethod def func_identity(x): return x def validate_python_test(self, context, expression, expected_compiled, expected_text, expected_variables, expected_not_variables, expected_objects): sheerka = context.sheerka conditions = BaseTestSheerkaRuleManagerRulesCompilation.get_conditions(context, expression) assert len(conditions) == 1 assert isinstance(conditions[0], CompiledCondition) if expected_compiled is None: # manage cases where we only check for variable existence assert conditions[0].evaluator_type is None assert conditions[0].return_value is None else: # check what was compiled ast_ = ast.parse(expected_compiled, "", 'exec' if "\n" in expected_compiled else 'eval') expected_python_node = PythonNode(expected_compiled, ast_, expected_text) assert conditions[0].evaluator_type == PYTHON_EVALUATOR_NAME assert sheerka.isinstance(conditions[0].return_value, BuiltinConcepts.RETURN_VALUE) assert sheerka.objvalue(conditions[0].return_value) == expected_python_node # check that variables detected assert conditions[0].variables == self.get_variables_names_from_expected_variables(expected_variables) # check that variables that MUST not be present assert conditions[0].not_variables == expected_not_variables # check the objects returned assert len(expected_objects) == len(conditions[0].objects) for obj in expected_objects: if isinstance(obj, tuple): assert conditions[0].objects[obj[0]] == obj[1] else: assert obj in conditions[0].objects return conditions class TestSheerkaRuleManagerRulesCompilationExists(BaseTestSheerkaRuleManagerRulesCompilation): """ Testing variable existence: __ret (exists) __ret.status (exists) body (exists) __ret and __ret.status (both exist) """ @pytest.mark.parametrize("expression, expected_as_list_of_str, expected_variables", [ ( "__ret", ["#__x_00__|__name__|'__ret'"], {"__ret"} ), ( "__ret.status", ["#__x_00__|__name__|'__ret.status'"], {"__ret.status"} ), ( "body", ["#__x_00__|__name__|'body'"], {"body"} ), ( "__ret and __ret.status", ["#__x_00__|__name__|'__ret'", "#__x_01__|__name__|'__ret.status'"], {"__ret", "__ret.status"} ), ]) def test_rete(self, expression, expected_as_list_of_str, expected_variables): sheerka, context = self.init_test().unpack() parser = ExpressionParser() expected = get_rete_conditions(*expected_as_list_of_str) 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 = ReteConditionExprVisitor(context) conditions = visitor.get_conditions(parsed) assert conditions == [expected] # check against a Rete network objects = self.get_testing_objects(context, expected_variables) self.check_against_rete(expression, conditions, objects) class TestSheerkaRuleManagerRulesCompilationNotExists(BaseTestSheerkaRuleManagerRulesCompilation): """ Testing NOT existence not __ret not not __ret not __ret.status not body not __ret and not __ret.status __ret and not ret.status __ret and not __error """ @pytest.mark.parametrize("expression, expected_as_list_of_str", [ ("not __ret", [NEGCOND("#__x_00__|__name__|'__ret'")]), ("not not __ret", ["#__x_00__|__name__|'__ret'"]), ("not __ret.status", [NEGCOND("#__x_00__|__name__|'__ret.status'")]), ("not body", [NEGCOND("#__x_00__|__name__|'body'")]), ( "not __ret and not __ret.status", [NEGCOND("#__x_00__|__name__|'__ret'"), NEGCOND("#__x_01__|__name__|'__ret.status'")] ), ( "__ret and not __ret.status", ["#__x_00__|__name__|'__ret'", NEGCOND("#__x_01__|__name__|'__ret.status'")] ), ( "__ret and not __error", ["#__x_00__|__name__|'__ret'", NEGCOND("#__x_01__|__name__|'__error'")] ), ]) def test_rete(self, expression, expected_as_list_of_str): sheerka, context = self.init_test().unpack() parser = ExpressionParser() expected = get_rete_conditions(*expected_as_list_of_str) 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 = ReteConditionExprVisitor(context) conditions = visitor.get_conditions(parsed) assert conditions == [expected] # # check against a Rete network # objects = self.get_testing_objects(context, expected_variables) # self.check_against_rete(expression, conditions, objects) # @pytest.mark.parametrize("expression, expected_variables, expected_not_variables", [ # ("not __ret", set(), {"__ret"}), # ("not not __ret", {"__ret"}, set()), # ("not __ret.status", set(), {"__ret.status"}), # ("not body", set(), {"body"}), # ("not __ret and not __ret.status", set(), {"__ret", "__ret.status"}), # ("__ret and not __ret.status", {"__ret"}, {"__ret.status"}), # ("__ret and not __error", {"__ret"}, {"__error"}), # ]) # def test_python(self, expression, expected_variables, expected_not_variables): # sheerka, context = self.init_test().unpack() # # conditions = self.validate_python_test(context, # expression, # None, # None, # expected_variables, # expected_not_variables, # set()) # # # check against SheerkaEvaluateRules # objects = self.get_testing_objects(context, expected_variables) # 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 a + b """ # @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" # ), # ( # "a + b", # "a + b", # "a + b", # {("a", 10), ("b", 1)}, # {}, # 11 # ), # ]) # 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: a == 10 __ret.status == True self == 'a' self == sheerka self == BuiltinConcepts.TO_DICT self == hello 'my friend' a == b """ @pytest.mark.parametrize("expression, expected_as_list_of_str, expected_variables", [ ("a == 10", ["#__x_00__|__name__|'a'", "#__x_00__|__self__|10"], {("a", 10)}), ("__ret.status == True", ["#__x_00__|__name__|'__ret'", "#__x_00__|status|True"], {"__ret"}), ("self == 'a'", ["#__x_00__|__name__|'self'", "#__x_00__|__self__|'a'"], {("self", 'a')}), ("self == sheerka", ["#__x_00__|__name__|'self'", "#__x_00__|__self__|'__sheerka__'"], {("self", "sheerka")}), ( "self == BuiltinConcepts.TO_DICT", ["#__x_00__|__name__|'self'", "#__x_00__|__self__|BuiltinConcepts.TO_DICT"], {("self", BuiltinConcepts.TO_DICT)} ), ("self == hello 'my friend'", ["#__x_00__|__name__|'self'", "#__x_00__|__is_concept__|True", "#__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( Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"), create_new=True ).unpack() parser = ExpressionParser() expected = get_rete_conditions(*expected_as_list_of_str) 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 = ReteConditionExprVisitor(context) conditions = visitor.get_conditions(parsed) assert conditions == [expected] # check against a Rete network objects_mappings = {"hello_my_friend": sheerka.new(greetings, a='my friend')} 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 == 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 == BuiltinConcepts.TO_DICT", # {("self", 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( # Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"), # create_new=True # ).unpack() # # conditions = self.validate_python_test(context, # expression, # expected_compiled, # expression, # expected_variables, # set(), # expected_objects) # # # check against SheerkaEvaluateRules # objects_mappings = {"hello_my_friend": sheerka.new(greetings, a='my friend')} # objects = self.get_testing_objects(context, expected_variables, objects_mappings) # 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 no var : isinstance('hello', str) with var: isinstance(a_string, str) with and : isinstance(a_string, str) and isinstance(an_int, int) function with concept: isinstance(self, girl) function with concept: isinstance(self, a little boy) function with enum: func_true(self, BuiltinConcepts.TO_DICT) """ def test_rete(self): pass # @pytest.mark.parametrize("expression, e_compiled, e_text, e_variables, e_objects", [ # ( # "isinstance('hello', str)", # "isinstance(__o_00__, str)", # "isinstance('hello', str)", # set(), # {"__o_00__"} # ), # ( # "isinstance(a_string, str)", # "isinstance(a_string, str)", # "isinstance(a_string, str)", # {"a_string"}, # {} # ), # ( # "not isinstance(an_int, str)", # "not (isinstance(an_int, str))", # "not (isinstance(an_int, str))", # {"an_int"}, # {} # ), # ( # "isinstance(a_string, str) and isinstance(an_int, int)", # "isinstance(a_string, str) and isinstance(an_int, int)", # "isinstance(a_string, str) and isinstance(an_int, int)", # {"an_int", "a_string"}, # {} # ), # ( # "isinstance(self, girl)", # "isinstance(self, __o_00__)", # "isinstance(self, girl)", # {("self", "girl")}, # {"__o_00__"} # ), # ( # "isinstance(self, a little boy)", # "isinstance(self, __o_00__)", # "isinstance(self, a little boy)", # {("self", "a little boy")}, # {"__o_00__"} # ), # ( # "func_true(self, BuiltinConcepts.TO_DICT)", # "func_true(self, BuiltinConcepts.TO_DICT)", # "func_true(self, BuiltinConcepts.TO_DICT)", # {("self", BuiltinConcepts.TO_DICT)}, # {} # ), # ]) # def test_python(self, expression, e_compiled, e_text, e_variables, e_objects): # sheerka, context, girl, little_boy = self.init_test().with_concepts( # Concept("girl"), # Concept("a little boy"), # create_new=True # ).unpack() # # conditions = self.validate_python_test(context, # expression, # e_compiled, # e_text, # e_variables, # set(), # e_objects) # # # check against SheerkaEvaluateRules # objects_mappings = {"girl": girl, "a little boy": little_boy} # objects = self.get_testing_objects(context, e_variables, objects_mappings) # objects["func_true"] = self.func_true # self.check_against_python(context, expression, conditions, objects) @pytest.mark.skip("too lazy to understand why it does not work anymore") class TestSheerkaRuleManagerRulesCompilationRecognizeConcept(BaseTestSheerkaRuleManagerRulesCompilation): """ Testing recognize(path, concept) recognize by name : recognize(__ret.body, greetings) recognize by id : recognize(__ret.body, c:|1001:) recognize by name using c_str : recognize(__ret.body, c:greetings:) recognize by name + str condition : recognize(__ret.body, greetings) and __ret.body.a == 'my friend' recognize by name + sheerka condition : recognize(__ret.body, greetings) and __ret.body.a == sheerka recognize by name + concept condition : recognize(__ret.body, greetings) and __ret.body.a == foo recognize by instance using sheerka : recognize(__ret.body, hello sheerka) recognize by instance using a string : recognize(__ret.body, hello 'my friend') recognize by instance using a concept : recognize(__ret.body, hello foo) recognize by instance using long concept : recognize(__ret.body, hello my best friend) recognize self : recognize(self, greetings) """ @pytest.mark.parametrize("expression, expected_as_list_of_str, expected_variable, greeting_var", [ ( "recognize(__ret.body, greetings)", ["#__x_00__|__name__|'__ret'", "#__x_00__|body|#__x_01__", "#__x_01__|__is_concept__|True", "#__x_01__|name|'greetings'"], "__ret", None ), ( "recognize(__ret.body, c:|1001:)", ["#__x_00__|__name__|'__ret'", "#__x_00__|body|#__x_01__", "#__x_01__|__is_concept__|True", "#__x_01__|id|'1001'"], "__ret", None ), ( "recognize(__ret.body, c:greetings:)", ["#__x_00__|__name__|'__ret'", "#__x_00__|body|#__x_01__", "#__x_01__|__is_concept__|True", "#__x_01__|name|'greetings'"], "__ret", None ), ( "recognize(__ret.body, greetings) and __ret.body.a == 'my friend'", ["#__x_00__|__name__|'__ret'", "#__x_00__|body|#__x_01__", "#__x_01__|__is_concept__|True", "#__x_01__|name|'greetings'", "#__x_01__|a|'my friend'"], "__ret", "my friend", ), ( "recognize(__ret.body, greetings) and __ret.body.a == sheerka", ["#__x_00__|__name__|'__ret'", "#__x_00__|body|#__x_01__", "#__x_01__|__is_concept__|True", "#__x_01__|name|'greetings'", "#__x_01__|a|'__sheerka__'"], "__ret", "sheerka", ), ( "recognize(__ret.body, greetings) and __ret.body.a == foo", ["#__x_00__|__name__|'__ret'", "#__x_00__|body|#__x_01__", "#__x_01__|__is_concept__|True", "#__x_01__|name|'greetings'", "#__x_01__|a|#__x_02__", "#__x_02__|__is_concept__|True", "#__x_02__|key|'foo'"], "__ret", "foo", ), ( "recognize(__ret.body, hello sheerka)", ["#__x_00__|__name__|'__ret'", "#__x_00__|body|#__x_01__", "#__x_01__|__is_concept__|True", "#__x_01__|key|'hello __var__0'", "#__x_01__|a|'__sheerka__'"], "__ret", "sheerka", ), ( "recognize(__ret.body, hello 'my friend')", ["#__x_00__|__name__|'__ret'", "#__x_00__|body|#__x_01__", "#__x_01__|__is_concept__|True", "#__x_01__|key|'hello __var__0'", "#__x_01__|a|'my friend'"], "__ret", "my friend", ), ( "recognize(__ret.body, hello foo)", ["#__x_00__|__name__|'__ret'", "#__x_00__|body|#__x_01__", "#__x_01__|__is_concept__|True", "#__x_01__|key|'hello __var__0'", "#__x_01__|a|#__x_02__", "#__x_02__|__is_concept__|True", "#__x_02__|key|'foo'"], "__ret", "foo", ), ( "recognize(__ret.body, hello my best friend)", ["#__x_00__|__name__|'__ret'", "#__x_00__|body|#__x_01__", "#__x_01__|__is_concept__|True", "#__x_01__|key|'hello __var__0'", "#__x_01__|a|#__x_02__", "#__x_02__|__is_concept__|True", "#__x_02__|key|'my best friend'"], "__ret", "my best friend", ), ( "recognize(self, greetings)", ["#__x_00__|__name__|'self'", "#__x_00__|__is_concept__|True", "#__x_00__|name|'greetings'"], "self", None, ) ]) def test_rete(self, expression, expected_as_list_of_str, expected_variable, greeting_var): sheerka, context, greetings, foo, my_best_friend = self.init_test().with_concepts( Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"), Concept("foo"), Concept("my best friend"), create_new=True ).unpack() parser = ExpressionParser() expected = get_rete_conditions(*expected_as_list_of_str) 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 = ReteConditionExprVisitor(context) conditions = visitor.get_conditions(parsed) assert conditions == [expected] # check against a Rete network variable_map = { "foo": foo, "my best friend": my_best_friend, "sheerka": sheerka } variable = variable_map.get(greeting_var, greeting_var) to_recognize = sheerka.new_from_template(greetings, greetings.key, a=variable) objects = self.get_testing_objects(context, [(expected_variable, to_recognize)]) self.check_against_rete(expression, conditions, objects) # @pytest.mark.parametrize("expression, e_compiled, e_text, e_variables, greeting_var, e_objects", [ # ( # "recognize(__ret.body, greetings)", # "__x_00__ = __ret.body\nisinstance(__x_00__, Concept) and __x_00__.name == 'greetings'", # "__x_00__ = __ret.body\nisinstance(__x_00__, Concept) and __x_00__.name == 'greetings'", # {"__ret"}, # None, # set() # ), # ( # "recognize(__ret.body, c:|1001:)", # "__x_00__ = __ret.body\nisinstance(__x_00__, Concept) and __x_00__.id == '1001'", # "__x_00__ = __ret.body\nisinstance(__x_00__, Concept) and __x_00__.id == '1001'", # {"__ret"}, # None, # set() # ), # ( # "recognize(__ret.body, c:greetings:)", # "__x_00__ = __ret.body\nisinstance(__x_00__, Concept) and __x_00__.name == 'greetings'", # "__x_00__ = __ret.body\nisinstance(__x_00__, Concept) and __x_00__.name == 'greetings'", # {"__ret"}, # None, # set() # ), # ( # "recognize(__ret.body, greetings) and __ret.body.a == 'my friend'", # "__x_00__ = __ret.body\nisinstance(__x_00__, Concept) and __x_00__.name == 'greetings' and __x_00__.a == __o_00__", # "__x_00__ = __ret.body\nisinstance(__x_00__, Concept) and __x_00__.name == 'greetings' and __ret.body.a == 'my friend'", # {"__ret"}, # "my friend", # {("__o_00__", "my friend")} # ), # ( # "recognize(__ret.body, greetings) and __ret.body.a == sheerka", # """__x_00__ = __ret.body # isinstance(__x_00__, Concept) and __x_00__.name == 'greetings' and is_sheerka(__x_00__.a)""", # """__x_00__ = __ret.body # isinstance(__x_00__, Concept) and __x_00__.name == 'greetings' and __ret.body.a == sheerka""", # {"__ret"}, # "sheerka", # set() # ), # ( # "recognize(__ret.body, greetings) and __ret.body.a == foo", # """__x_00__ = __ret.body # __x_01__ = __x_00__.a # isinstance(__x_00__, Concept) and __x_00__.name == 'greetings' and isinstance(__x_01__, Concept) and __x_01__.key == 'foo'""", # """__x_00__ = __ret.body # __x_01__ = __x_00__.a # isinstance(__x_00__, Concept) and __x_00__.name == 'greetings' and __ret.body.a == foo""", # {"__ret"}, # "foo", # set() # ), # ( # "recognize(__ret.body, hello sheerka)", # """__x_00__ = __ret.body # isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and is_sheerka(__x_00__.a)""", # """__x_00__ = __ret.body # isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and __x_00__.a == sheerka""", # {"__ret"}, # "sheerka", # set() # ), # ( # "recognize(__ret.body, hello 'my friend')", # """__x_00__ = __ret.body # isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and __x_00__.a == __o_00__""", # """__x_00__ = __ret.body # isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and __x_00__.a == 'my friend'""", # {"__ret"}, # "my friend", # {('__o_00__', 'my friend')} # ), # ( # "recognize(__ret.body, hello foo)", # """__x_00__ = __ret.body # __x_01__ = __x_00__.a # isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and isinstance(__x_01__, Concept) and __x_01__.key == 'foo'""", # """__x_00__ = __ret.body # __x_01__ = __x_00__.a # isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and __x_00__.a == c:foo|1002:""", # {"__ret"}, # "foo", # {'__o_00__'} # ), # ( # "recognize(__ret.body, hello my best friend)", # """__x_00__ = __ret.body # __x_01__ = __x_00__.a # isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and isinstance(__x_01__, Concept) and __x_01__.key == 'my best friend'""", # """__x_00__ = __ret.body # __x_01__ = __x_00__.a # isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and __x_00__.a == c:my best friend|1003:""", # {"__ret"}, # "my best friend", # {'__o_00__'} # ), # ( # "recognize(self, greetings)", # "isinstance(self, Concept) and self.name == 'greetings'", # "isinstance(self, Concept) and self.name == 'greetings'", # {"self"}, # None, # set() # ) # ]) # def test_python(self, expression, e_compiled, e_text, e_variables, greeting_var, e_objects): # sheerka, context, greetings, foo, my_best_friend = self.init_test().with_concepts( # Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"), # Concept("foo"), # Concept("my best friend"), # create_new=True # ).unpack() # # conditions = self.validate_python_test(context, # expression, # e_compiled, # e_text, # e_variables, # set(), # e_objects) # # # check against SheerkaEvaluateRules # variable_map = { # "foo": foo, # "my best friend": my_best_friend, # "sheerka": Expando("sheerka", {}) # } # variable = variable_map.get(greeting_var, greeting_var) # to_recognize = sheerka.new_from_template(greetings, greetings.key, a=variable) # expected_variable = next(iter(e_variables)) # objects = self.get_testing_objects(context, [(expected_variable, to_recognize)]) # self.check_against_python(context, expression, conditions, objects) class TestSheerkaRuleManagerRulesCompilationEvalQuestionConcept(BaseTestSheerkaRuleManagerRulesCompilation): """ Testing question using concepts with no variable : girl is a human with variable : self is a human 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' with a function : func(self) is a human """ def test_rete(self): pass # I don't know yet what to do # @pytest.mark.parametrize("expression, expected_compiled, expected_variables", [ # ( # "girl is a human", # "evaluate_question(__o_00__)", # set(), # ), # ( # "self is a human", # "evaluate_question(__o_00__)", # {"self"}, # ), # ( # "the little boy is a human being", # "evaluate_question(__o_00__)", # set(), # ), # ( # "the little boy is a self", # "evaluate_question(__o_00__)", # {"self"}, # ), # ( # "self is a human being", # "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(), # ), # ( # "func(self) 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( # Concept("girl"), # Concept("human"), # Concept("the little boy"), # Concept("human being"), # Concept("x is a y", pre="is_question()").def_var("x").def_var("y"), # create_new=True # ).unpack() # # 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 = ExprToConditionsVisitor(context) # conditions = visitor.get_conditions(parsed) # # assert len(conditions) == 1 # assert isinstance(conditions[0], CompiledCondition) # # ast_ = ast.parse(expected_compiled, "", 'exec' if "\n" in expected_compiled else 'eval') # expected_python_node = PythonNode(expected_compiled, ast_, expression) # assert conditions[0].evaluator_type == PYTHON_EVALUATOR_NAME # assert sheerka.isinstance(conditions[0].return_value, BuiltinConcepts.RETURN_VALUE) # assert sheerka.objvalue(conditions[0].return_value) == expected_python_node # # assert "__o_00__" in conditions[0].objects # assert conditions[0].variables == expected_variables # # assert len(conditions[0].concepts_to_reset) == 1 # assert sheerka.isinstance(next(iter(conditions[0].concepts_to_reset)), isa) # # # check against SheerkaEvaluateRules # self.check_against_python(context, expression, conditions, # self.get_testing_objects(context, expected_variables)) class TestSheerkaRuleManagerRulesCompilationEvalQuestionConceptWithNot(BaseTestSheerkaRuleManagerRulesCompilation): """ Testing question using concepts mixed with others conditions using not : not girl is a human using not : not self is a human """ def test_rete(self): pass # @pytest.mark.parametrize( # "expression, expected_compiled, expected_text, expected_variables", [ # ( # "not girl is a human", # "not (evaluate_question(__o_00__))", # "not (girl is a human)", # set(), # ), # ( # "not self is a human", # "not (evaluate_question(__o_00__))", # "not (self is a human)", # {"self"}, # ), # ]) # def test_python(self, expression, expected_compiled, expected_text, expected_variables): # sheerka, context, girl, human, little_boy, human_being, isa = self.init_test().with_concepts( # Concept("girl"), # Concept("human"), # Concept("the little boy"), # Concept("human being"), # Concept("x is a y", pre="is_question()").def_var("x").def_var("y"), # create_new=True # ).unpack() # # conditions = self.validate_python_test(context, # expression, # expected_compiled, # expected_text, # expected_variables, # set(), # {"__o_00__"}) # # # check against SheerkaEvaluateRules # self.check_against_python(context, # expression, # conditions, # self.get_testing_objects(context, expected_variables), # False) class TestSheerkaRuleManagerRulesCompilationEvalConceptMixedWithOther(BaseTestSheerkaRuleManagerRulesCompilation): """ Testing question using concepts mixed with others conditions using and with python : girl is a human being and isinstance(a_string, str) using and with another concept : self is a human being and isinstance(self, girl) starting with python : isinstance(x, str) and girl is a human being starting with python : isinstance(self, girl) and self is a human being multiple python + same variable : self is a human being and isinstance(self, girl) and isinstance(self, girl) """ def test_rete(self): pass # I don't know yet what to do # @pytest.mark.parametrize( # "expression, expected_compiled, expected_variables, expected_objects", [ # ( # "girl is a human being and isinstance(a_string, str)", # "evaluate_question(__o_00__) and isinstance(a_string, str)", # {"a_string"}, # {"__o_00__"} # ), # ( # "self is a human being and isinstance(self, girl)", # "evaluate_question(__o_00__) and isinstance(self, __o_01__)", # {("self", "girl")}, # {"__o_00__", "__o_01__"} # ), # ( # "isinstance(a_string, str) and girl is a human being", # "isinstance(a_string, str) and evaluate_question(__o_00__)", # {"a_string"}, # {"__o_00__"} # ), # ( # "isinstance(self, girl) and self is a human being", # "isinstance(self, __o_00__) and evaluate_question(__o_01__)", # {("self", "girl")}, # {"__o_00__", "__o_01__"} # ), # ( # "self is a human being and isinstance(self, girl) and isinstance(self, girl)", # "evaluate_question(__o_00__) and isinstance(self, __o_01__) and isinstance(self, __o_02__)", # {("self", "girl")}, # {"__o_00__", "__o_01__", "__o_02__"} # ), # ]) # def test_python(self, expression, expected_compiled, expected_variables, expected_objects): # sheerka, context, girl, human_being, isa = self.init_test().with_concepts( # Concept("girl"), # Concept("human being"), # Concept("x is a y", pre="is_question()").def_var("x").def_var("y"), # create_new=True # ).unpack() # # conditions = self.validate_python_test(context, # expression, # expected_compiled, # expression, # expected_variables, # set(), # expected_objects) # # # check against SheerkaEvaluateRules # variables_mapping = { # "girl": girl, # "human being": human_being # } # testing_objects = self.get_testing_objects(context, expected_variables, variables_mapping) # self.check_against_python(context, # expression, # conditions, # testing_objects, # True) class TestSheerkaRuleManagerRulesCompilationEvalNonQuestionConcept(BaseTestSheerkaRuleManagerRulesCompilation): """ Testing complex concepts composition with BNF : twenty two additions : twenty two + one additions : twenty two + twenty one additions : twenty two plus one additions : twenty two plus twenty one with function: func_identity(twenty two) with function: func_identity(twenty two + one) 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): pass # I don't know yet what to do # @pytest.mark.parametrize("expression, e_compiled, e_text, e_objects, e_result", [ # ( # "twenty two", # "__o_00__", # "twenty two", # {"__o_00__"}, # 22 # ), # ( # "twenty two + one", # "__o_00__", # "twenty two + one", # {("__o_00__", 23)}, # 23 # ), # ( # "twenty two + twenty one", # "__o_00__", # "twenty two + twenty one", # {("__o_00__", 43)}, # 43 # ), # ( # "twenty two plus one", # "__o_00__", # "twenty two plus one", # {"__o_00__"}, # 23 # ), # ( # "twenty two plus twenty one", # "__o_00__", # "twenty two plus twenty one", # {"__o_00__"}, # 43 # ), # ( # "func_identity(twenty two)", # "func_identity(__o_00__)", # "func_identity(twenty two)", # {"__o_00__"}, # 22 # ), # ( # "func_identity(twenty two + one)", # "func_identity(__o_00__)", # "func_identity(twenty two + one)", # {("__o_00__", 23)}, # 23 # ), # ( # "func_identity(twenty two + twenty one)", # "func_identity(__o_00__)", # "func_identity(twenty two + twenty one)", # {("__o_00__", 43)}, # 43 # ), # ( # "func_identity(twenty two plus one)", # "func_identity(__o_00__)", # "func_identity(twenty two plus one)", # {"__o_00__"}, # 23 # ), # ( # "func_identity(twenty two plus twenty one)", # "func_identity(__o_00__)", # "func_identity(twenty two plus twenty one)", # {"__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( # Concept("one", body="1"), # Concept("two", body="2"), # Concept("twenties", definition="'twenty' (one|two)=n", body='20 + n').def_var("n"), # Concept("a plus b", body="a + b").def_var("a").def_var("b"), # create_new=True # ).unpack() # # conditions = self.validate_python_test(context, # expression, # e_compiled, # e_text, # set(), # set(), # e_objects) # # # check against SheerkaEvaluateRules # namespace = {"func_identity": self.func_identity} # res = self.evaluate_condition(context, expression, conditions[0], namespace) # assert res.status # assert sheerka.objvalue(res) == e_result 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 self is a bar """ def test_rete(self): sheerka, context, bar, isa_1, isa_2 = self.init_test().with_concepts( Concept("bar"), Concept("x is a y").def_var("x").def_var("y"), Concept("u is a v").def_var("u").def_var("v"), create_new=True ).unpack() with pytest.raises(FailedToCompileError): parser = ExpressionParser() error_sink = ErrorSink() parser_input = ParserInput("self is a bar") parser.reset_parser_input(parser_input, error_sink) parsed = parser.parse_input(context, parser_input, error_sink) visitor = ReteConditionExprVisitor(context) visitor.get_conditions(parsed) class TestSheerkaRuleManagerRulesCompilationNot(BaseTestSheerkaRuleManagerRulesCompilation): """ 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