Implemented a first and basic version of a Rete rule engine

This commit is contained in:
2021-02-09 16:06:32 +01:00
parent 821dbed189
commit a2a8d5c5e5
110 changed files with 7301 additions and 1654 deletions
+11 -11
View File
@@ -65,9 +65,9 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
assert in_db == [ComparisonObj(context.event.get_digest(), "prop_name", two.str_id, one.str_id, ">", "#")]
def test_i_can_add_is_greater_than_for_rules(self):
sheerka, context, r1, r2 = self.init_test(cache_only=False).with_rules(("True", "true"),
("False", "false"),
compile_rule=False).unpack()
sheerka, context, r1, r2 = self.init_test(cache_only=False).with_format_rules(("True", "true"),
("False", "false"),
compile_rule=False).unpack()
service = sheerka.services[SheerkaComparisonManager.NAME]
@@ -106,10 +106,10 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
assert in_db == [ComparisonObj(context.event.get_digest(), "prop_name", one.str_id, two.str_id, "<", "#")]
def test_i_can_add_is_less_than_for_rules(self):
sheerka, context, r1, r2 = self.init_test(cache_only=False).with_rules(("True", "true"),
("False", "false"),
compile_rule=False,
create_new=True).unpack()
sheerka, context, r1, r2 = self.init_test(cache_only=False).with_format_rules(("True", "true"),
("False", "false"),
compile_rule=False,
create_new=True).unpack()
service = sheerka.services[SheerkaComparisonManager.NAME]
@@ -213,7 +213,7 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
assert sheerka.om.get(SheerkaComparisonManager.RESOLVED_COMPARISON_ENTRY, "prop_name|#") == expected_weights2
# I can retrieve the previous values
sheerka.pop_ontology()
sheerka.pop_ontology(context)
assert sheerka.om.get(SheerkaComparisonManager.COMPARISON_ENTRY, "prop_name|#") == expected_in_cache
assert sheerka.om.get(SheerkaComparisonManager.RESOLVED_COMPARISON_ENTRY, "prop_name|#") == expected_weights
@@ -544,9 +544,9 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
assert event_received
def test_an_event_is_fired_when_modifying_rule_precedence(self):
sheerka, context, r1, r2 = self.init_test(cache_only=False).with_rules(("True", "true"),
("False", "false"),
compile_rule=False).unpack()
sheerka, context, r1, r2 = self.init_test(cache_only=False).with_format_rules(("True", "true"),
("False", "false"),
compile_rule=False).unpack()
foo = Concept("foo")
event_received = False
sheerka.om.clear(SheerkaComparisonManager.COMPARISON_ENTRY)
+2 -2
View File
@@ -563,7 +563,7 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
assert updated.get_metadata().variables == [("a", None), ("c", "value")]
assert updated.get_metadata().props == {BuiltinConcepts.ISA: {"bar"}}
sheerka.pop_ontology()
sheerka.pop_ontology(context)
def test_i_cannot_modify_without_any_modification(self):
sheerka, context, foo = self.init_concepts("foo")
@@ -726,7 +726,7 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.CONCEPT_ALREADY_DEFINED)
sheerka.pop_ontology()
sheerka.pop_ontology(context)
# But I can if I remove the layer
res = sheerka.create_new_concept(context, Concept("bar"))
assert res.status
+10 -232
View File
@@ -1,12 +1,11 @@
import pytest
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from core.global_symbols import NotInit, NotFound
from core.sheerka.ExecutionContext import ExecutionContext
from core.sheerka.services.SheerkaDebugManager import SheerkaDebugManager, DebugItem, ConceptDebugObj
from parsers.PythonParser import PythonNode
from sdp.sheerkaDataProvider import Event
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -21,220 +20,12 @@ class DummyObj:
class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
def test_i_can_activate_debug(self):
sheerka, context = self.init_concepts()
return_value_id = 0
sheerka.set_debug(context, True)
assert sheerka.debug_activated()
sheerka.set_debug(context, False)
assert not sheerka.debug_activated()
def test_when_debug_mode_is_activated_context_are_in_debug_mode(self):
sheerka = self.get_sheerka()
ExecutionContext.ids.clear()
root_context = self.get_context(sheerka)
sheerka.set_debug(root_context, True)
context = root_context.push(BuiltinConcepts.NOP, None) # sub_context.id = 1
sub_context = context.push(BuiltinConcepts.NOP, None) # sub_sub_context.parent = 1
sub_context2 = context.push(BuiltinConcepts.NOP, None) # sub_sub_context2.parent = 1
sub_sub_context = sub_context.push(BuiltinConcepts.NOP, None) # is a child
assert context.id == 1
assert context.debug_enabled
assert sub_context.debug_enabled
assert sub_context2.debug_enabled
assert sub_sub_context.debug_enabled
assert not root_context.debug_enabled
def test_i_can_activate_debug_for_new_context(self):
sheerka = self.get_sheerka()
ExecutionContext.ids.clear()
root_context = self.get_context(sheerka)
sheerka.set_debug(root_context, True)
sheerka.set_explicit(root_context, True)
sheerka.activate_debug_for(root_context, 1)
context = ExecutionContext("test", Event(), sheerka, BuiltinConcepts.TESTING, None) # context.id = 1
assert context.debug_enabled
def test_i_can_activate_debug_for_new_context_2(self):
"""
This time children is also requested
:return:
"""
sheerka = self.get_sheerka()
ExecutionContext.ids.clear()
root_context = self.get_context(sheerka)
sheerka.set_debug(root_context, True)
sheerka.set_explicit(root_context, True)
sheerka.activate_debug_for(root_context, 1, children=True)
context = ExecutionContext("test", Event(), sheerka, BuiltinConcepts.TESTING, None) # context.id = 1
assert context.debug_enabled
def test_i_can_activate_debug_for_a_context_using_push(self):
sheerka = self.get_sheerka()
ExecutionContext.ids.clear()
root_context = self.get_context(sheerka)
service = sheerka.services[SheerkaDebugManager.NAME]
sheerka.set_debug(root_context, True)
sheerka.set_explicit(root_context, True)
sheerka.activate_debug_for(root_context, 1)
context = root_context.push(BuiltinConcepts.NOP, None) # sub_context.id = 1
sub_context = context.push(BuiltinConcepts.NOP, None) # sub_sub_context.parent = 1
assert context.id == 1
assert 1 in service.context_cache
assert context.debug_enabled
assert not sub_context.debug_enabled
assert not root_context.debug_enabled
def test_global_debug_must_be_activated_to_activate_context_debug(self):
sheerka = self.get_sheerka()
ExecutionContext.ids.clear()
root_context = self.get_context(sheerka)
service = sheerka.services[SheerkaDebugManager.NAME]
sheerka.set_debug(root_context, False)
sheerka.activate_debug_for(root_context, 1)
context = root_context.push(BuiltinConcepts.NOP, None) # sub_context.id = 1
assert context.id == 1
assert 1 in service.context_cache
assert not context.debug_enabled
def test_i_can_activate_debug_for_sub_children(self):
sheerka = self.get_sheerka()
ExecutionContext.ids.clear()
root_context = self.get_context(sheerka)
service = sheerka.services[SheerkaDebugManager.NAME]
sheerka.set_debug(root_context, True)
sheerka.set_explicit(root_context, True)
sheerka.activate_debug_for(root_context, 1, children=True)
context = root_context.push(BuiltinConcepts.NOP, None) # sub_context.id = 1
sub_context = context.push(BuiltinConcepts.NOP, None) # sub_sub_context.parent = 1
sub_context2 = context.push(BuiltinConcepts.NOP, None) # sub_sub_context2.parent = 1
sub_sub_context = sub_context.push(BuiltinConcepts.NOP, None) # is a child
assert context.id == 1
assert 1 in service.context_cache
assert "1+" in service.context_cache
assert context.debug_enabled
assert sub_context.debug_enabled
assert sub_context2.debug_enabled
assert sub_sub_context.debug_enabled
assert not root_context.debug_enabled
def test_i_can_deactivate_debug_for_a_context(self):
sheerka = self.get_sheerka()
ExecutionContext.ids.clear()
root_context = self.get_context(sheerka)
service = sheerka.services[SheerkaDebugManager.NAME]
sheerka.set_debug(root_context, True)
sheerka.set_explicit(root_context, True)
sheerka.activate_debug_for(root_context, 1)
sheerka.deactivate_debug_for(root_context, 1)
context = root_context.push(BuiltinConcepts.NOP, None)
assert context.id == 1
assert 1 not in service.context_cache
assert not context.debug_enabled
def test_i_can_deactivate_context_but_not_children(self):
sheerka = self.get_sheerka()
ExecutionContext.ids.clear()
root_context = self.get_context(sheerka)
service = sheerka.services[SheerkaDebugManager.NAME]
sheerka.set_debug(root_context, True)
sheerka.set_explicit(root_context, True)
sheerka.activate_debug_for(root_context, 1, True)
sheerka.deactivate_debug_for(root_context, 1)
context = root_context.push(BuiltinConcepts.NOP, None) # sub_context.id = 1
sub_context = context.push(BuiltinConcepts.NOP, None) # sub_sub_context.parent = 1
sub_context2 = context.push(BuiltinConcepts.NOP, None) # sub_sub_context2.parent = 1
sub_sub_context = sub_context.push(BuiltinConcepts.NOP, None) # is a child
assert context.id == 1
assert 1 not in service.context_cache
assert "1+" in service.context_cache
assert not context.debug_enabled
assert sub_context.debug_enabled
assert sub_context2.debug_enabled
assert sub_sub_context.debug_enabled
def test_i_can_deactivate_context_and_children(self):
sheerka = self.get_sheerka()
ExecutionContext.ids.clear()
root_context = self.get_context(sheerka)
service = sheerka.services[SheerkaDebugManager.NAME]
sheerka.set_debug(root_context, True)
sheerka.set_explicit(root_context, True)
sheerka.activate_debug_for(root_context, 1)
sheerka.deactivate_debug_for(root_context, 1, children=True)
context = root_context.push(BuiltinConcepts.NOP, None) # sub_context.id = 1
sub_context = context.push(BuiltinConcepts.NOP, None) # sub_sub_context.parent = 1
sub_context2 = context.push(BuiltinConcepts.NOP, None) # sub_sub_context2.parent = 1
sub_sub_context = sub_context.push(BuiltinConcepts.NOP, None) # is a child
assert 1 not in service.context_cache
assert "1+" not in service.context_cache
assert not context.debug_enabled
assert not sub_context.debug_enabled
assert not sub_context2.debug_enabled
assert not sub_sub_context.debug_enabled
def test_i_can_activate_debug_for_a_variable(self):
sheerka, context = self.init_concepts()
service = sheerka.services[SheerkaDebugManager.NAME]
sheerka.set_debug(context)
sheerka.activate_debug_for(context, "Out")
assert "Out" in service.variable_cache
assert sheerka.debug_activated_for("Out")
sheerka.deactivate_debug_for(context, "Out")
assert "Out" not in service.variable_cache
assert not sheerka.debug_activated_for("Out")
def test_i_can_activate_debug_for_sub_children_using_the_simplified_form(self):
sheerka = self.get_sheerka()
ExecutionContext.ids.clear()
root_context = self.get_context(sheerka)
service = sheerka.services[SheerkaDebugManager.NAME]
sheerka.set_debug(root_context, True)
sheerka.set_explicit(root_context, True)
sheerka.activate_debug_for(root_context, "1+")
context = root_context.push(BuiltinConcepts.NOP, None) # sub_context.id = 1
sub_context = context.push(BuiltinConcepts.NOP, None) # sub_sub_context.parent = 1
sub_context2 = context.push(BuiltinConcepts.NOP, None) # sub_sub_context2.parent = 1
sub_sub_context = sub_context.push(BuiltinConcepts.NOP, None) # is a child
assert context.id == 1
assert 1 in service.context_cache
assert "1+" in service.context_cache
assert context.debug_enabled
assert sub_context.debug_enabled
assert sub_context2.debug_enabled
assert sub_sub_context.debug_enabled
assert not root_context.debug_enabled
@classmethod
def setup(cls):
sheerka = cls().get_sheerka()
cls.return_value_id = sheerka.get_by_key("__RETURN_VALUE").id
@pytest.mark.parametrize("item_type", [
"vars", "rules", "concepts"
@@ -631,9 +422,6 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
root_context = self.get_context(sheerka)
sheerka.set_debug(root_context, True)
sheerka.set_explicit(root_context, False)
sheerka.activate_debug_for(root_context, 1, children=True)
sheerka.activate_debug_for(root_context, "SomeVar")
sheerka.debug_var(root_context, "service_name.*.var")
sheerka.debug_rule(root_context, 1)
sheerka.debug_concept(root_context, 1001)
@@ -642,9 +430,6 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
another_service.initialize_deferred(root_context, True)
assert another_service.activated
assert not another_service.explicit
assert another_service.context_cache == {1, "1+"}
assert another_service.variable_cache == {"SomeVar"}
assert another_service.debug_vars_settings == [
DebugItem('var', 'service_name', None, None, False, None, False, True)]
assert another_service.debug_rules_settings == [
@@ -688,7 +473,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
python_node = PythonNode("one + 1").init_ast()
res = sheerka.inspect(context, python_node)
assert set(res.body.keys()) == {"#type#", 'ast_', 'ast_str', 'compiled', 'objects', 'source'}
assert set(res.body.keys()) == {"#type#", 'ast_', 'ast_str', 'compiled', 'objects', 'source', 'original_source'}
def test_i_can_inspect_object_specified_attributes(self):
sheerka, context = self.init_concepts()
@@ -872,7 +657,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
assert res.body == {
'body': concept_debug_obj,
'#type#': 'ReturnValueConcept',
'id': '43',
'id': f'{self.return_value_id}',
'key': '__RETURN_VALUE',
'name': '__RETURN_VALUE',
'parents': [concept_debug_obj],
@@ -920,21 +705,18 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
sheerka.push_ontology(context, "new ontology")
service.set_debug(context)
service.set_explicit(context)
service.debug_var(context, "var_service.var_method.var_name", "1+", 1)
service.debug_rule(context, "rule_service.rule_method.rule_name", "2+", 2)
service.debug_concept(context, "concept_service.concept_method.concept_name", "3+", 3)
# sanity check
assert service.activated
assert service.explicit
assert service.debug_vars_settings != []
assert service.debug_rules_settings != []
assert service.debug_concepts_settings != []
sheerka.pop_ontology()
sheerka.pop_ontology(context)
assert not service.activated
assert not service.explicit
assert service.context_cache == set()
assert service.variable_cache == set()
assert service.debug_vars_settings == []
@@ -946,7 +728,6 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaDebugManager.NAME]
service.set_debug(context)
service.set_explicit(context)
service.debug_var(context, "v_service.v_method.v_name", "1+", 1)
service.debug_rule(context, "r_service.r_method.r_name", "2+", 2)
service.debug_concept(context, "c_serv.c_method.c_name", "3+", 3)
@@ -955,7 +736,6 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
# modify the state
service.set_debug(context, False)
service.set_explicit(context, False)
service.debug_var(context, "var_service2.var_method2.var_name2", "11+", 11)
service.debug_rule(context, "rule_service2.rule_method2.rule_name2", "22+", 22)
service.debug_concept(context, "concept_service2.concept_method2.concept_name2", "33+", 33)
@@ -967,10 +747,8 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
assert len(service.debug_rules_settings) == 2
assert len(service.debug_concepts_settings) == 2
sheerka.pop_ontology()
sheerka.pop_ontology(context)
assert service.activated
assert service.explicit
assert service.debug_vars_settings == [DebugItem("v_name", "v_service", "v_method", 1, True, 1, False, True)]
assert service.debug_rules_settings == [DebugItem("r_name", "r_service", "r_method", 2, True, 2, False, True)]
assert service.debug_concepts_settings == [DebugItem("c_name", "c_serv", "c_method", 3, True, 3, False, True)]
+179 -6
View File
@@ -1,15 +1,22 @@
import operator
from core.concept import Concept
from core.rule import Rule
from core.sheerka.services.SheerkaEvaluateRules import SheerkaEvaluateRules, LOW_PRIORITY_RULES, DISABLED_RULES
import pytest
from core.builtin_concepts_ids import BuiltinConcepts
from core.concept import Concept, DEFINITION_TYPE_DEF
from core.rule import Rule, ACTION_TYPE_EXEC
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 RuleCompiledPredicate, SheerkaRuleManager
from evaluators.PythonEvaluator import PythonEvaluator, Expando
from parsers.PythonParser import PythonParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
def test_i_can_evaluate_python_rules(self):
sheerka, context, r1, r2, r3, r4, r5, r6, r7, r8, r9 = self.init_test().with_rules(
sheerka, context, r1, r2, r3, r4, r5, r6, r7, r8, r9 = self.init_test().with_format_rules(
Rule(predicate="a == 1", action="", priority=1), # r1
Rule(predicate="a == 2", action="", priority=1), # r2
Rule(predicate="a == 3", action="", priority=0), # r3
@@ -32,9 +39,10 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
DISABLED_RULES: [r7]
}
def test_i_can_evaluate_concept_rules(self):
def test_i_can_evaluate_question_concept_rules(self):
sheerka, context, concept, r1, r2, r3, r4, r5, r6, r7, r8, r9 = self.init_test().with_concepts(
Concept("x equals y", body="x == y").def_var("x").def_var("y"), create_new=True).with_rules(
Concept("x equals y", body="x == y", pre="is_question()").def_var("x").def_var("y"),
create_new=True).with_format_rules(
Rule(predicate="a equals 1", action="", priority=1), # r1
Rule(predicate="a equals 2", action="", priority=1), # r2
Rule(predicate="a equals 3", action="", priority=0), # r3
@@ -58,6 +66,159 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
DISABLED_RULES: [r7]
}
@pytest.mark.parametrize("predicates", [
("True", "False"),
("False", "True"),
])
def test_i_can_eval_when_multiple_python_predicates(self, predicates):
"""
In this test, the rule has multiple predicates to evaluate
The test make sure that is one predicate is successful, the rule must be evaluated
"""
sheerka, context, my_rule = self.init_test().with_format_rules(Rule("my rule"),
compile_rule=False,
create_new=False).unpack()
service = sheerka.services[SheerkaEvaluateRules.NAME]
# create fake compiled predicates
parser = PythonParser()
my_rule.compiled_predicates = [
RuleCompiledPredicate("my rule", None, PythonEvaluator.NAME, parser.parse(context, ParserInput(exp)), None)
for exp in predicates]
my_rule.metadata.is_compiled = True
my_rule.metadata.is_enabled = True
res = service.evaluate_rules(context, [my_rule], {}, set())
assert res == {
True: [my_rule],
}
def test_i_can_evaluate_rules_when_concepts_are_questions(self):
sheerka, context, isa, cat, crocodile, pet, r1, r2, r3 = self.init_test().with_concepts(
Concept("x is a y", body="isa(x,y)", pre="is_question()").def_var("x").def_var("y"),
"cat",
"crocodile",
"pet",
create_new=True).with_format_rules(
Rule(predicate="cat is a pet", action=""),
Rule(predicate="crocodile is a pet", action=""),
Rule(predicate="not crocodile is a pet", action=""),
).unpack()
sheerka.set_isa(context, cat, pet)
service = sheerka.services[SheerkaEvaluateRules.NAME]
res = service.evaluate_rules(context, [r1, r2, r3], {}, set())
assert res == {True: [r1, r3], False: [r2]}
@pytest.mark.parametrize("predicate", [
"greetings",
"c:|1001:",
"hello 'kodjo'"
])
def test_i_can_evaluate_rules_when_concepts_are_not_questions(self, predicate):
"""
In this test, we evaluate rules that involves concepts that are not questions
"""
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=predicate, action="")).unpack()
service = sheerka.services[SheerkaEvaluateRules.NAME]
ret = sheerka.ret("evaluator", True, sheerka.new(greetings, a="kodjo"))
res = service.evaluate_rules(context, [rule], {"__ret": ret}, set())
assert res == {True: [rule]}
@pytest.mark.parametrize("recognized_by", [
RECOGNIZED_BY_ID,
RECOGNIZED_BY_NAME,
None
])
def test_i_can_evaluate_concept_rules_when_variable_is_a_one_word_concept(self, recognized_by):
"""
In this test, we evaluate rules that involves concepts that are not questions
"""
sheerka, context, greetings, there, rule = self.init_test().with_concepts(
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()
service = sheerka.services[SheerkaEvaluateRules.NAME]
there_instance = sheerka.new_from_template(there, there.key)
if recognized_by:
there_instance.set_hint(BuiltinConcepts.RECOGNIZED_BY, recognized_by)
ret = sheerka.ret("evaluator", True, sheerka.new(greetings, a=there_instance))
res = service.evaluate_rules(context, [rule], {"__ret": ret}, set())
assert res == {True: [rule]}
@pytest.mark.parametrize("recognized_by", [
RECOGNIZED_BY_ID,
RECOGNIZED_BY_NAME,
None
])
def test_i_can_evaluate_concept_rules_when_variable_is_a_two_words_concept(self, recognized_by):
"""
In this test, we evaluate rules that involves concepts that are not questions
"""
sheerka, context, greetings, my_friend, rule = self.init_test().with_concepts(
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()
service = sheerka.services[SheerkaEvaluateRules.NAME]
my_friend_instance = sheerka.new_from_template(my_friend, my_friend.key)
if recognized_by:
my_friend_instance.set_hint(BuiltinConcepts.RECOGNIZED_BY, recognized_by)
ret = sheerka.ret("evaluator", True, sheerka.new(greetings, a=my_friend_instance))
res = service.evaluate_rules(context, [rule], {"__ret": ret}, set())
assert res == {True: [rule]}
def test_i_can_evaluate_concept_rules_when_variable_is_an_expando(self):
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()
service = sheerka.services[SheerkaEvaluateRules.NAME]
ret = sheerka.ret("evaluator", True, sheerka.new(greetings, a=Expando("sheerka", {})))
res = service.evaluate_rules(context, [rule], {"__ret": ret}, set())
assert res == {True: [rule]}
def test_i_can_evaluate_concept_rules_when_same_name(self):
sheerka, context, g1, g2, rule = self.init_test().with_concepts(
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()
service = sheerka.services[SheerkaEvaluateRules.NAME]
ret1 = sheerka.ret("evaluator", True, sheerka.new(g1, a="kodjo"))
res = service.evaluate_rules(context, [rule], {"__ret": ret1}, set())
assert res == {True: [rule]}
ret2 = sheerka.ret("evaluator", True, sheerka.new(g2, a="kodjo"))
res = service.evaluate_rules(context, [rule], {"__ret": ret2}, set())
assert res == {True: [rule]}
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(
Concept("greetings", definition="hi a", definition_type=DEFINITION_TYPE_DEF).def_var("a")).unpack()
service = sheerka.services[SheerkaEvaluateRules.NAME]
ret1 = sheerka.ret("evaluator", True, sheerka.new(g1, a="kodjo"))
res = service.evaluate_rules(context, [rule], {"__ret": ret1}, set())
assert res == {True: [rule]}
ret2 = sheerka.ret("evaluator", True, sheerka.new(g2, a="kodjo"))
res = service.evaluate_rules(context, [rule], {"__ret": ret2}, set())
assert res == {True: [rule]}
def test_i_can_disable_rules_at_runtime(self):
sheerka, context, r1, r2, = self.init_format_rules(
Rule(predicate="a == 1", action="", priority=2), # r1
@@ -72,3 +233,15 @@ class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
True: [r2],
DISABLED_RULES: [r1]
}
def test_rete_network_is_updated_on_new_rule_creation(self):
sheerka, context = self.init_test().unpack()
evaluate_rule_service = sheerka.services[SheerkaEvaluateRules.NAME]
rule_manager_service = sheerka.services[SheerkaRuleManager.NAME]
rule = Rule(ACTION_TYPE_EXEC, "test", "ret.status == True", "test()")
rule_manager_service.init_rule(context, rule)
sheerka.create_new_rule(context, rule)
assert rule in evaluate_rule_service.network.rules
assert rule.rete_net == evaluate_rule_service.network
+1 -1
View File
@@ -80,6 +80,6 @@ example_of_class_method. event=xxx, data='42'
assert "my first topic" in service.subscribers
assert "my second topic" in service.subscribers
sheerka.pop_ontology()
sheerka.pop_ontology(context)
assert "my first topic" in service.subscribers
assert "my second topic" not in service.subscribers
@@ -122,7 +122,7 @@ class TestSheerkaFunctionsParametersHistory(TestUsingMemoryBasedSheerka):
3: [("'string value'", 1)]
})}
sheerka.pop_ontology()
sheerka.pop_ontology(context)
assert sheerka.om.copy(service.FUNCTIONS_PARAMETERS_ENTRY) == {"function": FunctionParametersObj(
context.event.get_digest(),
"function",
+1 -1
View File
@@ -322,7 +322,7 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
assert sheerka.isa(foo, group2)
# I can revert back
sheerka.pop_ontology()
sheerka.pop_ontology(context)
assert sheerka.isaset(context, group1)
assert sheerka.isinset(foo, group1)
assert sheerka.isa(foo, group1)
+679 -83
View File
@@ -3,15 +3,21 @@ import ast
import pytest
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, CMV
from core.global_symbols import RULE_COMPARISON_CONTEXT
from core.concept import Concept, CMV, DEFINITION_TYPE_DEF, CC, DoNotResolve
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.services.SheerkaRuleManager import SheerkaRuleManager, FormatRuleParser, \
from core.sheerka.Sheerka import RECOGNIZED_BY_ID, RECOGNIZED_BY_NAME
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, FormatRuleActionParser, \
FormatAstRawText, FormatAstVariable, FormatAstSequence, FormatAstFunction, \
FormatRuleSyntaxError, FormatAstList, UnexpectedEof, FormatAstColor, RulePredicate, FormatAstDict, FormatAstMulti
FormatRuleSyntaxError, FormatAstList, UnexpectedEof, FormatAstColor, RuleCompiledPredicate, FormatAstDict, \
FormatAstMulti, \
PythonCodeEmitter, NoConditionFound, FormatAstNode
from core.sheerka.services.sheerka_service import FailedToCompileError
from core.tokenizer import Token, TokenKind
from parsers.BaseNodeParser import SourceCodeWithConceptNode, SourceCodeNode
from parsers.PythonParser import PythonNode
from sheerkarete.common import V
from sheerkarete.conditions import Condition, AndConditions
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -32,7 +38,7 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
(ACTION_TYPE_EXEC, SheerkaRuleManager.EXEC_RULE_ENTRY),
])
def test_i_can_create_a_new_rule(self, action_type, cache_entry):
sheerka, context = self.init_concepts(cache_only=False)
sheerka, context = self.init_test(cache_only=False).unpack()
previous_rules_number = sheerka.om.get_all(sheerka.OBJECTS_IDS_ENTRY)[SheerkaRuleManager.RULE_IDS]
rule = Rule(action_type, "name", "True", "Hello world")
@@ -96,6 +102,114 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
sheerka.om.current_cache_manager().caches[
SheerkaRuleManager.FORMAT_RULE_ENTRY].cache) == 2 + previous_rules_number
@pytest.mark.parametrize("action_type, cache_entry", [
(ACTION_TYPE_PRINT, SheerkaRuleManager.FORMAT_RULE_ENTRY),
(ACTION_TYPE_EXEC, SheerkaRuleManager.EXEC_RULE_ENTRY),
])
def test_i_can_delete_a_rule(self, action_type, cache_entry):
sheerka, context, rule = self.init_test(cache_only=False).with_rules(
action_type,
Rule(action_type, "rule_name", "id.attr == 'value'", 'True')).unpack()
rule_to_delete = Rule(rule.compiled_action, rule_id=rule.id)
event_sink = []
self.sheerka.subscribe(EVENT_RULE_DELETED, lambda c, r: event_sink.append(r))
ret = sheerka.remove_rule(context, rule_to_delete)
assert ret.status
assert sheerka.om.get(cache_entry, rule.id) is NotFound
assert sheerka.om.get(SheerkaRuleManager.RULES_BY_NAME_ENTRY, rule.id) is NotFound
sheerka.om.commit(context)
assert sheerka.om.current_sdp().get(cache_entry, rule.id)
assert sheerka.om.current_sdp().get(SheerkaRuleManager.RULES_BY_NAME_ENTRY, rule.id)
assert event_sink == [rule]
def test_i_can_init_rule_with_a_exec_rule(self):
sheerka, context = self.init_test(cache_only=False).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
rule = Rule(ACTION_TYPE_EXEC, "name", "__input == 'hello world'", "'Hello back at you !'")
rule = service.init_rule(context, rule)
assert rule.metadata.is_compiled
assert rule.metadata.is_enabled
assert len(rule.compiled_predicates) == 1
assert len(rule.rete_disjunctions) == 1
assert sheerka.isinstance(rule.compiled_action, BuiltinConcepts.RETURN_VALUE)
assert rule.compiled_action.status
assert rule.error_sink is None
def test_i_can_init_rule_with_a_format_rule(self):
sheerka, context = self.init_test(cache_only=False).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
rule = Rule(ACTION_TYPE_PRINT, "name", "__input == 'hello world'", "Hello back at you !")
rule = service.init_rule(context, rule)
assert rule.metadata.is_compiled
assert rule.metadata.is_enabled
assert len(rule.compiled_predicates) == 1
assert len(rule.rete_disjunctions) == 1
assert isinstance(rule.compiled_action, FormatAstNode)
assert rule.error_sink is None
def test_i_do_not_init_rule_an_already_compiled_rule(self):
sheerka, context = self.init_test(cache_only=False).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
rule = Rule(ACTION_TYPE_EXEC, "name", "cannot build", "cannot compile either")
rule.metadata.is_compiled = True
rule = service.init_rule(context, rule)
assert rule.metadata.is_compiled
assert rule.error_sink is None # no error detected
@pytest.mark.parametrize("action_type, action", [
(ACTION_TYPE_EXEC, "'Hello back at you !'"),
(ACTION_TYPE_PRINT, "Hello back at you !"),
])
def test_init_rule_returns_errors_when_cannot_build_predicate(self, action_type, action):
sheerka, context = self.init_test(cache_only=False).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
rule = Rule(ACTION_TYPE_EXEC, "name", "cannot build", "'Hello back at you !'")
rule.metadata.is_enabled = True # it should be disabled
rule = service.init_rule(context, rule)
assert len(rule.error_sink["when"]) > 0
assert sheerka.is_error(rule.error_sink["when"][0])
assert "print" not in rule.error_sink
assert "then" not in rule.error_sink
assert rule.metadata.is_compiled
assert not rule.metadata.is_enabled
assert rule.compiled_predicates is None
assert rule.rete_disjunctions is None
@pytest.mark.parametrize("action_type, action", [
(ACTION_TYPE_EXEC, "cannot build action"),
(ACTION_TYPE_PRINT, "list("),
])
def test_init_rule_returns_error_when_cannot_build_action(self, action_type, action):
sheerka, context = self.init_test(cache_only=False).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
rule = Rule(action_type, "name", "__input == 'hello world'", action)
rule.metadata.is_enabled = True # it should be disabled
rule = service.init_rule(context, rule)
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 other_action_type not in rule.error_sink
assert "when" not in rule.error_sink
assert rule.metadata.is_compiled
assert not rule.metadata.is_enabled
assert rule.compiled_action is None
@pytest.mark.parametrize("text, expected", [
("", FormatAstRawText("")),
(" ", FormatAstRawText(" ")),
@@ -134,7 +248,7 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
("multi(var_name)", FormatAstMulti("var_name")),
])
def test_i_can_parse_format_rule(self, text, expected):
assert FormatRuleParser(text).parse() == expected
assert FormatRuleActionParser(text).parse() == expected
@pytest.mark.parametrize("text, expected_error", [
("{", UnexpectedEof("while parsing variable", Token(TokenKind.LBRACE, "{", 0, 1, 1))),
@@ -156,15 +270,52 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
("dict()", FormatRuleSyntaxError("variable name not found", None)),
])
def test_i_cannot_parse_invalid_format(self, text, expected_error):
parser = FormatRuleParser(text)
parser = FormatRuleActionParser(text)
parser.parse()
assert parser.error_sink == expected_error
@pytest.mark.parametrize("text", [
"__action == 'some_action' and True",
"__action == 'some_action' and not a question",
"__action == 'some_action' and is a question",
])
def test_i_can_compile_predicate_when_action_is_provided(self, text):
sheerka, context, *concepts = self.init_test().with_concepts(
"a question",
Concept("is a question", pre='is_question()'),
create_new=True).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
compiled_result = service.compile_when(context, "test", text)
res = compiled_result.compiled_predicates
assert len(res) == 1
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].action == 'some_action'
def test_i_can_compile___action_is_not_part_of_the_predicates(self):
sheerka, context, *concepts = self.init_concepts("foo")
service = sheerka.services[SheerkaRuleManager.NAME]
ast_ = ast.parse("a == 5", "<source>", 'eval')
expected_python_node = PythonNode('a == 5', ast_)
compiled_result = service.compile_when(context, "test", "__action == 'some action' and a == 5")
res = compiled_result.compiled_predicates
assert len(res) == 1
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].evaluator == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
assert sheerka.objvalue(res[0].predicate) == expected_python_node
assert res[0].concept is None
@pytest.mark.parametrize("text", [
"a == 5",
"foo == 5",
"foo > 5",
"func() == 5",
"not a == 5",
"not foo > 5",
"not func() == 5",
])
def test_i_can_compile_predicate_when_pure_python(self, text):
sheerka, context, *concepts = self.init_concepts("foo")
@@ -172,10 +323,11 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
ast_ = ast.parse(text, "<source>", 'eval')
expected_python_node = PythonNode(text, ast_)
res = service.compile_when(context, "test", text)
compiled_result = service.compile_when(context, "test", text)
res = compiled_result.compiled_predicates
assert len(res) == 1
assert isinstance(res[0], RulePredicate)
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].evaluator == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
assert sheerka.objvalue(res[0].predicate) == expected_python_node
@@ -184,6 +336,8 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
@pytest.mark.parametrize("text, expected_type", [
("isinstance(a, int)", SourceCodeWithConceptNode),
("func()", SourceCodeNode),
("not isinstance(a, int)", PythonNode),
("not func()", PythonNode),
])
def test_i_can_compile_predicates_that_resolve_to_python(self, text, expected_type):
sheerka, context, *concepts = self.init_concepts()
@@ -191,30 +345,15 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
ast_ = ast.parse(text, "<source>", 'eval')
expected_python_node = PythonNode(text, ast_)
res = service.compile_when(context, "test", text)
compiled_result = service.compile_when(context, "test", text)
res = compiled_result.compiled_predicates
assert len(res) == 1
assert isinstance(res[0], RulePredicate)
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].evaluator == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
assert isinstance(sheerka.objvalue(res[0].predicate), expected_type)
assert sheerka.objvalue(res[0].predicate).python_node == expected_python_node
assert res[0].concept is None
def test_i_can_compile_predicate_when_python_and_concept(self):
sheerka, context, *concepts = self.init_test().with_concepts(Concept("foo bar"), create_new=True).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
text = "foo bar == 5"
ast_ = ast.parse("__C__foo0bar__1001__C__ == 5", "<source>", 'eval')
resolved_expected = PythonNode(text, ast_)
res = service.compile_when(context, "test", text)
assert len(res) == 1
assert isinstance(res[0], RulePredicate)
assert res[0].evaluator == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
assert sheerka.objvalue(res[0].predicate) == resolved_expected
assert sheerka.objvalue(res[0].predicate).get_python_node() == expected_python_node
assert res[0].concept is None
@pytest.mark.parametrize("text, expected_variables", [
@@ -234,15 +373,106 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
expected = concepts[0]
expected.get_metadata().variables = [('x', expected_variables[0]), ('y', expected_variables[1])]
res = service.compile_when(context, "test", text)
compiled_result = service.compile_when(context, "test", text)
res = compiled_result.compiled_predicates
assert len(res) == 1
assert isinstance(res[0], RulePredicate)
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].evaluator == CONCEPT_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
assert sheerka.objvalue(res[0].predicate) == expected
assert res[0].concept == expected
@pytest.mark.parametrize("text, text_to_compile, expected_variables", [
("not cat is an animal", "not __C__00var0000is0an000var001__1001__C__", ["cat", "animal"]),
("not a is an animal", "not __C__00var0000is0an000var001__1001__C__", ["a", "animal"]),
("not cat is an b", "not __C__00var0000is0an000var001__1001__C__", ["cat", "b"]),
])
def test_i_can_compile_negative_predicate_when_exact_concept(self, text, text_to_compile, expected_variables):
sheerka, context, *concepts = self.init_test().with_concepts(
Concept("x is an y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
Concept("cat"),
Concept("animal"),
create_new=True
).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
expected_concept = concepts[0]
expected_concept.get_metadata().variables = [('x', expected_variables[0]), ('y', expected_variables[1])]
ast_ = ast.parse(text_to_compile, "<source>", 'eval')
expected_python_node = PythonNode(text_to_compile, ast_)
expected_python_node.original_source = text
expected_python_node.objects = {"__C__00var0000is0an000var001__1001__C__": expected_concept}
res = service.compile_when(context, "test", text)
assert len(res) == 1
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].evaluator == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
assert isinstance(sheerka.objvalue(res[0].predicate), PythonNode)
python_node = sheerka.objvalue(res[0].predicate).get_python_node()
assert python_node == expected_python_node
assert len(python_node.objects) == 1
assert python_node.objects["__C__00var0000is0an000var001__1001__C__"] == expected_concept
assert res[0].concept is None
@pytest.mark.skip("Not managed yet")
@pytest.mark.parametrize("text, text_to_compile, expected_variables", [
("not cat is an animal", "__C__00var0000is0an000var001__1001__C__", ["not cat", "animal"])
])
def test_i_can_compile_negative_predicate_when_exact_concept(self, text, text_to_compile, expected_variables):
sheerka, context, *concepts = self.init_test().with_concepts(
Concept("x is an y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
Concept("cat"),
Concept("animal"),
create_new=True
).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
expected_concept = concepts[0]
expected_concept.get_metadata().variables = [('x', expected_variables[0]), ('y', expected_variables[1])]
ast_ = ast.parse(text_to_compile, "<source>", 'eval')
expected_python_node = PythonNode(text_to_compile, ast_)
expected_python_node.original_source = text
expected_python_node.objects = {"__C__00var0000is0an000var001__1001__C__": expected_concept}
res = service.compile_when(context, "test", text)
assert len(res) == 1
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].evaluator == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
assert isinstance(sheerka.objvalue(res[0].predicate), PythonNode)
python_node = sheerka.objvalue(res[0].predicate).get_python_node()
assert python_node == expected_python_node
assert len(python_node.objects) == 1
assert python_node.objects["__C__00var0000is0an000var001__1001__C__"] == expected_concept
assert res[0].concept is None
@pytest.mark.parametrize("text, text_to_compile", [
("foo bar == 5", "__C__foo0bar__1001__C__ == 5"),
("not foo bar == 5", "not __C__foo0bar__1001__C__ == 5"),
])
def test_i_can_compile_predicate_when_python_and_concept(self, text, text_to_compile):
sheerka, context, *concepts = self.init_test().with_concepts(Concept("foo bar"), create_new=True).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
ast_ = ast.parse(text_to_compile, "<source>", 'eval')
resolved_expected = PythonNode(text_to_compile, ast_, text)
compiled_result = service.compile_when(context, "test", text)
res = compiled_result.compiled_predicates
assert len(res) == 1
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].evaluator == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
python_node = sheerka.objvalue(res[0].predicate).get_python_node()
assert python_node == resolved_expected
assert python_node.objects == {'__C__foo0bar__1001__C__': concepts[0]}
assert res[0].concept is None
@pytest.mark.parametrize("text, expected_variables", [
("a cat is an animal", ["a cat", "animal"]),
("a cat is an b", ["a cat", "b"]),
@@ -257,10 +487,11 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaRuleManager.NAME]
expected = CMV(concepts[0], x=expected_variables[0], y=expected_variables[1])
res = service.compile_when(context, "test", text)
compiled_result = service.compile_when(context, "test", text)
res = compiled_result.compiled_predicates
assert len(res) == 1
assert isinstance(res[0], RulePredicate)
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].evaluator == CONCEPT_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
assert sheerka.objvalue(res[0].predicate)[0].concept == expected
@@ -275,15 +506,101 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaRuleManager.NAME]
expected = concepts[1]
res = service.compile_when(context, "test", "cat is an animal")
compiled_result = service.compile_when(context, "test", "cat is an animal")
res = compiled_result.compiled_predicates
assert len(res) == 1
assert isinstance(res[0], RulePredicate)
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].evaluator == CONCEPT_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
assert sheerka.objvalue(res[0].predicate)[0].concept == expected
assert res[0].concept == expected
def test_i_can_compile_predicate_when_mix_of_concepts_and_python(self):
sheerka, context, animal, cat, dog, pet, is_a, is_an = self.init_test().with_concepts(
Concept("animal"),
Concept("a cat"),
Concept("dog"),
Concept("pet"),
Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
Concept("x is an y", pre="is_question()", definition="('cat'|'bird')=x 'is an' animal").def_var("x"),
create_new=True
).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
text = "a cat is a pet and bird is an animal and x > 5 and dog is a pet"
compiled_result = service.compile_when(context, "test", text)
res = compiled_result.compiled_predicates
to_compile = '__C__00var0000is0a000var001__1005__C__ and __C__00var0000is0an0y__1006__C__ and x > 5 and __C__00var0000is0a000var001__1005_1__C__'
ast_ = ast.parse(to_compile, "<source>", 'eval')
expected_python_node = PythonNode(to_compile, ast_, text)
assert len(res) == 1
assert isinstance(res[0], RuleCompiledPredicate)
python_node = res[0].predicate.body.body
assert python_node == expected_python_node
assert python_node.objects == {
"__C__00var0000is0a000var001__1005__C__": CC(is_a, x=cat, y=pet),
"__C__00var0000is0an0y__1006__C__": CC(is_an, exclude_body=True, x=DoNotResolve("bird"), animal=animal),
"__C__00var0000is0a000var001__1005_1__C__": CMV(is_a, x="dog", y="pet"),
}
@pytest.mark.parametrize("text", [
"a and not b",
"not b and a",
"__ret and not __ret.status",
])
def test_i_can_compile_negative_conjunctions_when_pure_python(self, text):
sheerka, context, *concepts = self.init_concepts("foo")
service = sheerka.services[SheerkaRuleManager.NAME]
ast_ = ast.parse(text, "<source>", 'eval')
expected_python_node = PythonNode(text, ast_)
compiled_result = service.compile_when(context, "test", text)
res = compiled_result.compiled_predicates
assert len(res) == 1
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].evaluator == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
assert sheerka.objvalue(res[0].predicate) == expected_python_node
assert res[0].concept is None
def test_i_can_compile_negative_conjunction_of_mix_of_concepts_and_python(self):
sheerka, context, animal, cat, dog, pet, is_a, is_an = self.init_test().with_concepts(
Concept("animal"),
Concept("a cat"),
Concept("dog"),
Concept("pet"),
Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
Concept("x is an y", pre="is_question()", definition="('cat'|'bird')=x 'is an' animal").def_var("x"),
create_new=True
).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
text = "not a cat is a pet and not bird is an animal and not x > 5 and not dog is a pet"
compiled_result = service.compile_when(context, "test", text)
res = compiled_result.compiled_predicates
to_compile = 'not __C__00var0000is0a000var001__1005__C__'
to_compile += ' and not __C__00var0000is0an0y__1006__C__'
to_compile += ' and not x > 5'
to_compile += ' and not __C__00var0000is0a000var001__1005_1__C__'
ast_ = ast.parse(to_compile, "<source>", 'eval')
expected_python_node = PythonNode(to_compile, ast_, text)
assert len(res) == 1
assert isinstance(res[0], RuleCompiledPredicate)
python_node = res[0].predicate.body.body
assert python_node == expected_python_node
assert python_node.objects == {
"__C__00var0000is0a000var001__1005__C__": CC(is_a, x=cat, y=pet),
"__C__00var0000is0an0y__1006__C__": CC(is_an, exclude_body=True, x=DoNotResolve("bird"), animal=animal),
"__C__00var0000is0a000var001__1005_1__C__": CMV(is_a, x="dog", y="pet"),
}
def test_i_can_compile_predicate_when_multiple_choices(self):
sheerka, context, *concepts = self.init_test().with_concepts(
Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
@@ -292,24 +609,185 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
res = service.compile_when(context, "test", "a is a b")
compiled_result = service.compile_when(context, "test", "a is a b")
res = compiled_result.compiled_predicates
assert len(res) == 2
assert isinstance(res[0], RulePredicate)
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].evaluator == CONCEPT_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
assert sheerka.objvalue(res[0].predicate)[0].concept == CMV(concepts[0], x="a", y="b")
assert res[0].concept == CMV(concepts[0], x="a", y="b")
assert isinstance(res[1], RulePredicate)
assert isinstance(res[1], RuleCompiledPredicate)
assert res[1].evaluator == CONCEPT_EVALUATOR_NAME
assert sheerka.isinstance(res[1].predicate, BuiltinConcepts.RETURN_VALUE)
assert sheerka.objvalue(res[1].predicate)[0].concept == CMV(concepts[1], x="a", y="b")
assert res[1].concept == CMV(concepts[1], x="a", y="b")
def test_i_can_compile_predicate_when_mix_and_multiple_choices(self):
sheerka, context, *concepts = self.init_test().with_concepts(
Concept("animal"),
Concept("a cat"),
Concept("dog"),
Concept("pet"),
Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
Concept("x is a y", pre="is_question()", body="isa(x, y)").def_var("x").def_var("y"),
Concept("x is an y", pre="is_question()", definition="('cat'|'bird')=x 'is an' animal").def_var("x"),
create_new=True
).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
text = "__action == 'value' and a cat is a pet and bird is an animal and x > 5 and dog is a pet"
compiled_result = service.compile_when(context, "test", text)
res = compiled_result.compiled_predicates
assert len(res) == 4
trimmed_source = "a cat is a pet and bird is an animal and x > 5 and dog is a pet"
current_res = res[0]
assert isinstance(current_res, RuleCompiledPredicate)
assert current_res.evaluator == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(current_res.predicate, BuiltinConcepts.RETURN_VALUE)
python_source = "__C__00var0000is0a000var001__1005__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1005_1__C__"
ast_ = ast.parse(python_source, "<source>", 'eval')
resolved_expected = PythonNode(python_source, ast_, trimmed_source)
assert sheerka.objvalue(current_res.predicate) == resolved_expected
assert current_res.concept is None
current_res = res[1]
assert isinstance(current_res, RuleCompiledPredicate)
assert current_res.evaluator == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(current_res.predicate, BuiltinConcepts.RETURN_VALUE)
python_source = "__C__00var0000is0a000var001__1005__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1006__C__"
ast_ = ast.parse(python_source, "<source>", 'eval')
resolved_expected = PythonNode(python_source, ast_, trimmed_source)
assert sheerka.objvalue(current_res.predicate) == resolved_expected
assert current_res.concept is None
current_res = res[2]
assert isinstance(current_res, RuleCompiledPredicate)
assert current_res.evaluator == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(current_res.predicate, BuiltinConcepts.RETURN_VALUE)
python_source = "__C__00var0000is0a000var001__1006__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1005__C__"
ast_ = ast.parse(python_source, "<source>", 'eval')
resolved_expected = PythonNode(python_source, ast_, trimmed_source)
assert sheerka.objvalue(current_res.predicate) == resolved_expected
assert current_res.concept is None
current_res = res[3]
assert isinstance(current_res, RuleCompiledPredicate)
assert current_res.evaluator == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(current_res.predicate, BuiltinConcepts.RETURN_VALUE)
python_source = "__C__00var0000is0a000var001__1006__C__ and __C__00var0000is0an0y__1007__C__ and x > 5 and __C__00var0000is0a000var001__1006_1__C__"
ast_ = ast.parse(python_source, "<source>", 'eval')
resolved_expected = PythonNode(python_source, ast_, trimmed_source)
assert sheerka.objvalue(current_res.predicate) == resolved_expected
assert current_res.concept is None
@pytest.mark.parametrize("text, mode, compiled_text", [
("greetings", "eval", f"__ret.status and isinstance(__ret.body, Concept) and __ret.body.name == 'greetings'"),
("c:|1001:", "eval", f"__ret.status and isinstance(__ret.body, Concept) and __ret.body.id == '1001'"),
("hello 'there'", "eval",
f"__ret.status and isinstance(__ret.body, Concept) and __ret.body.key == 'hello __var__0' and __ret.body.get_value('a') == 'there'"),
("hello there", "exec",
f"__x_00__ = __ret.body.get_value('a')\n__ret.status and isinstance(__ret.body, Concept) and __ret.body.key == 'hello __var__0' and isinstance(__x_00__, Concept) and __x_00__.key == 'there'"),
("hello my friend", "exec",
f"__x_00__ = __ret.body.get_value('a')\n__ret.status and isinstance(__ret.body, Concept) and __ret.body.key == 'hello __var__0' and isinstance(__x_00__, Concept) and __x_00__.key == 'my friend'"),
])
def test_i_can_compile_predicate_when_concept_is_not_a_question(self, text, mode, compiled_text):
sheerka, context, greetings, there, my_friend = self.init_test().with_concepts(
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
Concept("there"),
Concept("my friend"),
create_new=True
).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
ast_ = ast.parse(compiled_text, "<source>", mode)
expected_python_node = PythonNode(compiled_text, ast_)
compiled_result = service.compile_when(context, "test", text)
res = compiled_result.compiled_predicates
assert len(res) == 1
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].evaluator == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
assert sheerka.objvalue(res[0].predicate) == expected_python_node
assert res[0].concept is None
def test_i_can_compile_predicate_when_concept_is_not_a_question_and_involves_sheerka(self):
sheerka, context, greetings = self.init_test().with_concepts(
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
create_new=True
).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
compiled_text = "__x_00__ = __ret.body.get_value('a')\n"
compiled_text += "__ret.status"
compiled_text += " and isinstance(__ret.body, Concept) and __ret.body.key == 'hello __var__0'"
compiled_text += " and isinstance(__x_00__, Expando) and __x_00__.get_name() == 'sheerka'"
ast_ = ast.parse(compiled_text, "<source>", "exec")
expected_python_node = PythonNode(compiled_text, ast_)
compiled_result = service.compile_when(context, "test", "hello sheerka")
res = compiled_result.compiled_predicates
assert len(res) == 1
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].evaluator == PYTHON_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
assert sheerka.objvalue(res[0].predicate) == expected_python_node
assert res[0].concept is None
@pytest.mark.skip("Not managed yet")
def test_i_can_compile_when_concept_starts_with_not(self):
sheerka, context, *concepts = self.init_test().with_concepts(
Concept("not a cheesecake", pre="is_question()"),
create_new=True).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
text = "not a cheesecake"
expected = concepts[0]
compiled_result = service.compile_when(context, "test", text)
res = compiled_result.compiled_predicates
assert len(res) == 1
assert isinstance(res[0], RuleCompiledPredicate)
assert res[0].evaluator == CONCEPT_EVALUATOR_NAME
assert sheerka.isinstance(res[0].predicate, BuiltinConcepts.RETURN_VALUE)
assert sheerka.objvalue(res[0].predicate) == expected
assert res[0].concept == expected
def test_i_cannot_compile_when_concept_is_not_a_question_and_has_unknown_variable(self):
sheerka, context, greetings = self.init_test().with_concepts(
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
create_new=True
).unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
with pytest.raises(FailedToCompileError) as ex:
service.compile_when(context, "test", "hello there")
assert sheerka.isinstance(ex.value.cause[0], BuiltinConcepts.CONCEPT_EVAL_ERROR)
@pytest.mark.parametrize("text, expected_error", [
("__action == 'some_action'", NoConditionFound())
])
def test_i_cannot_compile_when_error(self, text, expected_error):
sheerka, context = self.init_test().unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
with pytest.raises(FailedToCompileError) as ex:
service.compile_when(context, "test", text)
assert ex.value.cause == [expected_error]
def test_i_can_get_rule_priorities(self):
sheerka, context, rule_true, rule_false = self.init_test().with_rules(("True", "True"),
("False", "False")).unpack()
sheerka, context, rule_true, rule_false = self.init_test().with_format_rules(("True", "True"),
("False", "False")).unpack()
sheerka.set_is_greater_than(context, BuiltinConcepts.PRECEDENCE,
rule_true,
@@ -322,7 +800,7 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
assert rules_from_cache[rule_false.id].priority == 1
def test_i_can_get_and_retrieve_rules_when_multiple_ontology_layers(self):
sheerka, context, rule_true = self.init_test().with_rules(("true", "True", "True")).unpack()
sheerka, context, rule_true = self.init_test().with_format_rules(("true", "True", "True")).unpack()
sheerka.push_ontology(context, "new ontology")
rule_false = sheerka.create_new_rule(context, Rule(ACTION_TYPE_EXEC, "false", "False", "False")).body.body
@@ -331,12 +809,12 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
assert sheerka.get_rule_by_id(rule_true.id) == rule_true
assert sheerka.get_rule_by_id(rule_false.id) == rule_false
sheerka.pop_ontology()
sheerka.pop_ontology(context)
assert sheerka.get_rule_by_id(rule_true.id) == rule_true
assert not sheerka.is_known(sheerka.get_rule_by_id(rule_false.id))
def test_i_can_resolve_rule(self):
sheerka, context, rule = self.init_test().with_rules(("my rule", "True", "True")).unpack()
sheerka, context, rule = self.init_test().with_format_rules(("my rule", "True", "True")).unpack()
context.add_to_short_term_memory("x", rule.id)
# direct access by id
@@ -370,57 +848,175 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
unresolved.metadata.id_is_unresolved = True
assert sheerka.resolve_rule(context, unresolved) == rule
# @pytest.mark.skip
# @pytest.mark.parametrize("text, expected", [
# ("cat is an animal", set()),
# ("a is an animal", {"a"}),
# ("a is an b", {"a", "b"}),
# ("cat is an b", {"b"}),
# ("a cat is an b", {"b"}),
#
# ("cat is a animal", set()),
# ("a is a animal", {"a"}),
# ("a is a b", {"a", "b"}),
# ("cat is a b", {"b"}),
# ("a cat is an b", {"b"}),
#
# ("a == 5", {"a"}),
# ("isinstance(a, int)", {"a"}),
# ("a cat == b", {"b"})
# ])
# def test_i_can_get_rules_variables(self, text, expected):
# sheerka, context, *concepts = self.init_concepts(
# Concept("x is a y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
# Concept("x is a y", pre="is_question()", body="isa(x, y)").def_var("x").def_var("y"),
# Concept("x is an y", pre="is_question()", body="isinstance(x, y)").def_var("x").def_var("y"),
# Concept("cat"),
# Concept("animal"),
# Concept("a cat"),
# create_new=True
# )
# service = sheerka.services[SheerkaRuleManager.NAME]
#
# compiled = service.compile_when(context, "test", "a is a b")
#
# assert service.get_unknown_variables(compiled) == expected
@pytest.mark.parametrize("obj, expected", [
("text value", "var == 'text value'"),
("text 'value'", '''var == "text 'value'"'''),
('text "value"', """var == 'text "value"'"""),
(10, "var == 10"),
(10.01, "var == 10.01"),
])
def test_i_can_test_python_code_emitter_for_basic_types(self, obj, expected):
sheerka, context = self.init_test().unpack()
assert PythonCodeEmitter(context).recognize(obj, "var").get_text() == expected
assert PythonCodeEmitter(context, "status").recognize(obj, "var").get_text() == "status and " + expected
@pytest.mark.parametrize("recognized_by, expected", [
(RECOGNIZED_BY_ID, "isinstance(var, Concept) and var.id == '1001'"),
(RECOGNIZED_BY_NAME, "isinstance(var, Concept) and var.name == 'greetings'"),
(None, "isinstance(var, Concept) and var.key == 'hello'"),
])
def test_i_can_test_python_code_emitter_for_concepts(self, recognized_by, expected):
sheerka, context, foo = self.init_concepts(
Concept("greetings", definition="hello", definition_type=DEFINITION_TYPE_DEF))
instance = sheerka.new_from_template(foo, foo.key)
if recognized_by:
instance.set_hint(BuiltinConcepts.RECOGNIZED_BY, recognized_by)
assert PythonCodeEmitter(context).recognize(instance, "var").get_text() == expected
assert PythonCodeEmitter(context, "status").recognize(instance, "var").get_text() == "status and " + expected
def test_i_can_test_python_code_emitter_for_concepts_with_variable(self):
sheerka, context, greetings, little, foo, bar, and_concept = self.init_concepts(
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
Concept("little x").def_var("x"),
"foo",
"bar",
Concept("a and b").def_var("a").def_var("b")
)
# variable is a string
greetings_instance = sheerka.new_from_template(greetings, greetings.key, a='sheerka')
expected = "isinstance(var, Concept) and var.key == 'hello __var__0' and var.get_value('a') == 'sheerka'"
text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
assert text == expected
# variable is a concept recognized by id
foo_instance = sheerka.new_from_template(foo, foo.key)
foo_instance.set_hint(BuiltinConcepts.RECOGNIZED_BY, RECOGNIZED_BY_ID)
greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=foo_instance)
expected = """__x_00__ = var.get_value('a')
isinstance(var, Concept) and var.key == 'hello __var__0' and isinstance(__x_00__, Concept) and __x_00__.id == '1003'"""
text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
assert text == expected
# variable is a concept recognized by name
foo_instance = sheerka.new_from_template(foo, foo.key)
foo_instance.set_hint(BuiltinConcepts.RECOGNIZED_BY, RECOGNIZED_BY_NAME)
greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=foo_instance)
expected = """__x_00__ = var.get_value('a')
isinstance(var, Concept) and var.key == 'hello __var__0' and isinstance(__x_00__, Concept) and __x_00__.name == 'foo'"""
text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
assert text == expected
# variable is a concept recognized by value
foo_instance = sheerka.new_from_template(foo, foo.key)
greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=foo_instance)
expected = """__x_00__ = var.get_value('a')
isinstance(var, Concept) and var.key == 'hello __var__0' and isinstance(__x_00__, Concept) and __x_00__.key == 'foo'"""
text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
assert text == expected
# variable is a concept witch has itself some variable
foo_instance = sheerka.new_from_template(foo, foo.key)
little_instance = sheerka.new_from_template(little, little.key, x=foo_instance)
greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=little_instance)
expected = """__x_00__ = var.get_value('a')
__x_01__ = __x_00__.get_value('x')
isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
" and isinstance(__x_00__, Concept) and __x_00__.key == 'little __var__0'" + \
" and isinstance(__x_01__, Concept) and __x_01__.key == 'foo'"""
text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
assert text == expected
# concept with multiple variables (which are themselves concepts)
foo_instance = sheerka.new_from_template(foo, foo.key)
bar_instance = sheerka.new_from_template(bar, bar.key)
little_instance = sheerka.new_from_template(little, little.key, x=foo_instance)
and_instance = sheerka.new_from_template(and_concept, and_concept.key, a=bar_instance, b=little_instance)
greetings_instance = sheerka.new_from_template(greetings, greetings.key, a=and_instance)
expected = """__x_00__ = var.get_value('a')
__x_01__ = __x_00__.get_value('a')
__x_02__ = __x_00__.get_value('b')
__x_03__ = __x_02__.get_value('x')
isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
" and isinstance(__x_00__, Concept) and __x_00__.key == '__var__0 and __var__1'" + \
" and isinstance(__x_01__, Concept) and __x_01__.key == 'bar'" + \
" and isinstance(__x_02__, Concept) and __x_02__.key == 'little __var__0'" + \
" and isinstance(__x_03__, Concept) and __x_03__.key == 'foo'"
text = PythonCodeEmitter(context).recognize(greetings_instance, "var").get_text()
assert text == expected
def test_i_can_get_format_rules(self):
sheerka, context = self.init_test().unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
sheerka.om.current_cache_manager().clear(service.FORMAT_RULE_ENTRY)
r1 = Rule(ACTION_TYPE_PRINT, "name 1", "True", "Hello world 1", priority=1)
r2 = Rule(ACTION_TYPE_PRINT, "name 2", "False", "Hello world 2", priority=3)
r3 = Rule(ACTION_TYPE_PRINT, "name 2", "None", "Hello world 3", priority=2)
sheerka.create_new_rule(context, r1)
sheerka.create_new_rule(context, r2)
sheerka.create_new_rule(context, r3)
res = sheerka.get_format_rules()
assert res == [r2, r3, r1]
def test_i_can_get_exec_rules(self):
sheerka, context = self.init_test().unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
sheerka.om.current_cache_manager().clear(service.EXEC_RULE_ENTRY)
r1 = Rule(ACTION_TYPE_EXEC, "name 1", "True", "'Hello world 1'", priority=1)
r2 = Rule(ACTION_TYPE_EXEC, "name 2", "False", "'Hello world 2'", priority=3)
r3 = Rule(ACTION_TYPE_EXEC, "name 2", "None", "'Hello world 3'", priority=2)
sheerka.create_new_rule(context, r1)
sheerka.create_new_rule(context, r2)
sheerka.create_new_rule(context, r3)
res = sheerka.get_exec_rules()
assert res == [r2, r3, r1]
def test_i_can_compile_rete_using_name(self):
sheerka, context, *concepts = self.init_test().unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
text = "__ret"
compiled_result = service.compile_when(context, "test", text)
res = compiled_result.rete_disjunctions
assert len(res) == 1
assert isinstance(res[0], AndConditions)
assert res[0].conditions == [Condition(V("__x_00__"), "__name__", "__ret")]
class TestSheerkaRuleManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
def test_rules_are_initialized_at_startup(self):
sheerka, context, *rules = self.init_format_rules(
sheerka, context, *rules = self.init_test().with_rules(
None,
Rule("print", "name1", "True", "Hello world"),
Rule("print", "name2", "value() is __EXPLANATION", "list(value())")
)
Rule("print", "name2", "value() is __EXPLANATION", "list(value())"),
Rule("exec", "name3", "True", "'Hello world'"),
Rule("exec", "name4", "value() is __EXPLANATION", "list(value())"),
).unpack()
sheerka.set_is_greater_than(context, BuiltinConcepts.PRECEDENCE,
rules[0],
rules[1],
RULE_COMPARISON_CONTEXT)
sheerka.set_is_less_than(context, BuiltinConcepts.PRECEDENCE,
rules[2],
rules[3],
RULE_COMPARISON_CONTEXT)
sheerka.om.commit(context)
expected_rules_by_id = sheerka.om.get_all(SheerkaRuleManager.FORMAT_RULE_ENTRY)
expected_rules_by_id.update(sheerka.om.get_all(SheerkaRuleManager.EXEC_RULE_ENTRY))
sheerka = self.new_sheerka_instance(False) # new instance
rules_by_id = sheerka.om.get_all(SheerkaRuleManager.FORMAT_RULE_ENTRY)
rules_by_id.update(sheerka.om.get_all(SheerkaRuleManager.EXEC_RULE_ENTRY))
assert len(rules_by_id) == len(expected_rules_by_id)
@@ -432,10 +1028,10 @@ class TestSheerkaRuleManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
assert rule.metadata.predicate == expected.metadata.predicate
assert rule.metadata.action == expected.metadata.action
assert rule.metadata.id == expected.metadata.id
assert rule.metadata.is_compiled == expected.metadata.is_compiled
assert rule.metadata.is_enabled == expected.metadata.is_enabled
assert rule.metadata.is_compiled
assert rule.metadata.is_enabled
assert rule.compiled_action == expected.compiled_action
assert rule.compiled_predicate == expected.compiled_predicate
assert rule.compiled_predicates == expected.compiled_predicates
assert rule.priority is not None
assert rule.priority == expected.priority
@@ -468,6 +1064,6 @@ class TestSheerkaRuleManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
assert rule.metadata.is_compiled == expected.metadata.is_compiled
assert rule.metadata.is_enabled == expected.metadata.is_enabled
assert rule.compiled_action == expected.compiled_action
assert rule.compiled_predicate == expected.compiled_predicate
assert rule.compiled_predicates == expected.compiled_predicates
assert rule.priority is not None
assert rule.priority == expected.priority
+2 -2
View File
@@ -110,11 +110,11 @@ class TestSheerkaVariable(TestUsingMemoryBasedSheerka):
assert sheerka.load_internal_var("TestSheerkaVariable", "lambda")(10) == 12
# I can revert back
sheerka.pop_ontology()
sheerka.pop_ontology(context)
assert sheerka.load_var("TestSheerkaVariable", "my_variable") == 1
assert sheerka.load_internal_var("TestSheerkaVariable", "lambda")(10) == 11
sheerka.pop_ontology()
sheerka.pop_ontology(context)
assert sheerka.load_var("TestSheerkaVariable", "my_variable") == 1
assert sheerka.load_internal_var("TestSheerkaVariable", "lambda")(10) == 11
+28 -3
View File
@@ -1,10 +1,9 @@
import ast
import pytest
import core.builtin_helpers
import pytest
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
from core.concept import Concept
from core.global_symbols import NotInit
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -157,6 +156,32 @@ class TestBuiltinHelpers(TestUsingMemoryBasedSheerka):
res = core.builtin_helpers.resolve_ambiguity(context, concepts)
assert [c.name for c in res] == expected
@pytest.mark.parametrize("pre, expected", [
("x and y", False),
("is_question()", True),
(" is_question ( ) ", True),
("context.in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)", True),
(" context . in_context ( BuiltinConcepts . EVAL_QUESTION_REQUESTED ) ", True),
(None, False),
("", False),
(NotInit, False),
("is _ question()", False),
("is_ question()", False),
("is _question()", False),
("context.in _context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)", False),
("not is_question()", False),
("not context.in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)", False),
("is_question() and True", True),
("is_question() and False", True), # don't care about the second argument if it is not related to question
("is_question() and xxx", True), # don't care about the second argument if it is not related to question
("is_question() and not is_question()", False), # error ?
("is_question() and not context.in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)", False), # error ?
])
def test_is_a_question(self, pre, expected):
sheerka, context = self.init_test().unpack()
concept = Concept("foo", pre=pre)
assert core.builtin_helpers.is_a_question(context, concept) == expected
# @pytest.mark.parametrize("return_values", [
# None,
# []
+5 -5
View File
@@ -340,7 +340,7 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
sheerka.modify_concept(context, foo, to_add={"variables": {"c": None}}, to_remove={"variables": ["b"]})
assert get_concept_attrs(foo) == ["a", "c"]
sheerka.pop_ontology()
sheerka.pop_ontology(context)
assert get_concept_attrs(foo) == ["a", "b"]
def test_i_can_manage_concepts_ids_on_multiple_ontology_layers(self):
@@ -356,7 +356,7 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
res = sheerka.create_new_concept(context, Concept("baz"))
assert res.body.body.id == "1003"
sheerka.pop_ontology()
sheerka.pop_ontology(context)
res = sheerka.create_new_concept(context, Concept("baz"))
assert res.body.body.id == "1002"
@@ -380,7 +380,7 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
# record the ontology
ontology = sheerka.get_ontology(context)
sheerka.pop_ontology()
sheerka.pop_ontology(context)
# Create another ontology with some other values
sheerka.push_ontology(context, "another ontology")
@@ -403,7 +403,7 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
assert get_concept_attrs(foo) == ["a", "b"]
# sanity check
sheerka.pop_ontology()
sheerka.pop_ontology(context)
assert sheerka.get_by_name("foo") == foo2
assert sheerka.get_by_name("bar") == bar
assert sheerka.locals == {"key2": "value2"}
@@ -562,7 +562,7 @@ class TestSheerkaUsingFileBasedSheerka(TestUsingFileBasedSheerka):
sheerka, context = self.init_test().unpack()
sheerka.push_ontology(context, "to remove")
sheerka.pop_ontology()
sheerka.pop_ontology(context)
sheerka.push_ontology(context, "new ontology")
sheerka.push_ontology(context, "another ontology")
+2 -2
View File
@@ -21,7 +21,7 @@ class TestSheerkaResultManager(TestUsingMemoryBasedSheerka):
@classmethod
def teardown_class(cls):
cls.sheerka.pop_ontology()
cls.sheerka.pop_ontology(TestSheerkaResultManager.context)
cls.root_ontology_name = SheerkaOntologyManager.ROOT_ONTOLOGY_NAME
def init_service(self):
@@ -410,7 +410,7 @@ class TestSheerkaResultManagerFileBased(TestUsingFileBasedSheerka):
@classmethod
def teardown_class(cls):
cls.sheerka.pop_ontology()
cls.sheerka.pop_ontology(TestSheerkaResultManagerFileBased.context)
cls.root_ontology_name = SheerkaOntologyManager.ROOT_ONTOLOGY_NAME
def test_i_can_retrieve_the_last_error_after_startup(self):
+228 -32
View File
@@ -8,7 +8,9 @@ from cache.IncCache import IncCache
from cache.ListCache import ListCache
from cache.ListIfNeededCache import ListIfNeededCache
from core.concept import Concept
from core.global_symbols import NotFound, Removed
from core.global_symbols import NotFound, Removed, EVENT_CONCEPT_ID_DELETED, \
EVENT_RULE_ID_DELETED
from core.rule import Rule, ACTION_TYPE_EXEC
from core.sheerka.SheerkaOntologyManager import SheerkaOntologyManager, OntologyManagerFrozen, OntologyManagerNotFrozen, \
OntologyManagerCannotPopLatest, OntologyAlreadyExists
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
@@ -168,22 +170,22 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert manager.current_cache_manager().has("cache_name", "key")
def test_i_cannot_pop_ontology_when_not_frozen(self):
sheerka = self.get_sheerka()
sheerka, context = self.init_test().unpack()
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
with pytest.raises(OntologyManagerNotFrozen):
manager.pop_ontology()
manager.pop_ontology(context)
def test_i_cannot_pop_the_latest_cache_manager(self):
sheerka = self.get_sheerka()
sheerka, context = self.init_test().unpack()
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
manager.freeze()
with pytest.raises(OntologyManagerCannotPopLatest):
manager.pop_ontology()
manager.pop_ontology(context)
def test_i_can_pop_ontology(self):
sheerka = self.get_sheerka()
sheerka, context = self.init_test().unpack()
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
manager.freeze()
@@ -191,13 +193,13 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
manager.push_ontology("ontology2")
manager.push_ontology("ontology3")
manager.pop_ontology()
manager.pop_ontology(context)
assert len(manager.ontologies) == 3
manager.pop_ontology()
manager.pop_ontology()
manager.pop_ontology(context)
manager.pop_ontology(context)
with pytest.raises(OntologyManagerCannotPopLatest):
manager.pop_ontology()
manager.pop_ontology(context)
def test_i_can_add_ontology(self):
sheerka, context = self.init_test().unpack()
@@ -217,7 +219,7 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert manager.get("cache_name", "key3") is NotFound
new_ontology = manager.get_ontology()
manager.pop_ontology()
manager.pop_ontology(context)
# add another ontology, with its own values
manager.push_ontology("another ontology")
@@ -250,7 +252,7 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert manager.get_ontology("name4")
def test_i_can_access_values_after_push_and_pop_cache_only_true(self):
sheerka = self.get_sheerka(cache_only=True)
sheerka, context = self.init_test(cache_only=True).unpack()
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
manager.register_cache("cache_name", Cache())
@@ -263,7 +265,7 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
manager.put("cache_name", "key", "value2")
assert manager.get("cache_name", "key") == "value2"
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("cache_name", "key") == "value1"
def test_i_can_access_values_after_push_and_pop_cache_only_false(self):
@@ -296,7 +298,7 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert manager.ontologies[1].cache_manager.sdp.state.data == {'cache_name': {'key': 'value1'}}
# remove a layer
manager.pop_ontology()
manager.pop_ontology(context)
assert not manager.current_cache_manager().has("cache_name", "key") # value is no longer in cache
assert manager.get("cache_name", "key") == "value1"
@@ -333,13 +335,13 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert manager.get("cache_name", "key") == "value4"
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("cache_name", "key") == "value3"
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("cache_name", "key") == "value2"
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("cache_name", "key") == "value1"
def test_i_have_access_to_sub_layers_values_cache_only_false(self):
@@ -368,6 +370,7 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
def test_i_can_get_value_from_all_layers(self):
sheerka = self.get_sheerka(cache_only=False)
context = self.get_context(sheerka)
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
manager.register_cache("cache_name", Cache().auto_configure("cache_name"))
@@ -381,14 +384,15 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert manager.get("cache_name", "key") == "value"
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("cache_name", "key") == "value"
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("cache_name", "key") == "value"
def test_i_can_only_get_top_layer_values_when_dictionary_cache(self):
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
manager.register_cache("cache_name", DictionaryCache().auto_configure("cache_name"))
@@ -407,7 +411,7 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert manager.get_all("cache_name") == {"key": "value", "key1": "value1"}
# I can get back my values after pop
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.copy("cache_name") == {"key": "value"}
def test_dictionary_caches_values_are_copied_when_a_new_ontology_is_pushed(self):
@@ -728,7 +732,7 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert manager.ontologies[1].cache_manager.sdp.state.data == {'cache_name': {"key": "value"}}
# The entry still exists in lower ontology
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("cache_name", "key") == "value"
def test_i_can_remove_when_value_is_in_both_low_and_current_level(self):
@@ -764,7 +768,7 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert manager.ontologies[1].cache_manager.sdp.state.data == {'cache_name': {"key": "value"}}
# The entry still exists in lower ontology
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("cache_name", "key") == "value"
def test_i_can_remove_when_value_is_not_low_level(self):
@@ -830,8 +834,8 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert manager.ontologies[2].cache_manager.sdp.state.data == {'cache_name': {"key": ["value", "value2"]}}
# The entry still exists in lower ontology
manager.pop_ontology()
manager.pop_ontology()
manager.pop_ontology(context)
manager.pop_ontology(context)
assert manager.get("cache_name", "key") == ["value", "value2"]
def test_i_can_add_concept_default_layer(self):
@@ -941,7 +945,7 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert manager.ontologies[1].cache_manager.sdp.get('by_id', foo.id) == foo
# so I can get the old values when I pop ontology
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("by_key", foo.key) == foo
assert manager.get("by_id", foo.id) == foo
@@ -990,7 +994,7 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert manager.ontologies[1].cache_manager.sdp.get('by_id', foo.id) == foo
# so I can get the old values when I pop ontology
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("by_key", foo.key) == foo
assert manager.get("by_id", foo.id) == foo
@@ -1119,12 +1123,12 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert manager.ontologies[2].cache_manager.sdp.get("by_key") == {foo.key: foo}
# So I can pop
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("by_id", foo.id) == foo
assert manager.get("by_key", foo.key) == foo
# and pop again
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("by_id", foo.id) == foo
assert manager.get("by_key", foo.key) == foo
@@ -1167,6 +1171,145 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
"key5": "value5"
}
def test_i_can_keep_track_of_created_concepts_by_ontologies(self):
sheerka, context, foo = self.init_concepts("foo", create_new=True)
def from_cache(entry):
return sheerka.om.self_cache_manager.copy(entry)
def from_db(entry):
return sheerka.om.self_cache_manager.sdp.get(entry)
# check that the new concept is tracked
assert from_cache(SheerkaOntologyManager.CONCEPTS_BY_ONTOLOGY_ENTRY) == {'#unit_test#': {'1001'}}
assert from_cache(SheerkaOntologyManager.ONTOLOGY_BY_CONCEPT_ENTRY) == {'1001': '#unit_test#'}
# add a new ontology and make sure the new concepts are tracked
sheerka.push_ontology(context, "new ontology")
sheerka.create_new_concept(context, Concept("bar"))
assert from_cache(SheerkaOntologyManager.CONCEPTS_BY_ONTOLOGY_ENTRY) == {'#unit_test#': {'1001'},
'new ontology': {'1002'}}
assert from_cache(SheerkaOntologyManager.ONTOLOGY_BY_CONCEPT_ENTRY) == {'1001': '#unit_test#',
'1002': 'new ontology'}
# commit the info and check the DB
sheerka.om.commit(context)
assert from_db(SheerkaOntologyManager.CONCEPTS_BY_ONTOLOGY_ENTRY) == {'#unit_test#': {'1001'},
'new ontology': {'1002'}, }
assert from_db(SheerkaOntologyManager.ONTOLOGY_BY_CONCEPT_ENTRY) == {'1001': '#unit_test#',
'1002': 'new ontology', }
# remove a concept a check
sheerka.remove_concept(context, sheerka.get_by_name("foo"))
assert from_cache(SheerkaOntologyManager.CONCEPTS_BY_ONTOLOGY_ENTRY) == {'new ontology': {'1002'}, }
assert from_cache(SheerkaOntologyManager.ONTOLOGY_BY_CONCEPT_ENTRY) == {'1002': 'new ontology', }
sheerka.remove_concept(context, sheerka.get_by_name("bar"))
assert from_cache(SheerkaOntologyManager.CONCEPTS_BY_ONTOLOGY_ENTRY) == {}
assert from_cache(SheerkaOntologyManager.ONTOLOGY_BY_CONCEPT_ENTRY) == {}
# commit again and check
sheerka.om.commit(context)
assert from_db(SheerkaOntologyManager.CONCEPTS_BY_ONTOLOGY_ENTRY) == {}
assert from_db(SheerkaOntologyManager.ONTOLOGY_BY_CONCEPT_ENTRY) == {}
def test_i_can_keep_track_of_created_rules_by_ontologies(self):
sheerka, context, rule1 = self.init_format_rules(("rule1", "id.attr == 'value'", "True"))
def rules_by_ontology_from_cache():
res = sheerka.om.self_cache_manager.copy(SheerkaOntologyManager.RULES_BY_ONTOLOGY_ENTRY)
del res[SheerkaOntologyManager.ROOT_ONTOLOGY_NAME] # discard builtin rules
return res
def ontologies_from_cache():
res = sheerka.om.self_cache_manager.copy(SheerkaOntologyManager.ONTOLOGY_BY_RULE_ENTRY)
return {k: v for k, v in res.items() if v != SheerkaOntologyManager.ROOT_ONTOLOGY_NAME}
def rules_by_ontology_from_db():
res = sheerka.om.self_cache_manager.sdp.get(SheerkaOntologyManager.RULES_BY_ONTOLOGY_ENTRY)
del res[SheerkaOntologyManager.ROOT_ONTOLOGY_NAME] # discard builtin rules
return res
def ontologies_from_db():
res = sheerka.om.self_cache_manager.sdp.get(SheerkaOntologyManager.ONTOLOGY_BY_RULE_ENTRY)
return {k: v for k, v in res.items() if v != SheerkaOntologyManager.ROOT_ONTOLOGY_NAME}
assert rules_by_ontology_from_cache() == {"#unit_test#": {rule1.id}}
assert ontologies_from_cache() == {rule1.id: "#unit_test#"}
# add a new rule from a new ontology and check
sheerka.push_ontology(context, "new ontology")
rule2 = Rule(ACTION_TYPE_EXEC, "rule2", "id2.attr2 == 'value'", "True")
sheerka.create_new_rule(context, rule2)
assert rules_by_ontology_from_cache() == {"#unit_test#": {rule1.id}, "new ontology": {rule2.id}}
assert ontologies_from_cache() == {rule1.id: "#unit_test#", rule2.id: "new ontology"}
# commit and check the result
sheerka.om.commit(context)
assert rules_by_ontology_from_db() == {"#unit_test#": {rule1.id}, "new ontology": {rule2.id}}
assert ontologies_from_db() == {rule1.id: "#unit_test#", rule2.id: "new ontology"}
sheerka.remove_rule(context, rule1)
assert rules_by_ontology_from_cache() == {"new ontology": {rule2.id}}
assert ontologies_from_cache() == {rule2.id: "new ontology"}
# remove the last rule
sheerka.remove_rule(context, rule2)
assert rules_by_ontology_from_cache() == {}
assert ontologies_from_cache() == {}
# commit and check the db
sheerka.om.commit(context)
assert rules_by_ontology_from_db() == {}
assert ontologies_from_db() == {}
def test_i_can_keep_track_of_created_concept_on_ontology_pop(self):
sheerka, context, foo = self.init_concepts("foo", create_new=True)
events_raised = set()
sheerka.subscribe(EVENT_CONCEPT_ID_DELETED, lambda ctx, c: events_raised.add(c))
def from_cache(entry):
return sheerka.om.self_cache_manager.copy(entry)
sheerka.push_ontology(context, "new ontology")
sheerka.create_new_concept(context, Concept("bar"))
sheerka.create_new_concept(context, Concept("baz"))
sheerka.pop_ontology(context)
assert from_cache(SheerkaOntologyManager.CONCEPTS_BY_ONTOLOGY_ENTRY) == {'#unit_test#': {'1001'}}
assert from_cache(SheerkaOntologyManager.ONTOLOGY_BY_CONCEPT_ENTRY) == {'1001': '#unit_test#'}
# check that the 'concept is deleted' events are raised
assert events_raised == {'1002', '1003'}
def test_i_can_keep_track_of_created_rules_on_ontology_pop(self):
sheerka, context, rule1 = self.init_format_rules(("rule1", "id.attr == 'value'", "True"))
events_raised = set()
sheerka.subscribe(EVENT_RULE_ID_DELETED, lambda ctx, r: events_raised.add(r))
def rules_by_ontology_from_cache():
res = sheerka.om.self_cache_manager.copy(SheerkaOntologyManager.RULES_BY_ONTOLOGY_ENTRY)
del res[SheerkaOntologyManager.ROOT_ONTOLOGY_NAME] # discard builtin rules
return res
def ontologies_from_cache():
res = sheerka.om.self_cache_manager.copy(SheerkaOntologyManager.ONTOLOGY_BY_RULE_ENTRY)
return {k: v for k, v in res.items() if v != SheerkaOntologyManager.ROOT_ONTOLOGY_NAME}
sheerka.push_ontology(context, "new ontology")
sheerka.create_new_rule(context, Rule(ACTION_TYPE_EXEC, "rule2", "id2.attr2 == 'value'", "True"))
sheerka.create_new_rule(context, Rule(ACTION_TYPE_EXEC, "rule3", "id3.attr3 == 'value'", "True"))
sheerka.pop_ontology(context)
assert rules_by_ontology_from_cache() == {'#unit_test#': {'10'}}
assert ontologies_from_cache() == {'10': '#unit_test#'}
# check that the 'rule is deleted' events are raised
assert events_raised == {'11', '12'}
# def test_i_can_list_by_key_when_dictionaries(self):
# sheerka = self.get_sheerka(cache_only=False)
# context = self.get_context(sheerka)
@@ -1268,7 +1411,6 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
# assert manager.list_by_key("cache_name", "key2") == ["e", "f", "g"]
# assert manager.list_by_key("cache_name", "key3") == ["a", "b", "c", "e", "f", "g"]
def test_i_can_get_call_when_a_cache_is_cleared(self):
sheerka = self.get_sheerka(cache_only=False)
context = self.get_context(sheerka)
@@ -1401,11 +1543,11 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
assert manager.ontologies[2].cache_manager.get_cache("cache_name").copy() == {'key1': 'value1',
'key2': 'value2'}
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("cache_name", "key1") == "new value1"
assert manager.get("cache_name", "key2") is NotFound
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("cache_name", "key1") == "value1"
assert manager.get("cache_name", "key2") == "value2"
@@ -1453,9 +1595,63 @@ class TestSheerkaOntologyWithFileBasedSheerka(TestUsingFileBasedSheerka):
assert manager.get("cache_name", "key") == "value2"
manager.pop_ontology()
manager.pop_ontology(context)
assert manager.get("cache_name", "key") == "value1"
# put back the previous ontology
manager.push_ontology("new ontology")
assert manager.get("cache_name", "key") == "value2"
def test_i_can_remember_concept_and_rules_by_ontology(self):
sheerka, context, foo, r1 = self.init_test().with_concepts(
"foo",
create_new=True
).with_format_rules(
("rule1", "__ret", "True"),
).unpack()
sheerka.om.commit(context)
sheerka = self.new_sheerka_instance(False)
context = self.get_context(sheerka)
sheerka.create_new_concept(context, Concept("bar"))
r2 = sheerka.create_new_rule(context, Rule(ACTION_TYPE_EXEC, "rule2", "__ret.status", "True")).body.body
sheerka.om.commit(context)
sheerka.push_ontology(context, "new ontology")
sheerka.create_new_concept(context, Concept("baz"))
sheerka.create_new_rule(context, Rule(ACTION_TYPE_EXEC, "rule3", "id3.attr3 == 'value'", "True"))
sheerka.om.commit(context)
sheerka = self.new_sheerka_instance(False)
context = self.get_context(sheerka)
sheerka.push_ontology(context, "another ontology")
sheerka.create_new_concept(context, Concept("qux"))
r4 = sheerka.create_new_rule(context, Rule(ACTION_TYPE_EXEC, "rule4", "id4.attr4", "True")).body.body
sheerka.remove_concept(context, foo)
sheerka.remove_rule(context, r2)
sheerka.om.commit(context)
assert sheerka.om.self_cache_manager.copy(SheerkaOntologyManager.CONCEPTS_BY_ONTOLOGY_ENTRY) == {
'#unit_test#': {'1002'},
'another ontology': {'1004'},
}
assert sheerka.om.self_cache_manager.copy(SheerkaOntologyManager.RULES_BY_ONTOLOGY_ENTRY) == {
'#unit_test#': {r1.id},
'another ontology': {r4.id},
}
# in db
assert sheerka.om.self_cache_manager.sdp.get(SheerkaOntologyManager.CONCEPTS_BY_ONTOLOGY_ENTRY) == {
'#unit_test#': {'1002'},
'another ontology': {'1004'},
'new ontology': {'1003'}}
rules_from_db = sheerka.om.self_cache_manager.sdp.get(SheerkaOntologyManager.RULES_BY_ONTOLOGY_ENTRY)
del rules_from_db["__default__"]
assert rules_from_db == {
'#unit_test#': {'10'},
'another ontology': {'13'},
'new ontology': {'12'}}
+7 -7
View File
@@ -368,19 +368,19 @@ second : 'value d'
sheerka.print(lst)
captured = capsys.readouterr()
assert captured.out == """(1001)foo a b
a : 'value a'
b : 'value b'
id : '1001'
name: 'foo a b'
key : 'foo __var__0 __var__1'
a : 'value a'
b : 'value b'
body: **NotInit**
self: (1001)foo a b
(1001)foo a b
a : 'value c'
b : 'value d'
id : '1001'
name: 'foo a b'
key : 'foo __var__0 __var__1'
a : 'value c'
b : 'value d'
body: **NotInit**
self: (1001)foo a b
"""
@@ -404,6 +404,9 @@ self: (1001)foo a b
sheerka.print(lst)
captured = capsys.readouterr()
assert captured.out == """(1001)foo a b
id : '1001'
name: 'foo a b'
key : 'foo __var__0 __var__1'
a : 'value a'
b : {'a' : 'value a'
'beta' : {'b1': 10
@@ -425,9 +428,6 @@ b : {'a' : 'value a'
'empty': ()}
'h' : {'set' : {'set-a'}
'empty': {}}}
id : '1001'
name: 'foo a b'
key : 'foo __var__0 __var__1'
body: **NotInit**
self: (1001)foo a b
"""
+31 -2
View File
@@ -1,7 +1,8 @@
from dataclasses import dataclass
import core.utils
import pytest
import core.utils
from core.builtin_concepts import BuiltinConcepts
from core.builtin_helpers import evaluate_expression
from core.concept import Concept
@@ -111,7 +112,7 @@ def test_i_can_get_sub_classes():
([['a'], ['b']], ['c', 'd', 'e'], [['a', 'c'], ['b', 'c'], ['a', 'd'], ['b', 'd'], ['a', 'e'], ['b', 'e']]),
])
def test_i_can_product(a, b, expected):
res = core.utils.product(a, b)
res = core.utils.sheerka_product(a, b)
assert res == expected
@@ -425,3 +426,31 @@ def test_i_can_deep_copy_a_custom_type():
assert core.utils.sheerka_deepcopy(NotInit) is NotInit
assert core.utils.sheerka_deepcopy(NotFound) is NotFound
assert core.utils.sheerka_deepcopy(Removed) is Removed
@pytest.mark.parametrize("expression1, expression2, expected", [
("foo bar baz", "foo bar baz", True),
("foo()", " foo ( ) ", True),
("is_instance()", "is _ instance()", False),
("foo bar baz", "foo bar", False)
])
def test_tokens_are_matching(expression1, expression2, expected):
assert core.utils.tokens_are_matching(Tokenizer(expression1), Tokenizer(expression2)) == expected
def test_tokens_are_matching_when_no_eof():
expression1 = "foo bar baz"
expression2 = "foo bar"
tokens1 = Tokenizer(expression1, yield_eof=False)
tokens2 = Tokenizer(expression2, yield_eof=False)
assert not core.utils.tokens_are_matching(tokens1, tokens2)
def test_tokens_are_matching_when_eof_differs():
expression1 = "foo bar baz"
expression2 = "foo bar baz"
tokens1 = Tokenizer(expression1, yield_eof=True)
tokens2 = Tokenizer(expression2, yield_eof=False)
assert core.utils.tokens_are_matching(tokens1, tokens2)