Fixed #18 : Parsing and evaluating Python
This commit is contained in:
@@ -4,28 +4,27 @@ import pytest
|
||||
|
||||
from base import BaseTest
|
||||
from core.BuiltinConcepts import BuiltinConcepts
|
||||
from core.ExecutionContext import ExecutionContext, ExecutionContextActions
|
||||
from core.ExecutionContext import ExecutionContext, ContextActions
|
||||
from core.ReturnValue import ReturnValue
|
||||
from core.services.SheerkaEngine import SheerkaEngine
|
||||
from evaluators.CreateParserInput import CreateParserInput
|
||||
from evaluators.base_evaluator import AllReturnValuesEvaluator, BaseEvaluator, EvaluatorEvalResult, \
|
||||
EvaluatorMatchResult, \
|
||||
OneReturnValueEvaluator
|
||||
EvaluatorMatchResult, OneReturnValueEvaluator
|
||||
from helpers import _rvc
|
||||
from services.SheerkaEngine import SheerkaEngine
|
||||
|
||||
ALL_STEPS = [
|
||||
ExecutionContextActions.BEFORE_PARSING,
|
||||
ExecutionContextActions.PARSING,
|
||||
ExecutionContextActions.AFTER_PARSING,
|
||||
ExecutionContextActions.BEFORE_EVALUATION,
|
||||
ExecutionContextActions.EVALUATION,
|
||||
ExecutionContextActions.AFTER_EVALUATION
|
||||
ContextActions.BEFORE_PARSING,
|
||||
ContextActions.PARSING,
|
||||
ContextActions.AFTER_PARSING,
|
||||
ContextActions.BEFORE_EVALUATION,
|
||||
ContextActions.EVALUATION,
|
||||
ContextActions.AFTER_EVALUATION
|
||||
]
|
||||
|
||||
|
||||
class OneReturnValueEvaluatorForTesting(OneReturnValueEvaluator):
|
||||
def __init__(self, name,
|
||||
step: ExecutionContextActions,
|
||||
step: ContextActions,
|
||||
priority: int,
|
||||
enabled=True,
|
||||
match: bool | Callable = True,
|
||||
@@ -56,12 +55,12 @@ class OneReturnValueEvaluatorForTesting(OneReturnValueEvaluator):
|
||||
if ret_val != return_value:
|
||||
ret_val.parents = [return_value]
|
||||
|
||||
return EvaluatorEvalResult(self.eval_result, self.eval_eaten or [return_value])
|
||||
return EvaluatorEvalResult(self.eval_result, [return_value] if self.eval_eaten is None else self.eval_eaten)
|
||||
|
||||
|
||||
class AllReturnValuesEvaluatorForTesting(AllReturnValuesEvaluator):
|
||||
def __init__(self, name,
|
||||
step: ExecutionContextActions,
|
||||
step: ContextActions,
|
||||
priority: int,
|
||||
enabled=True,
|
||||
match: bool | Callable = True,
|
||||
@@ -91,31 +90,31 @@ class AllReturnValuesEvaluatorForTesting(AllReturnValuesEvaluator):
|
||||
for ret_val in self.eval_result:
|
||||
ret_val.parents = return_values
|
||||
|
||||
return EvaluatorEvalResult(self.eval_result, self.eval_eaten or return_values)
|
||||
return EvaluatorEvalResult(self.eval_result, return_values if self.eval_eaten is None else self.eval_eaten)
|
||||
|
||||
|
||||
class TestSheerkaEngine(BaseTest):
|
||||
@pytest.fixture()
|
||||
def service(self, sheerka):
|
||||
return SheerkaEngine(sheerka)
|
||||
return SheerkaEngine(sheerka) # I want a new instance to keep Sheerka clean (when a change execution_plan)
|
||||
|
||||
def test_i_can_compute_execution_plan(self, service):
|
||||
assert service.compute_execution_plan([]) == {}
|
||||
|
||||
e1 = BaseEvaluator("eval1", ExecutionContextActions.BEFORE_EVALUATION, 5)
|
||||
e2 = BaseEvaluator("eval2", ExecutionContextActions.BEFORE_EVALUATION, 5)
|
||||
e3 = BaseEvaluator("eval3", ExecutionContextActions.BEFORE_EVALUATION, 10)
|
||||
e4 = BaseEvaluator("eval4", ExecutionContextActions.EVALUATION, 10)
|
||||
e5 = BaseEvaluator("eval5", ExecutionContextActions.AFTER_EVALUATION, 10, enabled=False)
|
||||
e1 = BaseEvaluator("eval1", ContextActions.BEFORE_EVALUATION, 5)
|
||||
e2 = BaseEvaluator("eval2", ContextActions.BEFORE_EVALUATION, 5)
|
||||
e3 = BaseEvaluator("eval3", ContextActions.BEFORE_EVALUATION, 10)
|
||||
e4 = BaseEvaluator("eval4", ContextActions.EVALUATION, 10)
|
||||
e5 = BaseEvaluator("eval5", ContextActions.AFTER_EVALUATION, 10, enabled=False)
|
||||
res = service.compute_execution_plan([e1, e2, e3, e4, e5])
|
||||
assert res == {ExecutionContextActions.BEFORE_EVALUATION: {5: [e1, e2], 10: [e3]},
|
||||
ExecutionContextActions.EVALUATION: {10: [e4]}}
|
||||
assert res == {ContextActions.BEFORE_EVALUATION: {5: [e1, e2], 10: [e3]},
|
||||
ContextActions.EVALUATION: {10: [e4]}}
|
||||
|
||||
def test_i_can_call_execute(self, sheerka, context, service):
|
||||
service.execution_plan = {ExecutionContextActions.BEFORE_EVALUATION: {50: [CreateParserInput()]}}
|
||||
service.execution_plan = {ContextActions.BEFORE_EVALUATION: {50: [CreateParserInput()]}}
|
||||
start = [ReturnValue("TestSheerkaEngine", True, sheerka.newn(BuiltinConcepts.USER_INPUT, command="1 + 1"))]
|
||||
|
||||
ret = service.execute(context, start, [ExecutionContextActions.BEFORE_EVALUATION])
|
||||
ret = service.execute(context, start, [ContextActions.BEFORE_EVALUATION])
|
||||
assert len(ret) == 1
|
||||
ret = ret[0]
|
||||
assert isinstance(ret, ReturnValue)
|
||||
@@ -127,7 +126,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
service.execution_plan = {}
|
||||
start = [_rvc("foo")]
|
||||
|
||||
ret = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
ret = service.execute(context, start, [ContextActions.EVALUATION])
|
||||
|
||||
assert ret == start
|
||||
|
||||
@@ -135,12 +134,12 @@ class TestSheerkaEngine(BaseTest):
|
||||
# properly init the service
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1", ExecutionContextActions.AFTER_PARSING, 21, match=False),
|
||||
_("eval2", ExecutionContextActions.BEFORE_EVALUATION, 5, match=False),
|
||||
_("eval3", ExecutionContextActions.AFTER_EVALUATION, 12, match=False),
|
||||
_("eval4", ExecutionContextActions.EVALUATION, 99, match=False),
|
||||
_("eval5", ExecutionContextActions.BEFORE_PARSING, 5, match=False),
|
||||
_("eval6", ExecutionContextActions.PARSING, 25, match=False),
|
||||
_("eval1", ContextActions.AFTER_PARSING, 21, match=False),
|
||||
_("eval2", ContextActions.BEFORE_EVALUATION, 5, match=False),
|
||||
_("eval3", ContextActions.AFTER_EVALUATION, 12, match=False),
|
||||
_("eval4", ContextActions.EVALUATION, 99, match=False),
|
||||
_("eval5", ContextActions.BEFORE_PARSING, 5, match=False),
|
||||
_("eval6", ContextActions.PARSING, 25, match=False),
|
||||
]
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
@@ -155,15 +154,15 @@ class TestSheerkaEngine(BaseTest):
|
||||
# properly init the service
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1", ExecutionContextActions.EVALUATION, 20, match=False),
|
||||
_("eval2", ExecutionContextActions.EVALUATION, 5, match=False),
|
||||
_("eval3", ExecutionContextActions.EVALUATION, 20, match=False),
|
||||
_("eval4", ExecutionContextActions.EVALUATION, 99, match=False),
|
||||
_("eval1", ContextActions.EVALUATION, 20, match=False),
|
||||
_("eval2", ContextActions.EVALUATION, 5, match=False),
|
||||
_("eval3", ContextActions.EVALUATION, 20, match=False),
|
||||
_("eval4", ContextActions.EVALUATION, 99, match=False),
|
||||
]
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [_rvc("foo")]
|
||||
service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
service.execute(context, start, [ContextActions.EVALUATION])
|
||||
|
||||
# to check what happened, look at the execution context children
|
||||
evaluators_executed = [ec.action_context["evaluator"] for ec in context.get_children() if
|
||||
@@ -176,7 +175,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
ContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[rv_bar])
|
||||
@@ -184,8 +183,8 @@ class TestSheerkaEngine(BaseTest):
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [rv_foo]
|
||||
service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
children = [ec for ec in context.get_children() if ec.action == ExecutionContextActions.EVALUATING_ITERATION]
|
||||
service.execute(context, start, [ContextActions.EVALUATION])
|
||||
children = [ec for ec in context.get_children() if ec.action == ContextActions.EVALUATING_ITERATION]
|
||||
assert len(children) == 2
|
||||
|
||||
def test_eval_is_not_called_if_match_fails_for_one_return(self, context, service):
|
||||
@@ -193,7 +192,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
ContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[_rvc("bar")])
|
||||
@@ -201,7 +200,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [_rvc("baz")]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
res = service.execute(context, start, [ContextActions.EVALUATION])
|
||||
assert res == start
|
||||
|
||||
# check what happen in details
|
||||
@@ -214,7 +213,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
ContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[_rvc("bar")])
|
||||
@@ -222,7 +221,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [_rvc("foo")]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
res = service.execute(context, start, [ContextActions.EVALUATION])
|
||||
assert res == [_rvc("bar")]
|
||||
assert res[0].parents == start
|
||||
|
||||
@@ -238,7 +237,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
ContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[rv_qux])
|
||||
@@ -246,7 +245,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [rv_bar, rv_foo, rv_baz]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
res = service.execute(context, start, [ContextActions.EVALUATION])
|
||||
assert res == [rv_bar, rv_qux, rv_baz] # We must keep the order ! rv_qux replaces rv_foo
|
||||
assert res[0].parents is None
|
||||
assert res[1].parents == [rv_foo]
|
||||
@@ -267,12 +266,12 @@ class TestSheerkaEngine(BaseTest):
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
ContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[rv_bar]),
|
||||
_("eval2",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
ContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[rv_baz])
|
||||
@@ -280,7 +279,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [rv_qux, rv_foo, rv_qux]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
res = service.execute(context, start, [ContextActions.EVALUATION])
|
||||
assert res == [rv_qux, rv_bar, rv_baz, rv_qux] # they both eat it !
|
||||
assert res[1].parents == [rv_foo]
|
||||
assert res[2].parents == [rv_foo]
|
||||
@@ -293,12 +292,12 @@ class TestSheerkaEngine(BaseTest):
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
ContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[rv_bar]),
|
||||
_("eval2",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
ContextActions.EVALUATION,
|
||||
30,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[rv_baz])
|
||||
@@ -306,7 +305,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [rv_foo]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
res = service.execute(context, start, [ContextActions.EVALUATION])
|
||||
assert res == [rv_baz]
|
||||
assert res[0].parents == start
|
||||
|
||||
@@ -315,7 +314,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
_ = AllReturnValuesEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
ContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r[0].value, "foo"),
|
||||
eval_result=[_rvc("bar")])
|
||||
@@ -323,11 +322,11 @@ class TestSheerkaEngine(BaseTest):
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [_rvc("baz")]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
res = service.execute(context, start, [ContextActions.EVALUATION])
|
||||
assert res == start
|
||||
|
||||
start = [_rvc("foo")]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
res = service.execute(context, start, [ContextActions.EVALUATION])
|
||||
assert res == [_rvc("bar")]
|
||||
assert res[0].parents == start
|
||||
|
||||
@@ -338,7 +337,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
_ = AllReturnValuesEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
ContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda lst: context.sheerka.isinstance(lst[0].value, "foo"),
|
||||
eval_result=[rv_bar])
|
||||
@@ -346,7 +345,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [rv_baz, rv_foo] # foo is not the first in the list
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
res = service.execute(context, start, [ContextActions.EVALUATION])
|
||||
assert res == start
|
||||
|
||||
# check what happen in details
|
||||
@@ -360,7 +359,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
_ = AllReturnValuesEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
ContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda lst: context.sheerka.isinstance(lst[0].value, "foo"),
|
||||
eval_result=[rv_bar])
|
||||
@@ -368,7 +367,7 @@ class TestSheerkaEngine(BaseTest):
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [rv_foo, rv_baz]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
res = service.execute(context, start, [ContextActions.EVALUATION])
|
||||
assert res == [rv_bar]
|
||||
assert res[0].parents == start
|
||||
|
||||
@@ -377,3 +376,28 @@ class TestSheerkaEngine(BaseTest):
|
||||
exec_context = next(filter(lambda ec: "evaluator" in ec.action_context, context.get_children()))
|
||||
evaluation_trace = exec_context.values["evaluation"]
|
||||
assert evaluation_trace == {"match": True, "new": res, "eaten": start}
|
||||
|
||||
def test_ret_val_not_removed_does_not_cause_infinite_recursion(self, context, service):
|
||||
rv_foo, rv_bar = _rvc("foo"), _rvc("bar") # rv => ReturnValue
|
||||
|
||||
# properly init the service
|
||||
# both evaluator want to eat 'foo'
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval",
|
||||
ContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[rv_bar], eval_eaten=[]),
|
||||
]
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
# in the test, 'foo' produces 'bar', but is not removed
|
||||
# during the second iteration, 'foo' still exists, so it will produce 'bar' again
|
||||
# and so on...
|
||||
# This test validate that the infinite loop is broken
|
||||
start = [rv_foo]
|
||||
res = service.execute(context, start, [ContextActions.EVALUATION])
|
||||
|
||||
assert res == [rv_bar]
|
||||
assert res[0].parents == [rv_foo]
|
||||
|
||||
Reference in New Issue
Block a user