Fixed #18 : Parsing and evaluating Python

This commit is contained in:
2023-05-14 12:12:29 +02:00
parent e41094f908
commit 09a0246420
46 changed files with 2084 additions and 165 deletions
+58
View File
@@ -0,0 +1,58 @@
import pytest
from base import BaseTest
from conftest import NewOntology
from core.BuiltinConcepts import BuiltinConcepts
from core.error import ErrorContext
from evaluators.PythonEvaluator import PythonEvaluator
from evaluators.PythonParser import PythonParser
from helpers import _rv, _rvf, define_new_concept, get_concepts, get_metadata
from parsers.ParserInput import ParserInput
def get_parser_input_from(sheerka, context, command):
pi = ParserInput(command)
pi.init()
parser_start = _rv(sheerka.newn(BuiltinConcepts.PARSER_INPUT, pi=pi))
ret = PythonParser().eval(context, None, parser_start)
return ret.new[0]
class TestPythonEvaluator(BaseTest):
@pytest.fixture()
def evaluator(self, sheerka):
return sheerka.evaluators[PythonEvaluator.NAME]
def test_i_can_match(self, sheerka, context, evaluator):
ret_val = _rv(sheerka.newn(BuiltinConcepts.PYTHON_CODE))
assert evaluator.matches(context, ret_val).status is True
ret_val = _rv(sheerka.newn(BuiltinConcepts.UNKNOWN_CONCEPT)) # it responds to USER_INPUT only
assert evaluator.matches(context, ret_val).status is False
ret_val = _rvf(sheerka.newn(BuiltinConcepts.PYTHON_CODE)) # status should be true
assert evaluator.matches(context, ret_val).status is False
@pytest.mark.parametrize("text, expected", [
("1 + 1", 2),
("echo('I have access to Sheerka !')", "I have access to Sheerka !"),
("sheerka.echo('I have access to Sheerka !')", "I have access to Sheerka !"),
("a=10\na", 10),
])
def test_i_can_evaluate_simple_expression(self, sheerka, context, evaluator, text, expected):
start = get_parser_input_from(sheerka, context, text)
ret = evaluator.eval(context, None, start)
assert ret.eaten == [start]
assert len(ret.new) == 1
assert ret.new[0].status is True
assert ret.new[0].value == expected
assert ret.new[0].parents == [start]
def test_i_can_detect_evaluation_error(self, sheerka, context, evaluator):
start = get_parser_input_from(sheerka, context, "a")
ret = evaluator.eval(context, None, start)
assert ret.eaten == []
assert len(ret.new) == 1
assert ret.new[0].status is False
assert isinstance(ret.new[0].value, ErrorContext)
assert ret.new[0].parents == [start]
+75
View File
@@ -0,0 +1,75 @@
import pytest
from base import BaseTest
from core.BuiltinConcepts import BuiltinConcepts
from core.error import ErrorContext
from evaluators.PythonParser import PythonParser
from helpers import _rv, _rvf
from parsers.ParserInput import ParserInput
class TestPythonParser(BaseTest):
@pytest.fixture()
def evaluator(self, sheerka):
return sheerka.evaluators[PythonParser.NAME]
def test_i_can_match(self, sheerka, context, evaluator):
ret_val = _rv(sheerka.newn(BuiltinConcepts.PARSER_INPUT, pi=ParserInput("a command")))
assert evaluator.matches(context, ret_val).status is True
ret_val = _rv(sheerka.newn(BuiltinConcepts.UNKNOWN_CONCEPT)) # it responds to USER_INPUT only
assert evaluator.matches(context, ret_val).status is False
ret_val = _rvf(sheerka.newn(BuiltinConcepts.PARSER_INPUT, pi=ParserInput("a command"))) # status should be true
assert evaluator.matches(context, ret_val).status is False
@pytest.mark.parametrize("text", [
"1 + 1",
"a = 20"
])
def test_i_can_parse_python(self, sheerka, context, evaluator, text):
pi = ParserInput(text)
pi.init()
start = _rv(sheerka.newn(BuiltinConcepts.PARSER_INPUT, pi=pi))
res = evaluator.eval(context, None, start)
assert res.eaten == [start]
assert len(res.new) == 1
ret_val = res.new[0]
assert ret_val.status is True
assert sheerka.isinstance(ret_val.value, BuiltinConcepts.PYTHON_CODE)
assert ret_val.parents == [start]
def test_invalid_python_are_rejected(self, sheerka, context, evaluator):
text = "1 + "
pi = ParserInput(text)
pi.init()
start = _rv(sheerka.newn(BuiltinConcepts.PARSER_INPUT, pi=pi))
res = evaluator.eval(context, None, start)
assert res.eaten == []
assert len(res.new) == 1
ret_val = res.new[0]
assert ret_val.status is False
assert isinstance(ret_val.value, ErrorContext)
assert ret_val.parents == [start]
def test_i_can_detect_concepts(self, sheerka, context, evaluator):
pi = ParserInput("c:one: + c:two:")
pi.init()
start = _rv(sheerka.newn(BuiltinConcepts.PARSER_INPUT, pi=pi))
res = evaluator.eval(context, None, start)
assert res.eaten == [start]
assert len(res.new) == 1
ret_val = res.new[0]
assert ret_val.status is True
assert sheerka.isinstance(ret_val.value, BuiltinConcepts.PYTHON_CODE)
assert ret_val.parents == [start]
assert len(ret_val.value.pf.namespace) == 2
assert ret_val.value.pf.namespace["__C__KEY_one__ID_00None00__C__"].value == ("one", None)
assert ret_val.value.pf.namespace["__C__KEY_two__ID_00None00__C__"].value == ("two", None)
+22
View File
@@ -0,0 +1,22 @@
import pytest
from core.error import ErrorContext, ErrorObj, MethodAccessError
class DummyErrorObj(ErrorObj):
def __init__(self, msg):
self.msg = msg
def get_error_msg(self) -> str:
return self.msg
@pytest.mark.parametrize("error_hint, expected", [
("some value", "some value"),
(["value a", "value b"], "value a, value b"),
(MethodAccessError("a"), "Cannot access method 'a'"),
(DummyErrorObj("error msg"), "error msg")
])
def test_i_can_get_error_msg(context, error_hint, expected):
error = ErrorContext("Test", context, error_hint)
assert error.get_error_msg() == expected