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
+101
View File
@@ -0,0 +1,101 @@
import pytest
from base import BaseTest
from common.global_symbols import NotInit
from conftest import NewOntology
from core.concept import ConceptDefaultProps
from core.python_fragment import PythonFragment
from helpers import define_new_concept, get_metadata
from services.SheerkaConceptEvaluator import ConceptEvaluator
from services.SheerkaPython import EvaluationRef
class TestConceptManager(BaseTest):
@pytest.fixture()
def service(self, sheerka) -> ConceptEvaluator:
return sheerka.services[ConceptEvaluator.NAME]
def test_i_can_build_concept(self, context, service):
metadata = get_metadata(
name="foo",
where="isinstance(x, Concept)",
pre="in_context(IS_QUESTION)",
body="one + a",
post="'post parameter'",
ret="self",
variables=(("a", "1"), ("b", "NotInit"))
)
compiled = service.build(context, metadata)
pf = getattr(compiled, ConceptDefaultProps.WHERE)
assert isinstance(pf, PythonFragment)
assert pf.source_code == metadata.where
pf = getattr(compiled, ConceptDefaultProps.PRE)
assert isinstance(pf, PythonFragment)
assert pf.source_code == metadata.pre
pf = getattr(compiled, ConceptDefaultProps.BODY)
assert isinstance(pf, PythonFragment)
assert pf.source_code == metadata.body
pf = getattr(compiled, ConceptDefaultProps.POST)
assert isinstance(pf, PythonFragment)
assert pf.source_code == metadata.post
pf = getattr(compiled, ConceptDefaultProps.RET)
assert isinstance(pf, PythonFragment)
assert pf.source_code == metadata.ret
pf = getattr(compiled, "a")
assert isinstance(pf, PythonFragment)
assert pf.source_code == metadata.variables[0][1]
pf = getattr(compiled, "b")
assert isinstance(pf, PythonFragment)
assert pf.source_code == metadata.variables[1][1]
def test_i_can_manage_when_no_source_code(self, context, service):
metadata = get_metadata(name="foo")
compiled = service.build(context, metadata)
assert getattr(compiled, ConceptDefaultProps.WHERE) is None
assert getattr(compiled, ConceptDefaultProps.PRE) is None
assert getattr(compiled, ConceptDefaultProps.BODY) is None
assert getattr(compiled, ConceptDefaultProps.POST) is None
assert getattr(compiled, ConceptDefaultProps.RET) is None
def test_i_can_detect_when_requested_names_are_concept_variables(self, context, service):
metadata = get_metadata(
name="foo",
body="one + a",
variables=(("a", "1"), ("b", "NotInit")))
compiled = service.build(context, metadata)
pf = getattr(compiled, ConceptDefaultProps.BODY)
assert isinstance(pf, PythonFragment)
assert pf.namespace == {"a": EvaluationRef("self", "a"),
"b": EvaluationRef("self", "b")}
def test_i_can_eval_concept_attributes(self, context, service):
with NewOntology(context, "test_i_can_eval_concept_attributes"):
foo_metadata = get_metadata(name="foo",
where="isinstance(a, int)",
pre="True",
body="2 + a",
post="'post parameter'",
ret="self",
variables=(("a", "1"), ("b", "NotInit")))
foo = define_new_concept(context, foo_metadata)
res = service.evaluate_concept(context, foo)
assert context.sheerka.isinstance(res, foo)
assert res.get_value("a") == 1
assert res.get_value("b") == NotInit
assert res.get_value(ConceptDefaultProps.WHERE) is True
assert res.get_value(ConceptDefaultProps.PRE) is True
assert res.get_value(ConceptDefaultProps.BODY) == 3
assert res.get_value(ConceptDefaultProps.POST) == "post parameter"
assert res.get_value(ConceptDefaultProps.RET) == res
+83 -4
View File
@@ -4,9 +4,9 @@ from base import BaseTest
from common.global_symbols import NotFound, NotInit
from conftest import NewOntology
from core.BuiltinConcepts import BuiltinConcepts
from core.ErrorContext import ErrorContext
from core.concept import ConceptMetadata
from core.services.SheerkaConceptManager import ConceptAlreadyDefined, ConceptManager
from core.error import ErrorContext
from services.SheerkaConceptManager import ConceptAlreadyDefined, ConceptManager
from helpers import get_metadata
@@ -24,7 +24,7 @@ class TestConceptManager(BaseTest):
"""
metadata = get_metadata("foo", "body")
digest = service.compute_metadata_digest(metadata)
assert digest == "21a1c2f420da62f4dc60f600c95b19dd9527b19dd28fd38e17f5c0e28963d176"
assert digest == "7c0f1708968e0312be622950d3f21d588f718f7ba568054ece64d077052a6476"
another_metadata = get_metadata("foo", "body")
other_digest = service.compute_metadata_digest(another_metadata)
@@ -86,7 +86,7 @@ class TestConceptManager(BaseTest):
assert metadata.name == "name"
assert metadata.key == "name"
assert metadata.body == "body"
assert metadata.digest == "eb0620bd4a317af8a403c0ae1e185a528f9b58f8b0878d990e62278f89cf10d5"
assert metadata.digest == "c75faa4efbc9ef9dbc5174c52786d5b066e2ece41486b81c27336e292917fecb"
assert metadata.all_attrs == ('#where#', '#pre#', '#post#', '#body#', '#ret#')
# is sorted in db
@@ -117,6 +117,11 @@ class TestConceptManager(BaseTest):
res = service.define_new_concept(context, "name", body="body")
assert res.status is True
def test_i_cannot_get_by_if_concept_does_not_exist(self, service):
assert service.get_by_id("unresolved_id") == NotFound
assert service.get_by_name("unresolved name") == NotFound
assert service.get_by_key("unresolved_hash") == NotFound
def test_i_can_get_a_newly_created_concept(self, context, service):
with NewOntology(context, "test_i_can_get_a_newly_created_concept"):
res = service.define_new_concept(context, "name", body="body")
@@ -141,6 +146,19 @@ class TestConceptManager(BaseTest):
assert foo.var1 == "value1"
assert foo.var2 == "value2"
def test_i_can_manage_when_concepts_with_the_same_name(self, context, service):
with NewOntology(context, "test_i_can_manage_when_concepts_with_the_same_name"):
service.define_new_concept(context, "foo", body="body1")
service.define_new_concept(context, "foo", body="body2")
concepts = service.newn("foo")
assert len(concepts) == 2
assert concepts[0].name == "foo"
assert concepts[0].get_metadata().body == "body1"
assert concepts[1].name == "foo"
assert concepts[1].get_metadata().body == "body2"
def test_i_can_instantiate_a_new_concept_by_its_id(self, context, service):
with NewOntology(context, "test_i_can_instantiate_a_new_concept_by_its_id"):
res = service.define_new_concept(context, "foo", variables=[("var1", None), ("var2", None)])
@@ -184,3 +202,64 @@ class TestConceptManager(BaseTest):
context.sheerka.om.pop_ontology(context)
assert service.get_by_id(res.value.metadata.id) is NotFound
def test_i_can_new(self, context, service):
with NewOntology(context, "test_i_can_new"):
res = service.define_new_concept(context, "name", body="body", variables=[("my_var", None)])
assert res.status
metadata = res.value.metadata
# I can create a new concept
res = service.new(metadata, my_var="my_var_value")
assert res.id == metadata.id
assert res.my_var == "my_var_value"
res = service.new((metadata.name, None), my_var="my_var_value")
assert res.id == metadata.id
assert res.my_var == "my_var_value"
res = service.new((None, metadata.id), my_var="my_var_value")
assert res.id == metadata.id
assert res.my_var == "my_var_value"
res = service.new("c:name:", my_var="my_var_value")
assert res.id == metadata.id
assert res.my_var == "my_var_value"
res = service.new("c:#1001:", my_var="my_var_value")
assert res.id == metadata.id
assert res.my_var == "my_var_value"
res = service.new("c:name#1001:", my_var="my_var_value")
assert res.id == metadata.id
assert res.my_var == "my_var_value"
# cannot new using id
assert service.new(f"1001").name == BuiltinConcepts.UNKNOWN_CONCEPT
def test_id_is_used_when_name_and_id_are_provided(self, context, service):
with NewOntology(context, "test_id_is_used_when_name_and_id_are_provided"):
res = service.define_new_concept(context, "name", body="body1")
metadata = res.value.metadata
service.define_new_concept(context, "name", body="body2")
assert service.new((metadata.name, metadata.id)).id == metadata.id
def test_unknown_concept_is_return_if_the_identifier_is_not_found(self, service):
assert service.new("unknown").name == BuiltinConcepts.UNKNOWN_CONCEPT
def test_can_get_all_concepts(self, context, service):
with NewOntology(context, "test_i_can_new"):
service.define_new_concept(context, "foo")
service.define_new_concept(context, "bar")
context.sheerka.om.push_ontology("another ontology")
service.define_new_concept(context, "baz")
service.define_new_concept(context, "qux")
all_concepts = service.get_all_concepts()
assert [c.name for c in all_concepts if not c.is_builtin] == ["foo", "bar", "baz", "qux"]
# sanity check. Concepts are discarded when ontology is popped
context.sheerka.om.pop_ontology(context)
all_concepts = service.get_all_concepts()
assert [c.name for c in all_concepts if not c.is_builtin] == ["foo", "bar"]
+29
View File
@@ -0,0 +1,29 @@
import pytest
from base import BaseTest
from services.SheerkaAdmin import SheerkaAdmin
from helpers import get_concepts
class TestConceptManager(BaseTest):
@pytest.fixture()
def service(self, sheerka):
return sheerka.services[SheerkaAdmin.NAME]
def test_i_can_test_extended_is_admin(self, context, service):
foo, bar = get_concepts(context, "foo", "bar", use_sheerka=True)
foo1 = context.sheerka.newn("foo")
assert service.extended_isinstance(1, int)
assert service.extended_isinstance(foo, "foo")
assert service.extended_isinstance(foo, foo1)
assert service.extended_isinstance(foo, foo1.get_metadata())
assert service.extended_isinstance(foo, "c:#1001:")
assert not service.extended_isinstance("1", int)
assert not service.extended_isinstance(foo, "bar")
assert not service.extended_isinstance(foo, bar)
assert not service.extended_isinstance(foo, bar.get_metadata())
assert not service.extended_isinstance(foo, "c:#1002:")
+82 -58
View File
@@ -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]
+75
View File
@@ -0,0 +1,75 @@
import pytest
from base import BaseTest, DummyObj
from caching.FastCache import FastCache
from core.ExecutionContext import ContextActions
from services.SheerkaMemory import SheerkaMemory
class TestSheerkaEngine(BaseTest):
@pytest.fixture()
def service(self, sheerka):
return SheerkaMemory(sheerka) # I want a new instance to keep Sheerka clean (when I update stm)
def test_i_can_add_to_global_short_term_memory(self, service):
dummy = DummyObj()
service.add_to_short_term_memory(None, "a", dummy)
assert service.short_term_objects.copy() == {'global': {'a': dummy}}
def test_i_can_add_and_get_stm_data(self, context, service):
sub_context = context.push("TestSheerkaEngine", ContextActions.TESTING, None)
service.add_to_short_term_memory(None, "a", "global level")
service.add_to_short_term_memory(context, "a", "context level")
service.add_to_short_term_memory(sub_context, "a", "sub context level")
assert service.get_from_short_term_memory(sub_context, "a") == "sub context level"
assert service.get_from_short_term_memory(context, "a") == "context level"
assert service.get_from_short_term_memory(None, "a") == "global level"
def test_i_can_list_stm_data(self, context, service):
sub_context = context.push("TestSheerkaEngine", ContextActions.TESTING, None)
service.add_to_short_term_memory(None, "a", "global a")
service.add_to_short_term_memory(None, "b", "global b")
service.add_to_short_term_memory(context, "a", "context a")
service.add_to_short_term_memory(context, "c", "context c")
service.add_to_short_term_memory(sub_context, "d", "sub context d")
service.add_to_short_term_memory(sub_context, "a", "sub context a")
assert service.list_short_term_memory(sub_context) == {"a": "sub context a",
"b": "global b",
"c": "context c",
"d": "sub context d"}
assert service.list_short_term_memory(context) == {"a": "context a",
"b": "global b",
"c": "context c"}
assert service.list_short_term_memory(None) == {"a": "global a",
"b": "global b"}
def test_i_can_list_stm_data_when_context_have_no_entry(self, context, service):
sub_context = context.push("TestSheerkaEngine", ContextActions.TESTING, None)
service.add_to_short_term_memory(sub_context, "d", "sub context d")
service.add_to_short_term_memory(sub_context, "a", "sub context a")
assert service.list_short_term_memory(sub_context) == {"a": "sub context a", "d": "sub context d"}
assert service.list_short_term_memory(context) == {}
assert service.list_short_term_memory(None) == {}
def test_i_value_are_removed_when_cache_is_full(self, context, service):
service.short_term_objects = FastCache(3)
context1 = context.push("TestSheerkaEngine", ContextActions.TESTING, None)
context2 = context.push("TestSheerkaEngine", ContextActions.TESTING, None)
context3 = context.push("TestSheerkaEngine", ContextActions.TESTING, None)
service.add_to_short_term_memory(context, "a", "context")
service.add_to_short_term_memory(context1, "b", "context 1")
service.add_to_short_term_memory(context2, "c", "context 2")
assert context.id in service.short_term_objects
service.add_to_short_term_memory(context3, "d", "context 3")
assert context.id not in service.short_term_objects
+127
View File
@@ -0,0 +1,127 @@
import pytest
from base import BaseTest, DummyObj
from common.global_symbols import NoFirstToken, NotFound, NotInit, Removed
from conftest import NewOntology
from core.BuiltinConcepts import BuiltinConcepts
from evaluators.PythonParser import PythonParser
from helpers import _rv, define_new_concept, get_concepts, get_metadata
from parsers.ParserInput import ParserInput
from services.SheerkaPython import EvaluationRef, SheerkaPython
def get_python_fragment(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].value.pf
class TestSheerkaPython(BaseTest):
@pytest.fixture()
def service(self, sheerka) -> SheerkaPython:
return sheerka.services[SheerkaPython.NAME]
@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),
("NotInit", NotInit),
("NotFound", NotFound),
("Removed", Removed),
("NoFirstToken", NoFirstToken),
])
def test_i_can_evaluate_simple_expression(self, sheerka, context, service, text, expected):
python_fragment = get_python_fragment(sheerka, context, text)
ret = service.evaluate_python(context, python_fragment)
assert ret == expected
def test_i_can_eval_isinstance_for_type(self, sheerka, context, service):
python_fragment = get_python_fragment(sheerka, context, "isinstance('some string', str)")
ret = service.evaluate_python(context, python_fragment)
assert ret is True
def test_i_can_eval_isinstance_for_concept(self, sheerka, context, service):
with NewOntology(context, "test_i_can_eval_isinstance_for_concept"):
get_concepts(context, "foo", use_sheerka=True)
python_fragment = get_python_fragment(sheerka, context, "isinstance(foo, 'foo')")
ret = service.evaluate_python(context, python_fragment)
assert ret is True
# 'foo' is also a Concept
python_fragment = get_python_fragment(sheerka, context, "isinstance(foo, Concept)")
ret = service.evaluate_python(context, python_fragment)
assert ret is True
def test_i_can_use_value_from_global_namespace(self, sheerka, context, service):
python_fragment = get_python_fragment(sheerka, context, "self.a")
ret = service.evaluate_python(context, python_fragment, {"self": DummyObj("my dummy value")})
assert ret == "my dummy value"
def test_i_can_eval_using_eval_ref(self, sheerka, context, service):
python_fragment = get_python_fragment(sheerka, context, "a")
python_fragment.namespace = {"a": EvaluationRef("self", "a")}
ret = service.evaluate_python(context, python_fragment, {"self": DummyObj("my dummy value")})
assert ret == "my dummy value"
@pytest.mark.skip("Concept evaluation is not implemented")
def test_i_can_eval_concept_properties(self, sheerka, context, service):
with NewOntology(context, "test_i_can_eval_concept_properties"):
foo_meta = get_metadata("foo", variables=[("a", "hello world")])
define_new_concept(context, foo_meta)
python_fragment = get_python_fragment(sheerka, context, "foo.a")
ret = service.evaluate_python(context, python_fragment)
assert ret == "hello world"
@pytest.mark.skip("Concept evaluation is not implemented")
def test_i_can_eval_python_mixed_with_concept(self, sheerka, context, service):
with NewOntology(context, "test_i_can_eval_python_mixed_with_concept"):
foo_meta = get_metadata("foo", variables=[("a", "1")])
bar_meta = get_metadata("bar", body="2")
get_concepts(context, foo_meta, bar_meta, use_sheerka=True)
python_fragment = get_python_fragment(sheerka, context, "bar + foo.a")
ret = service.evaluate_python(context, python_fragment)
assert ret == "3"
def test_i_can_remember_previous_results(self, sheerka, context, service):
python_fragment = get_python_fragment(sheerka, context, "a=10")
ret = service.evaluate_python(context, python_fragment)
assert ret is None
python_fragment = get_python_fragment(sheerka, context, "a")
ret = service.evaluate_python(context, python_fragment)
assert ret == 10
def test_i_can_import_module(self, sheerka, context, service):
python_fragment = get_python_fragment(sheerka, context, "import math")
ret = service.evaluate_python(context, python_fragment)
assert ret is None
python_fragment = get_python_fragment(sheerka, context, "math.sqrt(4)")
ret = service.evaluate_python(context, python_fragment)
assert ret == 2
def test_i_can_import_function_from_module(self, sheerka, context, service):
python_fragment = get_python_fragment(sheerka, context, "from math import sqrt")
ret = service.evaluate_python(context, python_fragment)
assert ret is None
python_fragment = get_python_fragment(sheerka, context, "sqrt(4)")
ret = service.evaluate_python(context, python_fragment)
assert ret == 2
def test_i_can_eval_when_context_is_needed(self, sheerka, context, service):
with NewOntology(context, "test_i_can_eval_when_context_is_needed"):
python_fragment = get_python_fragment(sheerka, context, "define_new_concept('foo')")
ret = service.evaluate_python(context, python_fragment)
assert sheerka.isinstance(ret.value, BuiltinConcepts.NEW_CONCEPT)
# for info, there are two level of value
# one for PythonEvaluator return value
# one for the ConceptManager return value