Implemented a first and basic version of a Rete rule engine
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user