Refactored sheerka execution flow + Enhanced log management

This commit is contained in:
2019-12-19 21:02:20 +01:00
parent 8dbe2e1b20
commit 5c95d918ad
32 changed files with 942 additions and 308 deletions
+2 -2
View File
@@ -41,7 +41,7 @@ def get_concept_part(part):
if isinstance(part, str):
node = PythonNode(part, ast.parse(part, mode="eval"))
return ReturnValueConcept(
who="Parsers:DefaultParser",
who="parsers.Default",
status=True,
value=ParserResultConcept(
source=part,
@@ -50,7 +50,7 @@ def get_concept_part(part):
if isinstance(part, PythonNode):
return ReturnValueConcept(
who="Parsers:DefaultParser",
who="parsers.Default",
status=True,
value=ParserResultConcept(
source=part.source,
+12
View File
@@ -729,6 +729,18 @@ def test_i_can_detect_indirect_infinite_recursion_with_sequence_or_ordered_choic
assert bar not in parser.concepts_grammars # removed because of the infinite recursion
def test_infinite_recursion_does_not_fail_if_a_concept_is_missing():
foo = Concept(name="foo")
bar = Concept(name="bar")
concepts = {
foo: bar
}
parser = ConceptLexerParser()
parser.initialize(get_context(), concepts)
assert foo in parser.concepts_grammars
def test_i_can_detect_indirect_infinite_recursion_with_optional():
# TODO infinite recursion with optional
pass
+15 -4
View File
@@ -6,7 +6,7 @@ from core.sheerka import Sheerka, ExecutionContext
from parsers.ConceptLexerParser import OrderedChoice, StrMatch, ConceptMatch
from parsers.PythonParser import PythonParser, PythonNode
from core.tokenizer import Keywords, Tokenizer
from parsers.DefaultParser import DefaultParser, NameNode, SyntaxErrorNode
from parsers.DefaultParser import DefaultParser, NameNode, SyntaxErrorNode, CannotHandleErrorNode
from parsers.DefaultParser import UnexpectedTokenErrorNode, DefConceptNode
from parsers.BnfParser import BnfParser
@@ -68,7 +68,7 @@ def get_concept(name, where=None, pre=None, post=None, body=None, definition=Non
concept.post = get_concept_part(post)
if definition:
concept.definition = ReturnValueConcept(
"Parsers:RegexParser",
"parsers.Bnf",
True,
definition)
@@ -85,7 +85,7 @@ def get_concept_part(part):
if isinstance(part, str):
node = PythonNode(part, ast.parse(part, mode="eval"))
return ReturnValueConcept(
who="Parsers:DefaultParser",
who="parsers.Default",
status=True,
value=ParserResultConcept(
source=part,
@@ -94,7 +94,7 @@ def get_concept_part(part):
if isinstance(part, PythonNode):
return ReturnValueConcept(
who="Parsers:DefaultParser",
who="parsers.Default",
status=True,
value=ParserResultConcept(
source=part.source,
@@ -359,3 +359,14 @@ def test_i_can_detect_empty_bnf_declaration():
assert not res.status
assert res.value.value[0] == SyntaxErrorNode([], "Empty declaration")
def test_i_can_detect_not_for_me():
text = "hello world"
context = get_context()
parser = DefaultParser()
res = parser.parse(context, text)
assert not res.status
assert context.sheerka.isinstance(res.value, BuiltinConcepts.NOT_FOR_ME)
assert isinstance(res.value.body[0], CannotHandleErrorNode)
+39
View File
@@ -0,0 +1,39 @@
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from core.sheerka import ExecutionContext
def test_id_is_incremented_by_event_digest():
a = ExecutionContext("foo", "event_1", None)
b = ExecutionContext("foo", "event_1", None)
c = ExecutionContext("foo", "event_2", None)
d = b.push()
e = c.push()
assert a.id == 0
assert b.id == 1
assert c.id == 0
assert d.id == 2
assert e.id == 1
def test_some_properties_are_given_to_the_child():
a = ExecutionContext("foo", "event_1", "fake_sheerka",
desc="some description",
obj=Concept("foo"),
step=BuiltinConcepts.EVALUATION,
iteration=15,
concepts={"bar": Concept("bar")})
b = a.push()
assert b.who == a.who
assert b.event_digest == a.event_digest
assert b.sheerka == a.sheerka
assert b.desc == ""
assert b.obj == a.obj
assert b.step == a.step
assert b.iteration == a.iteration
assert b.concepts == a.concepts
assert b.id == a.id + 1
assert b._tab == a._tab + " "
+53 -29
View File
@@ -61,12 +61,12 @@ def test_builtin_concepts_are_initialized():
def test_builtin_concepts_can_be_updated():
sheerka = get_sheerka(False, skip_builtins_in_db=False)
sheerka = get_sheerka(False, False)
loaded_sheerka = sheerka.get(BuiltinConcepts.SHEERKA)
loaded_sheerka.metadata.desc = "I have a description"
sheerka.sdp.modify("Test", sheerka.CONCEPTS_ENTRY, loaded_sheerka.key, loaded_sheerka)
sheerka = get_sheerka(False)
sheerka = get_sheerka(False, False)
loaded_sheerka = sheerka.get(BuiltinConcepts.SHEERKA)
assert loaded_sheerka.metadata.desc == "I have a description"
@@ -313,6 +313,12 @@ def test_i_cannot_get_value_when_no_body_and_allow_none_body_is_false():
body=concept)
def test_list_of_concept_is_sorted_by_id():
sheerka = get_sheerka(False, False)
concepts = sheerka.concepts()
assert concepts[0].id < concepts[-1].id
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#
# E V A L U A T I O N S
@@ -326,7 +332,7 @@ def test_i_cannot_get_value_when_no_body_and_allow_none_body_is_false():
def test_i_can_eval_python_expressions_with_no_variable(text, expected):
sheerka = get_sheerka()
res = sheerka.eval(text)
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert res[0].status
@@ -339,7 +345,7 @@ def test_i_can_eval_concept_with_python_body():
sheerka.add_in_cache(concept)
text = "one"
res = sheerka.eval(text)
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert res[0].status
assert res[0].value == 1
@@ -352,7 +358,7 @@ def test_i_can_eval_concept_with_concept_body():
sheerka.add_in_cache(concept_one)
sheerka.add_in_cache(concept_un)
res = sheerka.eval("un")
res = sheerka.evaluate_user_input("un")
return_value = res[0].value
assert len(res) == 1
assert res[0].status
@@ -365,7 +371,7 @@ def test_i_can_eval_concept_with_no_body():
sheerka.add_in_cache(concept)
text = "one"
res = sheerka.eval(text)
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert res[0].status
assert res[0].value == concept
@@ -378,7 +384,7 @@ def test_is_unique_property_is_used_when_evaluating():
sheerka.add_in_cache(concept)
text = "one"
res = sheerka.eval(text)
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert res[0].status
assert res[0].value == concept
@@ -403,7 +409,7 @@ as:
expected.init_key()
sheerka = get_sheerka()
res = sheerka.eval(text)
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert res[0].status
@@ -431,7 +437,7 @@ def test_i_can_eval_def_concept_part_when_one_part_is_a_ref_of_another_concept()
concept_a_plus_b = Concept(name="a plus b").set_prop("a").set_prop("b")
sheerka.add_in_cache(concept_a_plus_b)
res = sheerka.eval("def concept a xx b as a plus b")
res = sheerka.evaluate_user_input("def concept a xx b as a plus b")
expected = Concept(name="a xx b", body="a plus b").set_prop("a").set_prop("b").init_key()
expected.metadata.id = "1001"
@@ -462,14 +468,31 @@ as:
"""
sheerka = get_sheerka()
sheerka.eval(text)
res = sheerka.eval(text)
sheerka.evaluate_user_input(text)
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].value, BuiltinConcepts.CONCEPT_ALREADY_DEFINED)
def test_i_can_disable_an_evaluator():
sheerka = get_sheerka()
concept = Concept(name="one", body="1")
sheerka.add_in_cache(concept)
text = "one"
p = next(e for e in sheerka.evaluators if e.__name__ == "PythonEvaluator")
p.enabled = False # not that you disable the class, not the instance
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, BuiltinConcepts.PARSER_RESULT)
p.enabled = True # put back for the remaining unit tests
@pytest.mark.parametrize("text", [
"",
" ",
@@ -478,7 +501,7 @@ as:
def test_i_can_eval_a_empty_input(text):
sheerka = get_sheerka()
res = sheerka.eval(text)
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert res[0].status
@@ -492,7 +515,7 @@ def test_i_can_eval_concept_with_variable():
sheerka.add_in_cache(concept_hello)
sheerka.add_in_cache(concept_foo)
res = sheerka.eval("hello foo")
res = sheerka.evaluate_user_input("hello foo")
return_value = res[0].value
assert len(res) == 1
assert res[0].status
@@ -505,7 +528,7 @@ def test_i_can_eval_concept_with_variable_and_python_as_body():
sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").set_prop("a"))
sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
res = sheerka.eval("hello foo")
res = sheerka.evaluate_user_input("hello foo")
assert len(res) == 1
assert res[0].status
assert res[0].value, "hello foo"
@@ -518,7 +541,7 @@ def test_i_can_eval_duplicate_concepts_with_same_value():
sheerka.add_in_cache(Concept(name="hello foo", body="'hello foo'"))
sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
res = sheerka.eval("hello foo")
res = sheerka.evaluate_user_input("hello foo")
assert len(res) == 1
assert res[0].status
assert res[0].value, "hello foo"
@@ -532,7 +555,7 @@ def test_i_cannot_manage_duplicate_concepts_when_the_values_are_different():
sheerka.add_in_cache(Concept(name="hello foo", body="'hello foo'"))
sheerka.add_in_cache(Concept(name="foo", body="'another value'"))
res = sheerka.eval("hello foo")
res = sheerka.evaluate_user_input("hello foo")
assert len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].value, BuiltinConcepts.TOO_MANY_SUCCESS)
@@ -551,7 +574,7 @@ def test_i_can_manage_concepts_with_the_same_key_when_values_are_the_same():
sheerka.create_new_concept(context, Concept(name="hello a", body="'hello ' + a").set_prop("a"))
sheerka.create_new_concept(context, Concept(name="hello b", body="'hello ' + b").set_prop("b"))
res = sheerka.eval("hello 'foo'")
res = sheerka.evaluate_user_input("hello 'foo'")
assert len(res) == 1
assert res[0].status
assert res[0].value == "hello foo"
@@ -563,7 +586,7 @@ def test_i_can_create_concepts_with_python_code_as_body():
context = get_context(sheerka)
sheerka.create_new_concept(context, Concept(name="concepts", body="sheerka.concepts()"))
res = sheerka.eval("concepts")
res = sheerka.evaluate_user_input("concepts")
assert len(res) == 1
assert res[0].status
@@ -571,14 +594,14 @@ def test_i_can_create_concepts_with_python_code_as_body():
def test_i_can_create_concept_with_bnf_definition():
sheerka = get_sheerka()
sheerka = get_sheerka(False, False)
a = Concept("a")
sheerka.add_in_cache(a)
sheerka.concepts_grammars = ConceptLexerParser().initialize(
get_context(sheerka),
{a: OrderedChoice("one", "two")}).body
res = sheerka.eval("def concept plus from bnf a ('plus' plus)?")
res = sheerka.evaluate_user_input("def concept plus from bnf a ('plus' plus)?")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
@@ -605,21 +628,22 @@ def test_i_can_create_concept_with_bnf_definition():
def test_i_can_eval_bnf_definitions():
sheerka = get_sheerka()
concept_a = sheerka.eval("def concept a from bnf 'one' | 'two'")[0].body.body
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' | 'two'")[0].body.body
res = sheerka.eval("one")
res = sheerka.evaluate_user_input("one")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a)
def test_i_can_eval_bnf_definitions_with_variables():
sheerka = get_sheerka()
concept_a = sheerka.eval("def concept a from bnf 'one' | 'two'")[0].body.body
concept_b = sheerka.eval("def concept b from bnf a 'three'")[0].body.body
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' | 'two'")[0].body.body
concept_b = sheerka.evaluate_user_input("def concept b from bnf a 'three'")[0].body.body
res = sheerka.eval("one three")
res = sheerka.evaluate_user_input("one three")
assert len(res) == 1
assert res[0].status
@@ -635,14 +659,14 @@ def test_i_can_eval_bnf_definitions_from_separate_instances():
but make sure that the BNF are correctly persisted and loaded
"""
sheerka = get_sheerka(False)
concept_a = sheerka.eval("def concept a from bnf 'one' | 'two'")[0].body.body
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' | 'two'")[0].body.body
res = get_sheerka(False).eval("one")
res = get_sheerka(False).evaluate_user_input("one")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a)
res = get_sheerka(False).eval("two")
res = get_sheerka(False).evaluate_user_input("two")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a)
@@ -650,7 +674,7 @@ def test_i_can_eval_bnf_definitions_from_separate_instances():
def get_sheerka(use_dict=True, skip_builtins_in_db=True):
root = "mem://" if use_dict else root_folder
sheerka = Sheerka(skip_builtins_in_db)
sheerka = Sheerka(skip_builtins_in_db=skip_builtins_in_db)
sheerka.initialize(root)
return sheerka
+88
View File
@@ -22,6 +22,11 @@ def read_json_file(sdp, file_name):
class ObjWithKey:
"""
Object where the key can be resolved using get_key()
Not suitable for Json dump as there is no to_dict() method
"""
def __init__(self, a, b):
self.a = a
self.b = b
@@ -39,6 +44,11 @@ class ObjWithKey:
class ObjSetKey:
"""
Object where the key can be be automatically set thanks to set_key()
Not suitable for Json dump as there is no to_dict() method
"""
def __init__(self, value, key=None):
self.value = value
self.key = key
@@ -56,6 +66,11 @@ class ObjSetKey:
class ObjNoKey:
"""
Object with no key, they won't be ordered
Not suitable for Json dump as there is no to_dict() method
"""
def __init__(self, a, b):
self.a = a
self.b = b
@@ -73,6 +88,11 @@ class ObjNoKey:
class ObjDumpJson:
"""
Object where the key can be resolved using get_key()
that can be used to dump as Json
"""
def __init__(self, key=None, value=None):
self.key = key
self.value = value
@@ -104,6 +124,12 @@ class ObjDumpJson:
class ObjWithDigestNoKey:
"""
Object that can compute its digest.
It can be used to test objects sharing the same entry (but that are different)
Not suitable for Json dump as there is no to_dict() method
"""
def __init__(self, a, b):
self.a = a
self.b = b
@@ -124,6 +150,12 @@ class ObjWithDigestNoKey:
class ObjWithDigestWithKey:
"""
Object with a key that can compute its digest.
It can be used to test objects sharing the same key (but that are different)
Not suitable for Json dump as there is no to_dict() method
"""
def __init__(self, a, b):
self.a = a
self.b = b
@@ -908,6 +940,62 @@ def test_i_can_list_when_one_element(root):
assert list(result) == ["foo"]
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_list_when_multiple_entries_under_the_same_key(root):
sdp = SheerkaDataProvider(root)
sdp.add(evt_digest, "entry", ObjWithKey("a", "b"))
sdp.add(evt_digest, "entry", ObjWithKey("a", "c"))
result = sdp.list("entry")
assert list(result) == [[ObjWithKey("a", "b"), ObjWithKey("a", "c")]]
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_list_when_multiple_entries_under_the_same_key_when_reference(root):
sdp = SheerkaDataProvider(root)
sdp.serializer.register(PickleSerializer(lambda obj: isinstance(obj, ObjWithKey)))
sdp.add(evt_digest, "entry", ObjWithKey("a", "b"), use_ref=True)
sdp.add(evt_digest, "entry", ObjWithKey("a", "c"), use_ref=True)
result = sdp.list("entry")
assert list(result) == [[ObjWithKey("a", "b"), ObjWithKey("a", "c")]]
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_list_when_multiple_entries_under_the_same_entry(root):
sdp = SheerkaDataProvider(root)
sdp.add(evt_digest, "entry", ObjNoKey("a", "b"))
sdp.add(evt_digest, "entry", ObjNoKey("a", "c"))
result = sdp.list("entry")
assert list(result) == [ObjNoKey("a", "b"), ObjNoKey("a", "c")]
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_list_when_multiple_entries_under_the_same_entry_when_reference(root):
sdp = SheerkaDataProvider(root)
sdp.serializer.register(PickleSerializer(lambda obj: isinstance(obj, ObjNoKey)))
sdp.add(evt_digest, "entry", ObjNoKey("a", "b"), use_ref=True)
sdp.add(evt_digest, "entry", ObjNoKey("a", "c"), use_ref=True)
result = sdp.list("entry")
assert list(result) == [ObjNoKey("a", "b"), ObjNoKey("a", "c")]
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
+206
View File
@@ -0,0 +1,206 @@
# Make sure that the evaluators works as expected
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from core.sheerka import Sheerka, ExecutionContext
from evaluators.BaseEvaluator import OneReturnValueEvaluator, BaseEvaluator
def get_sheerka():
sheerka = Sheerka()
sheerka.initialize("mem://")
return sheerka
def get_context(sheerka):
return ExecutionContext("test", "xxx", sheerka)
def get_ret_val(sheerka, concept, who="who"):
concept.init_key()
if concept.key not in sheerka.concepts_cache:
sheerka.concepts_cache[concept.key] = concept
return sheerka.ret(who, True, sheerka.new(concept.key))
class EvaluatorWithPriority(OneReturnValueEvaluator):
out = []
def __init__(self, name, priority):
super().__init__(name, priority)
def matches(self, context, return_value):
target = str(return_value.body.key)
step = str(context.step)
text = f"{step} [{context.iteration}] "
text += f"{self.name[len(BaseEvaluator.PREFIX):]} - matches - target={target}"
self.out.append(text)
return True
def eval(self, context, return_value):
target = str(return_value.body.key)
step = str(context.step)
text = f"{step} [{context.iteration}] "
text += f"{self.name[len(BaseEvaluator.PREFIX):]} - eval - target={target}"
self.out.append(text)
class EvaluatorWithPriority10(EvaluatorWithPriority):
def __init__(self):
super().__init__("priority10", 10)
class EvaluatorWithPriority15(EvaluatorWithPriority):
def __init__(self):
super().__init__("priority15", 15)
class EvaluatorWithPriority20(EvaluatorWithPriority):
def __init__(self):
super().__init__("priority20", 20)
class EvaluatorModifyFoo(EvaluatorWithPriority):
def __init__(self):
super().__init__("modifyFoo", 10)
def matches(self, context, return_value):
super().matches(context, return_value)
return context.sheerka.isinstance(return_value.body, "foo")
def eval(self, context, return_value):
super().eval(context, return_value)
return get_ret_val(context.sheerka, Concept("bar"))
class EvaluatorModifyBar(EvaluatorWithPriority):
def __init__(self):
super().__init__("modifyBar", 10)
def matches(self, context, return_value):
super().matches(context, return_value)
return context.sheerka.isinstance(return_value.body, "bar")
def eval(self, context, return_value):
super().eval(context, return_value)
return get_ret_val(context.sheerka, Concept("baz"))
def test_that_return_values_is_unchanged_when_no_evaluator():
sheerka = get_sheerka()
sheerka.evaluators = []
entries = get_ret_val(sheerka, Concept("foo"))
return_values = sheerka.execute(get_context(sheerka), entries, [BuiltinConcepts.EVALUATION])
assert return_values == [entries]
def test_i_can_use_a_list_as_input():
sheerka = get_sheerka()
sheerka.evaluators = []
entries = [get_ret_val(sheerka, Concept("foo"))]
return_values = sheerka.execute(get_context(sheerka), entries, [BuiltinConcepts.EVALUATION])
assert return_values == entries
def test_step_concept_is_removed_after_processing_if_not_reduced():
"""
The entry is not modified by an evaluator
"""
sheerka = get_sheerka()
sheerka.evaluators = [EvaluatorWithPriority10]
entry = get_ret_val(sheerka, Concept("foo"))
return_values = sheerka.execute(get_context(sheerka), entry, [BuiltinConcepts.EVALUATION])
assert BuiltinConcepts.EVALUATION not in [r.body.key for r in return_values]
def test_step_concept_is_removed_after_processing_if_not_reduced_2():
"""
This time the entry is modified by an evaluator,
nevertheless, step concept is removed
"""
sheerka = get_sheerka()
sheerka.evaluators = [EvaluatorModifyFoo]
entry = get_ret_val(sheerka, Concept("foo"))
return_values = sheerka.execute(get_context(sheerka), entry, [BuiltinConcepts.EVALUATION])
assert BuiltinConcepts.EVALUATION not in [r.body.key for r in return_values]
def test_that_higher_priority_evaluators_are_evaluated_first():
sheerka = get_sheerka()
sheerka.evaluators = [EvaluatorWithPriority20, EvaluatorWithPriority10, EvaluatorWithPriority15]
entries = [get_ret_val(sheerka, Concept("foo"))]
EvaluatorWithPriority.out = []
sheerka.execute(get_context(sheerka), entries, [BuiltinConcepts.EVALUATION])
assert EvaluatorWithPriority.out == [
'__EVALUATION [0] priority20 - matches - target=foo',
'__EVALUATION [0] priority20 - eval - target=foo',
'__EVALUATION [0] priority20 - matches - target=__EVALUATION',
'__EVALUATION [0] priority20 - eval - target=__EVALUATION',
'__EVALUATION [0] priority15 - matches - target=foo',
'__EVALUATION [0] priority15 - eval - target=foo',
'__EVALUATION [0] priority15 - matches - target=__EVALUATION',
'__EVALUATION [0] priority15 - eval - target=__EVALUATION',
'__EVALUATION [0] priority10 - matches - target=foo',
'__EVALUATION [0] priority10 - eval - target=foo',
'__EVALUATION [0] priority10 - matches - target=__EVALUATION',
'__EVALUATION [0] priority10 - eval - target=__EVALUATION']
def test_that_predicate_is_checked_before_evaluation():
sheerka = get_sheerka()
sheerka.evaluators = [EvaluatorModifyFoo]
entries = [get_ret_val(sheerka, Concept("foo")), get_ret_val(sheerka, Concept("baz"))]
EvaluatorWithPriority.out = []
sheerka.execute(get_context(sheerka), entries, [BuiltinConcepts.EVALUATION])
assert EvaluatorWithPriority.out == [
'__EVALUATION [0] modifyFoo - matches - target=foo',
'__EVALUATION [0] modifyFoo - eval - target=foo',
'__EVALUATION [0] modifyFoo - matches - target=baz',
'__EVALUATION [0] modifyFoo - matches - target=__EVALUATION',
'__EVALUATION [1] modifyFoo - matches - target=bar',
'__EVALUATION [1] modifyFoo - matches - target=baz',
'__EVALUATION [1] modifyFoo - matches - target=__EVALUATION'
]
def test_evaluation_continue_until_no_more_modification():
sheerka = get_sheerka()
sheerka.evaluators = [EvaluatorModifyFoo, EvaluatorModifyBar]
entries = [get_ret_val(sheerka, Concept("foo")), get_ret_val(sheerka, Concept("baz"))]
EvaluatorWithPriority.out = []
sheerka.execute(get_context(sheerka), entries, [BuiltinConcepts.EVALUATION])
assert EvaluatorWithPriority.out == [
'__EVALUATION [0] modifyFoo - matches - target=foo',
'__EVALUATION [0] modifyFoo - eval - target=foo',
'__EVALUATION [0] modifyFoo - matches - target=baz',
'__EVALUATION [0] modifyFoo - matches - target=__EVALUATION',
'__EVALUATION [0] modifyBar - matches - target=foo',
'__EVALUATION [0] modifyBar - matches - target=baz',
'__EVALUATION [0] modifyBar - matches - target=__EVALUATION',
'__EVALUATION [1] modifyFoo - matches - target=bar',
'__EVALUATION [1] modifyFoo - matches - target=baz',
'__EVALUATION [1] modifyFoo - matches - target=__EVALUATION',
'__EVALUATION [1] modifyBar - matches - target=bar',
'__EVALUATION [1] modifyBar - eval - target=bar',
'__EVALUATION [1] modifyBar - matches - target=baz',
'__EVALUATION [1] modifyBar - matches - target=__EVALUATION',
'__EVALUATION [2] modifyFoo - matches - target=baz',
'__EVALUATION [2] modifyFoo - matches - target=baz',
'__EVALUATION [2] modifyFoo - matches - target=__EVALUATION',
'__EVALUATION [2] modifyBar - matches - target=baz',
'__EVALUATION [2] modifyBar - matches - target=baz',
'__EVALUATION [2] modifyBar - matches - target=__EVALUATION'
]