341 lines
17 KiB
Python
341 lines
17 KiB
Python
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 core.ExecutionContext import ContextActions
|
|
from core.concept import ConceptDefaultProps
|
|
from core.error import MethodAccessError
|
|
from evaluators.PythonParser import PythonParser
|
|
from helpers import _rv, define_new_concept, get_concepts, get_evaluated_concept, get_metadata
|
|
from parsers.ParserInput import ParserInput
|
|
from parsers.tokenizer import Token, TokenKind
|
|
from services.SheerkaPython import EvalMethod, EvaluationContext, EvaluationRef, Expando, MultipleResults, 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):
|
|
with NewOntology(context, "test_i_can_evaluate_simple_expression"):
|
|
python_fragment = get_python_fragment(sheerka, context, text)
|
|
ret = service.evaluate_python(context, EvaluationContext(), python_fragment)
|
|
assert ret == expected
|
|
|
|
def test_i_can_eval_isinstance_with_a_type(self, sheerka, context, service):
|
|
python_fragment = get_python_fragment(sheerka, context, "isinstance('some string', str)")
|
|
ret = service.evaluate_python(context, EvaluationContext(), python_fragment)
|
|
|
|
assert ret is True
|
|
|
|
def test_i_can_eval_isinstance_with_a_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, EvaluationContext(), 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, EvaluationContext(), 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, EvaluationContext(), 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, EvaluationContext(), python_fragment,
|
|
{"self": DummyObj("my dummy value")})
|
|
assert ret == "my dummy value"
|
|
|
|
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, EvaluationContext(), python_fragment)
|
|
assert ret == "hello world"
|
|
|
|
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, EvaluationContext(), 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, EvaluationContext(), python_fragment)
|
|
assert ret is None
|
|
|
|
python_fragment = get_python_fragment(sheerka, context, "a")
|
|
ret = service.evaluate_python(context, EvaluationContext(), 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, EvaluationContext(), python_fragment)
|
|
assert ret is None
|
|
|
|
python_fragment = get_python_fragment(sheerka, context, "math.sqrt(4)")
|
|
ret = service.evaluate_python(context, EvaluationContext(), 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, EvaluationContext(), python_fragment)
|
|
assert ret is None
|
|
|
|
python_fragment = get_python_fragment(sheerka, context, "sqrt(4)")
|
|
ret = service.evaluate_python(context, EvaluationContext(), 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, EvaluationContext(), 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
|
|
|
|
def test_i_can_return_multiple_results(self, sheerka, context, service):
|
|
with NewOntology(context, "test_i_can_return_multiple_values"):
|
|
foo_1, foo_2, foo_3 = get_concepts(context,
|
|
get_metadata("foo", body="'foo'"),
|
|
get_metadata("foo", body="True"),
|
|
get_metadata("foo", body="'bar'"),
|
|
use_sheerka=True)
|
|
|
|
python_fragment = get_python_fragment(sheerka, context, "foo")
|
|
|
|
evaluation_context = EvaluationContext(eval_method=EvalMethod.All)
|
|
ret = service.evaluate_python(context, evaluation_context, python_fragment)
|
|
|
|
assert ret == MultipleResults(get_evaluated_concept(foo_1, body='foo'),
|
|
"foo",
|
|
get_evaluated_concept(foo_2, body=True),
|
|
True,
|
|
get_evaluated_concept(foo_3, body='bar'),
|
|
"bar")
|
|
|
|
def test_i_can_eval_when_multiple_concepts(self, sheerka, context, service):
|
|
with NewOntology(context, "test_i_can_eval_when_multiple_concepts"):
|
|
get_concepts(context,
|
|
get_metadata("one", body="'one'"),
|
|
get_metadata("one", body="1"),
|
|
use_sheerka=True)
|
|
python_fragment = get_python_fragment(sheerka, context, "one + 1")
|
|
|
|
ret = service.evaluate_python(context, EvaluationContext(), python_fragment)
|
|
|
|
assert ret == 2
|
|
|
|
def test_i_can_eval_until_a_successful_result_is_found(self, sheerka, context, service):
|
|
with NewOntology(context, "test_i_can_eval_when_multiple_concepts"):
|
|
get_concepts(context,
|
|
get_metadata("one", body="'one'"),
|
|
get_metadata("one", body="1"),
|
|
get_metadata("one", body="2"),
|
|
use_sheerka=True)
|
|
python_fragment = get_python_fragment(sheerka, context, "one + 1")
|
|
service.evaluate_python(context, EvaluationContext(), python_fragment)
|
|
|
|
# check the number of evaluated namespaces
|
|
# there are 3 concepts, so there must be 6 results
|
|
# But we stop after the second 'one' concept
|
|
ec = next(filter(lambda _ec: _ec.action == ContextActions.EVALUATING_PYTHON, context.get_children()))
|
|
assert len(ec.values["all_results"]) == 4
|
|
|
|
def test_i_can_eval_all_namespaces(self, sheerka, context, service):
|
|
with NewOntology(context, "test_i_can_return_multiple_values"):
|
|
foo_1, foo_2, foo_3 = get_concepts(context,
|
|
get_metadata("foo", body="'foo'"),
|
|
get_metadata("foo", body="True"),
|
|
get_metadata("foo", body="'bar'"),
|
|
use_sheerka=True)
|
|
|
|
python_fragment = get_python_fragment(sheerka, context, "foo")
|
|
|
|
evaluation_context = EvaluationContext(eval_method=EvalMethod.All)
|
|
service.evaluate_python(context, evaluation_context, python_fragment)
|
|
|
|
# check the number of evaluated namespaces
|
|
ec = next(filter(lambda _ec: _ec.action == ContextActions.EVALUATING_PYTHON, context.get_children()))
|
|
assert len(ec.values["all_results"]) == 6
|
|
|
|
def test_i_can_eval_until_true(self, sheerka, context, service):
|
|
with NewOntology(context, "test_i_can_return_multiple_values"):
|
|
get_concepts(context,
|
|
get_metadata("foo", body="False"),
|
|
get_metadata("foo", body="True"),
|
|
get_metadata("foo", body="'bar'"),
|
|
use_sheerka=True)
|
|
|
|
python_fragment = get_python_fragment(sheerka, context, "foo")
|
|
|
|
evaluation_context = EvaluationContext(eval_method=EvalMethod.UntilTrue)
|
|
res = service.evaluate_python(context, evaluation_context, python_fragment)
|
|
|
|
assert res is True
|
|
|
|
# check the number of evaluated namespaces
|
|
# We stop after the second 'one' concept, so only 4 results
|
|
ec = next(filter(lambda _ec: _ec.action == ContextActions.EVALUATING_PYTHON, context.get_children()))
|
|
assert len(ec.values["all_results"]) == 4
|
|
|
|
def test_eval_until_success_return_false_if_true_is_not_found(self, sheerka, context, service):
|
|
with NewOntology(context, "test_i_can_return_multiple_values"):
|
|
get_concepts(context,
|
|
get_metadata("foo", body="False"),
|
|
get_metadata("foo", body="'bar'"),
|
|
use_sheerka=True)
|
|
|
|
python_fragment = get_python_fragment(sheerka, context, "foo")
|
|
|
|
evaluation_context = EvaluationContext(eval_method=EvalMethod.UntilTrue)
|
|
ret = service.evaluate_python(context, evaluation_context, python_fragment)
|
|
|
|
assert ret is False
|
|
|
|
def test_i_can_return_empty_list(self, sheerka, context, service):
|
|
python_fragment = get_python_fragment(sheerka, context, "[]")
|
|
ret = service.evaluate_python(context, EvaluationContext(), python_fragment)
|
|
|
|
assert ret == []
|
|
|
|
def test_can_create_namespaces(self, context, service):
|
|
with NewOntology(context, "test_i_can_eval_when_context_is_needed"):
|
|
namespace = service.create_namespace(context, ['in_context'], None, {}, {}, False)
|
|
assert namespace == {"in_context": context.in_context}
|
|
|
|
namespace = service.create_namespace(context, ['isinstance'], None, {}, {}, False)
|
|
assert namespace == {"isinstance": context.sheerka.extended_isinstance}
|
|
|
|
namespace = service.create_namespace(context, ['print'], None, {}, {}, False)
|
|
assert namespace == {"print": print}
|
|
|
|
namespace = service.create_namespace(context, ['print'], None, {}, {}, True)
|
|
assert namespace == {} # print method has side effect, so it's excluded
|
|
|
|
# ###################
|
|
# sheerka expando
|
|
# ###################
|
|
namespace = service.create_namespace(context, ['sheerka'], set(), {}, {}, False)
|
|
assert isinstance(namespace["sheerka"], Expando)
|
|
assert len(vars(namespace["sheerka"])) == 1 # 'expando_name' only
|
|
|
|
namespace = service.create_namespace(context, ['sheerka'], {"new", "echo"}, {}, {}, False)
|
|
assert isinstance(namespace["sheerka"], Expando)
|
|
assert len(vars(namespace["sheerka"])) == 3 # 'expando_name' + new() + echo()
|
|
|
|
with pytest.raises(MethodAccessError):
|
|
# new method is not allowed if expression_only is True
|
|
service.create_namespace(context, ['sheerka'], {"new", "echo"}, {}, {}, True)
|
|
|
|
# ###################
|
|
# sheerka methods
|
|
# ###################
|
|
namespace = service.create_namespace(context, ['new'], None, {}, {}, False)
|
|
assert namespace == {"new": context.sheerka.new} # Sheerka methods are not set
|
|
|
|
with pytest.raises(MethodAccessError):
|
|
# new method is not allowed if expression_only is True
|
|
service.create_namespace(context, ['new'], None, {}, {}, True)
|
|
|
|
# ###################
|
|
context.sheerka.add_to_short_term_memory("key", "short term memory value")
|
|
namespace = service.create_namespace(context, ['key'], None, {}, {}, False)
|
|
assert namespace == {"key": "short term memory value"}
|
|
|
|
foo = define_new_concept(context, get_metadata("foo", body="1"))
|
|
foo_token = Token(TokenKind.CONCEPT, ("foo", None), 0, 1, 1)
|
|
namespace = service.create_namespace(context, ['foo'], None, {"foo": foo_token}, {}, False)
|
|
assert context.sheerka.isinstance(namespace["foo"], foo)
|
|
assert namespace["foo"].body == 1 # local namespace are evaluated
|
|
|
|
namespace = service.create_namespace(context, ['foo'], None, {}, {"foo": foo}, False)
|
|
assert context.sheerka.isinstance(namespace["foo"], foo)
|
|
assert namespace["foo"].body is NotInit # global namespace are used as is
|
|
|
|
namespace = service.create_namespace(context, ['foo'], None, {}, {}, False)
|
|
assert context.sheerka.isinstance(namespace["foo"], foo)
|
|
assert namespace["foo"].body == 1 # concept instantiation are evaluated
|
|
|
|
def test_i_can_manage_concept_synonyms(self, context, service):
|
|
foo, bar, baz = get_concepts(context, "foo", "bar", "baz", use_sheerka=False)
|
|
# foo, bar and baz are supposed to be concept synonyms
|
|
namespace = {"a": "value a",
|
|
"foo": MultipleResults(foo, bar, baz),
|
|
"b": "value b",
|
|
"bar": MultipleResults(baz, bar)}
|
|
|
|
res = service.manage_multiple_choices(namespace)
|
|
|
|
assert len(res) == 6
|
|
assert res[0] == {"a": "value a", "b": "value b", "foo": foo, "bar": baz}
|
|
assert res[1] == {"a": "value a", "b": "value b", "foo": foo, "bar": bar}
|
|
assert res[2] == {"a": "value a", "b": "value b", "foo": bar, "bar": baz}
|
|
assert res[3] == {"a": "value a", "b": "value b", "foo": bar, "bar": bar}
|
|
assert res[4] == {"a": "value a", "b": "value b", "foo": baz, "bar": baz}
|
|
assert res[5] == {"a": "value a", "b": "value b", "foo": baz, "bar": bar}
|
|
|
|
def test_i_can_manage_namespaces_when_concepts_have_values(self, context, service):
|
|
foo, bar, baz = get_concepts(context, "foo", "bar", "baz", use_sheerka=False)
|
|
foo.set_value(ConceptDefaultProps.BODY, "foo value")
|
|
foo.get_runtime_info().is_evaluated = True
|
|
bar.set_value(ConceptDefaultProps.BODY, "bar value")
|
|
bar.get_runtime_info().is_evaluated = True
|
|
|
|
namespaces = [
|
|
{"a": "value a", "foo": foo, "baz": baz},
|
|
{"a": "value a", "foo": bar, "baz": baz},
|
|
]
|
|
|
|
res = service.manage_concepts_with_body(context, namespaces)
|
|
|
|
assert len(res) == 4
|
|
assert res == [
|
|
{"a": "value a", "baz": baz, "foo": foo},
|
|
{"a": "value a", "baz": baz, "foo": "foo value"},
|
|
{"a": "value a", "baz": baz, "foo": bar},
|
|
{"a": "value a", "baz": baz, "foo": "bar value"},
|
|
]
|
|
|
|
def test_multiple_results_concept_only_return_concepts(self, context):
|
|
foo, bar = get_concepts(context, "foo", "bar")
|
|
assert MultipleResults(foo, "one", bar, 1).concepts_only() == MultipleResults(foo, bar)
|
|
assert MultipleResults("one", 1).concepts_only() == MultipleResults()
|