import pytest from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts from core.concept import Concept, CB from core.sheerka.services.SheerkaExecute import ParserInput from evaluators.PythonEvaluator import PythonEvaluator, PythonEvalError from parsers.PythonParser import PythonNode, PythonParser from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka def get_concept_name(concept): return concept.name class TestPythonEvaluator(TestUsingMemoryBasedSheerka): @pytest.mark.parametrize("ret_val, expected", [ (ReturnValueConcept("some_name", True, ParserResultConcept(value=PythonNode("", None))), True), (ReturnValueConcept("some_name", True, ParserResultConcept(value="other thing")), False), (ReturnValueConcept("some_name", False, "not relevant"), False), (ReturnValueConcept("some_name", True, Concept()), False) ]) def test_i_can_match(self, ret_val, expected): context = self.get_context() assert PythonEvaluator().matches(context, ret_val) == expected @pytest.mark.parametrize("text, expected", [ ("1 + 1", 2), ("test()", "I have access to Sheerka !"), ("sheerka.test()", "I have access to Sheerka !"), ("a=10\na", 10), ]) def test_i_can_eval(self, text, expected): context = self.get_context() parsed = PythonParser().parse(context, ParserInput(text)) evaluated = PythonEvaluator().eval(context, parsed) assert evaluated.status assert evaluated.value == expected def test_i_can_eval_using_context(self): context = self.get_context() parsed = PythonParser().parse(context, ParserInput("test_using_context('value for param1', 10)")) evaluated = PythonEvaluator().eval(context, parsed) assert evaluated.status assert evaluated.value.startswith("I have access to Sheerka ! param1='value for param1', param2=10, event=") def test_i_can_eval_using_context_when_self_is_not_sheerka(self): sheerka, context = self.init_concepts() parsed = PythonParser().parse(context, ParserInput("create_new_concept(Concept('foo'))")) evaluated = PythonEvaluator().eval(context, parsed) assert evaluated.status assert sheerka.has_key("foo") @pytest.mark.parametrize("concept", [ Concept("foo"), Concept("foo", body="2"), Concept("foo").def_var("prop", "'a'"), Concept("foo", body="bar") ]) def test_simple_concepts_are_not_for_me(self, concept): context = self.get_context() context.sheerka.add_in_cache(Concept("foo")) parsed = PythonParser().parse(context, ParserInput("foo")) evaluated = PythonEvaluator().eval(context, parsed) assert not evaluated.status assert context.sheerka.isinstance(evaluated.value, BuiltinConcepts.NOT_FOR_ME) def test_i_can_eval_ast_expression_that_references_concepts(self): """ I can test modules with variables :return: """ context = self.get_context() context.sheerka.add_in_cache(Concept("foo", body="1")) parsed = PythonParser().parse(context, ParserInput("foo + 2")) evaluated = PythonEvaluator().eval(context, parsed) assert evaluated.status assert evaluated.value == 3 def test_i_can_eval_ast_module_that_references_concepts(self): """ I can test modules with variables :return: """ context = self.get_context() context.sheerka.add_in_cache(Concept("foo")) parsed = PythonParser().parse(context, ParserInput("def a(b):\n return b\na(c:foo:)")) evaluated = PythonEvaluator().eval(context, parsed) assert evaluated.status assert evaluated.value == Concept("foo").init_key() def test_i_can_eval_ast_module_that_references_concepts_with_body(self): """ I can test modules with variables :return: """ sheerka, context, foo = self.init_concepts(Concept("foo", body="2")) parsed = PythonParser().parse(context, ParserInput("def a(b):\n return b\na(foo)")) evaluated = PythonEvaluator().eval(context, parsed) assert evaluated.status assert evaluated.value == 2 def test_i_can_eval_concept_token(self): context = self.get_context() context.sheerka.add_in_cache(Concept("foo", body="2")) parsed = PythonParser().parse(context, ParserInput("get_concept_name(c:foo:)")) python_evaluator = PythonEvaluator() python_evaluator.globals["get_concept_name"] = get_concept_name evaluated = python_evaluator.eval(context, parsed) assert evaluated.status assert evaluated.value == "foo" def test_i_can_call_function_with_complex_concepts(self): sheerka, context, plus, mult = self.init_concepts( self.from_def_concept("plus", "a plus b", ["a", "b"]), self.from_def_concept("mult", "a mult b", ["a", "b"]), ) parsed = PythonParser().parse(context, ParserInput("set_is_greater_than(BuiltinConcepts.PRECEDENCE, mult, plus)")) python_evaluator = PythonEvaluator() evaluated = python_evaluator.eval(context, parsed) assert evaluated.status assert sheerka.get_concepts_weights(BuiltinConcepts.PRECEDENCE) == {'1001': 1, '1002': 2} def test_i_can_define_variables(self): sheerka, context = self.init_concepts() parsed = PythonParser().parse(context, ParserInput("a=10")) python_evaluator = PythonEvaluator() python_evaluator.eval(context, parsed) parsed = PythonParser().parse(context, ParserInput("a")) evaluated = python_evaluator.eval(context, parsed) assert evaluated.status assert evaluated.body == 10 def test_i_can_get_all_possibles_globals(self): sheerka, context, foo = self.init_concepts(Concept("foo", body="foo").auto_init()) python_evaluator = PythonEvaluator() my_globals = { "a": "a string", "b": self.test_i_can_get_all_possibles_globals, "foo": foo } all_globals = python_evaluator.get_all_possible_globals(context, my_globals) assert len(all_globals) == 2 assert all_globals[0]["foo"] == 'foo' assert all_globals[1]["foo"] == CB(foo, "foo") # body is evaluated def test_i_can_detect_one_error(self): sheerka, context, foo = self.init_concepts("foo") parsed = PythonParser().parse(context, ParserInput("foo + 1")) evaluated = PythonEvaluator().eval(context, parsed) assert not evaluated.status assert context.sheerka.isinstance(evaluated.value, BuiltinConcepts.ERROR) error = evaluated.body.body assert isinstance(error, PythonEvalError) assert isinstance(error.error, TypeError) assert error.error.args[0] == "unsupported operand type(s) for +: 'Concept' and 'int'" assert error.concepts == {'foo': foo} def test_i_can_detect_multiple_errors(self): sheerka, context, foo = self.init_concepts(Concept("foo", body="'string'")) parsed = PythonParser().parse(context, ParserInput("foo + 1")) evaluated = PythonEvaluator().eval(context, parsed) assert not evaluated.status assert context.sheerka.isinstance(evaluated.value, BuiltinConcepts.TOO_MANY_ERRORS) error0 = evaluated.body.body[0] assert isinstance(error0, PythonEvalError) assert isinstance(error0.error, TypeError) assert error0.error.args[0] == 'can only concatenate str (not "int") to str' assert error0.concepts == {'foo': 'string'} error1 = evaluated.body.body[1] assert isinstance(error1, PythonEvalError) assert isinstance(error1.error, TypeError) assert error1.error.args[0] == "unsupported operand type(s) for +: 'Concept' and 'int'" assert error1.concepts == {'foo': CB(foo, 'string')}