Fixed #68: Implement SheerkaQL
Fixed #70: SheerkaFilterManager : Pipe functions Fixed #71: SheerkaFilterManager : filter_objects Fixed #75: SheerkaMemory: Enhance memory() to use the filtering capabilities Fixed #76: SheerkaEvaluateConcept: Concepts that modify the state of the system must not be evaluated during question
This commit is contained in:
@@ -12,9 +12,12 @@ class TestExecutionContext(TestUsingMemoryBasedSheerka):
|
||||
def test_id_is_incremented_by_event_digest(self):
|
||||
sheerka = self.get_sheerka()
|
||||
|
||||
a = ExecutionContext("foo", Event("event_1"), sheerka, BuiltinConcepts.NOP, None)
|
||||
b = ExecutionContext("foo", Event("event_1"), sheerka, BuiltinConcepts.NOP, None)
|
||||
c = ExecutionContext("foo", Event("event_2"), sheerka, BuiltinConcepts.NOP, None)
|
||||
event1 = Event("event_1")
|
||||
event2 = Event("event_2")
|
||||
|
||||
a = ExecutionContext("foo", event1, sheerka, BuiltinConcepts.NOP, None)
|
||||
b = ExecutionContext("foo", event1, sheerka, BuiltinConcepts.NOP, None)
|
||||
c = ExecutionContext("foo", event2, sheerka, BuiltinConcepts.NOP, None)
|
||||
d = b.push(BuiltinConcepts.NOP, None)
|
||||
e = c.push(BuiltinConcepts.NOP, None)
|
||||
|
||||
@@ -177,6 +180,47 @@ class TestExecutionContext(TestUsingMemoryBasedSheerka):
|
||||
assert sub2.has_parent(root.id)
|
||||
assert not sub1.has_parent(sub2.id)
|
||||
assert not sub2.has_parent(sub1.id)
|
||||
|
||||
def test_i_can_reset_global_hints(self):
|
||||
sheerka = self.get_sheerka()
|
||||
|
||||
context = ExecutionContext("foo", Event("event_1"), sheerka, BuiltinConcepts.NOP, None)
|
||||
context.add_to_global_hints(BuiltinConcepts.TESTING)
|
||||
context.add_to_global_hints(BuiltinConcepts.DEBUG)
|
||||
|
||||
sub_context1 = context.push(BuiltinConcepts.NOP, None)
|
||||
assert BuiltinConcepts.TESTING in sub_context1.global_hints
|
||||
assert BuiltinConcepts.DEBUG in sub_context1.global_hints
|
||||
|
||||
sub_context2 = context.push(BuiltinConcepts.NOP, None, reset_hints={BuiltinConcepts.TESTING})
|
||||
assert BuiltinConcepts.TESTING not in sub_context2.global_hints
|
||||
assert BuiltinConcepts.DEBUG in sub_context2.global_hints
|
||||
|
||||
sub_context3 = context.push(BuiltinConcepts.NOP,
|
||||
None,
|
||||
reset_hints={BuiltinConcepts.DEBUG, BuiltinConcepts.TESTING})
|
||||
assert sub_context3.global_hints == set()
|
||||
|
||||
def test_i_can_reset_protected_hints(self):
|
||||
sheerka = self.get_sheerka()
|
||||
|
||||
context = ExecutionContext("foo", Event("event_1"), sheerka, BuiltinConcepts.NOP, None)
|
||||
context.add_to_protected_hints(BuiltinConcepts.TESTING)
|
||||
context.add_to_protected_hints(BuiltinConcepts.DEBUG)
|
||||
|
||||
sub_context1 = context.push(BuiltinConcepts.NOP, None)
|
||||
assert BuiltinConcepts.TESTING in sub_context1.protected_hints
|
||||
assert BuiltinConcepts.DEBUG in sub_context1.protected_hints
|
||||
|
||||
sub_context2 = context.push(BuiltinConcepts.NOP, None, reset_hints={BuiltinConcepts.TESTING})
|
||||
assert BuiltinConcepts.TESTING not in sub_context2.protected_hints
|
||||
assert BuiltinConcepts.DEBUG in sub_context2.protected_hints
|
||||
|
||||
sub_context3 = context.push(BuiltinConcepts.NOP,
|
||||
None,
|
||||
reset_hints={BuiltinConcepts.DEBUG, BuiltinConcepts.TESTING})
|
||||
assert sub_context3.protected_hints == set()
|
||||
|
||||
# def test_variables_are_passed_to_children_but_not_to_parents(self):
|
||||
# sheerka = self.get_sheerka()
|
||||
#
|
||||
|
||||
@@ -2,7 +2,7 @@ import pytest
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, ParserResultConcept
|
||||
from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved, \
|
||||
concept_part_value, DEFINITION_TYPE_DEF
|
||||
DEFINITION_TYPE_DEF
|
||||
from core.global_symbols import NotInit, NotFound
|
||||
from core.sheerka.services.SheerkaEvaluateConcept import SheerkaEvaluateConcept
|
||||
from core.sheerka.services.SheerkaMemory import SheerkaMemory
|
||||
@@ -420,7 +420,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
concept = Concept("foo", body="a")
|
||||
evaluated = sheerka.evaluate_concept(context, concept)
|
||||
assert evaluated.key == concept.key
|
||||
compare_with_test_object(evaluated.body, CB("a", "concept_a")) # this test was already done
|
||||
compare_with_test_object(evaluated.body, CB("a", "concept_a")) # this test was already done
|
||||
|
||||
# so check this one.
|
||||
concept = Concept("foo", body="a").def_var("a", "'property_a'")
|
||||
@@ -784,27 +784,6 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
assert evaluated.key == command.key
|
||||
assert sheerka.get_from_memory(context, "a").obj == 10
|
||||
|
||||
@pytest.mark.parametrize("metadata", [
|
||||
ConceptParts.WHERE,
|
||||
ConceptParts.PRE,
|
||||
ConceptParts.POST,
|
||||
ConceptParts.RET
|
||||
])
|
||||
def test_i_cannot_evaluate_python_statement_in_where_pre_post_ret(self, metadata, capsys):
|
||||
sheerka, context, foo = self.init_concepts("foo")
|
||||
setattr(foo.get_metadata(), concept_part_value(metadata), "a=10; print('10')")
|
||||
foo.get_metadata().need_validation = True
|
||||
|
||||
evaluated = sheerka.evaluate_concept(context, foo, eval_body=True)
|
||||
captured = capsys.readouterr()
|
||||
|
||||
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
|
||||
error = evaluated.body
|
||||
assert sheerka.isinstance(error, BuiltinConcepts.PYTHON_SECURITY_ERROR)
|
||||
assert error.prop == metadata
|
||||
assert error.body == "a=10; print('10')"
|
||||
assert captured.out == ""
|
||||
|
||||
def test_python_builtin_function_are_forbidden_in_where_pre_post_ret(self, capsys):
|
||||
# I do the test only for PRE, as it will be the same for the other ConceptPart
|
||||
sheerka, context, foo, bar = self.init_concepts(
|
||||
|
||||
@@ -9,8 +9,9 @@ from core.sheerka.Sheerka import RECOGNIZED_BY_ID, RECOGNIZED_BY_NAME
|
||||
from core.sheerka.services.SheerkaEvaluateRules import SheerkaEvaluateRules, LOW_PRIORITY_RULES, DISABLED_RULES
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, CompiledCondition
|
||||
from evaluators.PythonEvaluator import PythonEvaluator, Expando
|
||||
from evaluators.PythonEvaluator import PythonEvaluator
|
||||
from parsers.PythonParser import PythonParser
|
||||
from sheerkapython.python_wrapper import Expando
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
@@ -84,7 +85,7 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
|
||||
# create fake compiled predicates
|
||||
parser = PythonParser()
|
||||
my_rule.compiled_conditions = [
|
||||
CompiledCondition(PythonEvaluator.NAME, parser.parse(context, ParserInput(exp)), set(), set(), None)
|
||||
CompiledCondition(PythonEvaluator.NAME, parser.parse(context, ParserInput(exp)), set(), set(), None, set())
|
||||
for exp in predicates]
|
||||
my_rule.metadata.is_compiled = True
|
||||
my_rule.metadata.is_enabled = True
|
||||
@@ -114,9 +115,9 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
|
||||
assert res == {True: [r1, r3], False: [r2]}
|
||||
|
||||
@pytest.mark.parametrize("predicate", [
|
||||
"greetings",
|
||||
"c:|1001:",
|
||||
"hello 'kodjo'"
|
||||
"recognize(__ret.body, greetings)",
|
||||
"recognize(__ret.body, c:|1001:)",
|
||||
"recognize(__ret.body, hello 'kodjo')"
|
||||
])
|
||||
def test_i_can_evaluate_rules_when_concepts_are_not_questions(self, predicate):
|
||||
"""
|
||||
@@ -146,7 +147,7 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
Concept("there"),
|
||||
create_new=True).with_format_rules(
|
||||
Rule(predicate="hello there", action="")).unpack()
|
||||
Rule(predicate="recognize(__ret.body, hello there)", action="")).unpack()
|
||||
service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
|
||||
there_instance = sheerka.new_from_template(there, there.key)
|
||||
@@ -169,7 +170,7 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
Concept("my friend"),
|
||||
create_new=True).with_format_rules(
|
||||
Rule(predicate="hello my friend", action="")).unpack()
|
||||
Rule(predicate="recognize(__ret.body, hello my friend)", action="")).unpack()
|
||||
service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
|
||||
my_friend_instance = sheerka.new_from_template(my_friend, my_friend.key)
|
||||
@@ -183,7 +184,7 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
|
||||
sheerka, context, greetings, rule = self.init_test().with_concepts(
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
create_new=True).with_format_rules(
|
||||
Rule(predicate="hello sheerka", action="")).unpack()
|
||||
Rule(predicate="recognize(__ret.body, hello sheerka)", action="")).unpack()
|
||||
service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
|
||||
ret = sheerka.ret("evaluator", True, sheerka.new(greetings, a=Expando("sheerka", {})))
|
||||
@@ -196,7 +197,7 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
Concept("greetings", definition="hi a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
create_new=True).with_format_rules(
|
||||
Rule(predicate="greetings", action="")).unpack()
|
||||
Rule(predicate="recognize(__ret.body, greetings)", action="")).unpack()
|
||||
|
||||
service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
ret1 = sheerka.ret("evaluator", True, sheerka.new(g1, a="kodjo"))
|
||||
@@ -210,7 +211,7 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_evaluate_concept_rule_with_the_same_name_when_the_second_concept_is_declared_after(self):
|
||||
sheerka, context, g1, rule, g2 = self.init_test().with_concepts(
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
create_new=True).with_format_rules(Rule(predicate="greetings", action="")).with_concepts(
|
||||
create_new=True).with_format_rules(Rule(predicate="recognize(__ret.body, greetings)", action="")).with_concepts(
|
||||
Concept("greetings", definition="hi a", definition_type=DEFINITION_TYPE_DEF).def_var("a")).unpack()
|
||||
|
||||
service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
|
||||
@@ -87,7 +87,9 @@ class TestSheerkaMemory(TestUsingMemoryBasedSheerka):
|
||||
foo = Concept("foo")
|
||||
sheerka.add_to_memory(context, "a", foo)
|
||||
|
||||
assert sheerka.om.copy(SheerkaMemory.OBJECTS_ENTRY) == {"a": MemoryObject(context.event.get_digest(), foo)}
|
||||
assert sheerka.om.copy(SheerkaMemory.OBJECTS_ENTRY) == {"a": MemoryObject(context.event.get_digest(),
|
||||
context.event.date.timestamp(),
|
||||
foo)}
|
||||
assert id(sheerka.get_from_memory(context, "a").obj) == id(foo)
|
||||
|
||||
def test_i_can_use_memory_with_a_string(self):
|
||||
@@ -106,6 +108,44 @@ class TestSheerkaMemory(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert sheerka.memory(context, Concept("foo")) == foo
|
||||
|
||||
def test_i_can_use_memory_with_a_query(self):
|
||||
sheerka, context, foo, bar = self.init_concepts("foo", "bar")
|
||||
|
||||
sheerka.add_to_memory(context, "x", foo)
|
||||
sheerka.add_to_memory(context, "y", bar)
|
||||
|
||||
assert sheerka.memory(context, "self.name == 'foo'") == foo
|
||||
|
||||
def test_i_retrieve_the_last_entry_when_requesting_memory_with_a_query(self):
|
||||
sheerka, context, foo, bar, foo2 = self.init_concepts("foo", "bar", Concept("foo", body="2"))
|
||||
|
||||
sheerka.add_to_memory(context, "x", foo)
|
||||
sheerka.add_to_memory(context, "y", bar)
|
||||
|
||||
context2 = self.get_context(sheerka) # timestamp is newer
|
||||
sheerka.add_to_memory(context2, "z", foo2)
|
||||
|
||||
assert sheerka.memory(context, "self.name == 'foo'") == foo2
|
||||
|
||||
def test_i_can_look_in_the_previous_objects_when_using_query_to_request_the_memory(self):
|
||||
sheerka, context, foo, bar, baz = self.init_concepts("foo", "bar", "baz")
|
||||
|
||||
sheerka.add_to_memory(context, "x", foo)
|
||||
sheerka.add_to_memory(context, "y", bar)
|
||||
sheerka.add_to_memory(context, "z", baz)
|
||||
|
||||
# another layer
|
||||
sheerka.add_to_memory(context, "x", bar)
|
||||
sheerka.add_to_memory(context, "y", baz)
|
||||
|
||||
# another layer
|
||||
sheerka.add_to_memory(context, "x", baz)
|
||||
|
||||
# so under x there is [foo] -> [bar] -> [baz]
|
||||
# so under y there is [bar] -> [baz]
|
||||
# so under z there is [baz]
|
||||
assert sheerka.memory(context, "self.name == 'foo'") == foo
|
||||
|
||||
def test_concept_not_found_is_return_when_not_found(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
@dataclass
|
||||
class A:
|
||||
prop1: object
|
||||
prop2: object
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, A):
|
||||
return False
|
||||
|
||||
return self.prop1 == other.prop1 and self.prop2 == other.prop2
|
||||
|
||||
def __hash__(self):
|
||||
hash_res = []
|
||||
for p in [self.prop1, self.prop2]:
|
||||
hash_res.append(0 if isinstance(p, (list, dict, set)) else p)
|
||||
|
||||
return hash(tuple(hash_res))
|
||||
|
||||
|
||||
@dataclass
|
||||
class B(A):
|
||||
|
||||
def as_bag(self):
|
||||
return {
|
||||
"fake_prop1": self.prop1,
|
||||
"fake_prop2": self.prop2
|
||||
}
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.prop1, self.prop2))
|
||||
|
||||
|
||||
class TestSheerkaQueryManager(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_filter_objects_using_kwargs(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
lst = [A("a11", 10), A("a21", 3.14), A({1, "v"}, 0xab), A([0, 1], {"key": "value"})]
|
||||
|
||||
assert sheerka.filter_objects(context, lst, prop1="a21") == [lst[1]]
|
||||
assert sheerka.filter_objects(context, lst, prop2=10) == [lst[0]]
|
||||
assert sheerka.filter_objects(context, lst, prop2=3.14) == [lst[1]]
|
||||
assert sheerka.filter_objects(context, lst, prop2=0xab) == [lst[2]]
|
||||
assert sheerka.filter_objects(context, lst, prop1=[0, 1]) == [lst[3]]
|
||||
assert sheerka.filter_objects(context, lst, prop2={"key": "value"}) == [lst[3]]
|
||||
# assert sheerka.filter_objects(context, lst, prop1={1, "v"}) == [lst[2]] set are not supported
|
||||
|
||||
def test_i_can_filter_by_object_type(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
lst = [A("a11", "a12"), Concept("foo", body="a").auto_init(), Concept("foo", body="b").auto_init()]
|
||||
|
||||
assert sheerka.filter_objects(context, lst, __type="foo") == [lst[1], lst[2]]
|
||||
|
||||
def test_i_can_filter_on_atomic_def(self):
|
||||
sheerka, context, isa, plus, isa2 = self.init_concepts(
|
||||
Concept('x is a y').def_var("x").def_var("y"),
|
||||
Concept('a plus b').def_var("a").def_var("b"),
|
||||
Concept('u is a v').def_var("u").def_var("v"),
|
||||
)
|
||||
|
||||
lst = [isa, plus, isa2]
|
||||
assert sheerka.filter_objects(context, lst, atomic_def="is a") == [lst[0], lst[2]]
|
||||
|
||||
def test_i_can_filter_on_as_bag_property(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
lst = [B("a11", "a12"), B("a21", "a22"), B("a31", "a32")]
|
||||
|
||||
assert sheerka.filter_objects(context, lst, fake_prop1="a21") == [lst[1]]
|
||||
|
||||
def test_i_can_filter_container(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
lst = [A("a11", 10), A("a21", 3.14), A({1, "v"}, 0xab), A([0, 1], {"key": "value"})]
|
||||
container = sheerka.new(BuiltinConcepts.EXPLANATION, body=lst, digest="xxx", command="text")
|
||||
|
||||
res = sheerka.filter_objects(context, container, prop1="a21")
|
||||
assert sheerka.isinstance(res, BuiltinConcepts.EXPLANATION)
|
||||
assert res.digest == "xxx"
|
||||
assert res.command == "text"
|
||||
assert res.body == [lst[1]]
|
||||
|
||||
def test_i_can_filter_when_property_does_not_exist(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
lst = [A("a11", "a12"), B("a21", "a22"), B("a31", "a32")]
|
||||
|
||||
assert sheerka.filter_objects(context, lst, prop1="a11") == [lst[0]]
|
||||
|
||||
def test_i_can_filter_objets_using_predicate(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
lst = [A("a11", 10),
|
||||
A("a21", 3.14),
|
||||
A({1, "v"}, 0xab),
|
||||
A([0, 1], {"key": "value"}),
|
||||
Concept("foo", body="a").auto_init(),
|
||||
B("a21", "a22"),
|
||||
Concept("foo", body="b").auto_init(),
|
||||
B("a31", "a32")]
|
||||
|
||||
assert sheerka.filter_objects(context, lst, "self.prop1 == 'a21'") == [lst[1]]
|
||||
assert sheerka.filter_objects(context, lst, "self.prop2 >= 1") == [lst[0], lst[1], lst[2]]
|
||||
assert sheerka.filter_objects(context, lst, "get_type(self) == 'foo' ") == [lst[4], lst[6]]
|
||||
assert sheerka.filter_objects(context, lst, "self.fake_prop1 == 'a21' ") == [lst[5]]
|
||||
assert sheerka.filter_objects(context, lst, "hasattr(self, 'fake_prop1')") == [lst[5], lst[7]]
|
||||
|
||||
def test_i_can_filter_object_using_predicate_and_sheerka_objects(self):
|
||||
sheerka, context, foo, bar = self.init_concepts("foo", "bar")
|
||||
lst = [foo, bar, A("a21", 3.14)]
|
||||
|
||||
assert sheerka.filter_objects(context, lst, "self == bar") == [lst[1]]
|
||||
|
||||
def test_i_can_filter_objects_using_concept(self):
|
||||
sheerka, context, foo, bar, isa = self.init_concepts(
|
||||
"foo",
|
||||
"bar",
|
||||
Concept("x is a concept", body="isinstance(x, Concept)", pre="is_question()").def_var("x"),
|
||||
create_new=True)
|
||||
|
||||
lst = [foo, A("a21", 3.14), bar, B("a21", 3.14)]
|
||||
assert sheerka.filter_objects(context, lst, "self is a concept") == [foo, bar]
|
||||
|
||||
def test_i_can_filter_objects_when_no_kwargs_and_no_predicate(self):
|
||||
sheerka, context, foo, bar = self.init_concepts("foo", "bar")
|
||||
lst = [foo, bar, A("a21", 3.14)]
|
||||
|
||||
assert sheerka.filter_objects(context, lst) == lst
|
||||
|
||||
def test_i_must_select_object_property_using_string(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
with pytest.raises(SyntaxError):
|
||||
sheerka.select_objects(context, [], 00)
|
||||
|
||||
def test_i_can_select_objects_with_args(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
lst = [A("a11", 10), A("a21", 3.14), A({1, "v"}, 0xab), A([0, 1], {"key": "value"})]
|
||||
|
||||
assert sheerka.select_objects(context, lst, "prop1", "prop2") == (
|
||||
('a11', 10),
|
||||
('a21', 3.14),
|
||||
({1, 'v'}, 171),
|
||||
([0, 1], {'key': 'value'}))
|
||||
|
||||
def test_i_can_select_objects_when_container(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
lst = [A("a11", 10), A("a21", 3.14), A({1, "v"}, 0xab), A([0, 1], {"key": "value"})]
|
||||
container = sheerka.new(BuiltinConcepts.EXPLANATION, body=lst, digest="xxx", command="text")
|
||||
|
||||
res = sheerka.select_objects(context, container, "prop1", "prop2")
|
||||
assert sheerka.isinstance(res, BuiltinConcepts.EXPLANATION)
|
||||
assert res.digest == "xxx"
|
||||
assert res.command == "text"
|
||||
assert res.body == (('a11', 10),
|
||||
('a21', 3.14),
|
||||
({1, 'v'}, 171),
|
||||
([0, 1], {'key': 'value'}))
|
||||
|
||||
def test_i_can_select_objects_with_complicated_request(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
lst = [A("a11", 10), A("a21", 3.14), A({1, "v"}, 0xab)]
|
||||
|
||||
assert sheerka.select_objects(context, lst, "self.prop2 + 5") == (15, 8.14, 0xab + 5)
|
||||
assert sheerka.select_objects(context, lst, "isinstance(self.prop1, str)") == (True, True, False)
|
||||
|
||||
def test_error_when_collecting_returns_are_managed(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
lst = [A("a11", 10), A("a21", {"key": "value"})]
|
||||
res = sheerka.select_objects(context, lst, "self.prop2 + 5")
|
||||
|
||||
assert len(res) == 2
|
||||
assert res[0] == 15
|
||||
assert isinstance(res[1], TypeError)
|
||||
|
||||
def test_i_can_select_objects_using_kwargs(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
lst = [A("a11", 10), A("a21", 3.14), A({1, "v"}, 0xab), A([0, 1], {"key": "value"})]
|
||||
|
||||
assert sheerka.select_objects(context, lst, p1="prop1", p2="prop2") == (
|
||||
{"p1": "a11", "p2": 10},
|
||||
{"p1": "a21", "p2": 3.14},
|
||||
{"p1": {1, "v"}, "p2": 0xab},
|
||||
{"p1": [0, 1], "p2": {"key": "value"}},
|
||||
)
|
||||
|
||||
def test_i_can_collect_attributes(self):
|
||||
sheerka = self.get_sheerka()
|
||||
lst = [A("", ""),
|
||||
B("", ""),
|
||||
Concept("foo").def_var("a").auto_init(),
|
||||
Concept("bar").def_var("y").def_var("x").auto_init()]
|
||||
|
||||
res = sheerka.collect_attributes(lst)
|
||||
|
||||
assert sheerka.isinstance(res, BuiltinConcepts.TO_DICT)
|
||||
assert res.body == {
|
||||
"A": ["prop1", "prop2"],
|
||||
"B": ["fake_prop1", "fake_prop2"],
|
||||
"foo": ["a", 'body', 'id', 'key', 'name'],
|
||||
"bar": ['body', 'id', 'key', 'name', "x", "y"] # attributes are sorted
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
import ast
|
||||
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept
|
||||
@@ -7,26 +5,20 @@ from core.concept import Concept, DEFINITION_TYPE_DEF
|
||||
from core.global_symbols import RULE_COMPARISON_CONTEXT, NotFound, EVENT_RULE_DELETED
|
||||
from core.rule import Rule, ACTION_TYPE_PRINT, ACTION_TYPE_EXEC
|
||||
from core.sheerka.Sheerka import RECOGNIZED_BY_ID, RECOGNIZED_BY_NAME
|
||||
from core.sheerka.services.SheerkaEvaluateRules import SheerkaEvaluateRules
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, FormatRuleActionParser, \
|
||||
FormatAstRawText, FormatAstVariable, FormatAstSequence, FormatAstFunction, \
|
||||
FormatRuleSyntaxError, FormatAstList, UnexpectedEof, FormatAstColor, FormatAstDict, \
|
||||
FormatAstMulti, \
|
||||
PythonCodeEmitter, FormatAstNode, ReteConditionExprVisitor, PythonConditionExprVisitor, \
|
||||
CompiledCondition
|
||||
PythonCodeEmitter, FormatAstNode, ReteConditionExprVisitor
|
||||
from core.tokenizer import Token, TokenKind
|
||||
from evaluators.PythonEvaluator import Expando
|
||||
from parsers.BaseParser import ErrorSink
|
||||
from parsers.ExpressionParser import ExpressionParser
|
||||
from parsers.PythonParser import PythonNode
|
||||
from sheerkarete.common import V
|
||||
from sheerkarete.conditions import Condition, AndConditions, FilterCondition
|
||||
from sheerkarete.conditions import FilterCondition
|
||||
from sheerkarete.network import ReteNetwork
|
||||
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import get_rete_conditions, NEGCOND, \
|
||||
NCCOND
|
||||
from tests.parsers.parsers_utils import get_rete_conditions, NEGCOND, NCCOND
|
||||
|
||||
seq = FormatAstSequence
|
||||
raw = FormatAstRawText
|
||||
@@ -188,7 +180,7 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
|
||||
rule = service.init_rule(context, rule)
|
||||
|
||||
assert len(rule.error_sink["when"]) > 0
|
||||
assert sheerka.is_error(rule.error_sink["when"][0])
|
||||
assert sheerka.has_error(context, rule.error_sink["when"][0])
|
||||
assert "print" not in rule.error_sink
|
||||
assert "then" not in rule.error_sink
|
||||
assert rule.metadata.is_compiled
|
||||
@@ -210,7 +202,7 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
other_action_type = ACTION_TYPE_PRINT if action_type == ACTION_TYPE_EXEC else ACTION_TYPE_EXEC
|
||||
|
||||
assert sheerka.is_error(rule.error_sink[action_type])
|
||||
assert sheerka.has_error(context, rule.error_sink[action_type])
|
||||
assert other_action_type not in rule.error_sink
|
||||
assert "when" not in rule.error_sink
|
||||
assert rule.metadata.is_compiled
|
||||
@@ -282,30 +274,6 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert parser.error_sink == expected_error
|
||||
|
||||
@pytest.mark.parametrize("text, compiled_text", [
|
||||
("a == 5", "a == 5"),
|
||||
("foo > 5", "foo > 5"),
|
||||
("func() == 5", "func() == 5"),
|
||||
("not a == 5", "not (a == 5)"),
|
||||
("not foo > 5", "not (foo > 5)"),
|
||||
("not func() == 5", "not (func() == 5)"),
|
||||
])
|
||||
def test_i_can_compile_predicate_when_pure_python(self, text, compiled_text):
|
||||
sheerka, context, *concepts = self.init_concepts("foo")
|
||||
service = sheerka.services[SheerkaRuleManager.NAME]
|
||||
ast_ = ast.parse(compiled_text, "<source>", 'eval')
|
||||
expected_python_node = PythonNode(compiled_text, ast_)
|
||||
|
||||
compilation_result = service.compile_when(context, "test", text)
|
||||
res = compilation_result.python_conditions
|
||||
|
||||
assert len(res) == 1
|
||||
assert isinstance(res[0], CompiledCondition)
|
||||
assert res[0].evaluator_type == PYTHON_EVALUATOR_NAME
|
||||
assert sheerka.isinstance(res[0].return_value, BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.objvalue(res[0].return_value) == expected_python_node
|
||||
assert res[0].concept is None
|
||||
|
||||
def test_i_can_get_rule_priorities(self):
|
||||
sheerka, context, rule_true, rule_false = self.init_test().with_format_rules(("True", "True"),
|
||||
("False", "False")).unpack()
|
||||
@@ -499,20 +467,6 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
|
||||
res = sheerka.get_exec_rules()
|
||||
assert res == [r2, r3, r1]
|
||||
|
||||
@pytest.mark.skip
|
||||
def test_i_can_compile_rete_using_name(self):
|
||||
sheerka, context, *concepts = self.init_test().unpack()
|
||||
service = sheerka.services[SheerkaRuleManager.NAME]
|
||||
|
||||
text = "__ret"
|
||||
|
||||
compilation_result = service.compile_when(context, "test", text)
|
||||
res = compilation_result.rete_disjunctions
|
||||
|
||||
assert len(res) == 1
|
||||
assert isinstance(res[0], AndConditions)
|
||||
assert res[0].conditions == [Condition(V("__x_00__"), "__name__", "__ret")]
|
||||
|
||||
def test_i_can_properly_copy_a_rule(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
service = sheerka.services[SheerkaRuleManager.NAME]
|
||||
@@ -525,98 +479,6 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
|
||||
for k, v in vars(rule).items():
|
||||
assert getattr(clone, k) == getattr(rule, k)
|
||||
|
||||
@pytest.mark.parametrize("expression, expected_as_str, expected_variables", [
|
||||
(
|
||||
"__ret",
|
||||
["#__x_00__|__name__|'__ret'"],
|
||||
{"__ret"}
|
||||
),
|
||||
(
|
||||
"__ret.status == True",
|
||||
["#__x_00__|__name__|'__ret'", "#__x_00__|status|True"],
|
||||
{"__ret"}
|
||||
),
|
||||
(
|
||||
"__ret.status",
|
||||
["#__x_00__|__name__|'__ret.status'"],
|
||||
{"__ret.status"}
|
||||
),
|
||||
(
|
||||
"body",
|
||||
["#__x_00__|__name__|'body'"],
|
||||
{"body"}
|
||||
),
|
||||
(
|
||||
"__ret and __ret.status",
|
||||
["#__x_00__|__name__|'__ret'", "#__x_01__|__name__|'__ret.status'"],
|
||||
{"__ret", "__ret.status"}
|
||||
),
|
||||
])
|
||||
def test_i_can_get_rete_conditions(self, expression, expected_as_str, expected_variables):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
parser = ExpressionParser()
|
||||
expected = get_rete_conditions(*expected_as_str)
|
||||
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(expression)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
visitor = ReteConditionExprVisitor(context)
|
||||
conditions = visitor.get_conditions(parsed)
|
||||
|
||||
assert conditions == [expected]
|
||||
|
||||
# check against a Rete network
|
||||
network = ReteNetwork()
|
||||
rule = Rule("test", expression, None)
|
||||
rule.metadata.id = 9999
|
||||
rule.metadata.is_compiled = True
|
||||
rule.metadata.is_enabled = True
|
||||
rule.rete_disjunctions = conditions
|
||||
network.add_rule(rule)
|
||||
|
||||
return_value = ReturnValueConcept("Test", True, None)
|
||||
if "__ret" in expected_variables:
|
||||
network.add_obj("__ret", return_value)
|
||||
if "__ret.status" in expected_variables:
|
||||
network.add_obj("__ret.status", return_value.status)
|
||||
if "body" in expected_variables:
|
||||
network.add_obj("body", return_value.body)
|
||||
|
||||
matches = list(network.matches)
|
||||
assert len(matches) == 1
|
||||
|
||||
def test_i_can_get_rete_conditions_when_no_attribute(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
expression = "a == 10"
|
||||
expected_as_str = ["#__x_00__|__name__|'a'", "#__x_00__|__self__|10"]
|
||||
parser = ExpressionParser()
|
||||
expected = get_rete_conditions(*expected_as_str)
|
||||
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(expression)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
visitor = ReteConditionExprVisitor(context)
|
||||
conditions = visitor.get_conditions(parsed)
|
||||
|
||||
assert conditions == [expected]
|
||||
|
||||
# check against a Rete network
|
||||
network = ReteNetwork()
|
||||
rule = Rule("test", expression, None)
|
||||
rule.metadata.id = 9999
|
||||
rule.metadata.is_compiled = True
|
||||
rule.metadata.is_enabled = True
|
||||
rule.rete_disjunctions = conditions
|
||||
network.add_rule(rule)
|
||||
|
||||
network.add_obj("a", 10)
|
||||
matches = list(network.matches)
|
||||
assert len(matches) == 1
|
||||
|
||||
@pytest.mark.skip("No ready yet for SheerkaFilterCondition")
|
||||
def test_i_can_get_rete_conditions_when_function(self):
|
||||
sheerka, context, greetings = self.init_test().with_concepts(
|
||||
@@ -652,235 +514,6 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
|
||||
# matches = list(network.matches)
|
||||
# assert len(matches) == 1
|
||||
|
||||
@pytest.mark.parametrize("test_name, expression, variable_name, expected_as_str", [
|
||||
(
|
||||
"recognize by name",
|
||||
"recognize(__ret.body, greetings)",
|
||||
None,
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|name|'greetings'"]
|
||||
),
|
||||
(
|
||||
"recognize by id",
|
||||
"recognize(__ret.body, c:|1001:)",
|
||||
None,
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|id|'1001'"]
|
||||
),
|
||||
(
|
||||
"recognize by name using c_str",
|
||||
"recognize(__ret.body, c:greetings:)",
|
||||
None,
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|name|'greetings'"]
|
||||
),
|
||||
(
|
||||
"recognize by name and add other conditions (str)",
|
||||
"recognize(__ret.body, greetings) and __ret.body.a == 'my friend'",
|
||||
"my friend",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|name|'greetings'",
|
||||
"#__x_01__|a|'my friend'"]
|
||||
),
|
||||
(
|
||||
"recognize by name and add other conditions (sheerka)",
|
||||
"recognize(__ret.body, greetings) and __ret.body.a == sheerka",
|
||||
"sheerka",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|name|'greetings'",
|
||||
"#__x_01__|a|'__sheerka__'"]
|
||||
),
|
||||
(
|
||||
"recognize by name and add other conditions (concept)",
|
||||
"recognize(__ret.body, greetings) and __ret.body.a == foo",
|
||||
"foo",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|name|'greetings'",
|
||||
"#__x_01__|a|#__x_02__",
|
||||
"#__x_02__|__is_concept__|True",
|
||||
"#__x_02__|key|'foo'"]
|
||||
),
|
||||
(
|
||||
"recognize by instance",
|
||||
"recognize(__ret.body, hello sheerka)",
|
||||
"sheerka",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|key|'hello __var__0'",
|
||||
"#__x_01__|a|'__sheerka__'"]
|
||||
),
|
||||
(
|
||||
"recognize by instance",
|
||||
"recognize(__ret.body, hello 'my friend')",
|
||||
"my friend",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|key|'hello __var__0'",
|
||||
"#__x_01__|a|'my friend'"]
|
||||
),
|
||||
(
|
||||
"recognize by instance",
|
||||
"recognize(__ret.body, hello foo)",
|
||||
"foo",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|key|'hello __var__0'",
|
||||
"#__x_01__|a|#__x_02__",
|
||||
"#__x_02__|__is_concept__|True",
|
||||
"#__x_02__|key|'foo'",
|
||||
]
|
||||
),
|
||||
(
|
||||
"recognize by instance when long concept",
|
||||
"recognize(__ret.body, hello my best friend)",
|
||||
"my best friend",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|key|'hello __var__0'",
|
||||
"#__x_01__|a|#__x_02__",
|
||||
"#__x_02__|__is_concept__|True",
|
||||
"#__x_02__|key|'my best friend'",
|
||||
]
|
||||
),
|
||||
])
|
||||
def test_i_can_get_rete_using_recognize_function(self, test_name, expression, variable_name, expected_as_str):
|
||||
sheerka, context, greetings, foo, my_best_friend = self.init_test().with_concepts(
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
Concept("foo"),
|
||||
Concept("my best friend"),
|
||||
create_new=True
|
||||
).unpack()
|
||||
parser = ExpressionParser()
|
||||
expected = get_rete_conditions(*expected_as_str)
|
||||
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(expression)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
visitor = ReteConditionExprVisitor(context)
|
||||
conditions = visitor.get_conditions(parsed)
|
||||
|
||||
assert conditions == [expected]
|
||||
|
||||
# check against a Rete network
|
||||
network = ReteNetwork()
|
||||
rule = Rule("test", expression, None)
|
||||
rule.metadata.id = 9999
|
||||
rule.metadata.is_compiled = True
|
||||
rule.metadata.is_enabled = True
|
||||
rule.rete_disjunctions = conditions
|
||||
network.add_rule(rule)
|
||||
|
||||
variable_map = {
|
||||
"foo": foo,
|
||||
"my best friend": my_best_friend,
|
||||
"sheerka": sheerka
|
||||
}
|
||||
variable = variable_map.get(variable_name, variable_name)
|
||||
to_recognize = sheerka.new_from_template(greetings, greetings.key, a=variable)
|
||||
network.add_obj("__ret", ReturnValueConcept("Test", True, to_recognize))
|
||||
matches = list(network.matches)
|
||||
assert len(matches) == 1
|
||||
|
||||
@pytest.mark.parametrize("expression, variable_name, expected_as_str", [
|
||||
(
|
||||
"greetings",
|
||||
None,
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|name|'greetings'"]
|
||||
),
|
||||
(
|
||||
"c:|1001:",
|
||||
None,
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|id|'1001'"]
|
||||
),
|
||||
(
|
||||
"hello foo",
|
||||
"foo",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|key|'hello __var__0'",
|
||||
"#__x_01__|a|#__x_02__",
|
||||
"#__x_02__|__is_concept__|True",
|
||||
"#__x_02__|key|'foo'",
|
||||
]
|
||||
),
|
||||
(
|
||||
"hello my best friend",
|
||||
"my best friend",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
"#__x_00__|body|#__x_01__",
|
||||
"#__x_01__|__is_concept__|True",
|
||||
"#__x_01__|key|'hello __var__0'",
|
||||
"#__x_01__|a|#__x_02__",
|
||||
"#__x_02__|__is_concept__|True",
|
||||
"#__x_02__|key|'my best friend'",
|
||||
]
|
||||
),
|
||||
])
|
||||
def test_i_can_get_rete_when_a_concept_is_recognized(self, expression, variable_name, expected_as_str):
|
||||
sheerka, context, greetings, foo, my_best_friend = self.init_test().with_concepts(
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
Concept("foo"),
|
||||
Concept("my best friend"),
|
||||
create_new=True
|
||||
).unpack()
|
||||
parser = ExpressionParser()
|
||||
expected = get_rete_conditions(*expected_as_str)
|
||||
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(expression)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
visitor = ReteConditionExprVisitor(context)
|
||||
conditions = visitor.get_conditions(parsed)
|
||||
|
||||
assert conditions == [expected]
|
||||
|
||||
# check against a Rete network
|
||||
network = ReteNetwork()
|
||||
rule = Rule("test", expression, None)
|
||||
rule.metadata.id = 9999
|
||||
rule.metadata.is_compiled = True
|
||||
rule.metadata.is_enabled = True
|
||||
rule.rete_disjunctions = conditions
|
||||
network.add_rule(rule)
|
||||
|
||||
variable_map = {
|
||||
"foo": foo,
|
||||
"my best friend": my_best_friend,
|
||||
"sheerka": sheerka
|
||||
}
|
||||
variable = variable_map.get(variable_name, variable_name)
|
||||
to_recognize = sheerka.new_from_template(greetings, greetings.key, a=variable)
|
||||
network.add_obj("__ret", ReturnValueConcept("Test", True, to_recognize))
|
||||
matches = list(network.matches)
|
||||
assert len(matches) == 1
|
||||
|
||||
@pytest.mark.parametrize("expression, bag_key, expected", [
|
||||
("not __ret", "__other", [NEGCOND("#__x_00__|__name__|'__ret'")]),
|
||||
("not not __ret", "__ret", ["#__x_00__|__name__|'__ret'"]),
|
||||
@@ -894,6 +527,10 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
|
||||
"#__x_01__|key|'hello __var__0'",
|
||||
"#__x_01__|a|'__sheerka__'"])]),
|
||||
("__ret and not __error", "__ret", ["#__x_00__|__name__|'__ret'", NEGCOND("#__x_01__|__name__|'__error'")]),
|
||||
("not recognize(self, hello sheerka)", "__ret", ["#__x_00__|__name__|'self'",
|
||||
NCCOND(["#__x_00__|__is_concept__|True",
|
||||
"#__x_00__|key|'hello __var__0'",
|
||||
"#__x_00__|a|'__sheerka__'"])]),
|
||||
])
|
||||
def test_i_can_get_rete_using_not(self, expression, bag_key, expected):
|
||||
sheerka, context, greetings, foo = self.init_test().with_concepts(
|
||||
@@ -914,7 +551,7 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
|
||||
assert conditions == [expected_conditions]
|
||||
|
||||
@pytest.mark.skip("I am not sure yet of what I want to get")
|
||||
@pytest.mark.parametrize("expression, expected_as_str", [
|
||||
@pytest.mark.parametrize("expression, expected_as_list_of_str", [
|
||||
(
|
||||
"eval(__ret.body, 'foo' starts with 'f')",
|
||||
["#__x_00__|__name__|'__ret'",
|
||||
@@ -926,7 +563,7 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
|
||||
"$eval(__x_01__, a, b, c)"]
|
||||
),
|
||||
])
|
||||
def test_i_can_get_rete_conditions_using_eval_function(self, expression, expected_as_str):
|
||||
def test_i_can_get_rete_conditions_using_eval_function(self, expression, expected_as_list_of_str):
|
||||
sheerka, context, start_with = self.init_test().with_concepts(
|
||||
Concept("x starts with y",
|
||||
pre="is_question",
|
||||
@@ -935,7 +572,7 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
|
||||
).unpack()
|
||||
|
||||
parser = ExpressionParser()
|
||||
expected = get_rete_conditions(*expected_as_str)
|
||||
expected = get_rete_conditions(*expected_as_list_of_str)
|
||||
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(expression)
|
||||
@@ -961,372 +598,6 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
|
||||
matches = list(network.matches)
|
||||
assert len(matches) == 1
|
||||
|
||||
@pytest.mark.parametrize("expression, expected_compiled, expected_variables", [
|
||||
("__ret", None, {"__ret"}),
|
||||
("__ret.status == True", "__ret.status == True", {"__ret"}),
|
||||
("__ret.status", None, {"__ret.status"}),
|
||||
("body", None, {"body"}),
|
||||
("__ret and __ret.status", None, {"__ret", "__ret.status"})
|
||||
])
|
||||
def test_i_can_get_compiled_conditions(self, expression, expected_compiled, expected_variables):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
parser = ExpressionParser()
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(expression)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
visitor = PythonConditionExprVisitor(context)
|
||||
conditions = visitor.get_conditions(parsed)
|
||||
|
||||
assert len(conditions) == 1
|
||||
assert isinstance(conditions[0], CompiledCondition)
|
||||
if expected_compiled:
|
||||
ast_ = ast.parse(expected_compiled, "<source>", 'eval')
|
||||
expected_python_node = PythonNode(expected_compiled, ast_)
|
||||
assert conditions[0].evaluator_type == PYTHON_EVALUATOR_NAME
|
||||
assert sheerka.isinstance(conditions[0].return_value, BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.objvalue(conditions[0].return_value) == expected_python_node
|
||||
else:
|
||||
assert conditions[0].evaluator_type is None
|
||||
assert conditions[0].return_value is None
|
||||
assert conditions[0].concept is None
|
||||
assert conditions[0].variables == expected_variables
|
||||
|
||||
# check against SheerkaEvaluateRules
|
||||
evaluate_rules_service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
return_value = ReturnValueConcept("Test", True, None)
|
||||
bag = {}
|
||||
if "__ret" in expected_variables:
|
||||
bag["__ret"] = return_value
|
||||
if "__ret.status" in expected_variables:
|
||||
bag["__ret.status"] = return_value.status
|
||||
if "body" in expected_variables:
|
||||
bag["body"] = return_value.body
|
||||
with context.push(BuiltinConcepts.RULES_EVALUATION, bag, desc="Evaluating rules...") as sub_context:
|
||||
sub_context.sheerka.add_many_to_short_term_memory(sub_context, bag)
|
||||
rule = Rule(name="test_i_can_get_compiled_conditions", predicate=expression)
|
||||
rule.compiled_conditions = conditions
|
||||
res = evaluate_rules_service.evaluate_rule(sub_context, rule, bag)
|
||||
assert res.status
|
||||
assert self.sheerka.is_success(self.sheerka.objvalue(res))
|
||||
|
||||
def test_i_can_get_compiled_conditions_when_no_attribute(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
expression = "a == 10"
|
||||
expected_compiled = "a == 10"
|
||||
|
||||
parser = ExpressionParser()
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(expression)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
visitor = PythonConditionExprVisitor(context)
|
||||
conditions = visitor.get_conditions(parsed)
|
||||
|
||||
assert len(conditions) == 1
|
||||
assert isinstance(conditions[0], CompiledCondition)
|
||||
ast_ = ast.parse(expected_compiled, "<source>", 'eval')
|
||||
expected_python_node = PythonNode(expected_compiled, ast_)
|
||||
assert conditions[0].evaluator_type == PYTHON_EVALUATOR_NAME
|
||||
assert sheerka.isinstance(conditions[0].return_value, BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.objvalue(conditions[0].return_value) == expected_python_node
|
||||
assert conditions[0].concept is None
|
||||
assert conditions[0].variables == {"a"}
|
||||
|
||||
# check against SheerkaEvaluateRules
|
||||
evaluate_rules_service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
bag = {"a": 10}
|
||||
with context.push(BuiltinConcepts.RULES_EVALUATION, bag, desc="Evaluating rules...") as sub_context:
|
||||
sub_context.sheerka.add_many_to_short_term_memory(sub_context, bag)
|
||||
rule = Rule(name="test_i_can_get_compiled_conditions", predicate=expression)
|
||||
rule.compiled_conditions = conditions
|
||||
res = evaluate_rules_service.evaluate_rule(sub_context, rule, bag)
|
||||
assert res.status
|
||||
assert self.sheerka.is_success(self.sheerka.objvalue(res))
|
||||
|
||||
def test_i_can_get_compiled_conditions_when_function(self):
|
||||
sheerka, context, greetings = self.init_test().with_concepts(
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
).unpack()
|
||||
expression = "isinstance(a, greetings)"
|
||||
expected_compiled = "isinstance(a, greetings)"
|
||||
|
||||
parser = ExpressionParser()
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(expression)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
visitor = PythonConditionExprVisitor(context)
|
||||
conditions = visitor.get_conditions(parsed)
|
||||
|
||||
assert len(conditions) == 1
|
||||
assert isinstance(conditions[0], CompiledCondition)
|
||||
ast_ = ast.parse(expected_compiled, "<source>", 'eval')
|
||||
expected_python_node = PythonNode(expected_compiled, ast_)
|
||||
assert conditions[0].evaluator_type == PYTHON_EVALUATOR_NAME
|
||||
assert sheerka.isinstance(conditions[0].return_value, BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.objvalue(conditions[0].return_value) == expected_python_node
|
||||
assert conditions[0].concept is None
|
||||
assert conditions[0].variables == {"a"}
|
||||
|
||||
# check against SheerkaEvaluateRules
|
||||
evaluate_rules_service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
bag = {"a": sheerka.new(greetings, a="my friend")}
|
||||
with context.push(BuiltinConcepts.RULES_EVALUATION, bag, desc="Evaluating rules...") as sub_context:
|
||||
sub_context.sheerka.add_many_to_short_term_memory(sub_context, bag)
|
||||
rule = Rule(name="test_i_can_get_compiled_conditions", predicate=expression)
|
||||
rule.compiled_conditions = conditions
|
||||
res = evaluate_rules_service.evaluate_rule(sub_context, rule, bag)
|
||||
assert res.status
|
||||
assert self.sheerka.is_success(self.sheerka.objvalue(res))
|
||||
|
||||
@pytest.mark.parametrize("expression, variable_name, expected_compiled", [
|
||||
(
|
||||
"recognize(__ret.body, greetings)",
|
||||
None,
|
||||
"__x_00__ = __ret.body\nisinstance(__x_00__, Concept) and __x_00__.name == 'greetings'"
|
||||
),
|
||||
(
|
||||
"recognize(__ret.body, c:|1001:)",
|
||||
None,
|
||||
"__x_00__ = __ret.body\nisinstance(__x_00__, Concept) and __x_00__.id == '1001'"
|
||||
),
|
||||
(
|
||||
"recognize(__ret.body, c:greetings:)",
|
||||
None,
|
||||
"__x_00__ = __ret.body\nisinstance(__x_00__, Concept) and __x_00__.name == 'greetings'"
|
||||
),
|
||||
(
|
||||
"recognize(__ret.body, greetings) and __ret.body.a == 'my friend'",
|
||||
"my friend",
|
||||
"__x_00__ = __ret.body\nisinstance(__x_00__, Concept) and __x_00__.name == 'greetings' and __x_00__.a == 'my friend'"
|
||||
),
|
||||
(
|
||||
"recognize(__ret.body, greetings) and __ret.body.a == sheerka",
|
||||
"sheerka",
|
||||
"""__x_00__ = __ret.body
|
||||
isinstance(__x_00__, Concept) and __x_00__.name == 'greetings' and is_sheerka(__x_00__.a)"""
|
||||
),
|
||||
(
|
||||
"recognize(__ret.body, greetings) and __ret.body.a == foo",
|
||||
"foo",
|
||||
"""__x_00__ = __ret.body
|
||||
__x_01__ = __x_00__.a
|
||||
isinstance(__x_00__, Concept) and __x_00__.name == 'greetings' and isinstance(__x_01__, Concept) and __x_01__.key == 'foo'"""
|
||||
),
|
||||
(
|
||||
"recognize(__ret.body, hello sheerka)",
|
||||
"sheerka",
|
||||
"""__x_00__ = __ret.body
|
||||
isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and is_sheerka(__x_00__.a)"""
|
||||
),
|
||||
(
|
||||
"recognize(__ret.body, hello 'my friend')",
|
||||
"my friend",
|
||||
"""__x_00__ = __ret.body
|
||||
isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and __x_00__.a == 'my friend'"""
|
||||
),
|
||||
(
|
||||
"recognize(__ret.body, hello foo)",
|
||||
"foo",
|
||||
"""__x_00__ = __ret.body
|
||||
__x_01__ = __x_00__.a
|
||||
isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and isinstance(__x_01__, Concept) and __x_01__.key == 'foo'"""
|
||||
),
|
||||
(
|
||||
"recognize(__ret.body, hello my best friend)",
|
||||
"my best friend",
|
||||
"""__x_00__ = __ret.body
|
||||
__x_01__ = __x_00__.a
|
||||
isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and isinstance(__x_01__, Concept) and __x_01__.key == 'my best friend'"""
|
||||
),
|
||||
|
||||
])
|
||||
def test_i_can_get_compiled_using_recognize_function(self, expression, variable_name, expected_compiled):
|
||||
sheerka, context, greetings, foo, my_best_friend = self.init_test().with_concepts(
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
Concept("foo"),
|
||||
Concept("my best friend"),
|
||||
create_new=True
|
||||
).unpack()
|
||||
|
||||
parser = ExpressionParser()
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(expression)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
visitor = PythonConditionExprVisitor(context)
|
||||
conditions = visitor.get_conditions(parsed)
|
||||
|
||||
assert len(conditions) == 1
|
||||
assert isinstance(conditions[0], CompiledCondition)
|
||||
if expected_compiled:
|
||||
ast_ = ast.parse(expected_compiled, "<source>", 'exec')
|
||||
expected_python_node = PythonNode(expected_compiled, ast_, expected_compiled)
|
||||
assert conditions[0].evaluator_type == PYTHON_EVALUATOR_NAME
|
||||
assert sheerka.isinstance(conditions[0].return_value, BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.objvalue(conditions[0].return_value) == expected_python_node
|
||||
else:
|
||||
assert conditions[0].evaluator_type is None
|
||||
assert conditions[0].return_value is None
|
||||
assert conditions[0].concept is None
|
||||
assert conditions[0].variables == {"__ret"}
|
||||
|
||||
# check against SheerkaEvaluateRules
|
||||
evaluate_rules_service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
variable_map = {
|
||||
"foo": foo,
|
||||
"my best friend": my_best_friend,
|
||||
"sheerka": Expando("sheerka", {})
|
||||
}
|
||||
variable = variable_map.get(variable_name, variable_name)
|
||||
to_recognize = sheerka.new_from_template(greetings, greetings.key, a=variable)
|
||||
bag = {"__ret": ReturnValueConcept("Test", True, to_recognize)}
|
||||
with context.push(BuiltinConcepts.RULES_EVALUATION, bag, desc="Evaluating rules...") as sub_context:
|
||||
sub_context.sheerka.add_many_to_short_term_memory(sub_context, bag)
|
||||
rule = Rule(name="test_i_can_get_compiled_using_recognize_function", predicate=expression)
|
||||
rule.compiled_conditions = conditions
|
||||
res = evaluate_rules_service.evaluate_rule(sub_context, rule, bag)
|
||||
assert res.status
|
||||
assert self.sheerka.is_success(self.sheerka.objvalue(res))
|
||||
|
||||
@pytest.mark.parametrize("expression, variable_name, expected_compiled", [
|
||||
(
|
||||
"greetings",
|
||||
None,
|
||||
"__x_00__ = __ret.body\nisinstance(__x_00__, Concept) and __x_00__.name == 'greetings'"
|
||||
),
|
||||
(
|
||||
"c:|1001:",
|
||||
None,
|
||||
"__x_00__ = __ret.body\nisinstance(__x_00__, Concept) and __x_00__.id == '1001'"
|
||||
),
|
||||
(
|
||||
"hello foo",
|
||||
"foo",
|
||||
"""__x_00__ = __ret.body
|
||||
__x_01__ = __x_00__.a
|
||||
isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and isinstance(__x_01__, Concept) and __x_01__.key == 'foo'"""
|
||||
),
|
||||
(
|
||||
"hello my best friend",
|
||||
"my best friend",
|
||||
"""__x_00__ = __ret.body
|
||||
__x_01__ = __x_00__.a
|
||||
isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and isinstance(__x_01__, Concept) and __x_01__.key == 'my best friend'"""
|
||||
),
|
||||
])
|
||||
def test_i_can_get_compiled_when_a_concept_is_recognized(self, expression, variable_name, expected_compiled):
|
||||
sheerka, context, greetings, foo, my_best_friend = self.init_test().with_concepts(
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
Concept("foo"),
|
||||
Concept("my best friend"),
|
||||
create_new=True
|
||||
).unpack()
|
||||
|
||||
parser = ExpressionParser()
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(expression)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
visitor = PythonConditionExprVisitor(context)
|
||||
conditions = visitor.get_conditions(parsed)
|
||||
|
||||
assert len(conditions) == 1
|
||||
assert isinstance(conditions[0], CompiledCondition)
|
||||
if expected_compiled:
|
||||
ast_ = ast.parse(expected_compiled, "<source>", 'exec')
|
||||
expected_python_node = PythonNode(expected_compiled, ast_, expected_compiled)
|
||||
assert conditions[0].evaluator_type == PYTHON_EVALUATOR_NAME
|
||||
assert sheerka.isinstance(conditions[0].return_value, BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.objvalue(conditions[0].return_value) == expected_python_node
|
||||
else:
|
||||
assert conditions[0].evaluator_type is None
|
||||
assert conditions[0].return_value is None
|
||||
assert conditions[0].concept is None
|
||||
assert conditions[0].variables == {"__ret"}
|
||||
|
||||
# check against SheerkaEvaluateRules
|
||||
evaluate_rules_service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
variable_map = {
|
||||
"foo": foo,
|
||||
"my best friend": my_best_friend,
|
||||
"sheerka": Expando("sheerka", {})
|
||||
}
|
||||
variable = variable_map.get(variable_name, variable_name)
|
||||
to_recognize = sheerka.new_from_template(greetings, greetings.key, a=variable)
|
||||
bag = {"__ret": ReturnValueConcept("Test", True, to_recognize)}
|
||||
with context.push(BuiltinConcepts.RULES_EVALUATION, bag, desc="Evaluating rules...") as sub_context:
|
||||
sub_context.sheerka.add_many_to_short_term_memory(sub_context, bag)
|
||||
rule = Rule(name="test_i_can_get_compiled_using_recognize_function", predicate=expression)
|
||||
rule.compiled_conditions = conditions
|
||||
res = evaluate_rules_service.evaluate_rule(sub_context, rule, bag)
|
||||
assert res.status
|
||||
assert self.sheerka.is_success(self.sheerka.objvalue(res))
|
||||
|
||||
@pytest.mark.parametrize("expression, expected_compiled, variables, not_variables", [
|
||||
("not __ret", None, set(), {"__ret"}),
|
||||
("not not __ret", None, {"__ret"}, set()),
|
||||
("not __ret.status == True", "not (__ret.status == True)", {"__ret"}, set()),
|
||||
("not __ret.status", None, set(), {"__ret.status"},),
|
||||
("__ret and not __ret.status", None, {"__ret"}, {"__ret.status"}),
|
||||
("not recognize(__ret.body, hello sheerka)", """__x_00__ = __ret.body
|
||||
not (isinstance(__x_00__, Concept) and __x_00__.key == 'hello __var__0' and is_sheerka(__x_00__.a))""", {"__ret"},
|
||||
set()),
|
||||
("__ret and not __error", None, {"__ret"}, {"__error"}),
|
||||
])
|
||||
def test_i_can_get_compiled_condition_using_not(self, expression, expected_compiled, variables, not_variables):
|
||||
sheerka, context, greetings, foo = self.init_test().with_concepts(
|
||||
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
|
||||
Concept("foo"),
|
||||
).unpack()
|
||||
|
||||
parser = ExpressionParser()
|
||||
error_sink = ErrorSink()
|
||||
parser_input = ParserInput(expression)
|
||||
parser.reset_parser_input(parser_input, error_sink)
|
||||
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||
|
||||
visitor = PythonConditionExprVisitor(context)
|
||||
conditions = visitor.get_conditions(parsed)
|
||||
|
||||
assert len(conditions) == 1
|
||||
assert isinstance(conditions[0], CompiledCondition)
|
||||
if expected_compiled:
|
||||
if "\n" in expected_compiled:
|
||||
ast_ = ast.parse(expected_compiled, "<source>", 'exec')
|
||||
else:
|
||||
ast_ = ast.parse(expected_compiled, "<source>", 'eval')
|
||||
expected_python_node = PythonNode(expected_compiled, ast_)
|
||||
assert conditions[0].evaluator_type == PYTHON_EVALUATOR_NAME
|
||||
assert sheerka.isinstance(conditions[0].return_value, BuiltinConcepts.RETURN_VALUE)
|
||||
assert sheerka.objvalue(conditions[0].return_value) == expected_python_node
|
||||
|
||||
else:
|
||||
assert conditions[0].evaluator_type is None
|
||||
assert conditions[0].return_value is None
|
||||
assert conditions[0].variables == variables
|
||||
assert conditions[0].not_variables == not_variables
|
||||
assert conditions[0].concept is None
|
||||
|
||||
# check against SheerkaEvaluateRules
|
||||
evaluate_rules_service = sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
ret_val_key = "__ret" if "__ret" in conditions[0].variables else "__other"
|
||||
bag = {ret_val_key: ReturnValueConcept("Test", False, None)}
|
||||
with context.push(BuiltinConcepts.RULES_EVALUATION, bag, desc="Evaluating rules...") as sub_context:
|
||||
sub_context.sheerka.add_many_to_short_term_memory(sub_context, bag)
|
||||
rule = Rule(name="test_i_can_get_compiled_conditions", predicate=expression)
|
||||
rule.compiled_conditions = conditions
|
||||
res = evaluate_rules_service.evaluate_rule(sub_context, rule, bag)
|
||||
assert res.status
|
||||
assert self.sheerka.is_success(self.sheerka.objvalue(res))
|
||||
|
||||
|
||||
class TestSheerkaRuleManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
|
||||
def test_rules_are_initialized_at_startup(self):
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -182,6 +182,17 @@ class TestBuiltinHelpers(TestUsingMemoryBasedSheerka):
|
||||
concept = Concept("foo", pre=pre)
|
||||
assert core.builtin_helpers.is_a_question(context, concept) == expected
|
||||
|
||||
def test_context_hints_are_reset_when_call_evaluate_from_source(self):
|
||||
sheerka, context, one = self.init_concepts(Concept("one", body="1"))
|
||||
context.add_to_global_hints(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
context.add_to_protected_hints(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
context.add_to_private_hints(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
|
||||
res = core.builtin_helpers.evaluate_from_source(context, "one", eval_body=False)
|
||||
|
||||
evaluated = [r for r in res if r.status][0].body
|
||||
assert evaluated.body is NotInit
|
||||
|
||||
# @pytest.mark.parametrize("return_values", [
|
||||
# None,
|
||||
# []
|
||||
|
||||
+12
-12
@@ -439,27 +439,27 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_get_error_for_simple_objects(self, obj, expected):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
assert sheerka.get_errors(obj) == expected
|
||||
assert sheerka.get_errors(context, obj) == expected
|
||||
|
||||
def test_i_can_get_error_when_builtin_concept_in_error(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
obj = sheerka.new(BuiltinConcepts.ONTOLOGY_ALREADY_DEFINED)
|
||||
assert sheerka.get_errors(obj) == [obj]
|
||||
assert sheerka.get_errors(context, obj) == [obj]
|
||||
|
||||
def test_i_can_get_error_when_return_value(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
error = sheerka.err("an error")
|
||||
ret_val = ReturnValueConcept("Test", False, sheerka.err("an error"))
|
||||
assert sheerka.get_errors(ret_val) == [error]
|
||||
assert sheerka.get_errors(context, ret_val) == [error]
|
||||
|
||||
def test_i_can_get_inner_error(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
error = sheerka.err("an error")
|
||||
ret_val = ReturnValueConcept("Test", False, sheerka.err("an error"))
|
||||
assert sheerka.get_errors(ret_val) == [error]
|
||||
assert sheerka.get_errors(context, ret_val) == [error]
|
||||
|
||||
def test_i_can_get_error_when_embedded_errors(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
@@ -470,7 +470,7 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
||||
error = sheerka.err([concept_eval_error, unknown_concept, not_an_error])
|
||||
|
||||
ret_val = ReturnValueConcept("Test", False, error)
|
||||
errors_found = sheerka.get_errors(ret_val)
|
||||
errors_found = sheerka.get_errors(context, ret_val)
|
||||
|
||||
assert errors_found == [error, concept_eval_error, unknown_concept]
|
||||
|
||||
@@ -488,7 +488,7 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
||||
multiple_error = sheerka.new(BuiltinConcepts.MULTIPLE_ERRORS, body=[python_error, value_not_found])
|
||||
ret_val_2 = ReturnValueConcept("Test", False, multiple_error)
|
||||
|
||||
errors_found = sheerka.get_errors([ret_val_1, ret_val_2])
|
||||
errors_found = sheerka.get_errors(context, [ret_val_1, ret_val_2])
|
||||
|
||||
assert errors_found == [error, concept_eval_error, unknown_concept,
|
||||
multiple_error, python_error, value_not_found]
|
||||
@@ -502,7 +502,7 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
||||
error = sheerka.err([concept_eval_error, unknown_concept, python_error])
|
||||
ret_val = ReturnValueConcept("Test", False, error)
|
||||
|
||||
errors_found = sheerka.get_errors(ret_val, __type=BuiltinConcepts.CONCEPT_EVAL_ERROR)
|
||||
errors_found = sheerka.get_errors(context, ret_val, __type=BuiltinConcepts.CONCEPT_EVAL_ERROR)
|
||||
assert errors_found == [concept_eval_error]
|
||||
|
||||
def test_i_can_filter_error_by_class_name(self):
|
||||
@@ -514,7 +514,7 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
||||
error = sheerka.err([concept_eval_error, unknown_concept, python_error])
|
||||
ret_val = ReturnValueConcept("Test", False, error)
|
||||
|
||||
errors_found = sheerka.get_errors(ret_val, __type="PythonErrorNode")
|
||||
errors_found = sheerka.get_errors(context, ret_val, __type="PythonErrorNode")
|
||||
assert errors_found == [python_error]
|
||||
|
||||
def test_i_can_filter_error_by_concept_attribute(self):
|
||||
@@ -526,7 +526,7 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
||||
error = sheerka.err([concept_eval_error, unknown_concept, python_error])
|
||||
ret_val = ReturnValueConcept("Test", False, error)
|
||||
|
||||
errors_found = sheerka.get_errors(ret_val, concept_ref="a_concept_ref")
|
||||
errors_found = sheerka.get_errors(context, ret_val, concept_ref="a_concept_ref")
|
||||
assert errors_found == [unknown_concept]
|
||||
|
||||
def test_i_can_filter_error_by_class_attribute(self):
|
||||
@@ -538,7 +538,7 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
||||
error = sheerka.err([concept_eval_error, unknown_concept, python_error])
|
||||
ret_val = ReturnValueConcept("Test", False, error)
|
||||
|
||||
errors_found = sheerka.get_errors(ret_val, source="error source")
|
||||
errors_found = sheerka.get_errors(context, ret_val, source="error source")
|
||||
assert errors_found == [python_error]
|
||||
|
||||
def test_i_can_filter_error_on_multiple_criteria(self):
|
||||
@@ -550,14 +550,14 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
||||
error = sheerka.err([concept_eval_error, unknown_concept, value_not_found])
|
||||
ret_val = ReturnValueConcept("Test", False, error)
|
||||
|
||||
errors_found = sheerka.get_errors(ret_val, __type="ValueNotFound", item="an_item", value="a value")
|
||||
errors_found = sheerka.get_errors(context, ret_val, __type="ValueNotFound", item="an_item", value="a value")
|
||||
assert errors_found == [value_not_found]
|
||||
|
||||
def test_i_cannot_get_error_when_return_value_s_status_is_true(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
ret_val = ReturnValueConcept("Test", True, sheerka.err("an error"))
|
||||
assert sheerka.get_errors(ret_val) == []
|
||||
assert sheerka.get_errors(context, ret_val) == []
|
||||
|
||||
|
||||
class TestSheerkaUsingFileBasedSheerka(TestUsingFileBasedSheerka):
|
||||
|
||||
@@ -469,3 +469,28 @@ def test_tokens_are_matching_when_eof_differs():
|
||||
tokens2 = Tokenizer(expression2, yield_eof=False)
|
||||
|
||||
assert core.utils.tokens_are_matching(tokens1, tokens2)
|
||||
|
||||
|
||||
def test_sheerka_hasattr_get_attr():
|
||||
class A:
|
||||
def __init__(self, property_value):
|
||||
self.property_value = property_value
|
||||
|
||||
def as_bag(self):
|
||||
return {"prop": self.property_value}
|
||||
|
||||
# test object with bag
|
||||
a = A("foo")
|
||||
assert core.utils.sheerka_hasattr(a, "prop")
|
||||
assert core.utils.sheerka_getattr(a, "prop") == "foo"
|
||||
assert not core.utils.sheerka_hasattr(a, "property_value")
|
||||
with pytest.raises(AttributeError):
|
||||
core.utils.sheerka_getattr(a, "property_value")
|
||||
|
||||
# test for concept
|
||||
concept = Concept("foo").def_var("a", "value").auto_init()
|
||||
assert core.utils.sheerka_hasattr(concept, "a")
|
||||
assert core.utils.sheerka_getattr(concept, "a") == "value"
|
||||
assert not core.utils.sheerka_hasattr(concept, "b")
|
||||
with pytest.raises(AttributeError):
|
||||
core.utils.sheerka_getattr(concept, "b")
|
||||
|
||||
@@ -2,13 +2,14 @@ import ast
|
||||
|
||||
import pytest
|
||||
|
||||
from core.ast_helpers import NamesWithAttributesVisitor
|
||||
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
|
||||
from core.builtin_helpers import CreateObjectIdentifiers
|
||||
from core.concept import Concept
|
||||
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Tokenizer
|
||||
from evaluators.PythonEvaluator import PythonEvaluator, PythonEvalError, NamesWithAttributesVisitor
|
||||
from evaluators.PythonEvaluator import PythonEvaluator, PythonEvalError
|
||||
from parsers.BaseNodeParser import SourceCodeNode, SourceCodeWithConceptNode
|
||||
from parsers.FunctionParser import FunctionParser
|
||||
from parsers.PythonParser import PythonNode, PythonParser
|
||||
@@ -386,6 +387,16 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert evaluated.status
|
||||
assert evaluated.value == context.sheerka.get_rule_by_id(str(value)).name
|
||||
|
||||
def test_i_cannot_call_methods_with_side_effect_when_is_question_is_set(self):
|
||||
sheerka, context, foo, bar = self.init_concepts("foo", "bar")
|
||||
context.add_to_protected_hints(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
|
||||
parsed = PythonParser().parse(context, ParserInput("set_isa(foo, bar)"))
|
||||
python_evaluator = PythonEvaluator()
|
||||
evaluated = python_evaluator.eval(context, parsed)
|
||||
|
||||
assert sheerka.has_error(context, evaluated, __type="MethodAccessError")
|
||||
|
||||
def test_something(self):
|
||||
def func(**kwargs):
|
||||
for k, v in kwargs.items():
|
||||
|
||||
@@ -7,6 +7,7 @@ from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
|
||||
from evaluators.OneSuccessEvaluator import OneSuccessEvaluator
|
||||
from evaluators.PythonEvaluator import PythonEvalError
|
||||
from sheerkapython.python_wrapper import MethodAccessError
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
from tests.parsers.parsers_utils import CMV, CC, compare_with_test_object, CB
|
||||
|
||||
@@ -642,7 +643,7 @@ as:
|
||||
assert res[0].body == 21
|
||||
|
||||
def test_i_can_use_where_in_bnf(self):
|
||||
sheerka = self.get_sheerka()
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
init = [
|
||||
"def concept one as 1",
|
||||
@@ -683,12 +684,12 @@ as:
|
||||
assert len(res) == 1
|
||||
assert not res[0].status
|
||||
assert sheerka.isinstance(res[0].body, BuiltinConcepts.MULTIPLE_ERRORS)
|
||||
assert str(BuiltinConcepts.CONDITION_FAILED) in [error.key for error in sheerka.get_errors(res[0].body.body)]
|
||||
assert sheerka.has_error(context, res, __type=BuiltinConcepts.CONDITION_FAILED)
|
||||
|
||||
res = sheerka.evaluate_user_input("eval twenty three")
|
||||
assert len(res) == 1
|
||||
assert not res[0].status
|
||||
assert str(BuiltinConcepts.CONDITION_FAILED) in [error.key for error in sheerka.get_errors(res[0].body.body)]
|
||||
assert sheerka.has_error(context, res, __type=BuiltinConcepts.CONDITION_FAILED)
|
||||
|
||||
def test_i_can_manage_some_type_of_infinite_recursion(self):
|
||||
sheerka = self.get_sheerka()
|
||||
@@ -1298,6 +1299,7 @@ as:
|
||||
assert sheerka.objvalue(res[0].body.get_value("qty")) == 2
|
||||
|
||||
def test_i_can_implement_the_concept_and(self):
|
||||
# Normally, redefining and leads to a circular ref between the concept and the python
|
||||
init = [
|
||||
"def concept x and y as x and y",
|
||||
"set_is_lesser(__PRECEDENCE, c:x and y:, 'Sya')",
|
||||
@@ -1308,3 +1310,55 @@ as:
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
|
||||
def test_i_can_use_result_from_memory_filtering(self):
|
||||
init = [
|
||||
"def concept female",
|
||||
"def concept girl",
|
||||
"set_isa(girl, female)",
|
||||
"def concept she ret memory('isa(self, female)')",
|
||||
"girl"
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
context = self.get_context(sheerka)
|
||||
|
||||
res = sheerka.evaluate_user_input("set_attr(she, 'my_attr', 'my value')")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
|
||||
girl_from_memory = sheerka.get_last_from_memory(context, "girl")
|
||||
assert girl_from_memory.obj.get_value("my_attr") == "my value"
|
||||
|
||||
def test_i_can_use_result_from_memory_filtering_within_other_concept(self):
|
||||
init = [
|
||||
"def concept female",
|
||||
"def concept girl",
|
||||
"set_isa(girl, female)",
|
||||
"def concept she ret memory('isa(self, female)')",
|
||||
"def concept x attribute y equals z as set_attr(x, y, z)",
|
||||
"girl"
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
context = self.get_context(sheerka)
|
||||
|
||||
res = sheerka.evaluate_user_input("eval she attribute 'my_attr' equals 'my value'")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
|
||||
girl_from_memory = sheerka.get_last_from_memory(context, "girl")
|
||||
assert girl_from_memory.obj.get_value("my_attr") == "my value"
|
||||
|
||||
def test_i_cannot_use_method_that_alter_the_global_state_within_question(self):
|
||||
init = [
|
||||
"def concept foo as question(set_debug(True))",
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
context = self.get_context(sheerka)
|
||||
|
||||
res = sheerka.evaluate_user_input("question(set_debug(True))")
|
||||
assert sheerka.has_error(context, res, __type="MethodAccessError")
|
||||
|
||||
res = sheerka.evaluate_user_input("eval foo")
|
||||
assert sheerka.has_error(context, res, __type="MethodAccessError")
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
class TestSheerkaNonRegPipeFunctions(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_filter_a_list_using_pipe(self):
|
||||
init = [
|
||||
"def concept one as 1",
|
||||
"def concept two as 2",
|
||||
"def concept three as 3",
|
||||
"add_to_memory('x', [one, two, three])"
|
||||
]
|
||||
|
||||
sheerka = self.init_scenario(init)
|
||||
res = sheerka.evaluate_user_input("x | where(body=2)")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert isinstance(res[0].body, list)
|
||||
assert len(res[0].body) == 1
|
||||
assert sheerka.isinstance(res[0].body[0], "two")
|
||||
|
||||
res = sheerka.evaluate_user_input("x | where(__self=two)")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert isinstance(res[0].body, list)
|
||||
assert len(res[0].body) == 1
|
||||
assert sheerka.isinstance(res[0].body[0], "two")
|
||||
|
||||
def test_i_can_filter_using_sheerka_methods(self):
|
||||
init = [
|
||||
"def concept one as 1",
|
||||
"def concept number",
|
||||
"set_isa(one, number)",
|
||||
"add_to_memory('x', [one])"
|
||||
]
|
||||
|
||||
sheerka = self.init_scenario(init)
|
||||
res = sheerka.evaluate_user_input("x | where('isa(self, number)')")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert isinstance(res[0].body, list)
|
||||
assert len(res[0].body) == 1
|
||||
assert sheerka.isinstance(res[0].body[0], "one")
|
||||
|
||||
def test_i_can_select_properties(self):
|
||||
init = [
|
||||
"def concept one as 1",
|
||||
"def concept two as 2",
|
||||
"def concept three as 3",
|
||||
"add_to_memory('x', [one, two, three])"
|
||||
]
|
||||
|
||||
sheerka = self.init_scenario(init)
|
||||
|
||||
res = sheerka.evaluate_user_input("x | select('id', 'name')")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].body == (("1001", "one"), ("1002", "two"), ("1003", "three"))
|
||||
|
||||
res = sheerka.evaluate_user_input("x | select(p1='id', p2='name')")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].body == ({"p1": "1001", "p2": "one"},
|
||||
{"p1": "1002", "p2": "two"},
|
||||
{"p1": "1003", "p2": "three"})
|
||||
|
||||
def test_i_can_collect_properties(self):
|
||||
init = [
|
||||
"def concept one as 1",
|
||||
"def concept isa from x is a y def_var x def_var y",
|
||||
"def concept plus from a plus b as a + b",
|
||||
"add_to_memory('x', [one, isa, plus])"
|
||||
]
|
||||
|
||||
sheerka = self.init_scenario(init)
|
||||
res = sheerka.evaluate_user_input("x | props()")
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].body, BuiltinConcepts.TO_DICT)
|
||||
assert res[0].body.body == {'isa': ['body', 'id', 'key', 'name', 'x', 'y'],
|
||||
'one': ['body', 'id', 'key', 'name'],
|
||||
'plus': ['a', 'b', 'body', 'id', 'key', 'name']}
|
||||
@@ -5,7 +5,7 @@ from evaluators.PythonEvaluator import PythonEvalError
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
class TestSheerkaNonRegDisplay(TestUsingMemoryBasedSheerka):
|
||||
class TestSheerkaNonRegRules(TestUsingMemoryBasedSheerka):
|
||||
|
||||
@pytest.mark.skip
|
||||
def test_i_can_apply_simple_rule(self):
|
||||
|
||||
@@ -16,6 +16,7 @@ from parsers.BaseNodeParser import UnrecognizedTokensNode, SourceCodeNode, RuleN
|
||||
from parsers.FunctionParser import FunctionNode
|
||||
from parsers.PythonParser import PythonNode
|
||||
from parsers.SyaNodeParser import SyaConceptParserHelper
|
||||
from sheerkapython.python_wrapper import sheerka_globals
|
||||
from sheerkarete.common import V
|
||||
from sheerkarete.conditions import Condition, AndConditions, NegatedCondition, NegatedConjunctiveConditions
|
||||
|
||||
@@ -934,11 +935,18 @@ class FN:
|
||||
|
||||
@dataclass()
|
||||
class NEGCOND:
|
||||
"""
|
||||
Represents a NegatedCondition
|
||||
"""
|
||||
condition: str
|
||||
|
||||
|
||||
@dataclass()
|
||||
class NCCOND:
|
||||
"""
|
||||
Represents a NegatedConjunctiveConditions
|
||||
"""
|
||||
|
||||
conditions: List[str]
|
||||
|
||||
|
||||
@@ -1319,11 +1327,8 @@ def get_rete_conditions(*conditions):
|
||||
def get_value(obj):
|
||||
if obj.startswith("#"):
|
||||
return V(obj[1:])
|
||||
if obj.startswith("'"):
|
||||
return obj[1:-1]
|
||||
if obj in ("True", "False"):
|
||||
return obj == "True"
|
||||
return int(obj)
|
||||
|
||||
return eval(obj, sheerka_globals)
|
||||
|
||||
res = []
|
||||
for cond in conditions:
|
||||
|
||||
@@ -671,7 +671,7 @@ from give me the date !
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.value, BuiltinConcepts.ERROR)
|
||||
assert sheerka.has_error(res, __type="SyntaxErrorNode", message="Empty 'auto_eval' declaration.")
|
||||
assert sheerka.has_error(context, res, __type="SyntaxErrorNode", message="Empty 'auto_eval' declaration.")
|
||||
|
||||
def test_i_cannot_parse_when_wrong_auto_eval_value(self):
|
||||
sheerka, context, parser, *concepts = self.init_parser()
|
||||
@@ -709,4 +709,4 @@ from give me the date !
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.value, BuiltinConcepts.ERROR)
|
||||
assert sheerka.has_error(res, __type="SyntaxErrorNode", message="Empty 'def_var' declaration.")
|
||||
assert sheerka.has_error(context, res, __type="SyntaxErrorNode", message="Empty 'def_var' declaration.")
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.global_symbols import SyaAssociativity
|
||||
from core.sheerka.ExecutionContext import ExecutionContext
|
||||
from core.sheerka.services.SheerkaAdmin import SheerkaAdmin
|
||||
from sheerkapython.python_wrapper import Expando, create_namespace, inject_context, get_sheerka_method, Pipe, \
|
||||
MethodAccessError
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
class TestPythonWrapper(TestUsingMemoryBasedSheerka):
|
||||
|
||||
@pytest.mark.parametrize("name, expected", [
|
||||
("Concept", Concept),
|
||||
("BuiltinConcepts", BuiltinConcepts),
|
||||
("Expando", Expando),
|
||||
("ExecutionContext", ExecutionContext),
|
||||
("SyaAssociativity", SyaAssociativity),
|
||||
])
|
||||
def test_i_can_create_namespace_from_internal_references(self, name, expected):
|
||||
context = self.get_context()
|
||||
|
||||
assert create_namespace(context, "TestPythonWrapper", [name], None, {}, False) == {name: expected}
|
||||
|
||||
def test_i_can_create_namespace_with_context_method(self):
|
||||
context = self.get_context()
|
||||
|
||||
res = create_namespace(context, "TestPythonWrapper", ["in_context", "isinstance"], None, {}, False)
|
||||
assert res["in_context"] == context.in_context
|
||||
assert res["isinstance"] == context.sheerka.services[SheerkaAdmin.NAME].extended_isinstance
|
||||
|
||||
def test_i_can_create_namespace_when_sheerka_expando_object(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
res = create_namespace(context, "TestPythonWrapper", ["sheerka"], set(), {}, False)
|
||||
assert res["sheerka"] == Expando("sheerka", {})
|
||||
|
||||
res = create_namespace(context, "TestPythonWrapper", ["sheerka"], {"test", "set_debug"}, {}, False)
|
||||
assert isinstance(res["sheerka"], Expando)
|
||||
assert res["sheerka"].get_name() == "sheerka"
|
||||
assert set(vars(res["sheerka"])) == {"_Expando__name", "test", "set_debug"}
|
||||
|
||||
def test_i_can_create_namespace_when_short_term_memory(self):
|
||||
context = self.get_context()
|
||||
context.add_to_short_term_memory("my_key", "my_value")
|
||||
|
||||
assert create_namespace(context, "TestPythonWrapper", ["my_key"], None, {}, False) == {"my_key": "my_value"}
|
||||
|
||||
def test_i_can_create_namespace_when_value_from_memory(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
sheerka.add_to_memory(context, "my_key", "my_value")
|
||||
assert create_namespace(context, "TestPythonWrapper", ["my_key"], None, {}, False) == {"my_key": "my_value"}
|
||||
|
||||
def test_i_can_create_namespace_when_sheerka_methods(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
res = create_namespace(context, "TestPythonWrapper", ["test", "set_debug"], None, {}, False)
|
||||
|
||||
assert res["test"] == sheerka.test
|
||||
assert isinstance(res["set_debug"], type(inject_context))
|
||||
assert res["set_debug"].__name__ == "set_debug"
|
||||
|
||||
def test_i_can_create_namespace_when_value_from_context_obj(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
obj = Concept("foo").def_var("a", "value1").auto_init()
|
||||
context.obj = obj
|
||||
|
||||
res = create_namespace(context, "TestPythonWrapper", ["self", "a"], None, {}, False)
|
||||
assert res == {"self": obj, "a": "value1"}
|
||||
|
||||
def test_i_can_create_namespace_when_value_from_local_objects(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
obj = Concept("foo")
|
||||
objects = {"self": obj, "a": Concept("bar")}
|
||||
|
||||
res = create_namespace(context, "TestPythonWrapper", ["self", "a"], None, objects, False)
|
||||
assert res == {"self": obj, "a": objects["a"]}
|
||||
|
||||
def test_i_can_create_namespace_when_name_refers_to_a_concept(self):
|
||||
sheerka, context, foo = self.init_concepts("foo")
|
||||
|
||||
assert create_namespace(context, "TestPythonWrapper", ["foo"], None, {}, False) == {"foo": foo}
|
||||
|
||||
def test_internal_references_and_context_method_take_over_short_term_memory(self):
|
||||
context = self.get_context()
|
||||
context.add_to_short_term_memory("Concept", "short_term_value")
|
||||
context.add_to_short_term_memory("isinstance", "short_term_value")
|
||||
context.add_to_short_term_memory("in_context", "short_term_value")
|
||||
|
||||
res = create_namespace(context, "TestPythonWrapper", ["Concept", "isinstance", "in_context"], None, {}, False)
|
||||
|
||||
assert res == {
|
||||
"Concept": Concept,
|
||||
"isinstance": context.sheerka.services[SheerkaAdmin.NAME].extended_isinstance,
|
||||
"in_context": context.in_context,
|
||||
}
|
||||
|
||||
def test_short_term_memory_takes_precedence_over_long_term_memory(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
context.add_to_short_term_memory("my_key", "short_term")
|
||||
sheerka.add_to_memory(context, "my_key", "long_term")
|
||||
|
||||
assert create_namespace(context, "TestPythonWrapper", ["my_key"], None, {}, False) == {"my_key": "short_term"}
|
||||
|
||||
def test_long_term_memory_takes_precedence_over_sheerka_methods(self):
|
||||
# I am not really sure why
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
sheerka.add_to_memory(context, "test", "from memory")
|
||||
assert create_namespace(context, "TestPythonWrapper", ["test"], None, {}, False) == {"test": "from memory"}
|
||||
|
||||
def test_sheerka_method_takes_precedence_over_context_obj(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
obj = Concept("foo").def_var("test", "value1").auto_init()
|
||||
context.obj = obj
|
||||
|
||||
assert create_namespace(context, "TestPythonWrapper", ["test", ], None, {}, False) == {"test": sheerka.test}
|
||||
|
||||
def test_context_obj_takes_precedence_over_local_objects(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
obj = Concept("foo").def_var("a", "value1").auto_init()
|
||||
context.obj = obj
|
||||
objects = {"self": Concept("bar"), "a": Concept("bar")}
|
||||
|
||||
res = create_namespace(context, "TestPythonWrapper", ["self", "a"], None, objects, False)
|
||||
assert res == {"self": obj, "a": "value1"}
|
||||
|
||||
def test_local_objects_take_precedence_over_object_instantiation(self):
|
||||
sheerka, context, foo = self.init_concepts("from instantiation")
|
||||
objects = {"foo": Concept("from local")}
|
||||
|
||||
res = create_namespace(context, "TestPythonWrapper", ["foo"], None, objects, False)
|
||||
assert res == {"foo": objects["foo"]}
|
||||
|
||||
def test_i_can_get_sheerka_method(self):
|
||||
context = self.get_context()
|
||||
|
||||
# sheerka direct method
|
||||
assert get_sheerka_method(context, "TestPythonWrapper", "test", True) == context.sheerka.test
|
||||
|
||||
# sheerka indirect method
|
||||
assert get_sheerka_method(context, "TestPythonWrapper", "get_value", True) == context.sheerka.get_value
|
||||
|
||||
# method that need context are wrapped
|
||||
res = get_sheerka_method(context, "TestPythonWrapper", "test_using_context", True)
|
||||
assert res != context.sheerka.test_using_context
|
||||
assert type(res) == type(inject_context)
|
||||
assert res.__name__ == "test_using_context"
|
||||
|
||||
# return None when the method is not found
|
||||
assert get_sheerka_method(context, "TestPythonWrapper", "xxx", True) is None
|
||||
|
||||
def test_i_cannot_get_method_that_modifies_the_state_when_expression_only(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
assert get_sheerka_method(context, "TestPythonWrapper", "set_debug", expression_only=False) is not None
|
||||
|
||||
with pytest.raises(MethodAccessError) as ex:
|
||||
get_sheerka_method(context, "TestPythonWrapper", "set_debug", expression_only=True)
|
||||
assert ex.value.method_name == "set_debug"
|
||||
|
||||
def test_i_can_get_method_when_pipe_function(self):
|
||||
context = self.get_context()
|
||||
|
||||
res = get_sheerka_method(context, "TestPythonWrapper", "where", True)
|
||||
assert isinstance(res, Pipe)
|
||||
@@ -0,0 +1,570 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
import pytest
|
||||
|
||||
from sheerkaql.SheerkaQueryLangage import SheerkaQueryLanguage
|
||||
from sheerkaql.symbols import flwr_sequence, attribute_value
|
||||
|
||||
|
||||
def oset(x):
|
||||
return x
|
||||
|
||||
|
||||
class A(object):
|
||||
def __init__(self, q):
|
||||
self.q = q
|
||||
|
||||
def __repr__(self):
|
||||
return f"A({vars(self)})"
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, A):
|
||||
return False
|
||||
|
||||
return self.q == other.q
|
||||
|
||||
def __hash__(self):
|
||||
return hash(str(self.q))
|
||||
|
||||
|
||||
@dataclass
|
||||
class BagClass:
|
||||
property1: object
|
||||
property2: object
|
||||
|
||||
def as_bag(self):
|
||||
return {
|
||||
"prop1": self.property1,
|
||||
"prop2": self.property2,
|
||||
}
|
||||
|
||||
|
||||
execute = SheerkaQueryLanguage().execute
|
||||
|
||||
|
||||
class TestSheerkaQueryLanguage:
|
||||
|
||||
def test_i_can_get_the_root_of_a_query(self):
|
||||
hello = 'hello world!'
|
||||
q = SheerkaQueryLanguage().compile('hello')
|
||||
|
||||
assert q(locals()) == oset([hello])
|
||||
|
||||
def test_i_can_traverse_object(self):
|
||||
a = A(A(A("hello world!")))
|
||||
q = SheerkaQueryLanguage().compile("a.q.q.q")
|
||||
|
||||
assert q(locals()) == oset(["hello world!"])
|
||||
|
||||
def test_i_can_traverse_list(self):
|
||||
lst = [A("one"), A("two"), A("three")]
|
||||
a = A(lst)
|
||||
|
||||
assert execute("a.q.q", {"a": a}) == oset(["one", "two", "three"])
|
||||
|
||||
def test_i_can_traverse_list_of_list(self):
|
||||
sub_lst_number = [A("1"), A("2"), A("2")]
|
||||
sub_lst_letter = [A("a"), A("b"), A("c")]
|
||||
lst = [A("one"), A(sub_lst_number), A(sub_lst_letter)]
|
||||
a = A(lst)
|
||||
|
||||
res = execute("a.q.q", {"a": a})
|
||||
assert res == oset(["one", *sub_lst_number, *sub_lst_letter])
|
||||
|
||||
def test_i_can_traverse_object_when_where_condition_is_a_boolean(self):
|
||||
a = A(A(A("hello world!")))
|
||||
b_true = A(A(True))
|
||||
b_false = A(A(False))
|
||||
namespace = {"a": a, "hasattr": hasattr, "func": lambda x: x, "b_true": b_true, "b_false": b_false}
|
||||
|
||||
assert execute("a.q[1 == 1].q.q", namespace) == oset(["hello world!"])
|
||||
assert execute("a.q[hasattr(self, 'q')].q.q", namespace) == oset(["hello world!"])
|
||||
|
||||
assert execute("a.q[1 == 2].q.q", namespace) == oset([])
|
||||
assert execute("a.q[hasattr(self, 'x')].q.q", namespace) == oset([])
|
||||
|
||||
assert execute("a.q[True].q.q", namespace, allow_builtins=True) == oset(["hello world!"])
|
||||
assert execute("a.q[False].q.q", namespace, allow_builtins=True) == oset([])
|
||||
|
||||
assert execute("a.q[func(True)].q.q", namespace) == oset(["hello world!"])
|
||||
assert execute("a.q[func(False)].q.q", namespace) == oset([])
|
||||
|
||||
assert execute("a.q[b_true.q.q].q.q", namespace) == oset(["hello world!"])
|
||||
assert execute("a.q[b_false.q.q].q.q", namespace) == oset([])
|
||||
|
||||
def test_i_can_request_by_list_index(self):
|
||||
lst = [A("one"), A("two"), A("three")]
|
||||
a = A(lst)
|
||||
|
||||
assert execute("a.q[1]", {"a": a}) == oset([lst[1]])
|
||||
with pytest.raises(IndexError):
|
||||
execute("a.q[99]", {"a": a})
|
||||
with pytest.raises(TypeError):
|
||||
execute("a.q['key']", {"a": a})
|
||||
|
||||
def test_i_can_request_by_dictionary_key(self):
|
||||
lst = {"key1": "value1", "key2": "value2"}
|
||||
a = A(lst)
|
||||
|
||||
assert execute("a.q['key1']", {"a": a}) == oset([lst["key1"]])
|
||||
with pytest.raises(KeyError):
|
||||
execute("a.q['key3']", {"a": a})
|
||||
|
||||
def test_i_can_filter(self):
|
||||
l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
assert execute('l[self < 5]', locals()) == [0, 1, 2, 3, 4]
|
||||
|
||||
def test_i_cannot_traverse_object_when_where_condition_is_not_a_boolean(self):
|
||||
a = A("hello world!")
|
||||
namespace = {"a": a, "func": lambda x: x, "dictionary": {"key": "value"}, "list": ["value"]}
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
execute("a.q[1].q.q", namespace)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
execute("a.q[func(3)].q.q", namespace)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
execute("a.q[dictionary['key']].q.q", namespace)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
execute("a.q[list[0]].q.q", namespace)
|
||||
|
||||
def test_i_can_traverse_object_when_as_bag_is_defined(self):
|
||||
a = BagClass(BagClass("sub_value1", BagClass("sub_sub_value1", "sub_sub_value1")), "value2")
|
||||
|
||||
assert execute("a.prop1.prop2.prop1", {"a": a}) == oset(["sub_sub_value1"])
|
||||
|
||||
def test_i_can_traverse_objects_when_where_condition_uses_as_bag(self):
|
||||
hash_map = {"sub_sub_value1": "hello world!"}
|
||||
b = BagClass(BagClass("sub_value1", BagClass("sub_sub_value1", "sub_sub_value1")), "value2")
|
||||
a = A(hash_map)
|
||||
|
||||
assert execute("a.q[b.prop1.prop2.prop1]", {"a": a, "b": b}) == oset(["hello world!"])
|
||||
|
||||
def test_i_can_compute_set_operations(self):
|
||||
a = [1, 2, 3, 3]
|
||||
b = [2, 4, 3, 4]
|
||||
|
||||
assert execute("a | b", locals()) == [1, 2, 3, 4]
|
||||
assert execute("a - b", locals()) == [1]
|
||||
assert execute("b - a", locals()) == [4]
|
||||
assert execute("a & b", locals()) == [2, 3]
|
||||
|
||||
def test_can_execute_set_expression(self):
|
||||
a = [1, 2, 3, 3]
|
||||
b = [2, 4, 3, 4]
|
||||
c = [1, 2]
|
||||
|
||||
assert execute("return 1 if 1 in a else 0", locals()) == (1,)
|
||||
assert execute("return 1 if 1 not in a else 0", locals()) == (0,)
|
||||
assert execute("return 1 if 5 in a else 0", locals()) == (0,)
|
||||
assert execute("return 1 if 5 not in a else 0", locals()) == (1,)
|
||||
|
||||
assert execute("return 1 if <c> subset <a> else 0", locals()) == (1,)
|
||||
assert execute("return 1 if <c> superset <a> else 0", locals()) == (0,)
|
||||
|
||||
assert execute("return 1 if <a> subset <c> else 0", locals()) == (0,)
|
||||
assert execute("return 1 if <a> superset <c> else 0", locals()) == (1,)
|
||||
|
||||
l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
assert execute('l - l[self < 5]', locals()) == (5, 6, 7, 8, 9)
|
||||
|
||||
def test_i_can_traverse_a_complex_path(self):
|
||||
answer = 'o.x.y'
|
||||
|
||||
o = A('top')
|
||||
o.x = [A('asdf'), A('123')]
|
||||
o.x[0].y = A(answer)
|
||||
d = {'hasattr': hasattr, 'o': o}
|
||||
|
||||
assert execute('o/x[hasattr(self,"y")]/y/q', d) == oset([answer])
|
||||
assert execute('o/x', d) == oset(o.x)
|
||||
|
||||
def test_i_can_execute_comparison_in_where_clauses(self):
|
||||
a = A(5)
|
||||
assert execute('a[self.q == 5]', locals()) == oset([a])
|
||||
assert execute('a[self.q != 5]', locals()) == oset([])
|
||||
assert execute('a[self.q >= 5]', locals()) == oset([a])
|
||||
assert execute('a[self.q <= 5]', locals()) == oset([a])
|
||||
assert execute('a[self.q > 5]', locals()) == oset([])
|
||||
assert execute('a[self.q < 5]', locals()) == oset([])
|
||||
assert execute('a[self.q == 7]', locals()) == oset([])
|
||||
assert execute('a[self.q != 7]', locals()) == oset([a])
|
||||
assert execute('a[self.q >= 7]', locals()) == oset([])
|
||||
assert execute('a[self.q <= 7]', locals()) == oset([a])
|
||||
assert execute('a[self.q > 7]', locals()) == oset([])
|
||||
assert execute('a[self.q < 7]', locals()) == oset([a])
|
||||
assert execute('a[self.q == 3]', locals()) == oset([])
|
||||
assert execute('a[self.q != 3]', locals()) == oset([a])
|
||||
assert execute('a[self.q >= 3]', locals()) == oset([a])
|
||||
assert execute('a[self.q <= 3]', locals()) == oset([])
|
||||
assert execute('a[self.q > 3]', locals()) == oset([a])
|
||||
assert execute('a[self.q < 3]', locals()) == oset([])
|
||||
|
||||
def test_i_can_execute_boolean_expression_in_where_clauses(self):
|
||||
a = 'hello'
|
||||
true = True
|
||||
false = False
|
||||
assert execute('a[true]', locals()) == oset([a])
|
||||
assert execute('a[false]', locals()) == oset([])
|
||||
assert execute('a[not true]', locals()) == oset([])
|
||||
assert execute('a[not false]', locals()) == oset([a])
|
||||
assert execute('a[true and true]', locals()) == oset([a])
|
||||
assert execute('a[false and true]', locals()) == oset([])
|
||||
assert execute('a[not true and true]', locals()) == oset([])
|
||||
assert execute('a[not false and true]', locals()) == oset([a])
|
||||
assert execute('a[true or false]', locals()) == oset([a])
|
||||
assert execute('a[true or true]', locals()) == oset([a])
|
||||
assert execute('a[false or true]', locals()) == oset([a])
|
||||
assert execute('a[false or false]', locals()) == oset([])
|
||||
assert execute('a[not true or true]', locals()) == oset([a])
|
||||
assert execute('a[not false or false]', locals()) == oset([a])
|
||||
assert execute('a[true and true and true and true]', locals()) == oset([a])
|
||||
assert execute('a[true and true and true and false]', locals()) == oset([])
|
||||
assert execute('a[true and (false or true)]', locals()) == oset([a])
|
||||
assert execute('a[true and (false and true)]', locals()) == oset([])
|
||||
assert execute('a[true and (true and true)]', locals()) == oset([a])
|
||||
assert execute('a[true and (true and (not true or false))]', locals()) == oset([])
|
||||
|
||||
def test_i_can_execute_comparison_in_where_clauses_using_builtin_functions(self):
|
||||
a = 'hello'
|
||||
true = True
|
||||
false = False
|
||||
d = locals()
|
||||
assert execute('a[1 == 1]', d) == oset([a])
|
||||
assert execute('a[-1 == -1]', d) == oset([a])
|
||||
assert execute('a[2.2 == 2.2]', d) == oset([a])
|
||||
assert execute('a[2.2 == float("2.2")]', d, True) == oset([a])
|
||||
assert execute('a[2 == int(2.2)]', d, True) == oset([a])
|
||||
assert execute('a["hello" == a]', d, True) == oset([a])
|
||||
assert execute('a["HELLO" == a.upper()]', d, True) == oset([a])
|
||||
|
||||
def test_i_can_use_function_in_where_clauses(self):
|
||||
a = 'hello'
|
||||
|
||||
def f():
|
||||
return 'hello'
|
||||
|
||||
def g(x, y, z):
|
||||
return x + y + z
|
||||
|
||||
def h(f, x):
|
||||
return f(x)
|
||||
|
||||
def i(x):
|
||||
return x ** 2
|
||||
|
||||
def j(f):
|
||||
return f
|
||||
|
||||
true = True
|
||||
false = False
|
||||
d = locals()
|
||||
|
||||
assert execute('a[f() == "hello"]', d) == oset([a])
|
||||
assert execute('a[g(1,2,3) == 6]', d) == oset([a])
|
||||
assert execute('a[h(i,3) == 9]', d) == oset([a])
|
||||
assert execute('a[i(j(j)(j)(j)(h)(i,3)) == 81]', d) == oset([a])
|
||||
with pytest.raises(TypeError):
|
||||
execute('a[f()]', d)
|
||||
|
||||
def test_i_can_use_lists_in_where_clauses(self):
|
||||
a = 'hello'
|
||||
l = [1, 2, 3, 4, 5, 6, 7, [1, 2, 3, 4, 5, 6, 7, [1, 2, 3, 4, 5, 6, 7, 8]]]
|
||||
d = locals()
|
||||
|
||||
assert execute('a[l[0] == 1]', d) == oset([a])
|
||||
assert execute('a[l[1] == 2]', d) == oset([a])
|
||||
assert execute('a[l[7][0] == 1]', d) == oset([a])
|
||||
assert execute('a[l[7][1] == 2]', d) == oset([a])
|
||||
assert execute('a[l[7][7][0] == 1]', d) == oset([a])
|
||||
assert execute('a[l[7][7][1] == 2]', d) == oset([a])
|
||||
assert execute('a[l[7][7][7] == 8]', d) == oset([a])
|
||||
|
||||
def test_i_can_use_dicts_in_where_clauses(self):
|
||||
a = 'hello'
|
||||
l = {"one": 1, "two": 2, "next": {"one": 1, "two": 2, "next": {"one": 1, "two": 2}}}
|
||||
d = locals()
|
||||
|
||||
assert execute('a[l["one"] == 1]', d) == oset([a])
|
||||
assert execute('a[l["two"] == 2]', d) == oset([a])
|
||||
assert execute('a[l["next"]["one"] == 1]', d) == oset([a])
|
||||
assert execute('a[l["next"]["two"] == 2]', d) == oset([a])
|
||||
assert execute('a[l["next"]["next"]["one"] == 1]', d) == oset([a])
|
||||
assert execute('a[l["next"]["next"]["two"] == 2]', d) == oset([a])
|
||||
|
||||
def test_i_can_use_callable_in_where_clauses(self):
|
||||
a = 'hello'
|
||||
|
||||
def f():
|
||||
return 'hello'
|
||||
|
||||
def g(x, y, z):
|
||||
return x + y + z
|
||||
|
||||
def h(f, x):
|
||||
return f(x)
|
||||
|
||||
def i(x):
|
||||
return x ** 2
|
||||
|
||||
def j(f):
|
||||
return f
|
||||
|
||||
m = {"one": 1, "two": 2, "next": [1, 2, 3, 4, 5, 6, 7, j]}
|
||||
d = locals()
|
||||
|
||||
assert execute('a[m["next"][7](j)(m["next"][7])(m["next"])[7](i)(m["two"]) == 4]', d) == oset([a])
|
||||
|
||||
def test_i_can_execute_flwr_expression(self):
|
||||
def f():
|
||||
return 1, 2, 3
|
||||
|
||||
d = locals()
|
||||
assert execute('for x in f() return x', d) == (1, 2, 3)
|
||||
assert execute('for x in f() let y = f() return x, y', d) == ((1, (1, 2, 3)), (2, (1, 2, 3)), (3, (1, 2, 3)))
|
||||
|
||||
def test_i_can_execute_flwr_with_order_by(self):
|
||||
def f():
|
||||
return [1, 3, 2]
|
||||
|
||||
d = locals()
|
||||
with pytest.raises(SyntaxError):
|
||||
execute('for x in f() order by "asdf" asc return x', d)
|
||||
with pytest.raises(SyntaxError):
|
||||
execute('for x in f() order by 0 asc return "asdf":x', d)
|
||||
assert execute('for x in f() order by 0 asc return x', d) == (1, 2, 3)
|
||||
assert execute('for x in f() order by 0 desc return x', d) == (3, 2, 1)
|
||||
|
||||
def test_i_can_execute_flwr_with_user_defined_functions(self):
|
||||
a = 'hello'
|
||||
l = [1, 2, 3, 4, 5, 6, 7, [1, 2, 3, 4, 5, 6, 7, [1, 2, 3, 4, 5, 6, 7, 8]]]
|
||||
d = locals()
|
||||
|
||||
assert execute('''
|
||||
for i in l
|
||||
let f = function() { 125 }
|
||||
return f()
|
||||
''', d) == (125, 125, 125, 125, 125, 125, 125, 125)
|
||||
|
||||
assert execute('''
|
||||
for i in l
|
||||
let f = function(q) {
|
||||
for _ in <a>
|
||||
where isinstance(q, list)
|
||||
return {
|
||||
for j in q
|
||||
return f(j)
|
||||
}
|
||||
}
|
||||
return f(i)
|
||||
''', d, True) == ((), (), (), (), (), (), (),
|
||||
(((), (), (), (), (), (), (),
|
||||
(((), (), (), (), (), (), (), ()),)),))
|
||||
|
||||
def test_i_can_execute_flwr_with_if_expression(self):
|
||||
a = 'hello'
|
||||
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
q = True
|
||||
d = locals()
|
||||
|
||||
assert execute('''
|
||||
for x in <a> return if (q) then 1 else 0
|
||||
''', d) == (1,)
|
||||
|
||||
assert execute('''
|
||||
for x in <l> return if (x % 2 == 0) then 1 else 0
|
||||
''', d) == (0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
|
||||
|
||||
assert execute('''
|
||||
for x in <l> return if x % 2 == 0 then 1 else 0
|
||||
''', d) == (0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
|
||||
|
||||
assert execute('''
|
||||
for x in <l> return 1 if x % 2 == 0 else 0
|
||||
''', d) == (0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
|
||||
|
||||
assert execute('''
|
||||
for x in <l> return 1 if (x % 2 == 0) else 0
|
||||
''', d) == (0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
|
||||
|
||||
assert execute('''
|
||||
for x in <a> return if (True or X) then 1 else 0
|
||||
''', d, True) == (1,)
|
||||
|
||||
def test_if_short_circuit(self):
|
||||
a = 'hello'
|
||||
l = [1, 2, 3, 4, 5, 6, 7, [1, 2, 3, 4, 5, 6, 7, [1, 2, 3, 4, 5, 6, 7, 8]]]
|
||||
d = locals()
|
||||
|
||||
assert execute('''
|
||||
for x in <a> return if (True or X) then 1 else 0
|
||||
''', d, True) == (1,)
|
||||
|
||||
assert execute('''
|
||||
for x in <a> return if (False and false.x) then 1 else 0
|
||||
''', d, True) == (0,)
|
||||
|
||||
def test_i_can_flatten_result(self):
|
||||
a = 'hello'
|
||||
l = [1, 2, 3, 4, 5, 6, 7, [1, 2, 3, 4, 5, 6, 7, [1, 2, 3, 4, 5, 6, 7, 8]]]
|
||||
d = locals()
|
||||
|
||||
assert execute('''
|
||||
for x in l return flatten x
|
||||
''', d, True) == (1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 8)
|
||||
|
||||
def test_flattened_return(self):
|
||||
a = 'hello'
|
||||
l = [1, 2, 3, 4, 5, 6, 7, [1, 2, 3, 4, 5, 6, 7, [1, 2, 3, 4, 5, 6, 7, 8]]]
|
||||
d = locals()
|
||||
|
||||
assert execute('''
|
||||
for i in l
|
||||
let f = function(l) {
|
||||
if (isinstance(l, list))
|
||||
then {for j in l return f(j)}
|
||||
else l
|
||||
}
|
||||
return flatten f(i)''', d, True) == (1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 8)
|
||||
|
||||
assert execute('''
|
||||
for i in l
|
||||
let f = function(l) {
|
||||
if (isinstance(l, list))
|
||||
then {for j in l return f(j)}
|
||||
else {a:l}
|
||||
}
|
||||
return flatten f(i)
|
||||
''', d, True) == tuple({a: i} for i in (1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 8))
|
||||
|
||||
def test_i_can_return_none(self):
|
||||
a = 'hello'
|
||||
l = [1, 2, 3, 4, 5, 6, 7, [1, 2, 3, 4, 5, 6, 7, [1, 2, 3, 4, 5, 6, 7, 8]]]
|
||||
d = locals()
|
||||
|
||||
assert execute('for x in l return None', d, True) == (None, None, None, None, None, None, None, None)
|
||||
|
||||
def test_i_can_return_a_class(self):
|
||||
l = [1, 2, 3]
|
||||
d = {"A": A, "l": l}
|
||||
|
||||
assert execute('for x in l return A(x)', d, True) == (A(1), A(2), A(3))
|
||||
|
||||
def test_i_can_execute_flwr_when_there_is_no_for_statement(self):
|
||||
a = 'hello'
|
||||
l = [1, 2, 3, 4, 5, 6, 7, [1, 2, 3, 4, 5, 6, 7, [1, 2, 3, 4, 5, 6, 7, 8]]]
|
||||
d = locals()
|
||||
|
||||
flwr = flwr_sequence([attribute_value('hello', scalar=True)])
|
||||
assert flwr(d) == ('hello',)
|
||||
assert execute("return l", d) == (l,)
|
||||
assert execute('''
|
||||
let f = function(l) {
|
||||
if (isinstance(l, list))
|
||||
then {for j in l return f(j)}
|
||||
else l
|
||||
}
|
||||
return flatten f(l)
|
||||
''', d, True) == (1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 8)
|
||||
|
||||
def test_can_collect(self):
|
||||
l = [1, 2, 3, 4, 5, 6, 7, 3, 4, 5, 6, 7, 3, 4]
|
||||
d = locals()
|
||||
|
||||
assert execute('''
|
||||
for n in l
|
||||
collect n as n with function(prev, next) {
|
||||
if prev == None then 1 else prev + 1
|
||||
}
|
||||
''', d, True) == {1: 1, 2: 1, 3: 3, 4: 3, 5: 2, 6: 2, 7: 2}
|
||||
|
||||
assert execute('''
|
||||
for n in [1,2,3,4,5,6,7,3,4,5,6,7,3,4]
|
||||
collect n as n with function(prev, next) {
|
||||
if prev == None then 1 else prev + 1
|
||||
}
|
||||
''', d, True) == {1: 1, 2: 1, 3: 3, 4: 3, 5: 2, 6: 2, 7: 2}
|
||||
|
||||
def test_i_can_perform_calculations(self):
|
||||
d = locals()
|
||||
|
||||
assert execute('''
|
||||
for n in [
|
||||
4.0*3.0/2.0,
|
||||
4.0/3.0*2.0,
|
||||
(3.0+9.0)*4.0/8.0,
|
||||
((9.0-3.0)+(5.0-3.0))/2.0 + 2.0,
|
||||
5.0 * 4.0 / 2.0 - 10.0 + 5.0 - 2.0 + 3.0,
|
||||
5.0 / 4.0 * 2.0 + 10.0 - 5.0 * 2.0 / 3.0
|
||||
]
|
||||
return n
|
||||
''', d, True) == (
|
||||
4.0 * 3.0 / 2.0,
|
||||
4.0 / 3.0 * 2.0,
|
||||
(3.0 + 9.0) * 4.0 / 8.0,
|
||||
((9.0 - 3.0) + (5.0 - 3.0)) / 2.0 + 2.0,
|
||||
5.0 * 4.0 / 2.0 - 10.0 + 5.0 - 2.0 + 3.0,
|
||||
5.0 / 4.0 * 2.0 + 10.0 - 5.0 * 2.0 / 3.0
|
||||
)
|
||||
|
||||
def test_i_can_execute_flwr_with_in_and_not_in(self):
|
||||
l = [[1, 2, 3], [4, 5, 6], [7, 4, 3], [5, 6, 7], [3, 4]]
|
||||
d = locals()
|
||||
|
||||
assert execute('''
|
||||
for n in l
|
||||
where 4 in n
|
||||
return n
|
||||
''', d, True) == ([4, 5, 6], [7, 4, 3], [3, 4])
|
||||
|
||||
assert execute('''
|
||||
for n in l
|
||||
where 4 not in n
|
||||
return n
|
||||
''', d, True) == ([1, 2, 3], [5, 6, 7])
|
||||
|
||||
def test_multi_collect(self):
|
||||
l = [1, 2, 3, 4, 5, 6, 7, 3, 4, 5, 6, 7, 3, 4]
|
||||
d = locals()
|
||||
|
||||
assert execute('''
|
||||
for n in l
|
||||
let counter = function(prev, next) {
|
||||
if prev == None then 1 else prev + 1
|
||||
}
|
||||
where 1 in l and 12 not in l
|
||||
collect n as n with counter
|
||||
collect n as (int(n)/int(2)) with counter
|
||||
''', d, True), (
|
||||
{1: 1, 2: 1, 3: 3, 4: 3, 5: 2, 6: 2, 7: 2},
|
||||
{0: 1, 1: 4, 2: 5, 3: 4})
|
||||
|
||||
def test_i_can_execute_flwr_on_objects_attributes(self):
|
||||
lst = [A(1), A(2), A(3)]
|
||||
d = locals()
|
||||
|
||||
assert execute('for x in <lst.q> return x', d) == (1, 2, 3)
|
||||
assert execute('for x in lst return x.q', d) == (1, 2, 3) # another way
|
||||
|
||||
def test_exception_during_return_are_caught(self):
|
||||
lst = [A(1), A([2])]
|
||||
d = locals()
|
||||
|
||||
res = execute('for x in lst return x.q + [2]', d)
|
||||
assert len(res) == 2
|
||||
assert isinstance(res[0], TypeError)
|
||||
assert res[1] == [2,2]
|
||||
|
||||
def test_i_cannot_execute_flwr_on_attributes_that_does_not_exist(self):
|
||||
lst = [A(1), A(2), A(3)]
|
||||
d = locals()
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
execute('for x in <lst.x> return x', d)
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
execute('for x in lst.q return x', d) # AttributeError: 'list' object has no attribute 'q'
|
||||
@@ -0,0 +1,122 @@
|
||||
from contextlib import contextmanager
|
||||
|
||||
from ply import lex
|
||||
|
||||
from sheerkaql import lexer
|
||||
|
||||
|
||||
def compare(a, b):
|
||||
return (a.type == b.type and a.value == b.value and
|
||||
a.lexpos == b.lexpos and a.lineno == b.lineno)
|
||||
|
||||
|
||||
def token(token_type, value, pos, line):
|
||||
t = lex.LexToken()
|
||||
t.type = token_type
|
||||
t.value = value
|
||||
t.lexpos = pos
|
||||
t.lineno = line
|
||||
return t
|
||||
|
||||
|
||||
@contextmanager
|
||||
def comparable_tokens():
|
||||
eq = lex.LexToken.__eq__
|
||||
ne = lex.LexToken.__ne__
|
||||
setattr(lex.LexToken, "__eq__", compare)
|
||||
setattr(lex.LexToken, "__ne__", lambda a, b: not compare(a, b))
|
||||
yield
|
||||
setattr(lex.LexToken, "__eq__", eq)
|
||||
setattr(lex.LexToken, "__ne__", ne)
|
||||
|
||||
|
||||
class TestSheerkaQueryLanguageLexer:
|
||||
def test_context_manager(self):
|
||||
t1 = token("NAME", 'a', 0, 1)
|
||||
t2 = token("NAME", 'a', 0, 1)
|
||||
assert t1 != t2
|
||||
with comparable_tokens():
|
||||
assert t1 == t2
|
||||
|
||||
def test_NAME(self):
|
||||
clex = lexer.Lexer()
|
||||
clex.input('a 9a')
|
||||
tokens = [token("NAME", 'a', 0, 1),
|
||||
token("NUMBER", 9, 2, 1),
|
||||
token("NAME", 'a', 3, 1)]
|
||||
with comparable_tokens():
|
||||
for t in tokens:
|
||||
assert next(clex) == t
|
||||
|
||||
def test_STRING(self):
|
||||
clex = lexer.Lexer()
|
||||
clex.input("'asdf' \"asdf\" '\n'")
|
||||
tokens = [token("STRING", 'asdf', 0, 1),
|
||||
token("STRING", 'asdf', 7, 1),
|
||||
token("STRING", '\n', 14, 1), ]
|
||||
with comparable_tokens():
|
||||
for t in tokens:
|
||||
assert next(clex) == t
|
||||
|
||||
def test_HEX(self):
|
||||
clex = lexer.Lexer()
|
||||
clex.input("0xab 0xab")
|
||||
tokens = [token("NUMBER", 0xab, 0, 1),
|
||||
token("NUMBER", 171, 5, 1)]
|
||||
with comparable_tokens():
|
||||
for t in tokens:
|
||||
assert next(clex) == t
|
||||
|
||||
def test_FLOAT(self):
|
||||
clex = lexer.Lexer()
|
||||
clex.input("1.2 .2 2.3e4 .2 2.3e4")
|
||||
tokens = [token("NUMBER", 1.2, 0, 1), token("NUMBER", .2, 4, 1),
|
||||
token("NUMBER", 2.3e4, 7, 1), token("NUMBER", .2, 13, 1),
|
||||
token("NUMBER", 2.3e4, 16, 1)]
|
||||
with comparable_tokens():
|
||||
for t in tokens:
|
||||
assert next(clex) == t
|
||||
|
||||
def test_OCT(self):
|
||||
clex = lexer.Lexer()
|
||||
clex.input("073 073 073")
|
||||
tokens = [token("NUMBER", 0o73, 0, 1),
|
||||
token("NUMBER", 59, 4, 1),
|
||||
token("NUMBER", 59, 8, 1)]
|
||||
with comparable_tokens():
|
||||
for t in tokens:
|
||||
assert next(clex) == t
|
||||
|
||||
def test_INTEGER(self):
|
||||
clex = lexer.Lexer()
|
||||
clex.input("73 730 7")
|
||||
tokens = [token("NUMBER", 73, 0, 1),
|
||||
token("NUMBER", 730, 3, 1),
|
||||
token("NUMBER", 7, 7, 1)]
|
||||
with comparable_tokens():
|
||||
for t in tokens:
|
||||
assert next(clex) == t
|
||||
|
||||
def test_KEYWORDS(self):
|
||||
for value, token_type in list(lexer.reserved.items()):
|
||||
clex = lexer.Lexer()
|
||||
clex.input(value)
|
||||
tokens = [token(token_type, value, 0, 1)]
|
||||
with comparable_tokens():
|
||||
for t in tokens:
|
||||
assert next(clex) == t
|
||||
|
||||
def test_chrs(self):
|
||||
for token_type, value in [(attr[2:], getattr(lexer.Lexer, attr))
|
||||
for attr in dir(lexer.Lexer)
|
||||
if attr[:2] == 't_' and
|
||||
isinstance(getattr(lexer.Lexer, attr), str) and
|
||||
attr[2:] != 'ignore']:
|
||||
if value[0] == '\\':
|
||||
value = value[1:]
|
||||
clex = lexer.Lexer()
|
||||
clex.input(value)
|
||||
tokens = [token(token_type, value, 0, 1)]
|
||||
with comparable_tokens():
|
||||
for t in tokens:
|
||||
assert next(clex) == t
|
||||
@@ -0,0 +1,297 @@
|
||||
import pytest
|
||||
|
||||
from sheerkaql.SheerkaQueryLangage import SheerkaQueryLanguage
|
||||
from sheerkaql.lexer import Lexer
|
||||
from sheerkaql.parser import Parser
|
||||
|
||||
|
||||
class TestSheerkaQueryLanguageParser:
|
||||
def test_hello(self):
|
||||
SheerkaQueryLanguage().compile('hello')
|
||||
with pytest.raises(SyntaxError) as ex:
|
||||
SheerkaQueryLanguage().compile('hello there')
|
||||
|
||||
def test_i_can_parse_with_slash(self):
|
||||
SheerkaQueryLanguage().compile('hello/part1')
|
||||
SheerkaQueryLanguage().compile('hello/part1/part2/part3')
|
||||
SheerkaQueryLanguage().compile('hello/part1 / part2 / part3')
|
||||
with pytest.raises(SyntaxError):
|
||||
SheerkaQueryLanguage().compile('hello/part1/part3 part4/part5')
|
||||
|
||||
def test_i_can_parse_with_dot(self):
|
||||
SheerkaQueryLanguage().compile('hello.part1')
|
||||
SheerkaQueryLanguage().compile('hello.part1.part2.part3')
|
||||
SheerkaQueryLanguage().compile('hello.part1 . part2 . part3')
|
||||
with pytest.raises(SyntaxError):
|
||||
SheerkaQueryLanguage().compile('hello.part1.part3 part4.part5')
|
||||
|
||||
def test_i_can_parse_simple_where_conditions(self):
|
||||
SheerkaQueryLanguage().compile('hello[wheRe]/hello[asdf]')
|
||||
SheerkaQueryLanguage().compile('hello/hello[asdf]/asdf/wef')
|
||||
SheerkaQueryLanguage().compile('hello/hello/wewe[asdf]/wef/waef/awef/weaf')
|
||||
SheerkaQueryLanguage().compile('hello.hello[ asdf ] . wewe. wef[asdf] .waef .awef[asdf].weaf')
|
||||
SheerkaQueryLanguage().compile('hello["foo"]')
|
||||
SheerkaQueryLanguage().compile('hello[123]')
|
||||
SheerkaQueryLanguage().compile('hello[123.234]')
|
||||
with pytest.raises(SyntaxError):
|
||||
SheerkaQueryLanguage().compile('hello/aef[asdf] hello[adsf]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_comparisons(self):
|
||||
SheerkaQueryLanguage().compile('hello[1 == 1]')
|
||||
SheerkaQueryLanguage().compile('hello[1 != 1]')
|
||||
SheerkaQueryLanguage().compile('hello[1 < 1]')
|
||||
SheerkaQueryLanguage().compile('hello[1 <= 1]')
|
||||
SheerkaQueryLanguage().compile('hello[1 > 1]')
|
||||
SheerkaQueryLanguage().compile('hello[1 >= 1]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_logical_operations(self):
|
||||
SheerkaQueryLanguage().compile('hello[a and b]')
|
||||
SheerkaQueryLanguage().compile('hello[a or b]')
|
||||
SheerkaQueryLanguage().compile('hello[not a or b]')
|
||||
SheerkaQueryLanguage().compile('hello[a or not b]')
|
||||
SheerkaQueryLanguage().compile('hello[not a and b]')
|
||||
SheerkaQueryLanguage().compile('hello[a and not b]')
|
||||
SheerkaQueryLanguage().compile('hello[not a or not b]')
|
||||
SheerkaQueryLanguage().compile('hello[not a and not b]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_logical_operations_and_parenthesis(self):
|
||||
SheerkaQueryLanguage().compile('hello[((a and b) and not (a or b) or not (a and b)) and not (not a or b)]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_arithmetic_operations(self):
|
||||
SheerkaQueryLanguage().compile('hello[a + b]')
|
||||
SheerkaQueryLanguage().compile('hello[a - b]')
|
||||
SheerkaQueryLanguage().compile('hello[a * b]')
|
||||
SheerkaQueryLanguage().compile('hello[a / b]')
|
||||
SheerkaQueryLanguage().compile('hello[(a + b) / (a - b)]')
|
||||
SheerkaQueryLanguage().compile('hello[-a]')
|
||||
SheerkaQueryLanguage().compile('hello[a + b * c / e]')
|
||||
|
||||
def test_i_can_parse_nested_where_conditions(self):
|
||||
SheerkaQueryLanguage().compile('hello[a]')
|
||||
SheerkaQueryLanguage().compile("hello[a[0]['hello']]")
|
||||
SheerkaQueryLanguage().compile("hello[a[0][\"hello\"]]")
|
||||
|
||||
def test_i_can_parse_where_conditions_with_function_call(self):
|
||||
SheerkaQueryLanguage().compile("hello[a[0]['hello']()]")
|
||||
SheerkaQueryLanguage().compile("hello[a[0]['hello'](0)]")
|
||||
SheerkaQueryLanguage().compile("hello[a[0]['hello']('asdf')]")
|
||||
SheerkaQueryLanguage().compile("hello[a[0]['hello'](asdf)]")
|
||||
SheerkaQueryLanguage().compile("hello[a[0]['hello'](0, 'asdf', asdf)()()(1,2)]")
|
||||
SheerkaQueryLanguage().compile('hello[f(1)]')
|
||||
SheerkaQueryLanguage().compile('hello[f(1,2,3)]')
|
||||
SheerkaQueryLanguage().compile('hello[f(a,b,c)]')
|
||||
SheerkaQueryLanguage().compile('hello[f(a(),b(),c())]')
|
||||
SheerkaQueryLanguage().compile('hello[f(a[a],b[b],c[c])]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_attributes_parsing(self):
|
||||
SheerkaQueryLanguage().compile('hello[foo.bar.baz]')
|
||||
SheerkaQueryLanguage().compile('hello[foo[12].bar().baz]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_flwr(self):
|
||||
SheerkaQueryLanguage().compile('hello[f(1,<asdf>,{for x in <asdf> return x})]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_quantified_expressions(self):
|
||||
SheerkaQueryLanguage().compile('hello[every x in <asdf> satisfies (x)]')
|
||||
with pytest.raises(SyntaxError):
|
||||
SheerkaQueryLanguage().compile('hello[every x in <asdf> statisfies (x)]')
|
||||
with pytest.raises(SyntaxError):
|
||||
SheerkaQueryLanguage().compile('hello[every x in <asdf> statisfies x]')
|
||||
SheerkaQueryLanguage().compile('hello[some x in <asdf> satisfies (x)]')
|
||||
SheerkaQueryLanguage().compile('hello[some x in <self/asdf> satisfies (x)]')
|
||||
SheerkaQueryLanguage().compile('hello[some x in {for x in <asdf> return x} satisfies (x)]')
|
||||
SheerkaQueryLanguage().compile('hello[some x in {for x in <asdf> return x} satisfies (x == y)]')
|
||||
SheerkaQueryLanguage().compile('hello[some x in {for x in <asdf> return x} satisfies (x and not y(1,2))]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_set_comparisons(self):
|
||||
SheerkaQueryLanguage().compile('hello[a in <qs>]')
|
||||
SheerkaQueryLanguage().compile('hello[a not in <qs>]')
|
||||
SheerkaQueryLanguage().compile('hello[not a in <qs>]')
|
||||
SheerkaQueryLanguage().compile('hello[<a> subset <qs>]')
|
||||
SheerkaQueryLanguage().compile('hello[<a> superset <qq>]')
|
||||
SheerkaQueryLanguage().compile('hello[<a> proper subset <aq>]')
|
||||
SheerkaQueryLanguage().compile('hello[<a> proper superset <aq>]')
|
||||
SheerkaQueryLanguage().compile('hello[<a> is <qs>]')
|
||||
SheerkaQueryLanguage().compile('hello[<a> is not <qs>]')
|
||||
|
||||
def test_i_can_parse_operations_on_sets(self):
|
||||
SheerkaQueryLanguage().compile('asdf - asdf')
|
||||
SheerkaQueryLanguage().compile('asdf & asdf')
|
||||
SheerkaQueryLanguage().compile('asdf | asdf')
|
||||
SheerkaQueryLanguage().compile('(asdf | asdf) & asdf - (asdf & asdf) - (asdf & (afsd | asdf))')
|
||||
SheerkaQueryLanguage().compile('asdf/asdf - asdf/asd[erw]')
|
||||
|
||||
def test_i_can_parse_flwr_expression(self):
|
||||
SheerkaQueryLanguage().compile('for x in y return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd> return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd>, y in <adsf> return x')
|
||||
SheerkaQueryLanguage().compile('for x in {for x in <asdf> return x} return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd> where x == y return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd> let y = <x/asdf> return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd> let y = {for x in <asdf> return x} return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd> let y = <x/asdf>, x = <adf> return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd> let y = <x/asdf> let x = <adf> return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd>, z in <asdf> let y = <x/asdf> let x = <adf> return x')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q)
|
||||
return x''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q)
|
||||
return x,y,z''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q)
|
||||
return x,y.sdf.asd,z''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q)
|
||||
return x,y.sdf.asd,z()()()[asdf][asfd](1,2,3)''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q)
|
||||
return 'asdf':asdf''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q)
|
||||
return 'asdf':asdf, "hello":"hello World!"''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q == z and (<y> is not <z>))
|
||||
return 'asdf':asdf, "one":1, "2.0":2.0''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>, y in <asdf/asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q == z and (<y> is not <z>))
|
||||
return 'asdf':asdf, "one":1, "2.0":2.0''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>, y in <asdf/asdf>
|
||||
let y = <x/asdf>, y1 = <Afd>, y2 = <asdf>, y3 = <asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q == z and (<y> is not <z>))
|
||||
return 'asdf':asdf, "one":1, "2.0":2.0''')
|
||||
|
||||
def test_i_can_parse_flwr_with_attribute_value(self):
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>, y in sdaf.asdf(asdf, asdf)[1]
|
||||
let y = <x/asdf>, y1 = <Afd>, y2 = <asdf>, y3 = <asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q == z and (<y> is not <z>))
|
||||
return 'asdf':asdf, "one":1, "2.0":2.0''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>, y in sdaf.asdf(asdf, asdf)[1]
|
||||
let y = <x/asdf>, y1 = <Afd>, y2 = <asdf>, y3 = <asdf>
|
||||
let x = <adf>
|
||||
let q = sadf.asdf().asfd[1](1,2,3)
|
||||
where every x in <y> satisfies (q == z and (<y> is not <z>))
|
||||
return 'asdf':asdf, "one":1, "2.0":2.0''')
|
||||
|
||||
def test_flwr_orderby(self):
|
||||
SheerkaQueryLanguage().compile('for x in <asdf> order by "adsf" desc return "adsf":x')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>, y in sdaf.asdf(asdf, asdf)[1]
|
||||
let y = <x/asdf>, y1 = <Afd>, y2 = <asdf>, y3 = <asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q == z and (<y> is not <z>))
|
||||
order by "asdf" desc
|
||||
return 'asdf':asdf, "one":1, "2.0":2.0''')
|
||||
SheerkaQueryLanguage().compile('for x in <asdf> order by 0 asc return x')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>, y in sdaf.asdf(asdf, asdf)[1]
|
||||
let y = <x/asdf>, y1 = <Afd>, y2 = <asdf>, y3 = <asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q == z and (<y> is not <z>))
|
||||
order by 1 asc
|
||||
return asdf, 1, 2.0''')
|
||||
|
||||
def test_flwr_function_noargs(self):
|
||||
SheerkaQueryLanguage().compile('''
|
||||
for x in <asdf>
|
||||
let f = function() { for y in <asdf> return y }
|
||||
return f
|
||||
''')
|
||||
|
||||
def test_flwr_function_args(self):
|
||||
SheerkaQueryLanguage().compile('''
|
||||
for x in <asdf>
|
||||
let f = function(q) { for y in q return y }
|
||||
return f
|
||||
''')
|
||||
|
||||
def test_if(self):
|
||||
SheerkaQueryLanguage().compile('''
|
||||
for x in <asdf> return if (0) then 1 else 0
|
||||
''')
|
||||
|
||||
def test_reduce(self):
|
||||
SheerkaQueryLanguage().compile('''
|
||||
for x in <asdf>
|
||||
collect x.tree as x.attr with function(prev, next) {
|
||||
if prev == None then next else prev.combine(next)
|
||||
}
|
||||
''')
|
||||
|
||||
def test_in_list1(self):
|
||||
SheerkaQueryLanguage().compile("hello['foo' in ['foo','bar']]")
|
||||
|
||||
def test_in_list2(self):
|
||||
SheerkaQueryLanguage().compile("hello['baz' in ['foo','bar']]")
|
||||
|
||||
def test_not_in_list1(self):
|
||||
SheerkaQueryLanguage().compile("hello['foo' not in ['foo','bar']]")
|
||||
|
||||
def test_not_in_list2(self):
|
||||
SheerkaQueryLanguage().compile("hello['baz' not in ['foo','bar']]")
|
||||
|
||||
def test_in_list3(self):
|
||||
result = SheerkaQueryLanguage().execute("res[test_elt in ['foo','bar']]",
|
||||
{'res': True, 'test_elt': 'foo'})
|
||||
assert bool(result)
|
||||
|
||||
def test_in_list4(self):
|
||||
result = SheerkaQueryLanguage().execute("res[test_elt in ['foo','bar']]",
|
||||
{'res': True, 'test_elt': 'baz'})
|
||||
|
||||
assert not bool(result)
|
||||
|
||||
def test_not_in_list4(self):
|
||||
result = SheerkaQueryLanguage().execute("res[test_elt not in ['foo','bar']]",
|
||||
{'res': True, 'test_elt': 'baz'})
|
||||
assert bool(result)
|
||||
|
||||
def test_not_in_list5(self):
|
||||
result = SheerkaQueryLanguage().execute("res[test_elt not in ['foo','bar']]",
|
||||
{'res': True, 'test_elt': 'foo'})
|
||||
assert not bool(result)
|
||||
|
||||
@pytest.mark.parametrize("text, expected", [
|
||||
("hello", {"hello"}),
|
||||
("hello.foo.bar", {"hello"}),
|
||||
("hello/foo/bar", {"hello"}),
|
||||
("hello[foo.bar.baz]", {"hello", "foo"}),
|
||||
("hello[foo()]", {"hello", "foo"}),
|
||||
("hello[foo(bar)]", {"hello", "foo", "bar"}),
|
||||
("hello[foo(1, bar.baz)]", {"hello", "foo", "bar"}),
|
||||
("hello[foo[bar]]", {"hello", "foo", "bar"}),
|
||||
("hello[foo > bar]", {"hello", "foo", "bar"}),
|
||||
("hello[foo + bar]", {"hello", "foo", "bar"}),
|
||||
("hello[[a,b,c]]", {"hello", "a", "b", "c"}),
|
||||
("hello[{a:b}]", {"hello", "a", "b"}),
|
||||
])
|
||||
def test_i_can_get_names(self, text, expected):
|
||||
parser = Parser()
|
||||
parser.parse(bytes(text, 'utf-8').decode('unicode_escape'), lexer=Lexer())
|
||||
assert parser.names == expected
|
||||
|
||||
@pytest.mark.parametrize("text", [
|
||||
"sheerka.method",
|
||||
"sheerka/method",
|
||||
"hello[sheerka.method]",
|
||||
"hello[sheerka.method.xx]",
|
||||
])
|
||||
def test_i_can_get_sheerka_methods(self, text):
|
||||
parser = Parser()
|
||||
parser.parse(bytes(text, 'utf-8').decode('unicode_escape'), lexer=Lexer())
|
||||
assert parser.sheerka_names == {"method"}
|
||||
Reference in New Issue
Block a user