Reimplemented explain feature

This commit is contained in:
2020-06-04 18:43:15 +02:00
parent c498b394e3
commit d7573f095f
27 changed files with 1673 additions and 1161 deletions
+213
View File
@@ -0,0 +1,213 @@
from dataclasses import dataclass
import pytest
from core.builtin_concepts import BuiltinConcepts
from core.sheerka.services.SheerkaFilter import Pipe, SheerkaFilter
from printer.FormatInstructions import FormatInstructions, FormatDetailDesc, FormatDetailType
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@dataclass
class Obj:
prop1: str
prop2: str
@dataclass
class ObjWithAsBag:
prop1: str
prop2: str
def as_bag(self):
return {
"first_prop": self.prop1,
"second_prop": self.prop2,
}
class TestSheerkaFilter(TestUsingMemoryBasedSheerka):
def test_i_can_pipe_using_decorator(self):
@Pipe
def is_ok_with_decorator(iterable):
for item in iterable:
yield item + " ok"
def exclamation(iterable):
for item in iterable:
yield item + "!"
res = ["one", "two", "three"] | is_ok_with_decorator | Pipe(exclamation)
assert list(res) == ["one ok!", "two ok!", "three ok!"]
def test_i_can_pipe_function_with_context_as_first_parameter(self):
def func_with_context(context, iterable, var_name):
for item in iterable:
yield f"{context.desc}: {var_name}={item}"
sheerka, context = self.init_concepts()
context.desc = "desc"
pipeable = Pipe(func_with_context, context)
assert pipeable.need_context
assert list(["one", "two", "three"] | pipeable("var")) == ['desc: var=one', 'desc: var=two', 'desc: var=three']
def test_i_can_pipe_function_with_context_as_only_parameter(self):
# This time, func_with_context does not have other parameter than context and iterable
def func_with_context(context, iterable):
for item in iterable:
yield f"{context.desc}: var={item}"
sheerka, context = self.init_concepts()
context.desc = "desc"
pipeable = Pipe(func_with_context, context)
assert pipeable.need_context
assert list(["one", "two", "three"] | pipeable) == ['desc: var=one', 'desc: var=two', 'desc: var=three']
def test_i_can_pipe_explanation_concept(self):
sheerka, context = self.init_concepts()
execution_contexts = [context.push(desc=f"desc_{i}") for i in range(4)]
explanation_node = sheerka.new(BuiltinConcepts.EXPLANATION, body=execution_contexts)
@Pipe
def get_desc(iterable):
for item in iterable:
yield item.desc
res = explanation_node | get_desc
assert sheerka.isinstance(res, BuiltinConcepts.EXPLANATION)
assert list(res.body) == ["desc_0", "desc_1", "desc_2", "desc_3"] # body is modified
@pytest.mark.parametrize("predicate, expected", [
("True", ["one", "two", "three"]),
("self == 'two'", ["two"])
])
def test_i_can_filter(self, predicate, expected):
filter_service = SheerkaFilter(None)
res = ["one", "two", "three"] | Pipe(filter_service.pipe_filter)(predicate)
assert list(res) == expected
def test_i_can_filter_obj(self):
filter_service = SheerkaFilter(None)
lst = [Obj("a", "b"), Obj("c", "d")]
predicate = "prop2 == 'd'"
res = lst | Pipe(filter_service.pipe_filter)(predicate)
assert list(res) == [Obj("c", "d")]
def test_i_can_filter_obj_implementing_as_bag(self):
filter_service = SheerkaFilter(None)
lst = [ObjWithAsBag("a", "b"), ObjWithAsBag("c", "d")]
predicate = "second_prop == 'd'"
res = lst | Pipe(filter_service.pipe_filter)(predicate)
assert list(res) == [ObjWithAsBag("c", "d")]
def test_i_can_manage_name_error(self):
filter_service = SheerkaFilter(None)
lst = [Obj("a", "b"), Obj("c", "d"), ObjWithAsBag("a", "b"), ObjWithAsBag("c", "d")]
predicate = "second_prop == 'd'" # 'second_prop' does not exist in Obj
res = lst | Pipe(filter_service.pipe_filter)(predicate)
assert list(res) == [ObjWithAsBag("c", "d")]
def test_i_cannot_filter_if_the_predicate_is_incorrect(self):
filter_service = SheerkaFilter(None)
lst = [Obj("a", "b"), Obj("c", "d")]
predicate = "prop2 =="
with pytest.raises(SyntaxError):
res = lst | Pipe(filter_service.pipe_filter)(predicate)
list(res)
def test_i_can_format_l(self):
sheerka, context, foo, bar = self.init_concepts("foo", "bar")
lst = [foo, bar]
res = lst | Pipe(SheerkaFilter.pipe_format_l)("my_format")
res = list(res)
assert len(res) == 2
format_instructions = res[0].get_prop(BuiltinConcepts.FORMAT_INSTRUCTIONS)
assert isinstance(format_instructions, FormatInstructions)
assert format_instructions.format_l[f"c:{foo.id}:"] == "my_format"
format_instructions = res[1].get_prop(BuiltinConcepts.FORMAT_INSTRUCTIONS)
assert isinstance(format_instructions, FormatInstructions)
assert format_instructions.format_l[f"c:{bar.id}:"] == "my_format"
def test_i_can_format_d(self):
sheerka, context, foo, bar = self.init_concepts("foo", "bar")
lst = [foo, bar]
res = lst | Pipe(SheerkaFilter.pipe_format_d)("id", "name", "body", id="%red%{id}%reset%")
res = list(res)
expected_props = {
"id": "%red%{id}%reset%",
"name": "{name}",
"body": "{body}"
}
assert len(res) == 2
format_instructions = res[0].get_prop(BuiltinConcepts.FORMAT_INSTRUCTIONS)
assert isinstance(format_instructions, FormatInstructions)
assert format_instructions.format_d[f"c:{foo.id}:"] == FormatDetailDesc(FormatDetailType.Props_In_Line, expected_props)
format_instructions = res[1].get_prop(BuiltinConcepts.FORMAT_INSTRUCTIONS)
assert isinstance(format_instructions, FormatInstructions)
assert format_instructions.format_d[f"c:{bar.id}:"] == FormatDetailDesc(FormatDetailType.Props_In_Line, expected_props)
def test_i_can_format_d_all_properties(self):
sheerka, context, foo, bar = self.init_concepts("foo", "bar")
lst = [foo, bar]
res = lst | Pipe(SheerkaFilter.pipe_format_d)()
res = list(res)
expected_props = {
'id': '{id}',
'name': '{name}',
'key': '{key}',
'body': '{body}',
'self': '{self}'
}
assert len(res) == 2
format_instructions = res[0].get_prop(BuiltinConcepts.FORMAT_INSTRUCTIONS)
assert isinstance(format_instructions, FormatInstructions)
assert format_instructions.format_d[f"c:{foo.id}:"] == FormatDetailDesc(FormatDetailType.Props_In_Line, expected_props)
def test_i_can_set_recurse(self):
sheerka, context, foo, bar = self.init_concepts("foo", "bar")
lst = [foo, bar]
res = lst | Pipe(SheerkaFilter.pipe_recurse)(10)
res = list(res)
assert len(res) == 2
format_instructions = res[0].get_prop(BuiltinConcepts.FORMAT_INSTRUCTIONS)
assert isinstance(format_instructions, FormatInstructions)
assert format_instructions.recursive_props["children"] == 10
format_instructions = res[1].get_prop(BuiltinConcepts.FORMAT_INSTRUCTIONS)
assert isinstance(format_instructions, FormatInstructions)
assert format_instructions.recursive_props["children"] == 10
res = lst | Pipe(SheerkaFilter.pipe_recurse)(15, "other_prop")
res = list(res)
assert len(res) == 2
format_instructions = res[0].get_prop(BuiltinConcepts.FORMAT_INSTRUCTIONS)
assert isinstance(format_instructions, FormatInstructions)
assert format_instructions.recursive_props["children"] == 10
assert format_instructions.recursive_props["other_prop"] == 15
+147
View File
@@ -0,0 +1,147 @@
import types
from core.builtin_concepts import BuiltinConcepts
from core.sheerka.services.SheerkaResultManager import SheerkaResultConcept
from sdp.sheerkaDataProvider import Event
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestSheerkaResultManager(TestUsingMemoryBasedSheerka):
@classmethod
def setup_class(cls):
sheerka = cls().get_sheerka()
sheerka.save_execution_context = True
@classmethod
def teardown_class(cls):
sheerka = cls().get_sheerka()
sheerka.save_execution_context = False
def test_i_can_get_the_result_by_digest(self):
sheerka, context = self.init_concepts()
sheerka.evaluate_user_input("def concept one as 1")
digest = sheerka.get_last_execution().event.get_digest()
res = sheerka.get_results_by_digest(context, digest)
assert sheerka.isinstance(res, BuiltinConcepts.EXPLANATION)
assert res.command == "def concept one as 1"
assert res.digest == digest
assert isinstance(res.body, types.GeneratorType)
assert sheerka.load(SheerkaResultConcept.NAME, "digest") == digest
previous_results = list(res.body)
# Second test,
# I can get the result from the recorded digest
res = sheerka.get_results(context)
assert sheerka.isinstance(res, BuiltinConcepts.EXPLANATION)
assert res.command == "def concept one as 1"
assert res.digest == digest
assert isinstance(res.body, types.GeneratorType)
assert list(res.body) == previous_results
def test_i_cannot_get_result_by_digest_if_the_digest_does_not_exist(self):
sheerka, context = self.init_concepts()
res = sheerka.get_results_by_digest(context, "fake digest")
assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND)
assert res.body == {'digest': 'fake digest'}
def test_i_cannot_get_results_if_no_previous_digest(self):
sheerka, context = self.init_concepts()
assert sheerka.get_results(context) is None
def test_i_can_get_the_result_by_command_name(self):
sheerka, context = self.init_concepts()
sheerka.evaluate_user_input("def concept one as 1")
digest = sheerka.get_last_execution().event.get_digest()
sheerka.evaluate_user_input("one") # another command
res = sheerka.get_results_by_command(context, "def concept")
assert sheerka.isinstance(res, BuiltinConcepts.EXPLANATION)
assert res.command == "def concept one as 1"
assert res.digest == digest
assert isinstance(res.body, types.GeneratorType)
def test_i_can_get_the_result_by_command_when_not_in_the_same_page_size(self):
sheerka, context = self.init_concepts()
sheerka.evaluate_user_input("def concept one as 1")
sheerka.evaluate_user_input("one")
sheerka.evaluate_user_input("one")
sheerka.evaluate_user_input("one")
service = SheerkaResultConcept(sheerka, 2)
res = service.get_results_by_command(context, "def concept")
assert sheerka.isinstance(res, BuiltinConcepts.EXPLANATION)
assert res.command == "def concept one as 1"
def test_i_cannot_get_results_from_command_if_the_command_does_not_exist(self):
sheerka, context = self.init_concepts()
res = sheerka.get_results_by_command(context, "def concept")
assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND)
assert res.body == {'command': 'def concept'}
def test_i_cannot_get_result_from_command_if_the_command_does_not_exists_multiple_pages(self):
sheerka, context = self.init_concepts()
sheerka.evaluate_user_input("def concept one as 1")
sheerka.evaluate_user_input("one")
sheerka.evaluate_user_input("one")
sheerka.evaluate_user_input("one")
service = SheerkaResultConcept(sheerka, 2)
res = service.get_results_by_command(context, "fake command")
assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND)
assert res.body == {'command': 'fake command'}
def test_i_can_get_last_results(self):
sheerka, context = self.init_concepts()
sheerka.evaluate_user_input("def concept one as 1")
sheerka.evaluate_user_input("one")
res = sheerka.get_last_results(context)
assert sheerka.isinstance(res, BuiltinConcepts.EXPLANATION)
assert res.command == "one"
def test_i_can_get_last_results_when_event_with_no_result(self):
sheerka, context = self.init_concepts()
sheerka.sdp.save_event(Event("event 1"))
sheerka.sdp.save_event(Event("event 2"))
sheerka.sdp.save_event(Event("event 3"))
sheerka.evaluate_user_input("def concept one as 1")
res = sheerka.get_last_results(context)
assert sheerka.isinstance(res, BuiltinConcepts.EXPLANATION)
assert res.command == "def concept one as 1"
def test_i_cannot_get_last_results_when_no_result(self):
sheerka, context = self.init_concepts()
res = sheerka.get_last_results(context)
assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND)
assert res.body == {'query': 'last'}
def test_i_cannot_get_last_results_when_only_events(self):
sheerka, context = self.init_concepts()
sheerka.sdp.save_event(Event("event 1"))
sheerka.sdp.save_event(Event("event 2"))
sheerka.sdp.save_event(Event("event 3"))
res = sheerka.get_last_results(context)
assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND)
assert res.body == {'query': 'last'}
+255 -48
View File
@@ -3,7 +3,8 @@ from dataclasses import dataclass
import pytest
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, ConceptParts
from parsers.ExpressionParser import TrueNode, LambdaNode
from core.sheerka.services.SheerkaFilter import Pipe, SheerkaFilter
from printer.Formatter import Formatter, BraceToken
from printer.SheerkaPrinter import FormatInstructions
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -149,7 +150,43 @@ class TestSheerkaPrinter(TestUsingMemoryBasedSheerka):
(None)level33
"""
def test_i_can_format_concept(self, capsys):
def test_i_can_format_l_concepts_using_default_format_l_definition(self, capsys):
# default format_l definition
# for all obj of a given type
sheerka = self.get_sheerka()
foo = Concept("foo a b").def_var("a").def_var("b").init_key()
foo.set_value("a", "value a").set_value("b", "value b")
foo.set_value(ConceptParts.BODY, "body")
sheerka.set_id_if_needed(foo, False)
sheerka.printer_handler.register_format_l(foo, "DEFAULT:{id}-{name}-{key}-{body}-{a}-{b}")
sheerka.print(foo)
captured = capsys.readouterr()
assert captured.out == "DEFAULT:1001-foo a b-foo __var__0 __var__1-body-value a-value b\n"
def test_i_can_format_l_concepts_using_context_format_l_definition(self, capsys):
# context format_l definition
# for all obj of a given type in the current print call
sheerka = self.get_sheerka()
foo = Concept("foo a b").def_var("a").def_var("b").init_key()
foo.set_value("a", "value a").set_value("b", "value b")
foo.set_value(ConceptParts.BODY, "body")
sheerka.set_id_if_needed(foo, False)
sheerka.printer_handler.register_format_l(foo, "DEFAULT:{id}-{name}-{key}-{body}-{a}-{b}")
context_instructions = FormatInstructions().set_format_l(foo, "CONTEXT:{id}-{name}-{key}-{body}-{a}-{b}")
sheerka.print(foo, context_instructions)
captured = capsys.readouterr()
assert captured.out == "CONTEXT:1001-foo a b-foo __var__0 __var__1-body-value a-value b\n"
def test_i_can_format_l_concepts_using_item_format_l_definition(self, capsys):
# item format_l definition
# for the item only
sheerka = self.get_sheerka()
foo = Concept("foo a b").def_var("a").def_var("b").init_key()
foo.set_value("a", "value a").set_value("b", "value b")
@@ -157,12 +194,16 @@ class TestSheerkaPrinter(TestUsingMemoryBasedSheerka):
sheerka.set_id_if_needed(foo, False)
sheerka.printer_handler.register_format_l(foo, "{id}-{name}-{key}-{body}-{a}-{b}")
context_instructions = FormatInstructions().set_format_l(foo, "CONTEXT:{id}-{name}-{key}-{body}-{a}-{b}")
item_instructions = FormatInstructions().set_format_l(foo, "ITEM:{id}-{name}-{key}-{body}-{a}-{b}")
sheerka.print(foo)
foo.set_prop(BuiltinConcepts.FORMAT_INSTRUCTIONS, item_instructions)
sheerka.print(foo, context_instructions)
captured = capsys.readouterr()
assert captured.out == "1001-foo a b-foo __var__0 __var__1-body-value a-value b\n"
assert captured.out == "ITEM:1001-foo a b-foo __var__0 __var__1-body-value a-value b\n"
def test_i_can_format_object(self, capsys):
def test_i_can_format_l_objects(self, capsys):
sheerka = self.get_sheerka()
foo = Obj("value a", "value b")
@@ -172,6 +213,21 @@ class TestSheerkaPrinter(TestUsingMemoryBasedSheerka):
captured = capsys.readouterr()
assert captured.out == "value a-value b\n"
def test_i_can_format_l_execution_context(self, capsys):
# In this test, no format_l definition is provided
# The system knows how to format ExecutionContext
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
execution_context = context.push("test_sheerka_printer", "Testing Execution Context Printing")
ret_val = sheerka.ret("test_sheerka_printer", True, sheerka.new(BuiltinConcepts.SUCCESS))
execution_context.add_values(return_value=ret_val)
ec = execution_context.as_bag()
sheerka.print(execution_context)
captured = capsys.readouterr()
assert captured.out == f"[{ec['id']:3}] {ec['desc']} ({ec['status']})\n"
def test_i_can_register_a_custom_format_by_its_name(self, capsys):
sheerka = self.get_sheerka()
foo = Obj("value a", "value b")
@@ -182,80 +238,196 @@ class TestSheerkaPrinter(TestUsingMemoryBasedSheerka):
captured = capsys.readouterr()
assert captured.out == "value a-value b\n"
def test_i_can_define_format_in_print_instruction(self, capsys):
sheerka = self.get_sheerka()
foo = Obj("value a", "value b")
def test_i_can_format_d_concepts_using_default_definition(self, capsys):
sheerka, context, foo = self.init_concepts(Concept("foo a b").def_var("a").def_var("b"))
foo_1 = sheerka.new(foo.key, a="value a", b="value b")
foo_2 = sheerka.new(foo.key, a="value c", b="value d")
lst = [foo_1, foo_2]
instructions = FormatInstructions().set_format_l("tests.core.test_sheerka_printer.Obj", "{a}-{b}")
sheerka.print(foo, instructions)
sheerka.printer_handler.register_format_d(foo, {"a": "DEFAULT:{a}", "b": "DEFAULT:{b}"})
sheerka.print(lst)
captured = capsys.readouterr()
assert captured.out == "value a-value b\n"
assert captured.out == """(1001)foo a b
a: DEFAULT:'value a'
b: DEFAULT:'value b'
(1001)foo a b
a: DEFAULT:'value c'
b: DEFAULT:'value d'
"""
def test_format_print_instruction_override_register_format(self, capsys):
sheerka = self.get_sheerka()
foo = Obj("value a", "value b")
def test_i_can_format_d_concepts_using_context_definition(self, capsys):
sheerka, context, foo = self.init_concepts(Concept("foo a b").def_var("a").def_var("b"))
foo_1 = sheerka.new(foo.key, a="value a", b="value b")
foo_2 = sheerka.new(foo.key, a="value c", b="value d")
lst = [foo_1, foo_2]
sheerka.printer_handler.register_format_l("tests.core.test_sheerka_printer.Obj", "{a}-{b}")
instructions = FormatInstructions().set_format_l("tests.core.test_sheerka_printer.Obj", "a={a} <> b={b}")
sheerka.print(foo, instructions)
sheerka.printer_handler.register_format_d(foo, {"a": "DEFAULT:{a}", "b": "DEFAULT:{b}"})
context_instructions = FormatInstructions().set_format_d(foo, {"a": "CONTEXT:{a}", "b": "CONTEXT:{b}"})
sheerka.print(lst, context_instructions)
captured = capsys.readouterr()
assert captured.out == "a=value a <> b=value b\n"
assert captured.out == """(1001)foo a b
a: CONTEXT:'value a'
b: CONTEXT:'value b'
(1001)foo a b
a: CONTEXT:'value c'
b: CONTEXT:'value d'
"""
def test_i_can_format_d(self, capsys):
def test_i_can_format_d_concepts_using_item_definition(self, capsys):
sheerka, context, foo = self.init_concepts(Concept("foo a b").def_var("a").def_var("b"))
item_instructions = FormatInstructions().set_format_d(foo, {"a": "ITEM:{a}", "b": "ITEM:{b}"})
foo.set_format_instructions(item_instructions)
foo_1 = sheerka.new(foo.key, a="value a", b="value b")
foo_2 = sheerka.new(foo.key, a="value c", b="value d")
lst = [foo_1, foo_2]
sheerka.printer_handler.register_format_d(foo, {"a": "DEFAULT:{a}", "b": "DEFAULT:{b}"})
context_instructions = FormatInstructions().set_format_d(foo, {"a": "CONTEXT:{a}", "b": "CONTEXT:{b}"})
# Note that this time, foo has a format instruction defined
sheerka.print(lst, context_instructions)
captured = capsys.readouterr()
assert captured.out == """(1001)foo a b
a: ITEM:'value a'
b: ITEM:'value b'
(1001)foo a b
a: ITEM:'value c'
b: ITEM:'value d'
"""
def test_i_can_format_d_objects(self, capsys):
sheerka = self.get_sheerka()
foo = [Obj("value a", "value b"), Obj("value c", "value d")]
sheerka.printer_handler.register_format_d(TrueNode(), ["a", "b"])
sheerka.printer_handler.register_format_d(Obj, {"a": "CUSTOM:{a}", "b": "CUSTOM:{b}"})
sheerka.print(foo)
captured = capsys.readouterr()
assert captured.out == """Obj(a='value a', b='value b')
a: value a
b: value b
a: CUSTOM:'value a'
b: CUSTOM:'value b'
Obj(a='value c', b='value d')
a: value c
b: value d
a: CUSTOM:'value c'
b: CUSTOM:'value d'
"""
def test_i_can_format_d_with_only_a_list_of_properties(self, capsys):
sheerka = self.get_sheerka()
foo = [Obj("value a", "value b"), Obj("value c", "value d")]
sheerka.printer_handler.register_format_d(Obj, ["a", "b"])
sheerka.print(foo)
captured = capsys.readouterr()
assert captured.out == """Obj(a='value a', b='value b')
a: 'value a'
b: 'value b'
Obj(a='value c', b='value d')
a: 'value c'
b: 'value d'
"""
def test_i_can_format_d_and_align_properties(self, capsys):
sheerka = self.get_sheerka()
foo = [ObjLongProp("value a", "value b"), ObjLongProp("value c", "value d")]
sheerka.printer_handler.register_format_d(TrueNode(), ["first_property_name", "second"])
sheerka.printer_handler.register_format_d(ObjLongProp, ["first_property_name", "second"])
sheerka.print(foo)
captured = capsys.readouterr()
assert captured.out == """ObjLongProp(first_property_name='value a', second='value b')
first_property_name: value a
second : value b
first_property_name: 'value a'
second : 'value b'
ObjLongProp(first_property_name='value c', second='value d')
first_property_name: value c
second : value d
first_property_name: 'value c'
second : 'value d'
"""
def test_i_can_format_d_all_properties_of_a_concept(self, capsys):
sheerka, context, foo = self.init_concepts(Concept("foo a b").def_var("a").def_var("b"))
foo_1 = sheerka.new(foo.key, a="value a", b="value b")
foo_2 = sheerka.new(foo.key, a="value c", b="value d")
lst = [foo_1, foo_2]
sheerka.printer_handler.register_format_d(foo)
sheerka.print(lst)
captured = capsys.readouterr()
assert captured.out == """(1001)foo a b
a : 'value a'
var.a: *name 'var' is not defined*
b : 'value b'
var.b: *name 'var' is not defined*
id : '1001'
name : 'foo a b'
key : 'foo __var__0 __var__1'
body : __NOT_INITIALIZED
self : (1001)foo a b
(1001)foo a b
a : 'value c'
var.a: *name 'var' is not defined*
b : 'value d'
var.b: *name 'var' is not defined*
id : '1001'
name : 'foo a b'
key : 'foo __var__0 __var__1'
body : __NOT_INITIALIZED
self : (1001)foo a b
"""
def test_i_can_format_d_when_dictionary(self, capsys):
sheerka, context, foo = self.init_concepts(Concept("foo a b").def_var("a").def_var("b"))
dict_value = {
"a": "value a",
"beta": {"b1": 10, "b2": Obj("10", 15), "b3": ["items", "in", "a", "list"]},
"gamma": {"list": ["'quoted string'", '"double" \'single\'', "c3"], "empty": []},
"epsilon": ["a", "b", "c"],
"g": {"tuple": ("tuple-a", "tuple-b", "tuple-b"), "empty": tuple()},
"h": {"set": {"set-a"}, "empty": set()},
}
foo_1 = sheerka.new(foo.key, a="value a", b=dict_value)
lst = [foo_1]
sheerka.printer_handler.register_format_d(foo)
sheerka.print(lst)
captured = capsys.readouterr()
assert captured.out == """(1001)foo a b
a : 'value a'
var.a: *name 'var' is not defined*
b : {'a' : 'value a'
'beta' : {'b1': 10
'b2': Obj(a='10', b=15)
'b3': ['items',
'in',
'a',
'list']}
'gamma' : {'list' : ["'quoted string'",
""double" 'single'",
'c3']
'empty': []}
'epsilon': ['a',
'b',
'c']
'g' : {'tuple': ('tuple-a',
'tuple-b',
'tuple-b')
'empty': ()}
'h' : {'set' : {'set-a'}
'empty': {}}}
var.b: *name 'var' is not defined*
id : '1001'
name : 'foo a b'
key : 'foo __var__0 __var__1'
body : __NOT_INITIALIZED
self : (1001)foo a b
"""
def test_i_can_manage_when_property_does_not_exist(self, capsys):
sheerka = self.get_sheerka()
foo = Obj("value a", "value b")
sheerka.printer_handler.register_format_d(TrueNode(), ["foo", "bar"])
sheerka.printer_handler.register_format_d(Obj, ["foo", "bar"])
sheerka.print(foo)
captured = capsys.readouterr()
assert captured.out == """Obj(a='value a', b='value b')
foo: *Undefined*
bar: *Undefined*
"""
def test_i_can_select_the_object_to_format_d(self, capsys):
sheerka = self.get_sheerka()
foo = [Obj("value a", "value b"), ObjLongProp("value c", "value d")]
sheerka.printer_handler.register_format_d(LambdaNode(lambda o: isinstance(o, Obj)), ["a", "b"])
sheerka.print(foo)
captured = capsys.readouterr()
assert captured.out == """Obj(a='value a', b='value b')
a: value a
b: value b
ObjLongProp(first_property_name='value c', second='value d')
foo: *name 'foo' is not defined*
bar: *name 'bar' is not defined*
"""
@pytest.mark.parametrize("template, expected", [
@@ -265,7 +437,6 @@ ObjLongProp(first_property_name='value c', second='value d')
("{b}\\+", "value b+\n"),
("+", "+\n"),
("\\+", "\\+\n"),
("+\\", "+\\\n"),
])
def test_i_can_concat_print_instruction_and_register_format(self, capsys, template, expected):
sheerka = self.get_sheerka()
@@ -277,3 +448,39 @@ ObjLongProp(first_property_name='value c', second='value d')
sheerka.print(foo, instructions)
captured = capsys.readouterr()
assert captured.out == expected
def test_i_can_manage_exception_when_printing(self, capsys):
sheerka = self.get_sheerka()
filter_service = SheerkaFilter(sheerka)
predicate = "self='two'" # it should be self=='two'
items = ["one", "two", "three"] | Pipe(filter_service.pipe_filter)(predicate)
sheerka.print(items)
captured = capsys.readouterr()
assert captured.out == "\x1b[31mSyntaxError: invalid syntax\nself='two'\n ^\x1b[0m\n"
@pytest.mark.parametrize("template, expected", [
(None, []),
("", []),
("foo", []),
("{foo}", [BraceToken(0, 4, -1)]),
("xxx{foo}yyy", [BraceToken(3, 7, -1)]),
("{foo}{bar}-{baz}", [BraceToken(0, 4, -1), BraceToken(5, 9, -1), BraceToken(11, 15, -1)]),
("xxx{{foo}}yyy", []),
("xxx{{foo}yyy", []),
("xxx{yyy", []),
("xxx{", []),
])
def test_i_can_get_braces(self, template, expected):
assert list(Formatter.braces(template)) == expected
@pytest.mark.parametrize("template, expected", [
(None, None),
("", ""),
("foo", "foo"),
("{foo}", "{format_obj(foo, 0)}"),
("{foo : >16}", "{format_obj(foo , 0): >16}"),
("{foo : >16}{bar}xxx{baz}", "{format_obj(foo , 0): >16}{format_obj(bar, 0)}xxx{format_obj(baz, 0)}"),
])
def test_i_can_inject_format_obj(self, template, expected):
assert Formatter.inject_format_obj(template, 0) == expected
-317
View File
@@ -1,317 +0,0 @@
import os
import pytest
from core.builtin_concepts import ParserResultConcept, ReturnValueConcept, BuiltinConcepts
from core.concept import Concept
from core.sheerka.ExecutionContext import ExecutionContext
from evaluators.ExplainEvaluator import ExplainEvaluator
from parsers.ExplainParser import ExplanationNode, RecurseDefNode, FormatLNode, UnionNode, FilterNode, FormatDNode
from parsers.ExpressionParser import PropertyEqualsNode, PropertyEqualsSequenceNode, TrueNode, IsaNode
from printer.FormatInstructions import FormatDetailDesc, FormatDetailType
from pytest import fixture
from sdp.sheerkaDataProvider import Event
from sdp.sheerkaSerializer import Serializer, SerializerContext
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@fixture(scope="module")
def serializer():
"""
Return a :class:`sdp.sheerkaSerializer.Serializer` instance for the module
"""
return Serializer()
class EC:
"""
Helper to create execution context (AKA execution result)
"""
def __init__(self, children=None, **props):
self.props = props
self.children = children
def get_return_value(expr):
if isinstance(expr, ExplanationNode):
value = expr
else:
value = ExplanationNode("xxx_test_explain_evaluator_xxx", "", expr=expr)
return ReturnValueConcept(
"TestEvaluator",
True,
ParserResultConcept(parser="parser", value=value))
def create_executions_results(context, list_of_ecs):
def update(execution_context, ec):
for prop_name, pro_value in ec.props.items():
setattr(execution_context, prop_name, pro_value)
if ec.children:
for child_ec in ec.children:
child_execution_context = execution_context.push("TestEvaluator")
update(child_execution_context, child_ec)
res = []
for ec in list_of_ecs:
execution_context = ExecutionContext("TestEvaluator", context.event, context.sheerka)
update(execution_context, ec)
res.append(execution_context)
return res
def get_execution_result_from_file(sheerka, digest, serializer):
target_path = os.path.join("../_fixture/", digest) + "_result"
with open(target_path, "rb") as f:
context = SerializerContext(sheerka=sheerka)
return serializer.deserialize(f, context)
def get_execution_result_from_list(executions_result):
return executions_result
class TestExplainEvaluator(TestUsingMemoryBasedSheerka):
@staticmethod
def init_evaluator_with_file(self, serializer):
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
evaluator = ExplainEvaluator()
evaluator.get_execution_result = lambda s, d: get_execution_result_from_file(s, d, serializer)
return sheerka, context, evaluator
def init_evaluator_with_list(self, list_of_ecs):
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
evaluator = ExplainEvaluator()
executions_result = create_executions_results(context, list_of_ecs)
evaluator.get_execution_result = lambda s, d: get_execution_result_from_list(executions_result)
return sheerka, context, evaluator, executions_result
@pytest.mark.parametrize("ret_val, expected", [
(ReturnValueConcept("some_name", True, ParserResultConcept(value=ExplanationNode("", ""))), True),
(ReturnValueConcept("some_name", True, ParserResultConcept(value="other thing")), False),
(ReturnValueConcept("some_name", False, "not relevant"), False),
(ReturnValueConcept("some_name", True, Concept()), False)
])
def test_i_can_match(self, ret_val, expected):
context = self.get_context()
assert ExplainEvaluator().matches(context, ret_val) == expected
def test_i_can_eval_in_list(self, serializer):
sheerka, context, evaluator, execution_results = self.init_evaluator_with_list(
[
EC(desc="correct desc"),
EC(desc="wrong desc"),
]
)
ret_val = get_return_value(UnionNode(
[
FilterNode(TrueNode()),
FilterNode(PropertyEqualsNode("desc", "correct desc")),
]))
res = evaluator.eval(context, ret_val)
assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.EXPLANATION)
filtered = res.body.body
assert filtered == [execution_results[0]]
def test_i_can_eval_in_children(self):
sheerka, context, evaluator, execution_results = self.init_evaluator_with_list(
[
EC(desc="wrong desc", children=[EC(desc="wrong sub"), EC(desc="good sub")]),
EC(desc="wrong desc", children=[EC(desc="good sub")]),
]
)
ret_val = get_return_value(UnionNode(
[
FilterNode(TrueNode()),
FilterNode(PropertyEqualsNode("desc", "good sub")),
]))
res = evaluator.eval(context, ret_val)
assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.EXPLANATION)
filtered = res.body.body
assert filtered == [
execution_results[0].children[1],
execution_results[1].children[0],
]
def test_i_can_evaluate_multiple_filter_node(self):
sheerka, context, evaluator, execution_results = self.init_evaluator_with_list(
[
EC(desc="parent1", _id=1, children=[EC(desc="wrong sub"), EC(desc="good sub")]),
EC(desc="parent2", children=[EC(desc="wrong sub"), EC(desc="good sub")]),
EC(desc="good sub")
])
ret_val = get_return_value(UnionNode(
[
FilterNode(TrueNode()),
FilterNode(PropertyEqualsNode("id", "1")),
FilterNode(PropertyEqualsNode("desc", "good sub")),
]))
res = evaluator.eval(context, ret_val)
assert res.status
assert len(res.body) == 2
assert sheerka.isinstance(res.body[0], BuiltinConcepts.EXPLANATION)
assert sheerka.isinstance(res.body[1], BuiltinConcepts.EXPLANATION)
assert res.body[0].body == [execution_results[0]]
assert res.body[1].body == [
execution_results[0].children[1],
execution_results[1].children[1],
execution_results[2]
]
def test_i_can_eval_parent_and_child(self):
sheerka, context, evaluator, execution_results = self.init_evaluator_with_list(
[
EC(desc="parent1", children=[EC(desc="wrong sub"), EC(desc="good sub")]),
EC(desc="parent2", children=[EC(desc="wrong sub"), EC(desc="good sub")]),
EC(desc="good sub")
]
)
ret_val = get_return_value(UnionNode(
[
FilterNode(TrueNode()),
FilterNode(PropertyEqualsSequenceNode(["desc", "desc"], ["parent1", "good sub"])),
]))
res = evaluator.eval(context, ret_val)
assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.EXPLANATION)
filtered = res.body.body
assert filtered == [
execution_results[0].children[1],
]
def test_i_correctly_create_format_instructions(self):
sheerka, context, evaluator, execution_results = self.init_evaluator_with_list([])
ret_val = get_return_value(UnionNode(
[
FilterNode(TrueNode(), [
RecurseDefNode(2),
FormatLNode("abc"),
FormatDNode({"a": "{a}", "b": "{b}"})
]),
]))
res = evaluator.eval(context, ret_val)
assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.EXPLANATION)
instructions = res.body.instructions
assert instructions.recursive_props == {"children": 2}
assert instructions.format_l == {'core.sheerka.ExecutionContext.ExecutionContext': 'abc'}
assert instructions.format_d == [FormatDetailDesc(
IsaNode(ExecutionContext),
FormatDetailType.Props_In_Line,
{"a": "{a}", "b": "{b}"})]
def test_i_correctly_create_format_instructions_with_filtering(self):
sheerka, context, evaluator, execution_results = self.init_evaluator_with_list([])
ret_val = get_return_value(UnionNode(
[
FilterNode(TrueNode()),
FilterNode(PropertyEqualsNode("id", "1"), [RecurseDefNode(2), FormatLNode("abc")]),
]))
res = evaluator.eval(context, ret_val)
assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.EXPLANATION)
instructions = res.body.instructions
assert instructions.format_l == {'core.sheerka.ExecutionContext.ExecutionContext': 'abc'}
assert instructions.recursive_props == {"children": 2}
def test_i_can_have_different_instructions_for_different_filtering(self):
sheerka, context, evaluator, execution_results = self.init_evaluator_with_list([])
ret_val = get_return_value(UnionNode(
[
FilterNode(TrueNode()),
FilterNode(PropertyEqualsNode("id", "1"), [RecurseDefNode(2)]),
FilterNode(PropertyEqualsNode("desc", "good sub"), [FormatLNode("abc")]),
]))
res = evaluator.eval(context, ret_val)
assert res.status
assert len(res.body) == 2
assert res.body[0].instructions.recursive_props == {"children": 2}
assert res.body[1].instructions.format_l == {'core.sheerka.ExecutionContext.ExecutionContext': 'abc'}
def test_filtering_instructions_inherit_from_the_first_filtering_node(self):
sheerka, context, evaluator, execution_results = self.init_evaluator_with_list([])
ret_val = get_return_value(UnionNode(
[
FilterNode(TrueNode(), [RecurseDefNode(2)]),
FilterNode(PropertyEqualsNode("id", "1"), [RecurseDefNode(1)]),
FilterNode(PropertyEqualsNode("desc", "good sub"), [FormatLNode("abc")]),
]))
res = evaluator.eval(context, ret_val)
assert res.status
assert len(res.body) == 2
assert res.body[0].instructions.recursive_props == {"children": 1} # overridden
assert res.body[1].instructions.format_l == {'core.sheerka.ExecutionContext.ExecutionContext': 'abc'}
assert res.body[1].instructions.recursive_props == {"children": 2}
def test_i_can_reuse_a_recorded_digest(self):
sheerka, context, evaluator, execution_results = self.init_evaluator_with_list([])
expr = UnionNode([FilterNode(TrueNode(), [RecurseDefNode(2)])])
# need a valid result to test this feature
event = Event("fake message")
execution_context = ExecutionContext("TestExplainEvaluator", event, sheerka)
sheerka.sdp.save_result(execution_context)
# save another result
event2 = Event("fake message")
execution_context = ExecutionContext("TestExplainEvaluator", event2, sheerka)
sheerka.sdp.save_result(execution_context)
# digest is recorded during the first call
explanation_node = ExplanationNode(event.get_digest(), "", expr=expr, record_digest=True)
ret_val = get_return_value(explanation_node)
evaluator.eval(context, ret_val)
# the next call to get_event_digest will load the recorded digest
explanation_node = ExplanationNode("", "", expr=expr, record_digest=False) # digest is not provided
digest = evaluator.get_event_digest(sheerka, explanation_node)
assert digest == event.get_digest()
# test I can record another digest
explanation_node = ExplanationNode(event2.get_digest(), "", expr=expr, record_digest=True)
ret_val = get_return_value(explanation_node)
evaluator.eval(context, ret_val)
explanation_node = ExplanationNode("", "", expr=expr, record_digest=False) # digest is not provided
digest = evaluator.get_event_digest(sheerka, explanation_node)
assert digest == event2.get_digest()
# test can now reset the recorded digest
# (a digest is provided, but record_digest is set to False)
explanation_node = ExplanationNode(event.get_digest(), "", expr=expr, record_digest=False)
ret_val = get_return_value(explanation_node)
evaluator.eval(context, ret_val)
explanation_node = ExplanationNode("", "", expr=expr, record_digest=False) # digest is not provided
digest = evaluator.get_event_digest(sheerka, explanation_node)
assert digest is None
-205
View File
@@ -1,205 +0,0 @@
import pytest
from core.builtin_concepts import BuiltinConcepts
from parsers.BaseParser import UnexpectedTokenErrorNode, UnexpectedEof
from parsers.ExplainParser import ExplainParser, ExplanationNode, MultipleDigestError, ValueErrorNode, \
RecurseDefNode, FormatLNode, UnionNode, FilterNode, FormatDNode
from parsers.ExpressionParser import PropertyContainsNode, PropertyEqualsNode, TrueNode, AndNode, OrNode
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestExplainParser(TestUsingMemoryBasedSheerka):
def init_parser(self, **kwargs):
sheerka = self.get_sheerka(singleton=True, **kwargs)
context = self.get_context(sheerka)
parser = ExplainParser()
return sheerka, context, parser
def test_i_cannot_parse_empty_string(self):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, "")
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.NOT_FOR_ME)
def test_i_cannot_parse_if_not_for_me(self):
sheerka, context, parser = self.init_parser()
text = "foo"
res = parser.parse(context, text)
not_for_me = res.body
assert not res.status
assert sheerka.isinstance(not_for_me, BuiltinConcepts.NOT_FOR_ME)
assert not_for_me.body == text
assert isinstance(not_for_me.reason[0], UnexpectedTokenErrorNode)
@pytest.mark.parametrize("text, digest, command, directives", [
# ("explain", "", "explain", []),
("explain digest", "digest", "explain digest", []),
("explain -r 3", "", "explain -r 3", [RecurseDefNode(3)]),
("explain digest -r 3", "digest", "explain digest -r 3", [RecurseDefNode(3)]),
])
def test_i_can_parse_explain_without_filter(self, text, digest, command, directives):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, text)
parser_result = res.body
explanation_node = res.body.body
assert res.status
assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT)
assert parser_result.parser.name == "parsers.Explain"
assert parser_result.source == text
assert explanation_node.digest == digest
assert explanation_node.command == command
assert explanation_node.expr == UnionNode([FilterNode(TrueNode(), directives)])
def test_i_can_parse_using_filter(self):
sheerka, context, parser = self.init_parser()
text = "explain -f a=b"
res = parser.parse(context, text)
parser_result = res.body
explanation_node = res.body.body
assert res.status
assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT)
assert parser_result.parser.name == "parsers.Explain"
assert parser_result.source == text
assert explanation_node.expr == UnionNode([
FilterNode(TrueNode()),
FilterNode(PropertyContainsNode("a", "b"))])
@pytest.mark.parametrize("text, expected", [
("-f a==b", PropertyEqualsNode("a", "b")),
("--filter a==b", PropertyEqualsNode("a", "b")),
("-f a==b and c=d", AndNode(PropertyEqualsNode("a", "b"), PropertyContainsNode("c", "d"))),
("-f a==b or c=d", OrNode(PropertyEqualsNode("a", "b"), PropertyContainsNode("c", "d"))),
("-f a==b or c==d and e==f", OrNode(
PropertyEqualsNode("a", "b"),
AndNode(PropertyEqualsNode("c", "d"), PropertyEqualsNode("e", "f")))),
("-f a==b and c==d or e==f", OrNode(
AndNode(PropertyEqualsNode("a", "b"), PropertyEqualsNode("c", "d")),
PropertyEqualsNode("e", "f"))),
("-f (a==b or c==d) and e==f", AndNode(
OrNode(PropertyEqualsNode("a", "b"), PropertyEqualsNode("c", "d")),
PropertyEqualsNode("e", "f"))),
])
def test_i_can_parse_filter_expressions(self, text, expected):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, "explain " + text)
parser_result = res.body
explanation_node = res.body.body
expr_node = explanation_node.expr.filters[-1].expr
assert res.status
assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT)
assert isinstance(explanation_node, ExplanationNode)
assert expr_node == expected
@pytest.mark.parametrize("text, expected", [
("-r 2", [
FilterNode(TrueNode(), [RecurseDefNode(2)])
]),
("--format_l 'abc'", [
FilterNode(TrueNode(), [FormatLNode('abc')])
]),
("--format_d 'abc'", [
FilterNode(TrueNode(), [FormatDNode({"abc": "{abc}"})])
]),
("--format_d a,b,c", [
FilterNode(TrueNode(), [FormatDNode({"a": "{a}", "b": "{b}", "c": "{c}"})])
]),
("--format_d a , b , c", [
FilterNode(TrueNode(), [FormatDNode({"a": "{a}", "b": "{b}", "c": "{c}"})])
]),
("-r 2 --format_l 'abc'", [
FilterNode(TrueNode(), [RecurseDefNode(2), FormatLNode('abc')])
]),
("--format_d a, b -r 2", [
FilterNode(TrueNode(), [FormatDNode({"a": "{a}", "b": "{b}"}), RecurseDefNode(2)])
]),
("-f a==b -r 3", [
FilterNode(TrueNode()),
FilterNode(PropertyEqualsNode("a", "b"), [RecurseDefNode(3)]),
]),
("-f a==b --format_l 'abc'", [
FilterNode(TrueNode()),
FilterNode(PropertyEqualsNode("a", "b"), [FormatLNode("abc")]),
]),
("-r 3 -f a==b", [
FilterNode(TrueNode(), [RecurseDefNode(3)]),
FilterNode(PropertyEqualsNode("a", "b"), []),
]),
("--format_l 'abc' -f a==b", [
FilterNode(TrueNode(), [FormatLNode("abc")]),
FilterNode(PropertyEqualsNode("a", "b"), []),
]),
("-f a==b -f c==d", [
FilterNode(TrueNode()),
FilterNode(PropertyEqualsNode("a", "b")),
FilterNode(PropertyEqualsNode("c", "d"))
]),
("-r 1 -f a==b -r 2 -f c==d -r 3", [
FilterNode(TrueNode(), [RecurseDefNode(1)]),
FilterNode(PropertyEqualsNode("a", "b"), [RecurseDefNode(2)]),
FilterNode(PropertyEqualsNode("c", "d"), [RecurseDefNode(3)])
]),
])
def test_i_can_parse_other_directives(self, text, expected):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, "explain " + text)
parser_result = res.body
explanation_node = res.body.body
expr_node = explanation_node.expr
assert res.status
assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT)
assert isinstance(explanation_node, ExplanationNode)
assert expr_node.filters == expected
@pytest.mark.parametrize("text, expected", [
("explain -d digest", "digest"),
("explain -d", ""),
("explain -d -f a=b", "")
])
def test_i_can_parse_record_digest(self, text, expected):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, text)
explanation_node = res.body.body
assert explanation_node.digest == expected
assert explanation_node.record_digest
@pytest.mark.parametrize("text, expected_error_type", [
("explain digest1 digest2", MultipleDigestError),
("explain -r", UnexpectedEof),
("explain -r foo", ValueErrorNode),
("explain -r 1.2", ValueErrorNode),
("explain -f -r 1.2", UnexpectedTokenErrorNode),
("explain -f", UnexpectedEof),
("explain --format_d", UnexpectedEof),
("explain --format_l", UnexpectedEof),
("explain --format_l -r foo", UnexpectedTokenErrorNode),
("explain --format_d -r foo", UnexpectedTokenErrorNode),
])
def test_i_cannot_parse(self, text, expected_error_type):
sheerka, context, parser = self.init_parser()
res = parser.parse(context, text)
error = res.body
errors = res.body.body
assert not res.status
assert sheerka.isinstance(error, BuiltinConcepts.ERROR)
assert len(errors) == 1
assert isinstance(errors[0], expected_error_type)