Files
Sheerka-Old/tests/evaluators/test_PythonEvaluator.py
T
2020-09-21 21:30:38 +02:00

318 lines
12 KiB
Python

import ast
import pytest
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
from core.concept import Concept, CB, NotInit
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Tokenizer
from evaluators.PythonEvaluator import PythonEvaluator, PythonEvalError
from parsers.BaseNodeParser import SourceCodeNode, SourceCodeWithConceptNode
from parsers.PythonParser import PythonNode, PythonParser
from parsers.PythonWithConceptsParser import PythonWithConceptsParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
def get_concept_name(concept):
return concept.name
def get_source_code_node(source_code, concepts=None):
if concepts:
for concept_name, concept in sorted(concepts.items(), key=lambda kv: len(kv[0]), reverse=True):
identifier = "__C__" + PythonWithConceptsParser.sanitize(concept.name)
if concept.id:
identifier += "__" + concept.id
identifier += "__C__"
source_code = source_code.replace(concept_name, identifier)
concepts[identifier] = concept
if source_code:
python_node = PythonNode(source_code, ast.parse(source_code, f"<source>", 'eval'))
else:
python_node = PythonNode("", None)
if concepts is None:
tokens = list(Tokenizer(source_code, yield_eof=False))
return SourceCodeNode(0, len(tokens), tokens, python_node=python_node)
else:
python_node.concepts = concepts
scwcn = SourceCodeWithConceptNode(None, None)
scwcn.python_node = python_node
return scwcn
def get_ret_val_from_source_code(context, source_code, concepts):
parsed = get_source_code_node(source_code, concepts)
return context.sheerka.ret("parsers.??", True, ParserResultConcept(value=parsed))
class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
@pytest.mark.parametrize("ret_val, expected", [
(ReturnValueConcept("some_name", True, ParserResultConcept(value=PythonNode("", None))), True),
(ReturnValueConcept("some_name", True, ParserResultConcept(value=get_source_code_node(""))), True),
(ReturnValueConcept("some_name", True, ParserResultConcept(value=get_source_code_node("", {}))), 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
@pytest.mark.parametrize("source_code_node, expected", [
(get_source_code_node("1 + 1"), 2),
(get_source_code_node("one + one", {"one": Concept("one", body="1")}), 2)
])
def test_i_can_eval_source_code_node(self, source_code_node, expected):
context = self.get_context()
return_value = context.sheerka.ret("parsers.??", True, ParserResultConcept(value=source_code_node))
evaluated = PythonEvaluator().eval(context, return_value)
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 == CB("foo", 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_eval_when_expect_success(self):
context = self.get_context()
context.sheerka.add_in_cache(Concept("foo", body="2"))
parsed = PythonParser().parse(context, ParserInput("foo==2"))
python_evaluator = PythonEvaluator()
evaluated = python_evaluator.eval(context, parsed)
assert evaluated.status
assert not evaluated.value # the first test is between Concept(foo) and int(2)
context.protected_hints.add(BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED)
evaluated = python_evaluator.eval(context, parsed)
assert evaluated.status
assert evaluated.value # we test until we compare foo.body and 2
parsed = PythonParser().parse(context, ParserInput("foo==3"))
evaluated = python_evaluator.eval(context, parsed)
assert evaluated.status
assert not evaluated.value # neither foo or foo.body ==3
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"] == CB(foo, "foo")
assert all_globals[1]["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] == "unsupported operand type(s) for +: 'Concept' and 'int'"
assert error0.concepts == {'foo': CB(foo, 'string')}
error1 = evaluated.body.body[1]
assert isinstance(error1, PythonEvalError)
assert isinstance(error1.error, TypeError)
assert error1.error.args[0] == 'can only concatenate str (not "int") to str'
assert error1.concepts == {'foo': 'string'}
def test_i_do_not_include_not_initialized_variables_when_evaluating(self):
sheerka, context, foo = self.init_concepts(
Concept("foo a", pre="a == 'True'").def_var("a", "'True'").def_var("b"))
foo.set_value("b", "'Initialized!'")
context.obj = foo
assert foo.get_value("a") == NotInit
assert foo.get_value("b") == "'Initialized!'"
my_globals = {}
PythonEvaluator().update_globals_with_context(my_globals, context)
assert my_globals == {"self": foo, "b": "'Initialized!'"}
def test_i_can_use_sheerka_locals(self):
sheerka, context = self.init_concepts()
def func(i):
return i + 1
sheerka.locals["func"] = func
parsed = PythonParser().parse(context, ParserInput("func(10)"))
python_evaluator = PythonEvaluator()
evaluated = python_evaluator.eval(context, parsed)
assert evaluated.status
assert evaluated.value == 11
def test_i_can_eval_concept_with_ret(self):
sheerka, context, one, the = self.init_concepts("one", Concept("the a", ret="a").def_var("a"))
ret_val = get_ret_val_from_source_code(context, "test_using_context(one, the one)", {
"the one": self.get_concept_instance(sheerka, the, a="one"),
"one": self.get_concept_instance(sheerka, "one")
})
evaluated = PythonEvaluator().eval(context, ret_val)
assert evaluated.status
assert evaluated.value.startswith("I have access to Sheerka ! param1=(1001)one, param2=(1001)one, event=")