import pytest from core.builtin_concepts_ids import BuiltinConcepts from core.builtin_helpers import ensure_asts from core.concept import Concept from core.global_symbols import SyaAssociativity from core.sheerka.ExecutionContext import ExecutionContext from core.sheerka.services.SheerkaAdmin import SheerkaAdmin from sheerkapython.python_wrapper import Expando, MethodAccessError, Pipe, create_namespace, get_sheerka_method, \ get_variables_from_concept_asts, inject_context from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka class TestPythonWrapper(TestUsingMemoryBasedSheerka): @pytest.mark.parametrize("name, expected", [ ("Concept", Concept), ("BuiltinConcepts", BuiltinConcepts), ("Expando", Expando), ("ExecutionContext", ExecutionContext), ("SyaAssociativity", SyaAssociativity), ]) def test_i_can_create_namespace_from_internal_references(self, name, expected): context = self.get_context() assert create_namespace(context, "TestPythonWrapper", [name], None, {}, False) == {name: expected} def test_i_can_create_namespace_with_context_method(self): context = self.get_context() res = create_namespace(context, "TestPythonWrapper", ["in_context", "isinstance"], None, {}, False) assert res["in_context"] == context.in_context assert res["isinstance"] == context.sheerka.services[SheerkaAdmin.NAME].extended_isinstance def test_i_can_create_namespace_when_sheerka_expando_object(self): sheerka, context = self.init_test().unpack() res = create_namespace(context, "TestPythonWrapper", ["sheerka"], set(), {}, False) assert res["sheerka"] == Expando("sheerka", {}) res = create_namespace(context, "TestPythonWrapper", ["sheerka"], {"test", "set_debug"}, {}, False) assert isinstance(res["sheerka"], Expando) assert res["sheerka"].get_name() == "sheerka" assert set(vars(res["sheerka"])) == {"_Expando__name", "test", "set_debug"} def test_i_can_create_namespace_when_short_term_memory(self): context = self.get_context() context.add_to_short_term_memory("my_key", "my_value") assert create_namespace(context, "TestPythonWrapper", ["my_key"], None, {}, False) == {"my_key": "my_value"} def test_i_can_create_namespace_when_value_from_memory(self): sheerka, context = self.init_test().unpack() sheerka.add_to_memory(context, "my_key", "my_value") assert create_namespace(context, "TestPythonWrapper", ["my_key"], None, {}, False) == {"my_key": "my_value"} def test_i_can_create_namespace_when_sheerka_methods(self): sheerka, context = self.init_test().unpack() res = create_namespace(context, "TestPythonWrapper", ["test", "set_debug"], None, {}, False) assert res["test"] == sheerka.test assert isinstance(res["set_debug"], type(inject_context)) assert res["set_debug"].__name__ == "set_debug" def test_i_can_create_namespace_when_value_from_context_obj(self): sheerka, context = self.init_test().unpack() obj = Concept("foo").def_var("a", "value1").auto_init() context.obj = obj res = create_namespace(context, "TestPythonWrapper", ["self", "a"], None, {}, False) assert res == {"self": obj, "a": "value1"} def test_i_can_create_namespace_when_value_from_local_objects(self): sheerka, context = self.init_test().unpack() obj = Concept("foo") objects = {"self": obj, "a": Concept("bar")} res = create_namespace(context, "TestPythonWrapper", ["self", "a"], None, objects, False) assert res == {"self": obj, "a": objects["a"]} def test_i_can_create_namespace_when_name_refers_to_a_concept(self): sheerka, context, foo = self.init_concepts("foo") assert create_namespace(context, "TestPythonWrapper", ["foo"], None, {}, False) == {"foo": foo} def test_internal_references_and_context_method_take_over_short_term_memory(self): context = self.get_context() context.add_to_short_term_memory("Concept", "short_term_value") context.add_to_short_term_memory("isinstance", "short_term_value") context.add_to_short_term_memory("in_context", "short_term_value") res = create_namespace(context, "TestPythonWrapper", ["Concept", "isinstance", "in_context"], None, {}, False) assert res == { "Concept": Concept, "isinstance": context.sheerka.services[SheerkaAdmin.NAME].extended_isinstance, "in_context": context.in_context, } def test_short_term_memory_takes_precedence_over_long_term_memory(self): sheerka, context = self.init_test().unpack() context.add_to_short_term_memory("my_key", "short_term") sheerka.add_to_memory(context, "my_key", "long_term") assert create_namespace(context, "TestPythonWrapper", ["my_key"], None, {}, False) == {"my_key": "short_term"} def test_long_term_memory_takes_precedence_over_sheerka_methods(self): # I am not really sure why sheerka, context = self.init_test().unpack() sheerka.add_to_memory(context, "test", "from memory") assert create_namespace(context, "TestPythonWrapper", ["test"], None, {}, False) == {"test": "from memory"} def test_sheerka_method_takes_precedence_over_context_obj(self): sheerka, context = self.init_test().unpack() obj = Concept("foo").def_var("test", "value1").auto_init() context.obj = obj assert create_namespace(context, "TestPythonWrapper", ["test", ], None, {}, False) == {"test": sheerka.test} def test_context_obj_takes_precedence_over_local_objects(self): sheerka, context = self.init_test().unpack() obj = Concept("foo").def_var("a", "value1").auto_init() context.obj = obj objects = {"self": Concept("bar"), "a": Concept("bar")} res = create_namespace(context, "TestPythonWrapper", ["self", "a"], None, objects, False) assert res == {"self": obj, "a": "value1"} def test_local_objects_take_precedence_over_object_instantiation(self): sheerka, context, foo = self.init_concepts("from instantiation") objects = {"foo": Concept("from local")} res = create_namespace(context, "TestPythonWrapper", ["foo"], None, objects, False) assert res == {"foo": objects["foo"]} def test_external_value_takes_precedence_over_concept_parameter(self): """ To manage : Concept("x is a y").def_var("x").def_var("y"), "y is a number" -> "call_concept(__o_00__, x=y)" If 'y' is not given, it will use the concept parameter 'y' But if y is given (as a short term memory) it must be prioritized :return: """ sheerka, context = self.init_test().unpack() obj = Concept("x is a y").def_var("x").def_var("y", "concept value").auto_init() context.obj = obj objects = {"y": "object value"} res = create_namespace(context, "TestPythonWrapper", ["y"], None, objects, False) assert res == {'y': 'concept value'} context.add_to_short_term_memory("y", "stm value") res = create_namespace(context, "TestPythonWrapper", ["y"], None, objects, False) assert res == {'y': 'stm value'} def test_i_can_get_sheerka_method(self): context = self.get_context() # sheerka direct method assert get_sheerka_method(context, "TestPythonWrapper", "test", True) == context.sheerka.test # sheerka indirect method assert get_sheerka_method(context, "TestPythonWrapper", "get_value", True) == context.sheerka.get_value # method that need context are wrapped res = get_sheerka_method(context, "TestPythonWrapper", "test_using_context", True) assert res != context.sheerka.test_using_context assert type(res) == type(inject_context) assert res.__name__ == "test_using_context" # return None when the method is not found assert get_sheerka_method(context, "TestPythonWrapper", "xxx", True) is None def test_i_cannot_get_method_that_modifies_the_state_when_expression_only(self): sheerka, context = self.init_test().unpack() assert get_sheerka_method(context, "TestPythonWrapper", "set_debug", expression_only=False) is not None with pytest.raises(MethodAccessError) as ex: get_sheerka_method(context, "TestPythonWrapper", "set_debug", expression_only=True) assert ex.value.method_name == "set_debug" def test_i_can_get_method_when_pipe_function(self): context = self.get_context() res = get_sheerka_method(context, "TestPythonWrapper", "where", True) assert isinstance(res, Pipe) @pytest.mark.parametrize("concept, known_variables, expected", [ (Concept("foo").def_var("x", "True"), set(), {}), (Concept("foo").def_var("x"), set(), {}), (Concept("foo").def_var("x", "self"), set(), {"x": {"self"}}), (Concept("foo").def_var("x", "self + a"), set(), {"x": {"self", "a"}}), (Concept("foo").def_var("x", "self + a").def_var("y", "b"), set(), {'x': {'a', 'self'}, 'y': {'b'}}), (Concept("foo", body="x").def_var("x"), set(), {}), # 'x' is a concept var, so it can be resolved (Concept("foo", body="x").def_var("x", "x"), set(), {'x': {'x'}}), (Concept("foo").def_var("x", "func(y)"), set(), {"x": {"y"}}), (Concept("foo").def_var("x", "x"), set(), {'x': {'x'}}), (Concept("foo").def_var("x", "y"), set(), {'x': {'y'}}), (Concept("foo").def_var("x", "x"), {"x"}, {"x": {"x"}}), (Concept("foo").def_var("x"), {"x"}, {}), # var x has no value, there no way to link the two 'x's (Concept("foo", body="x").def_var("x"), {"x"}, {"#body#": {"x"}}), (Concept("foo").def_var("x", "bar"), set(), {}), (Concept("foo").def_var("x", "bar"), {"bar"}, {"x": {"bar"}}), ]) def test_get_variables_from_concept_asts(self, concept, known_variables, expected): sheerka, context, foo, bar = self.init_concepts(concept, "bar") ensure_asts(context, concept) variables = get_variables_from_concept_asts(context, concept, known_variables, parameters_only=False) assert variables == expected