Fixed #3: Added sheerka.resolve_rule()

Fixed #5: Refactored SheerkaComparisonManager
Fixed #6: Sya parser no longer works after restart
This commit is contained in:
2021-01-15 07:11:04 +01:00
parent e26c83a825
commit 821dbed189
44 changed files with 1617 additions and 1068 deletions
+8 -1
View File
@@ -6,7 +6,8 @@ from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.cache import FakeSdp
class TestListIfNeededCache(TestUsingMemoryBasedSheerka):
class TestListCache(TestUsingMemoryBasedSheerka):
def test_i_can_put_and_retrieve_value_from_list_cache(self):
cache = ListCache()
@@ -61,6 +62,12 @@ class TestListIfNeededCache(TestUsingMemoryBasedSheerka):
cache.put("key", "value2", alt_sdp=FakeSdp(get_alt_value=lambda cache_name, key: "xxx"))
assert cache.get("key") == ["value1", "value2"]
def test_i_can_get_when_alt_sdp(self):
cache = ListCache(sdp=FakeSdp(get_value=lambda cache_name, key: NotFound)).auto_configure("cache_name")
cache.get("key", alt_sdp=FakeSdp(get_alt_value=lambda cache_name, key: ["value1"]))
assert cache.get("key") == ["value1"]
def test_i_can_update_from_list_cache(self):
cache = ListCache()
+249 -31
View File
@@ -1,16 +1,35 @@
import pytest
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from core.global_symbols import EVENT_CONCEPT_PRECEDENCE_MODIFIED, CONCEPT_COMPARISON_CONTEXT, \
EVENT_RULE_PRECEDENCE_MODIFIED, \
RULE_COMPARISON_CONTEXT
EVENT_RULE_PRECEDENCE_MODIFIED, RULE_COMPARISON_CONTEXT
from core.sheerka.services.SheerkaComparisonManager import SheerkaComparisonManager, ComparisonObj
from core.sheerka.services.SheerkaConceptManager import ChickenAndEggError
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
@staticmethod
def get_comparison_objs(lst, prop_name="prop_name", context="#"):
for item in lst:
if ">>" in item:
a = item.split(">>")[0]
yield ComparisonObj("id", prop_name, a.strip(), None, ">>", context)
elif "<<" in item:
a = item.split("<<")[0]
yield ComparisonObj("id", prop_name, a.strip(), None, "<<", context)
elif ">" in item:
a, b = item.split(">")
yield ComparisonObj("id", prop_name, a.strip(), b.strip(), ">", context)
elif "<" in item:
a, b = item.split("<")
yield ComparisonObj("id", prop_name, a.strip(), b.strip(), "<", context)
else:
a, b = item.split("=")
yield ComparisonObj("id", prop_name, a.strip(), b.strip(), "=", context)
@staticmethod
def execution_definition(context, service, concepts_map, definition):
if ">>" in definition:
@@ -214,13 +233,13 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
for entry in entries:
self.execution_definition(context, service, concepts_map, entry)
assert service.get_concepts_weights("prop_name") == expected
assert service.get_weights("prop_name") == expected
def test_i_can_get_concept_weight_when_no_comparison_is_defined(self):
sheerka, context = self.init_concepts()
service = sheerka.services[SheerkaComparisonManager.NAME]
assert service.get_concepts_weights("prop_name") == {}
assert service.get_weights("prop_name") == {}
def test_i_can_recover_from_deleted_weight(self):
sheerka, context, one = self.init_concepts("one")
@@ -229,7 +248,7 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
service.set_is_lesser(context, "prop_name", one)
sheerka.om.clear(service.RESOLVED_COMPARISON_ENTRY)
assert service.get_concepts_weights("prop_name") == {"c:one|1001:": 0}
assert service.get_weights("prop_name") == {"c:one|1001:": 0}
def test_i_can_get_partition(self):
sheerka, context, one, two, three = self.init_concepts("one", "two", "three")
@@ -246,6 +265,38 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
3: ["c:three|1003:"],
}
def test_i_can_toposort(self):
# using sample test from https://code.activestate.com/recipes/578272-topological-sort/
comparison_objs = self.get_comparison_objs([
"2 < 11",
"11 > 9",
"9 < 8",
"10 < 11",
"3 > 10",
"11 < 7",
"11 < 5",
"7 > 8",
"3 > 8"])
assert list(SheerkaComparisonManager.toposort(comparison_objs)) == [{'2', '9', '10'},
{'8', '11'},
{'3', '5', '7'}]
def test_i_can_toposort_when_no_data(self):
assert list(SheerkaComparisonManager.toposort([])) == []
def test_i_cannot_toposort_when_cycle(self):
comparison_objs = self.get_comparison_objs([
"1 < 2",
"2 < 3",
"3 < 1",
"1 < 4", # no issue with this
"2 < 5", # no issue with this
])
with pytest.raises(ChickenAndEggError) as ex:
list(SheerkaComparisonManager.toposort(comparison_objs))
assert ex.value.concepts == {"1", "2", "3"}
def test_i_can_detect_chicken_and_egg(self):
sheerka, context, one, two = self.init_concepts("one", "two")
service = sheerka.services[SheerkaComparisonManager.NAME]
@@ -255,7 +306,7 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.CHICKEN_AND_EGG)
assert set(res.body.body) == {one, two}
assert set(res.body.body) == {one.str_id, two.str_id}
def test_i_can_detect_more_complex_chicken_and_egg(self):
sheerka, context, one, two, three, four, five = self.init_concepts("one", "two", "three", "four", "five")
@@ -270,7 +321,7 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.CHICKEN_AND_EGG)
assert set(res.body.body) == {one, two, five}
assert set(res.body.body) == {one.str_id, two.str_id, five.str_id}
def test_i_can_give_the_same_information_in_many_ways(self):
sheerka, context, one, two = self.init_concepts("one", "two")
@@ -292,10 +343,10 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaComparisonManager.NAME]
service.set_is_lesser(context, "prop_name", one)
assert service.get_concepts_weights("prop_name") == {"c:one|1001:": 0} # DEFAULT_COMPARISON_VALUE - 1
assert service.get_weights("prop_name") == {"c:one|1001:": 0} # DEFAULT_COMPARISON_VALUE - 1
sheerka.set_is_greater_than(context, "prop_name", three, two)
assert service.get_concepts_weights("prop_name") == {"c:one|1001:": 0, "c:two|1002:": 1, "c:three|1003:": 2}
assert service.get_weights("prop_name") == {"c:one|1001:": 0, "c:two|1002:": 1, "c:three|1003:": 2}
# I can commit
sheerka.om.commit(context)
@@ -315,7 +366,7 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
sheerka.set_is_less_than(context, "prop_name", less_l, lesser)
sheerka.set_is_greater_than(context, "prop_name", less_l, even_more_l)
assert service.get_concepts_weights("prop_name") == {"c:lesser|1001:": 0,
assert service.get_weights("prop_name") == {"c:lesser|1001:": 0,
"c:less_l|1002:": -1,
"c:even_less_l|1003:": -2}
@@ -325,46 +376,46 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
unless minus_one is defined as lesser itself
:return:
"""
sheerka, context, lesser, foo = self.init_concepts("lesser", "foo")
sheerka, context, lesser, foo, bar = self.init_concepts("lesser", "foo", "bar")
service = sheerka.services[SheerkaComparisonManager.NAME]
service.set_is_lesser(context, "prop_name", lesser)
res = sheerka.set_is_less_than(context, "prop_name", foo, lesser)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.INVALID_LESSER_OPERATION)
# sanity check
res = sheerka.set_is_greater_than(context, "prop_name", foo, lesser)
assert res.status
res = sheerka.set_is_less_than(context, "prop_name", bar, lesser)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.INVALID_LESSER_OPERATION)
assert sheerka.isinstance(res.body, BuiltinConcepts.IS_LESSER_CONSTRAINT_ERROR)
def test_a_greatest_concept_has_the_highest_weight(self):
sheerka, context, one, two, three = self.init_concepts("one", "two", "three")
service = sheerka.services[SheerkaComparisonManager.NAME]
service.set_is_greatest(context, "prop_name", three)
assert service.get_concepts_weights("prop_name") == {"c:three|1003:": 2} # DEFAULT_COMPARISON_VALUE + 1
assert service.get_weights("prop_name") == {"c:three|1003:": 2} # DEFAULT_COMPARISON_VALUE + 1
sheerka.set_is_greater_than(context, "prop_name", two, one)
assert service.get_concepts_weights("prop_name") == {"c:one|1001:": 1, "c:two|1002:": 2, "c:three|1003:": 3}
assert service.get_weights("prop_name") == {"c:one|1001:": 1, "c:two|1002:": 2, "c:three|1003:": 3}
def test_i_cannot_define_greater_than_a_greatest_if_not_a_greater_itself(self):
sheerka, context, greatest, foo = self.init_concepts("greatest", "foo")
sheerka, context, greatest, foo, bar = self.init_concepts("greatest", "foo", "bar")
service = sheerka.services[SheerkaComparisonManager.NAME]
service.set_is_greatest(context, "prop_name", greatest)
# sanity check
res = sheerka.set_is_less_than(context, "prop_name", foo, greatest)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.INVALID_GREATEST_OPERATION)
assert res.status
res = sheerka.set_is_greater_than(context, "prop_name", foo, greatest)
res = sheerka.set_is_greater_than(context, "prop_name", bar, greatest)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.INVALID_GREATEST_OPERATION)
assert sheerka.isinstance(res.body, BuiltinConcepts.IS_GREATEST_CONSTRAINT_ERROR)
@pytest.mark.parametrize("definitions, expected", [
(["foo >>", "foo <<"], BuiltinConcepts.INVALID_GREATEST_OPERATION),
(["foo <<", "foo >>"], BuiltinConcepts.INVALID_LESSER_OPERATION),
(["foo >>", "foo <<"], BuiltinConcepts.IS_GREATEST_CONSTRAINT_ERROR),
(["foo <<", "foo >>"], BuiltinConcepts.IS_LESSER_CONSTRAINT_ERROR),
])
def test_i_cannot_define_a_concept_as_lesser_and_greatest_at_the_same_time(self, definitions, expected):
sheerka, context, foo = self.init_concepts("foo")
@@ -386,7 +437,7 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
sheerka.set_is_less_than(context, "prop_name", greatest, more_g)
sheerka.set_is_greater_than(context, "prop_name", even_more_g, more_g)
assert service.get_concepts_weights("prop_name") == {"c:greatest|1001:": 2,
assert service.get_weights("prop_name") == {"c:greatest|1001:": 2,
"c:more_g|1002:": 3,
"c:even_more_g|1003:": 4}
@@ -405,7 +456,7 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
sheerka.set_is_less_than(context, "prop_name", three, four)
assert service.get_concepts_weights("prop_name") == {
assert service.get_weights("prop_name") == {
"c:one|1001:": -1,
"c:two|1002:": 0,
"c:three|1003:": 1,
@@ -417,7 +468,7 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
sheerka.set_is_less_than(context, "prop_name", three_and_half, four)
sheerka.set_is_greater_than(context, "prop_name", three_and_half, three)
assert service.get_concepts_weights("prop_name") == {
assert service.get_weights("prop_name") == {
"c:one|1001:": -1,
"c:two|1002:": 0,
"c:three|1003:": 1,
@@ -446,7 +497,7 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
service.set_is_greater_than(context, "prop_name", five, one)
service.set_is_greater_than(context, "prop_name", five, three)
assert service.get_concepts_weights("prop_name") == {
assert service.get_weights("prop_name") == {
"c:zero|1001:": 0,
"c:one|1002:": 1,
"c:two|1003:": 2,
@@ -471,7 +522,7 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
res = self.execution_definition(context, service, concepts_map, definition)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.CONCEPT_ALREADY_DEFINED)
assert sheerka.isinstance(res.body, BuiltinConcepts.COMPARISON_ALREADY_DEFINED)
def test_an_event_is_fired_when_modifying_concepts_precedence(self):
sheerka, context, one, two, foo = self.init_concepts("one", "two", "foo")
@@ -514,3 +565,170 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
sheerka.set_is_greater_than(context, BuiltinConcepts.PRECEDENCE, r1, r2, RULE_COMPARISON_CONTEXT)
assert event_received
@pytest.mark.parametrize("entries, expected", [
([], (set(), set(), set())),
(["a<<", "a<<", "b<<", "a<c"], (set(), {"a", "b"}, {"a", "b", "c"})),
(["a>>", "a>>", "b>>", "a<c"], ({"a", "b"}, set(), {"a", "b", "c"})),
(["a<<", "b>>", "c=d", "e<f", "g>h"], ({"b"}, {"a"}, {"a", "b", "c", "d", "e", "f", "g", "h"})),
])
def test_i_can_get_objs_groups(self, entries, expected):
comparison_objs = self.get_comparison_objs(entries)
assert SheerkaComparisonManager.get_objs_groups(comparison_objs) == expected
@pytest.mark.parametrize("entries, greatest, lowest, expected_tuple", [
# greatest
(["a < b"], {"a", "b"}, set(), (["a < b"], [], [], [])),
(["a > b"], {"a", "b"}, set(), (["a > b"], [], [], [])),
# lowest
(["a < b"], set(), {"a", "b"}, ([], ["a < b"], [], [])),
(["a > b"], set(), {"a", "b"}, ([], ["a > b"], [], [])),
# equiv
(["a = b"], set(), set(), ([], [], ["a = b"], [])),
# neither
(["a < b"], set(), set(), ([], [], [], ["a < b"])),
(["a > b"], set(), set(), ([], [], [], ["a > b"])),
# irrelevant information
(["a > b"], {"a"}, set(), ([], [], [], [])),
(["a > b"], set(), {"b"}, ([], [], [], [])),
(["a < b"], {"b"}, set(), ([], [], [], [])),
(["a < b"], set(), {"a"}, ([], [], [], [])),
# mixed
(["a<b", "c<d", "e<f", "z=b"], {"a", "b", "c", "d"}, set(), (["a<b", "c<d"], [], ["z=b"], ["e<f"])),
])
def test_i_can_group_comparison_objs(self, entries, greatest, lowest, expected_tuple):
comparison_objs = self.get_comparison_objs(entries)
g, l, e, o = SheerkaComparisonManager.group_comparison_objs(comparison_objs, greatest, lowest)
def compare_results(actual_result, expected_result):
assert len(actual_result) == len(expected_result)
for actual, expected in zip(actual_result, expected_result):
expected_comparison_obj = list(self.get_comparison_objs([expected]))[0]
assert actual.a == expected_comparison_obj.a
assert actual.b == expected_comparison_obj.b
assert actual.op == expected_comparison_obj.op
compare_results(g, expected_tuple[0])
compare_results(l, expected_tuple[1])
compare_results(e, expected_tuple[2])
compare_results(o, expected_tuple[3])
@pytest.mark.parametrize("entries, expected", [
([], {}),
(["a < b"], {"a": 1, "b": 2}),
(["a > b"], {"a": 2, "b": 1}),
(["a < b", "b > a"], {"a": 1, "b": 2}),
(["a < b", "b < c"], {"a": 1, "b": 2, "c": 3}),
(["a < b", "a < c"], {"a": 1, "b": 2, "c": 2}),
# greatest between themselves
(["a < b", "a>>", "b>>"], {"a": 2, "b": 3}),
(["a > b", "a>>", "b>>"], {"a": 3, "b": 2}),
(["a < b", "b > a", "a>>", "b>>"], {"a": 2, "b": 3}),
(["a < b", "b < c", "a>>", "b>>", "c>>"], {"a": 2, "b": 3, "c": 4}),
(["a < b", "a < c", "a>>", "b>>", "c>>"], {"a": 2, "b": 3, "c": 3}),
# lowest between themselves
(["a < b", "a<<", "b<<"], {"a": -1, "b": 0}),
(["a > b", "a<<", "b<<"], {"a": 0, "b": -1}),
(["a < b", "b > a", "a<<", "b<<"], {"a": -1, "b": 0}),
(["a < b", "b < c", "a<<", "b<<", "c<<"], {"a": -2, "b": -1, "c": 0}),
(["a < b", "a < c", "a<<", "b<<", "c<<"], {"a": -1, "b": 0, "c": 0}),
# greatest that does not appear in other relations
(["a >>", "b < c"], {"a": 3, "b": 1, "c": 2}),
(["a >>", "a > b"], {"a": 2, "b": 1}),
(["a >>", "a > b", "c > d", "d > e"], {"a": 4, "b": 1, "c": 3, "d": 2, "e": 1}),
# lowest that does not appear in other relations
(["a <<", "b < c"], {"a": 0, "b": 1, "c": 2}),
(["a <<", "a < b"], {"a": 0, "b": 1}),
(["a <<", "a < b", "c < d", "d < e"], {"a": 0, "b": 1, "c": 1, "d": 2, "e": 3}),
(["z <<", "a<<", "b<<", "c<<", "a < b", "b < c"], {"a": -2, "b": -1, "c": 0, "z": -3}),
# eq
(["a = b"], {"a": 1, "b": 1}),
(["a = b", "b > c"], {"a": 2, "b": 2, "c": 1}),
(["a = z", "z>>", "b<c", "c<d"], {"a": 4, "b": 1, "c": 2, "d": 3, "z": 4}),
(["b = a", "c = b", "a > d"], {"a": 2, "b": 2, "c": 2, "d": 1}),
(["a = b", "b = c", "a > d"], {"a": 2, "b": 2, "c": 2, "d": 1}),
#(["a = b", "b = c", "c > d"], {"a": 2, "b": 2, "c": 2, "d": 1}), # not working
# mix greatest and lesser
(["a >>", "b<<", "a > b"], {"a": 2, "b": 0}),
])
def test_i_can_compute_weight_new(self, entries, expected):
comparison_objs = list(self.get_comparison_objs(entries))
assert SheerkaComparisonManager.compute_weights(comparison_objs) == expected
@pytest.mark.parametrize("previous_entries, new_entry, items_in_cycle", [
(["a > b"], "b > a", {"a", "b"}),
(["a > b", "c > d"], "b > a", {"a", "b"}),
(["a < b", "b < c"], "c < a", {"a", "b", "c"}),
])
def test_validate_new_entry_i_can_detect_cycle(self, previous_entries, new_entry, items_in_cycle):
sheerka, context = self.init_test().unpack()
new_co = list(self.get_comparison_objs([new_entry]))[0]
previous_comparison_objs = list(self.get_comparison_objs(previous_entries))
res = SheerkaComparisonManager.validate_new_entry(context, new_co, previous_comparison_objs)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.CHICKEN_AND_EGG)
assert set(res.body.body) == items_in_cycle
@pytest.mark.parametrize("previous_entries, new_entry", [
(["a > b"], "a > b"),
(["a < b"], "a < b"),
(["a = b"], "a = b"),
(["a <<"], "a <<"),
(["a >>"], "a >>"),
])
def test_validate_new_entry_i_can_detect_duplicate_entries(self, previous_entries, new_entry):
sheerka, context = self.init_test().unpack()
new_co = list(self.get_comparison_objs([new_entry]))[0]
previous_comparison_objs = list(self.get_comparison_objs(previous_entries))
res = SheerkaComparisonManager.validate_new_entry(context, new_co, previous_comparison_objs)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.COMPARISON_ALREADY_DEFINED)
@pytest.mark.parametrize("previous_entries, new_entry", [
(["a>>"], "a<<"),
(["a>>"], "a < b"),
(["a>>"], "b > a"),
])
def test_validate_new_entry_i_can_detect_is_greatest_constraint_error(self, previous_entries, new_entry):
sheerka, context = self.init_test().unpack()
new_co = list(self.get_comparison_objs([new_entry]))[0]
previous_comparison_objs = list(self.get_comparison_objs(previous_entries))
res = SheerkaComparisonManager.validate_new_entry(context, new_co, previous_comparison_objs)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.IS_GREATEST_CONSTRAINT_ERROR)
@pytest.mark.parametrize("previous_entries, new_entry", [
(["a<<"], "a>>"),
(["a<<"], "a > b"),
(["a<<"], "b < a"),
])
def test_validate_new_entry_i_can_detect_is_lesser_constraint_error(self, previous_entries, new_entry):
sheerka, context = self.init_test().unpack()
new_co = list(self.get_comparison_objs([new_entry]))[0]
previous_comparison_objs = list(self.get_comparison_objs(previous_entries))
res = SheerkaComparisonManager.validate_new_entry(context, new_co, previous_comparison_objs)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.IS_LESSER_CONSTRAINT_ERROR)
+274 -20
View File
@@ -1,18 +1,20 @@
import pytest
from cache.CacheManager import ConceptNotFound
from core.builtin_concepts import BuiltinConcepts
from core.builtin_helpers import ensure_bnf
from core.concept import PROPERTIES_TO_SERIALIZE, Concept, DEFINITION_TYPE_DEF, get_concept_attrs, \
DEFINITION_TYPE_BNF
from core.global_symbols import NotInit, NotFound
from core.sheerka.Sheerka import Sheerka
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager, NoModificationFound, ForbiddenAttribute, \
UnknownAttribute, CannotRemoveMeta, ValueNotFound, ConceptIsReferenced
from parsers.BaseNodeParser import BaseNodeParser
from parsers.BnfNodeParser import Sequence, StrMatch, ConceptExpression
UnknownAttribute, CannotRemoveMeta, ValueNotFound, ConceptIsReferenced, NoFirstTokenError
from parsers.BnfNodeParser import Sequence, StrMatch, ConceptExpression, OrderedChoice, Optional, ZeroOrMore, OneOrMore
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
compute_concepts_by_first_token = SheerkaConceptManager.compute_concepts_by_first_token
resolve_concepts_by_first_keyword = SheerkaConceptManager.resolve_concepts_by_first_keyword
class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
def test_i_can_create_a_concept(self):
@@ -48,15 +50,15 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
assert sheerka.get_by_hash(concept.get_definition_hash()) == concept
# I can get by the first entry
assert sheerka.om.get(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "+") == [concept.id]
assert sheerka.om.get(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "+") == [concept.id]
assert sheerka.om.get(service.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "+") == [concept.id]
assert sheerka.om.get(service.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "+") == [concept.id]
# saved in sdp
assert sheerka.om.current_sdp().exists(service.CONCEPTS_BY_ID_ENTRY, concept.id)
assert sheerka.om.current_sdp().exists(service.CONCEPTS_BY_KEY_ENTRY, concept.key)
assert sheerka.om.current_sdp().exists(service.CONCEPTS_BY_NAME_ENTRY, concept.name)
assert sheerka.om.current_sdp().exists(service.CONCEPTS_BY_HASH_ENTRY, concept.get_definition_hash())
assert sheerka.om.current_sdp().exists(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "+")
assert sheerka.om.current_sdp().exists(service.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "+")
def test_i_cannot_create_a_bnf_concept_that_references_a_concept_that_cannot_be_resolved(self):
sheerka, context, one_1, one_1_0 = self.init_concepts(Concept("one", body="1"), Concept("one", body="1.0"))
@@ -104,7 +106,7 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
assert sheerka.om.current_sdp().exists(service.CONCEPTS_BY_KEY_ENTRY, concept.key)
assert sheerka.om.current_sdp().exists(service.CONCEPTS_BY_NAME_ENTRY, concept.name)
assert sheerka.om.current_sdp().exists(service.CONCEPTS_BY_HASH_ENTRY, concept.get_definition_hash())
assert sheerka.om.current_sdp().exists(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "hello")
assert sheerka.om.current_sdp().exists(service.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "hello")
def test_i_cannot_add_the_same_concept_twice(self):
"""
@@ -185,8 +187,8 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
assert res.status
# I can get by the first entry
assert sheerka.om.get(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [concept.id]
assert sheerka.om.get(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [concept.id]
assert sheerka.om.get(SheerkaConceptManager.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [concept.id]
assert sheerka.om.get(SheerkaConceptManager.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [concept.id]
@pytest.mark.parametrize("expression", [
"--'filter' ('one' | 'two') ",
@@ -198,8 +200,8 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
create_new=True).unpack()
# I can get by the first entry
assert sheerka.om.get(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [bnf_concept.id]
assert sheerka.om.get(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [bnf_concept.id]
assert sheerka.om.get(SheerkaConceptManager.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [bnf_concept.id]
assert sheerka.om.get(SheerkaConceptManager.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [bnf_concept.id]
def test_concept_references_are_updated_1(self):
sheerka, context, one, two, number, twenty, twenties = self.init_test().with_concepts(
@@ -494,11 +496,11 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
Concept("baz", definition="foo"),
create_new=True).unpack()
assert sheerka.om.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
assert sheerka.om.copy(SheerkaConceptManager.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
"foo": ["1001"],
"bar": ["1002"],
'c:|1001:': ['1003']}
assert sheerka.om.copy(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
assert sheerka.om.copy(SheerkaConceptManager.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
'foo': ['1001', '1003'],
'bar': ['1002']}
@@ -506,10 +508,10 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
res = sheerka.modify_concept(context, foo, to_add)
assert res.status
assert sheerka.om.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
assert sheerka.om.copy(SheerkaConceptManager.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
"bar": ["1002", "1001"],
'c:|1001:': ['1003']}
assert sheerka.om.copy(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
assert sheerka.om.copy(SheerkaConceptManager.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
'bar': ['1002', '1001', '1003']}
def test_references_are_updated_after_concept_modification(self):
@@ -531,7 +533,7 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
assert twenty_one.get_metadata().definition == "'twenty' one"
assert twenty_one.get_bnf() is None
BaseNodeParser.ensure_bnf(context, twenty_one)
ensure_bnf(context, twenty_one)
assert twenty_one.get_bnf() == Sequence(StrMatch('twenty'), ConceptExpression(modified, rule_name='one'))
def test_i_can_modify_on_top_of_a_new_ontology_layer(self):
@@ -730,6 +732,258 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_CONCEPT)
@pytest.mark.parametrize("concept, expected", [
(Concept("foo"), {"foo": ["1001"]}),
(Concept("foo a").def_var("a"), {"foo": ["1001"]}),
(Concept("a b foo").def_var("a").def_var("b"), {"foo": ["1001"]}),
])
def test_i_can_get_concepts_by_first_keyword(self, concept, expected):
"""
Given a concept, i can find the first know token
example:
Concept("a foo b").def_var("a").def_var("b")
'a' and 'b' are properties
the first 'real' token is foo
:return:
"""
sheerka, context, *updated = self.init_concepts(concept)
res = SheerkaConceptManager.compute_concepts_by_first_token(context, updated)
assert res.status
assert res.body == expected
@pytest.mark.parametrize("bnf, expected", [
(StrMatch("foo"), {"foo": ["1002"]}),
(StrMatch("bar"), {"bar": ["1002"]}),
(ConceptExpression("bar"), {"c:|1001:": ["1002"]}),
(Sequence(StrMatch("foo"), StrMatch("bar")), {"foo": ["1002"]}),
(Sequence(StrMatch("foo"), ConceptExpression("bar")), {"foo": ["1002"]}),
(Sequence(ConceptExpression("bar"), StrMatch("foo")), {"c:|1001:": ["1002"]}),
(OrderedChoice(StrMatch("foo"), StrMatch("bar")), {"foo": ["1002"], "bar": ["1002"]}),
(Optional(StrMatch("foo")), {"foo": ["1002"]}),
(ZeroOrMore(StrMatch("foo")), {"foo": ["1002"]}),
(OneOrMore(StrMatch("foo")), {"foo": ["1002"]}),
(StrMatch("--filter"), {"--filter": ["1002"]}), # add both entries
])
def test_i_can_get_concepts_by_first_keyword_with_bnf(self, bnf, expected):
sheerka, context = self.init_test().unpack()
bar = Concept("bar").init_key()
sheerka.set_id_if_needed(bar, False)
sheerka.test_only_add_in_cache(bar)
concept = Concept("foo").init_key()
concept.set_bnf(bnf)
sheerka.set_id_if_needed(concept, False)
res = compute_concepts_by_first_token(context, [concept])
assert res.status
assert res.body == expected
def test_i_can_get_concepts_by_first_keyword_when_multiple_concepts(self):
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
bar = Concept("bar").init_key()
sheerka.set_id_if_needed(bar, False)
sheerka.test_only_add_in_cache(bar)
baz = Concept("baz").init_key()
sheerka.set_id_if_needed(baz, False)
sheerka.test_only_add_in_cache(baz)
foo = Concept("foo").init_key()
foo.set_bnf(OrderedChoice(ConceptExpression("bar"), ConceptExpression("baz"), StrMatch("qux")))
sheerka.set_id_if_needed(foo, False)
res = compute_concepts_by_first_token(context, [bar, baz, foo])
assert res.status
assert res.body == {
"bar": ["1001"],
"baz": ["1002"],
"c:|1001:": ["1003"],
"c:|1002:": ["1003"],
"qux": ["1003"],
}
def test_i_can_get_concepts_by_first_keyword_using_sheerka(self):
sheerka, context, *updated = self.init_test().with_concepts(
"one",
"two",
Concept("twenty", definition="'twenty' (one|two)"),
create_new=True
).unpack()
bar = Concept("bar").init_key()
sheerka.set_id_if_needed(bar, False)
sheerka.test_only_add_in_cache(bar)
foo = Concept("foo").init_key()
foo.set_bnf(OrderedChoice(ConceptExpression("one"), ConceptExpression("bar"), StrMatch("qux")))
sheerka.set_id_if_needed(foo, False)
res = compute_concepts_by_first_token(context, [bar, foo], use_sheerka=True)
assert res.status
assert res.body == {
"one": ["1001"],
"two": ["1002"],
"twenty": ["1003"],
"bar": ["1004"],
"c:|1001:": ["1005"],
"c:|1004:": ["1005"],
"qux": ["1005"],
}
def test_i_cannot_get_concept_by_first_keyword_when_no_first_keyword(self):
sheerka, context, foo = self.init_concepts(Concept("x y", body="x y").def_var("x").def_var("y"))
res = compute_concepts_by_first_token(context, [foo])
assert not res.status
assert res.body == NoFirstTokenError(foo, foo.key)
def test_i_can_resolve_concepts_by_first_keyword(self):
sheerka, context, *updated = self.init_concepts(
"one",
Concept("two", definition="one"),
Concept("three", definition="two"))
concepts_by_first_keywords = {
"one": ["1001"],
"c:|1001:": ["1002"],
"c:|1002:": ["1003"],
}
resolved_ret_val = resolve_concepts_by_first_keyword(context, concepts_by_first_keywords)
assert resolved_ret_val.status
assert resolved_ret_val.body == {
"one": ["1001", "1002", "1003"],
}
def test_i_can_resolve_when_concepts_are_sets(self):
sheerka, context, number, *concepts = self.init_concepts(
"number",
"one",
"two",
"twenty",
"hundred",
Concept("twenties", definition="twenty number"),
Concept("hundreds", definition="number hundred"),
)
sheerka.set_isa(context, sheerka.new("one"), number)
sheerka.set_isa(context, sheerka.new("two"), number)
sheerka.set_isa(context, sheerka.new("twenty"), number)
sheerka.set_isa(context, sheerka.new("thirty"), number)
sheerka.set_isa(context, sheerka.new("hundred"), number)
sheerka.set_isa(context, sheerka.new("twenties"), number)
sheerka.set_isa(context, sheerka.new("hundreds"), number)
sheerka.concepts_grammars.clear() # reset all the grammar to simulate Sheerka restart
# cbft : concept_by_first_token (I usually don't use abbreviation)
cbft = compute_concepts_by_first_token(context, [number] + concepts).body
resolved_ret_val = resolve_concepts_by_first_keyword(context, cbft)
assert resolved_ret_val.status
assert resolved_ret_val.body == {
'number': ['1001'],
'one': ['1002', '1007'],
'two': ['1003', '1007'],
'twenty': ['1004', '1006', '1007'],
'hundred': ['1005', '1007'],
}
def test_concepts_are_defined_once(self):
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
good = self.create_and_add_in_cache_concept(sheerka, "good")
foo = self.create_and_add_in_cache_concept(sheerka, "foo", bnf=ConceptExpression("good"))
bar = self.create_and_add_in_cache_concept(sheerka, "bar", bnf=ConceptExpression("good"))
baz = self.create_and_add_in_cache_concept(sheerka, "baz", bnf=OrderedChoice(
ConceptExpression("foo"),
ConceptExpression("bar")))
concepts_by_first_keywords = compute_concepts_by_first_token(context, [good, foo, bar, baz]).body
resolved_ret_val = resolve_concepts_by_first_keyword(context, concepts_by_first_keywords)
assert resolved_ret_val.status
assert resolved_ret_val.body == {
"good": ["1001", "1002", "1003", "1004"],
}
def test_i_can_resolve_more_complex(self):
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
a = self.create_and_add_in_cache_concept(sheerka, "a", bnf=Sequence("one", "two"))
b = self.create_and_add_in_cache_concept(sheerka, "b", bnf=Sequence(ConceptExpression("a"), "two"))
concepts_by_first_keywords = compute_concepts_by_first_token(context, [a, b]).body
resolved_ret_val = resolve_concepts_by_first_keyword(context, concepts_by_first_keywords)
assert resolved_ret_val.status
assert resolved_ret_val.body == {
"one": ["1001", "1002"],
}
def tests_i_can_detect_direct_recursion(self):
sheerka, context, good, foo, bar = self.init_concepts(
"good",
self.bnf_concept("foo", ConceptExpression("bar")),
self.bnf_concept("bar", ConceptExpression("foo")),
)
concepts_by_first_keywords = compute_concepts_by_first_token(context, [good, foo, bar]).body
resolved_ret_val = resolve_concepts_by_first_keyword(context, concepts_by_first_keywords)
assert resolved_ret_val.status
assert resolved_ret_val.body == {
"good": ["1001"],
}
assert sheerka.chicken_and_eggs.get(foo.id) == {foo.id, bar.id}
assert sheerka.chicken_and_eggs.get(bar.id) == {foo.id, bar.id}
def test_i_can_detect_indirect_infinite_recursion(self):
sheerka, context, good, one, two, three = self.init_concepts(
"good",
self.bnf_concept("one", ConceptExpression("two")),
self.bnf_concept("two", ConceptExpression("three")),
self.bnf_concept("three", ConceptExpression("two")),
)
concepts_by_first_keywords = compute_concepts_by_first_token(context, [good, one, two, three]).body
resolved_ret_val = resolve_concepts_by_first_keyword(context, concepts_by_first_keywords)
assert resolved_ret_val.status
assert resolved_ret_val.body == {
"good": ["1001"],
}
assert sheerka.chicken_and_eggs.get(one.id) == {one.id, two.id, three.id}
assert sheerka.chicken_and_eggs.get(two.id) == {one.id, two.id, three.id}
assert sheerka.chicken_and_eggs.get(three.id) == {one.id, two.id, three.id}
def test_i_can_detect_the_longest_infinite_recursion_chain(self):
sheerka, context, good, one, two, three = self.init_concepts(
"good",
self.bnf_concept("two", ConceptExpression("three")),
self.bnf_concept("three", ConceptExpression("two")),
self.bnf_concept("one", ConceptExpression("three")),
)
concepts_by_first_keywords = compute_concepts_by_first_token(context, [good, one, two, three]).body
resolved_ret_val = resolve_concepts_by_first_keyword(context, concepts_by_first_keywords)
assert resolved_ret_val.status
assert resolved_ret_val.body == {
"good": ["1001"],
}
assert sheerka.chicken_and_eggs.get(one.id) == {one.id, two.id, three.id}
assert sheerka.chicken_and_eggs.get(two.id) == {one.id, two.id, three.id}
assert sheerka.chicken_and_eggs.get(three.id) == {one.id, two.id, three.id}
class TestSheerkaConceptManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
def test_i_can_add_several_concepts(self):
@@ -759,8 +1013,8 @@ class TestSheerkaConceptManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
assert sheerka.om.current_sdp().exists(service.CONCEPTS_BY_HASH_ENTRY, hello.get_definition_hash())
assert sheerka.om.current_sdp().exists(service.CONCEPTS_BY_HASH_ENTRY, greeting.get_definition_hash())
assert sheerka.om.current_sdp().exists(Sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "Hello")
assert sheerka.om.current_sdp().exists(Sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "Greeting")
assert sheerka.om.current_sdp().exists(service.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "Hello")
assert sheerka.om.current_sdp().exists(service.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "Greeting")
def test_i_cannot_add_the_same_concept_twice_using_sdp(self):
"""
+1
View File
@@ -973,3 +973,4 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
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)]
+1 -12
View File
@@ -88,17 +88,6 @@ class TestSheerkaMemory(TestUsingMemoryBasedSheerka):
assert sheerka.om.copy(SheerkaMemory.OBJECTS_ENTRY) == {"a": MemoryObject(context.event.get_digest(), foo)}
assert id(sheerka.get_from_memory(context, "a").obj) == id(foo)
def test_i_can_use_memory_to_get_the_list_of_all_objects(self):
sheerka, context = self.init_test(cache_only=False).unpack()
foo = Concept("foo")
bar = Concept("bar")
sheerka.add_to_memory(context, "foo", 'value that will not appear')
sheerka.add_to_memory(context, "foo", foo)
sheerka.add_to_memory(context, "bar", bar)
sheerka.om.commit(context)
assert sheerka.memory(context) == {"foo": foo, "bar": bar}
def test_i_can_use_memory_with_a_string(self):
sheerka, context = self.init_test().unpack()
@@ -138,7 +127,7 @@ class TestSheerkaMemory(TestUsingMemoryBasedSheerka):
def test_object_are_not_added_in_memory_during_the_initialisation(self):
sheerka, context = self.init_test().unpack()
assert len(sheerka.memory(context)) == 0
assert len(sheerka.om.get_all(SheerkaMemory.OBJECTS_ENTRY)) == 0
class TestSheerkaMemoryUsingFileBase(TestUsingFileBasedSheerka):
+37 -2
View File
@@ -1,9 +1,10 @@
import ast
import pytest
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, CMV
from core.global_symbols import RULE_COMPARISON_CONTEXT, NotFound
from core.global_symbols import RULE_COMPARISON_CONTEXT
from core.rule import Rule, ACTION_TYPE_PRINT, ACTION_TYPE_EXEC
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, FormatRuleParser, \
FormatAstRawText, FormatAstVariable, FormatAstSequence, FormatAstFunction, \
@@ -11,7 +12,6 @@ from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, FormatR
from core.tokenizer import Token, TokenKind
from parsers.BaseNodeParser import SourceCodeWithConceptNode, SourceCodeNode
from parsers.PythonParser import PythonNode
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -335,6 +335,41 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
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()
context.add_to_short_term_memory("x", rule.id)
# direct access by id
assert sheerka.resolve_rule(context, rule.id) == rule
# direct access by token
assert sheerka.resolve_rule(context, Token(TokenKind.RULE, ("i_do_not_care", rule.id), -1, -1, -1)) == rule
# indirect access by token
assert sheerka.resolve_rule(context, Token(TokenKind.RULE, ("i_do_not_care", "x"), -1, -1, -1)) == rule
# Simple returns the rule if id is resolved
assert sheerka.resolve_rule(context, rule) == rule
# look for the correct rule when id is unresolved
unresolved = Rule(rule_id="x")
unresolved.metadata.id_is_unresolved = True
assert sheerka.resolve_rule(context, unresolved) == rule
# look for the correct rule when id is unresolved
unresolved = Rule(rule_id="y")
unresolved.metadata.id_is_unresolved = True
assert sheerka.resolve_rule(context, unresolved) is None # no error raised
# I still can get the value when the indirection has the wrong type
context.add_to_short_term_memory("z", int(rule.id))
assert sheerka.resolve_rule(context, Token(TokenKind.RULE, ("i_do_not_care", "z"), -1, -1, -1)) == rule
unresolved = Rule(rule_id="z")
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()),
+4 -4
View File
@@ -539,21 +539,21 @@ class TestSheerkaUsingFileBasedSheerka(TestUsingFileBasedSheerka):
create_new=True).unpack()
sheerka.om.commit(context)
assert sheerka.om.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
assert sheerka.om.copy(SheerkaConceptManager.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
'bar': ['1002'],
'c:|1001:': ['1003'],
'foo': ['1001']}
assert sheerka.om.copy(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
assert sheerka.om.copy(SheerkaConceptManager.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
'bar': ['1002'],
'foo': ['1001', '1003']
}
sheerka = self.get_sheerka() # another instance
assert sheerka.om.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
assert sheerka.om.copy(SheerkaConceptManager.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
'bar': ['1002'],
'c:|1001:': ['1003'],
'foo': ['1001']}
assert sheerka.om.copy(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
assert sheerka.om.copy(SheerkaConceptManager.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
'bar': ['1002'],
'foo': ['1001', '1003']
}
+68 -8
View File
@@ -1,12 +1,13 @@
import types
import pytest
from core.builtin_concepts import BuiltinConcepts
from core.sheerka.ExecutionContext import ExecutionContext
from core.sheerka.SheerkaOntologyManager import SheerkaOntologyManager
from core.sheerka.services.SheerkaResultManager import SheerkaResultConcept
from core.sheerka.services.SheerkaResultManager import SheerkaResultManager
from sdp.sheerkaDataProvider import Event
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -25,7 +26,7 @@ class TestSheerkaResultManager(TestUsingMemoryBasedSheerka):
def init_service(self):
sheerka, context = self.init_test().unpack()
service = sheerka.services[SheerkaResultConcept.NAME]
service = sheerka.services[SheerkaResultManager.NAME]
return sheerka, context, service
@@ -64,7 +65,7 @@ class TestSheerkaResultManager(TestUsingMemoryBasedSheerka):
assert isinstance(res.body, types.GeneratorType)
# the digest is correctly recorded
assert sheerka.load_var(SheerkaResultConcept.NAME, "digest") == digest
assert sheerka.load_var(SheerkaResultManager.NAME, "digest") == digest
previous_results = list(res.body)
@@ -93,7 +94,7 @@ class TestSheerkaResultManager(TestUsingMemoryBasedSheerka):
assert isinstance(res.body, types.GeneratorType)
# the digest is correctly recorded
assert sheerka.load_var(SheerkaResultConcept.NAME, "digest") == digest
assert sheerka.load_var(SheerkaResultManager.NAME, "digest") == digest
previous_results = list(res.body)
@@ -148,7 +149,7 @@ class TestSheerkaResultManager(TestUsingMemoryBasedSheerka):
sheerka.evaluate_user_input("one")
sheerka.evaluate_user_input("one")
service = SheerkaResultConcept(sheerka, 2)
service = SheerkaResultManager(sheerka, 2)
res = service.get_results_by_command(context, "def concept")
assert sheerka.isinstance(res, BuiltinConcepts.EXPLANATION)
assert res.command == "def concept one as 1"
@@ -171,7 +172,7 @@ class TestSheerkaResultManager(TestUsingMemoryBasedSheerka):
sheerka.evaluate_user_input("one")
sheerka.evaluate_user_input("one")
service = SheerkaResultConcept(sheerka, 2)
service = SheerkaResultManager(sheerka, 2)
res = service.get_results_by_command(context, "fake command")
assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND)
assert res.body == {'command': 'fake command'}
@@ -336,7 +337,7 @@ class TestSheerkaResultManager(TestUsingMemoryBasedSheerka):
def test_i_can_manage_invalid_predicates(self):
predicate = {"filter": "a b c"}
with pytest.raises(SyntaxError):
SheerkaResultConcept.get_predicate(**predicate)
SheerkaResultManager.get_predicate(**predicate)
def test_i_can_get_last_return_value(self):
sheerka, context, service = self.init_service()
@@ -368,3 +369,62 @@ class TestSheerkaResultManager(TestUsingMemoryBasedSheerka):
assert service.last_created_concept_id == new_concept.id
assert sheerka.get_last_created_concept(context) == new_concept
def test_last_error_is_recorded(self):
sheerka, context, foo = self.init_test().with_concepts("foo", create_new=True).unpack()
service = sheerka.services[SheerkaResultManager.NAME]
res = sheerka.evaluate_user_input("bar") # does not exist, will cause an error
sheerka.evaluate_user_input("foo") # exists, to validate that the error is not reset
assert service.last_error_event_id is not None
assert len(res) == 1
assert sheerka.get_last_error() == res[0]
def test_multiple_errors_are_recorded(self):
sheerka, context, foo = self.init_test().with_concepts("foo", create_new=True).unpack()
service = sheerka.services[SheerkaResultManager.NAME]
service.test_only_reset()
res = sheerka.evaluate_user_input("x x") # cannot be parsed
sheerka.evaluate_user_input("foo") # exists, to validate that the error is not reset
assert service.last_error_event_id is not None
assert len(res) > 1
assert sheerka.get_last_error() == [r for r in res if not r.status]
def test_i_cannot_get_last_error_when_no_error(self):
sheerka, context = self.init_test().unpack()
service = sheerka.services[SheerkaResultManager.NAME]
service.test_only_reset()
assert service.last_error_event_id is None
assert sheerka.get_last_error() == self.sheerka.new(BuiltinConcepts.NOT_FOUND, body={"query": "get_last_error"})
class TestSheerkaResultManagerFileBased(TestUsingFileBasedSheerka):
@classmethod
def setup_class(cls):
sheerka = cls().get_sheerka(cache_only=False, ontology="#TestSheerkaResultManager#")
sheerka.save_execution_context = True
cls.root_ontology_name = "#TestSheerkaResultManager#"
@classmethod
def teardown_class(cls):
cls.sheerka.pop_ontology()
cls.root_ontology_name = SheerkaOntologyManager.ROOT_ONTOLOGY_NAME
def test_i_can_retrieve_the_last_error_after_startup(self):
sheerka, context, foo = self.init_test().with_concepts("foo", create_new=True).unpack()
service = sheerka.services[SheerkaResultManager.NAME]
res_in_error = sheerka.evaluate_user_input("bar") # does not exist, will cause an error
sheerka.evaluate_user_input("foo") # exists, to validate that the error is not reset
assert service.last_error_event_id is not None
assert service.get_last_error() == res_in_error[0]
# simulate restart
sheerka = self.new_sheerka_instance(False)
service = sheerka.services[SheerkaResultManager.NAME]
assert service.last_error_event_id is not None
assert service.get_last_error() == res_in_error[0]
+100 -99
View File
@@ -1167,106 +1167,107 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
"key5": "value5"
}
def test_i_can_list_by_key_when_dictionaries(self):
sheerka = self.get_sheerka(cache_only=False)
context = self.get_context(sheerka)
# def test_i_can_list_by_key_when_dictionaries(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"))
# manager.freeze()
#
# manager.put("cache_name", "key1", {"a": "value1", "b": "value2", "c": "value3"})
# manager.commit(context)
#
# manager.push_ontology("new ontology")
# manager.put("cache_name", "key1", {"a": "new value1", "d": "value4"}) # only in cache
#
# manager.push_ontology("another ontology")
# with manager.current_sdp().get_transaction(context.event) as transaction:
# transaction.add("cache_name", "key1", {"b": "new value2", "e": "value5"})
#
# assert manager.list_by_key("cache_name", "key1") == {
# "a": "new value1",
# "b": "new value2",
# "c": "value3",
# "d": "value4",
# "e": "value5",
# }
#
# def test_i_can_list_by_key_when_lists(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"))
# manager.freeze()
#
# manager.put("cache_name", "key1", ["a", "b", "c"])
# manager.commit(context)
#
# manager.push_ontology("new ontology")
# manager.put("cache_name", "key1", ["a", "d"]) # only in cache
#
# manager.push_ontology("another ontology")
# with manager.current_sdp().get_transaction(context.event) as transaction:
# transaction.add("cache_name", "key1", ["b", "e"])
#
# assert manager.list_by_key("cache_name", "key1") == ["a", "b", "c", "a", "d", "b", "e"]
#
# def test_i_can_list_by_key_when_dictionaries_and_entries_are_removed(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"))
# manager.freeze()
#
# manager.put("cache_name", "key1", {"a": "value1", "b": "value2", "c": "value3"})
# manager.put("cache_name", "key2", {"a": "value1", "b": "value2", "c": "value3"})
# manager.put("cache_name", "key3", {"a": "value1", "b": "value2", "c": "value3"})
# manager.commit(context)
#
# manager.push_ontology("new ontology")
# manager.put("cache_name", "key1", Removed) # removed in cache
# with manager.current_sdp().get_transaction(context.event) as transaction:
# transaction.add("cache_name", "key2", Removed) # removed in sdp
#
# manager.push_ontology("another ontology")
# manager.put("cache_name", "key1", {"e": "value1", "f": "value2", "g": "value3"})
# manager.put("cache_name", "key2", {"e": "value1", "f": "value2", "g": "value3"})
# manager.put("cache_name", "key3", {"e": "value1", "f": "value2", "g": "value3"})
#
# assert manager.list_by_key("cache_name", "key1") == {"e": "value1", "f": "value2", "g": "value3"}
# assert manager.list_by_key("cache_name", "key2") == {"e": "value1", "f": "value2", "g": "value3"}
# assert manager.list_by_key("cache_name", "key3") == {"a": "value1", "b": "value2", "c": "value3",
# "e": "value1", "f": "value2", "g": "value3"}
#
# def test_i_can_list_by_key_when_lists_and_entries_are_removed(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"))
# manager.freeze()
#
# manager.put("cache_name", "key1", ["a", "b", "c"])
# manager.put("cache_name", "key2", ["a", "b", "c"])
# manager.put("cache_name", "key3", ["a", "b", "c"])
# manager.commit(context)
#
# manager.push_ontology("new ontology")
# manager.put("cache_name", "key1", Removed) # removed in cache
# with manager.current_sdp().get_transaction(context.event) as transaction:
# transaction.add("cache_name", "key2", Removed) # removed in sdp
#
# manager.push_ontology("another ontology")
# manager.put("cache_name", "key1", ["e", "f", "g"])
# manager.put("cache_name", "key2", ["e", "f", "g"])
# manager.put("cache_name", "key3", ["e", "f", "g"])
#
# assert manager.list_by_key("cache_name", "key1") == ["e", "f", "g"]
# 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"]
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
manager.register_cache("cache_name", Cache().auto_configure("cache_name"))
manager.freeze()
manager.put("cache_name", "key1", {"a": "value1", "b": "value2", "c": "value3"})
manager.commit(context)
manager.push_ontology("new ontology")
manager.put("cache_name", "key1", {"a": "new value1", "d": "value4"}) # only in cache
manager.push_ontology("another ontology")
with manager.current_sdp().get_transaction(context.event) as transaction:
transaction.add("cache_name", "key1", {"b": "new value2", "e": "value5"})
assert manager.list_by_key("cache_name", "key1") == {
"a": "new value1",
"b": "new value2",
"c": "value3",
"d": "value4",
"e": "value5",
}
def test_i_can_list_by_key_when_lists(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"))
manager.freeze()
manager.put("cache_name", "key1", ["a", "b", "c"])
manager.commit(context)
manager.push_ontology("new ontology")
manager.put("cache_name", "key1", ["a", "d"]) # only in cache
manager.push_ontology("another ontology")
with manager.current_sdp().get_transaction(context.event) as transaction:
transaction.add("cache_name", "key1", ["b", "e"])
assert manager.list_by_key("cache_name", "key1") == ["a", "b", "c", "a", "d", "b", "e"]
def test_i_can_list_by_key_when_dictionaries_and_entries_are_removed(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"))
manager.freeze()
manager.put("cache_name", "key1", {"a": "value1", "b": "value2", "c": "value3"})
manager.put("cache_name", "key2", {"a": "value1", "b": "value2", "c": "value3"})
manager.put("cache_name", "key3", {"a": "value1", "b": "value2", "c": "value3"})
manager.commit(context)
manager.push_ontology("new ontology")
manager.put("cache_name", "key1", Removed) # removed in cache
with manager.current_sdp().get_transaction(context.event) as transaction:
transaction.add("cache_name", "key2", Removed) # removed in sdp
manager.push_ontology("another ontology")
manager.put("cache_name", "key1", {"e": "value1", "f": "value2", "g": "value3"})
manager.put("cache_name", "key2", {"e": "value1", "f": "value2", "g": "value3"})
manager.put("cache_name", "key3", {"e": "value1", "f": "value2", "g": "value3"})
assert manager.list_by_key("cache_name", "key1") == {"e": "value1", "f": "value2", "g": "value3"}
assert manager.list_by_key("cache_name", "key2") == {"e": "value1", "f": "value2", "g": "value3"}
assert manager.list_by_key("cache_name", "key3") == {"a": "value1", "b": "value2", "c": "value3",
"e": "value1", "f": "value2", "g": "value3"}
def test_i_can_list_by_key_when_lists_and_entries_are_removed(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"))
manager.freeze()
manager.put("cache_name", "key1", ["a", "b", "c"])
manager.put("cache_name", "key2", ["a", "b", "c"])
manager.put("cache_name", "key3", ["a", "b", "c"])
manager.commit(context)
manager.push_ontology("new ontology")
manager.put("cache_name", "key1", Removed) # removed in cache
with manager.current_sdp().get_transaction(context.event) as transaction:
transaction.add("cache_name", "key2", Removed) # removed in sdp
manager.push_ontology("another ontology")
manager.put("cache_name", "key1", ["e", "f", "g"])
manager.put("cache_name", "key2", ["e", "f", "g"])
manager.put("cache_name", "key3", ["e", "f", "g"])
assert manager.list_by_key("cache_name", "key1") == ["e", "f", "g"]
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)
+20 -2
View File
@@ -1,6 +1,7 @@
import ast
import pytest
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
from core.concept import Concept, CB
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
@@ -11,7 +12,6 @@ from parsers.BaseNodeParser import SourceCodeNode, SourceCodeWithConceptNode
from parsers.FunctionParser import FunctionParser
from parsers.PythonParser import PythonNode, PythonParser
from parsers.PythonWithConceptsParser import PythonWithConceptsParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -226,7 +226,7 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
evaluated = python_evaluator.eval(context, parsed)
assert evaluated.status
assert sheerka.get_concepts_weights(BuiltinConcepts.PRECEDENCE) == {'c:__var__0 plus __var__1|1001:': 1,
assert sheerka.get_weights(BuiltinConcepts.PRECEDENCE) == {'c:__var__0 plus __var__1|1001:': 1,
'c:__var__0 mult __var__1|1002:': 2}
def test_i_can_define_variables(self):
@@ -370,3 +370,21 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
sequence = visitor.get_sequences(ast_, "foo")
assert sequence == expected
@pytest.mark.parametrize("parser, value", [
(PythonParser(), "3"),
(FunctionParser(), "3"),
(PythonParser(), 3),
(FunctionParser(), 3),
])
def test_i_can_eval_unresolved_rules(self, parser, value):
context = self.get_context()
context.add_to_short_term_memory("get_obj_name", get_obj_name)
context.add_to_short_term_memory("x", value)
parsed = parser.parse(context, ParserInput("get_obj_name(r:|x:)"))
python_evaluator = PythonEvaluator()
evaluated = python_evaluator.eval(context, parsed)
assert evaluated.status
assert evaluated.value == context.sheerka.get_rule_by_id(str(value)).name
+4 -4
View File
@@ -1,6 +1,6 @@
import pytest
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
from core.rule import Rule, ACTION_TYPE_DEFERRED
from core.rule import Rule
from evaluators.RuleEvaluator import RuleEvaluator
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -37,11 +37,11 @@ class TestRuleEvaluator(TestUsingMemoryBasedSheerka):
assert result.value == expected
assert result.parents == [ret_val]
def test_i_can_evaluate_deferred_rules(self):
def test_i_can_evaluate_unresolved_rules(self):
context = self.get_context()
rule = Rule().set_id("i")
rule.metadata.action_type = ACTION_TYPE_DEFERRED
rule.metadata.id_is_unresolved = True
ret_val = ReturnValueConcept("some_name", True, ParserResultConcept(value=[rule]), True)
context.add_to_short_term_memory("i", 1)
evaluator = RuleEvaluator()
@@ -57,7 +57,7 @@ class TestRuleEvaluator(TestUsingMemoryBasedSheerka):
sheerka, context = self.init_concepts()
rule = Rule().set_id("unknown variable")
rule.metadata.action_type = ACTION_TYPE_DEFERRED
rule.metadata.id_is_unresolved = True
ret_val = ReturnValueConcept("some_name", True, ParserResultConcept(value=[rule]), True)
evaluator = RuleEvaluator()
+17
View File
@@ -87,4 +87,21 @@ ReturnValue(who=evaluators.Concept, status=True, value=(1002)foo)
test 1
#unit_test#
__default__
"""
def test_i_can_display_objects_in_memory(self, capsys):
init = [
"def concept one as 1",
"def concept two as 2",
"one",
"two"
]
sheerka = self.init_scenario(init)
capsys.readouterr()
sheerka.enable_process_return_values = True
sheerka.evaluate_user_input("in_memory()")
captured = capsys.readouterr()
assert captured.out == """one: (1001)one
two: (1002)two
"""
+18 -5
View File
@@ -116,7 +116,7 @@ as:
assert service.has_id(concept_saved.id)
assert service.has_name(concept_saved.name)
assert service.has_hash(concept_saved.get_definition_hash())
assert sheerka.om.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {'+': ['1001']}
assert sheerka.om.copy(SheerkaConceptManager.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {'+': ['1001']}
# sdp is up to date
assert sheerka.om.current_sdp().exists(SheerkaConceptManager.CONCEPTS_BY_KEY_ENTRY, expected.key)
@@ -865,7 +865,7 @@ as:
res = sheerka.evaluate_user_input("set_is_less_than('some_prop', two, three)")
assert res[0].status
res = sheerka.evaluate_user_input("get_concepts_weights('some_prop')")
res = sheerka.evaluate_user_input("get_weights('some_prop')")
assert res[0].status
assert res[0].body == {'c:one|1001:': 1, 'c:two|1002:': 2, 'c:three|1003:': 3}
@@ -874,7 +874,7 @@ as:
res = sheerka.evaluate_user_input("eval four > three")
assert res[0].status
assert sheerka.get_concepts_weights("some_prop") == {'c:one|1001:': 1,
assert sheerka.get_weights("some_prop") == {'c:one|1001:': 1,
'c:two|1002:': 2,
'c:three|1003:': 3,
'c:four|1004:': 4}
@@ -898,14 +898,14 @@ as:
res = sheerka.evaluate_user_input(expression)
assert res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.SUCCESS)
assert sheerka.get_concepts_weights("some_prop") == {'c:one|1001:': 1, 'c:two|1002:': 2}
assert sheerka.get_weights("some_prop") == {'c:one|1001:': 1, 'c:two|1002:': 2}
# it now also works using the concepts names
expression = "eval two < three"
res = sheerka.evaluate_user_input(expression)
assert res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.SUCCESS)
assert sheerka.get_concepts_weights("some_prop") == {'c:one|1001:': 1, 'c:two|1002:': 2, 'c:three|1003:': 3}
assert sheerka.get_weights("some_prop") == {'c:one|1001:': 1, 'c:two|1002:': 2, 'c:three|1003:': 3}
def test_i_can_detect_multiple_errors_when_evaluating_a_concept(self):
sheerka, context, foo, plus_one = self.init_concepts(
@@ -1229,6 +1229,19 @@ as:
assert res[0].status
assert res[0].body == 21
def test_i_can_define_rules_priorities(self):
sheerka, context, r1, r2 = self.init_test().with_rules(("True", "True"), ("False", "False")).unpack()
sheerka.evaluate_user_input("def concept rule x > rule y where isinstance(x, int) and isinstance(y, int) as set_is_greater_than(__PRECEDENCE, r:|x:, r:|y:, 'Rule')")
res = sheerka.evaluate_user_input(f"eval rule {r1.id} > rule {r2.id}")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.SUCCESS)
weights = sheerka.get_weights(BuiltinConcepts.PRECEDENCE, 'Rule')
assert weights[r1.str_id] == weights[r2.str_id] + 1
class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
def test_i_can_def_several_concepts(self):
-294
View File
@@ -1,294 +0,0 @@
import pytest
from core.concept import Concept
from parsers.BaseNodeParser import BaseNodeParser, NoFirstTokenError
from parsers.BnfNodeParser import StrMatch, Sequence, OrderedChoice, Optional, ZeroOrMore, OneOrMore, ConceptExpression
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestBaseNodeParser(TestUsingMemoryBasedSheerka):
@pytest.mark.parametrize("concept, expected", [
(Concept("foo"), {"foo": ["1001"]}),
(Concept("foo a").def_var("a"), {"foo": ["1001"]}),
(Concept("a b foo").def_var("a").def_var("b"), {"foo": ["1001"]}),
])
def test_i_can_get_concepts_by_first_keyword(self, concept, expected):
"""
Given a concept, i can find the first know token
example:
Concept("a foo b").def_var("a").def_var("b")
'a' and 'b' are properties
the first 'real' token is foo
:return:
"""
sheerka, context, *updated = self.init_concepts(concept)
res = BaseNodeParser.compute_concepts_by_first_token(context, updated)
assert res.status
assert res.body == expected
@pytest.mark.parametrize("bnf, expected", [
(StrMatch("foo"), {"foo": ["1002"]}),
(StrMatch("bar"), {"bar": ["1002"]}),
(ConceptExpression("bar"), {"c:|1001:": ["1002"]}),
(Sequence(StrMatch("foo"), StrMatch("bar")), {"foo": ["1002"]}),
(Sequence(StrMatch("foo"), ConceptExpression("bar")), {"foo": ["1002"]}),
(Sequence(ConceptExpression("bar"), StrMatch("foo")), {"c:|1001:": ["1002"]}),
(OrderedChoice(StrMatch("foo"), StrMatch("bar")), {"foo": ["1002"], "bar": ["1002"]}),
(Optional(StrMatch("foo")), {"foo": ["1002"]}),
(ZeroOrMore(StrMatch("foo")), {"foo": ["1002"]}),
(OneOrMore(StrMatch("foo")), {"foo": ["1002"]}),
(StrMatch("--filter"), {"--filter": ["1002"]}), # add both entries
])
def test_i_can_get_concepts_by_first_keyword_with_bnf(self, bnf, expected):
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
bar = Concept("bar").init_key()
sheerka.set_id_if_needed(bar, False)
sheerka.test_only_add_in_cache(bar)
concept = Concept("foo").init_key()
concept.set_bnf(bnf)
sheerka.set_id_if_needed(concept, False)
res = BaseNodeParser.compute_concepts_by_first_token(context, [concept])
assert res.status
assert res.body == expected
def test_i_can_get_concepts_by_first_keyword_when_multiple_concepts(self):
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
bar = Concept("bar").init_key()
sheerka.set_id_if_needed(bar, False)
sheerka.test_only_add_in_cache(bar)
baz = Concept("baz").init_key()
sheerka.set_id_if_needed(baz, False)
sheerka.test_only_add_in_cache(baz)
foo = Concept("foo").init_key()
foo.set_bnf(OrderedChoice(ConceptExpression("bar"), ConceptExpression("baz"), StrMatch("qux")))
sheerka.set_id_if_needed(foo, False)
res = BaseNodeParser.compute_concepts_by_first_token(context, [bar, baz, foo])
assert res.status
assert res.body == {
"bar": ["1001"],
"baz": ["1002"],
"c:|1001:": ["1003"],
"c:|1002:": ["1003"],
"qux": ["1003"],
}
def test_i_can_get_concepts_by_first_keyword_using_sheerka(self):
sheerka, context, *updated = self.init_test().with_concepts(
"one",
"two",
Concept("twenty", definition="'twenty' (one|two)"),
create_new=True
).unpack()
bar = Concept("bar").init_key()
sheerka.set_id_if_needed(bar, False)
sheerka.test_only_add_in_cache(bar)
foo = Concept("foo").init_key()
foo.set_bnf(OrderedChoice(ConceptExpression("one"), ConceptExpression("bar"), StrMatch("qux")))
sheerka.set_id_if_needed(foo, False)
res = BaseNodeParser.compute_concepts_by_first_token(context, [bar, foo], use_sheerka=True)
assert res.status
assert res.body == {
"one": ["1001"],
"two": ["1002"],
"twenty": ["1003"],
"bar": ["1004"],
"c:|1001:": ["1005"],
"c:|1004:": ["1005"],
"qux": ["1005"],
}
def test_i_cannot_get_concept_by_first_keyword_when_no_first_keyword(self):
sheerka, context, foo = self.init_concepts(Concept("x y", body="x y").def_var("x").def_var("y"))
res = BaseNodeParser.compute_concepts_by_first_token(context, [foo])
assert not res.status
assert res.body == NoFirstTokenError(foo, foo.key)
def test_i_can_resolve_concepts_by_first_keyword(self):
sheerka, context, *updated = self.init_concepts(
"one",
Concept("two", definition="one"),
Concept("three", definition="two"))
concepts_by_first_keywords = {
"one": ["1001"],
"c:|1001:": ["1002"],
"c:|1002:": ["1003"],
}
resolved_ret_val = BaseNodeParser.resolve_concepts_by_first_keyword(context, concepts_by_first_keywords)
assert resolved_ret_val.status
assert resolved_ret_val.body == {
"one": ["1001", "1002", "1003"],
}
def test_i_can_resolve_when_concepts_are_sets(self):
sheerka, context, number, *concepts = self.init_concepts(
"number",
"one",
"two",
"twenty",
"hundred",
Concept("twenties", definition="twenty number"),
Concept("hundreds", definition="number hundred"),
)
sheerka.set_isa(context, sheerka.new("one"), number)
sheerka.set_isa(context, sheerka.new("two"), number)
sheerka.set_isa(context, sheerka.new("twenty"), number)
sheerka.set_isa(context, sheerka.new("thirty"), number)
sheerka.set_isa(context, sheerka.new("hundred"), number)
sheerka.set_isa(context, sheerka.new("twenties"), number)
sheerka.set_isa(context, sheerka.new("hundreds"), number)
sheerka.concepts_grammars.clear() # reset all the grammar to simulate Sheerka restart
# cbft : concept_by_first_token (I usually don't use abbreviation)
cbft = BaseNodeParser.compute_concepts_by_first_token(context, [number] + concepts).body
resolved_ret_val = BaseNodeParser.resolve_concepts_by_first_keyword(context, cbft)
assert resolved_ret_val.status
assert resolved_ret_val.body == {
'number': ['1001'],
'one': ['1002', '1007'],
'two': ['1003', '1007'],
'twenty': ['1004', '1006', '1007'],
'hundred': ['1005', '1007'],
}
def test_concepts_are_defined_once(self):
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
good = self.create_and_add_in_cache_concept(sheerka, "good")
foo = self.create_and_add_in_cache_concept(sheerka, "foo", bnf=ConceptExpression("good"))
bar = self.create_and_add_in_cache_concept(sheerka, "bar", bnf=ConceptExpression("good"))
baz = self.create_and_add_in_cache_concept(sheerka, "baz", bnf=OrderedChoice(
ConceptExpression("foo"),
ConceptExpression("bar")))
concepts_by_first_keywords = BaseNodeParser.compute_concepts_by_first_token(
context, [good, foo, bar, baz]).body
resolved_ret_val = BaseNodeParser.resolve_concepts_by_first_keyword(context, concepts_by_first_keywords)
assert resolved_ret_val.status
assert resolved_ret_val.body == {
"good": ["1001", "1002", "1003", "1004"],
}
def test_i_can_resolve_more_complex(self):
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
a = self.create_and_add_in_cache_concept(sheerka, "a", bnf=Sequence("one", "two"))
b = self.create_and_add_in_cache_concept(sheerka, "b", bnf=Sequence(ConceptExpression("a"), "two"))
concepts_by_first_keywords = BaseNodeParser.compute_concepts_by_first_token(
context, [a, b]).body
resolved_ret_val = BaseNodeParser.resolve_concepts_by_first_keyword(context, concepts_by_first_keywords)
assert resolved_ret_val.status
assert resolved_ret_val.body == {
"one": ["1001", "1002"],
}
def tests_i_can_detect_direct_recursion(self):
sheerka, context, good, foo, bar = self.init_concepts(
"good",
self.bnf_concept("foo", ConceptExpression("bar")),
self.bnf_concept("bar", ConceptExpression("foo")),
)
concepts_by_first_keywords = BaseNodeParser.compute_concepts_by_first_token(context, [good, foo, bar]).body
resolved_ret_val = BaseNodeParser.resolve_concepts_by_first_keyword(context, concepts_by_first_keywords)
assert resolved_ret_val.status
assert resolved_ret_val.body == {
"good": ["1001"],
}
assert sheerka.chicken_and_eggs.get(foo.id) == {foo.id, bar.id}
assert sheerka.chicken_and_eggs.get(bar.id) == {foo.id, bar.id}
def test_i_can_detect_indirect_infinite_recursion(self):
sheerka, context, good, one, two, three = self.init_concepts(
"good",
self.bnf_concept("one", ConceptExpression("two")),
self.bnf_concept("two", ConceptExpression("three")),
self.bnf_concept("three", ConceptExpression("two")),
)
concepts_by_first_keywords = BaseNodeParser.compute_concepts_by_first_token(context, [good, one, two, three]).body
resolved_ret_val = BaseNodeParser.resolve_concepts_by_first_keyword(context, concepts_by_first_keywords)
assert resolved_ret_val.status
assert resolved_ret_val.body == {
"good": ["1001"],
}
assert sheerka.chicken_and_eggs.get(one.id) == {one.id, two.id, three.id}
assert sheerka.chicken_and_eggs.get(two.id) == {one.id, two.id, three.id}
assert sheerka.chicken_and_eggs.get(three.id) == {one.id, two.id, three.id}
def test_i_can_detect_the_longest_infinite_recursion_chain(self):
sheerka, context, good, one, two, three = self.init_concepts(
"good",
self.bnf_concept("two", ConceptExpression("three")),
self.bnf_concept("three", ConceptExpression("two")),
self.bnf_concept("one", ConceptExpression("three")),
)
concepts_by_first_keywords = BaseNodeParser.compute_concepts_by_first_token(context, [good, one, two, three]).body
resolved_ret_val = BaseNodeParser.resolve_concepts_by_first_keyword(context, concepts_by_first_keywords)
assert resolved_ret_val.status
assert resolved_ret_val.body == {
"good": ["1001"],
}
assert sheerka.chicken_and_eggs.get(one.id) == {one.id, two.id, three.id}
assert sheerka.chicken_and_eggs.get(two.id) == {one.id, two.id, three.id}
assert sheerka.chicken_and_eggs.get(three.id) == {one.id, two.id, three.id}
#
# def test_i_can_detect_infinite_recursion_from_ordered_choice(self):
# sheerka = self.get_sheerka()
# good = self.get_concept(sheerka, "good")
# one = self.get_concept(sheerka, "one", ConceptExpression("two"))
# two = self.get_concept(sheerka, "two", OrderedChoice(ConceptExpression("one"), ConceptExpression("two")))
#
# concepts_by_first_keywords = BaseNodeParser.get_concepts_by_first_token(sheerka, [good, one, two]).body
#
# resolved_ret_val = BaseNodeParser.resolve_concepts_by_first_keyword(sheerka, concepts_by_first_keywords)
# assert resolved_ret_val.status
# assert resolved_ret_val.body == {
# "good": ["1001"],
# BuiltinConcepts.CHICKEN_AND_EGG: ["1002", "1003"]
# }
#
# def test_i_can_detect_infinite_recursion_with_sequence(self):
# sheerka = self.get_sheerka()
# good = self.get_concept(sheerka, "good")
# one = self.get_concept(sheerka, "one", ConceptExpression("two"))
# two = self.get_concept(sheerka, "two", Sequence(StrMatch("yes"), ConceptExpression("one")))
#
# concepts_by_first_keywords = BaseNodeParser.get_concepts_by_first_token(sheerka, [good, one, two]).body
#
# resolved_ret_val = BaseNodeParser.resolve_concepts_by_first_keyword(sheerka, concepts_by_first_keywords)
# assert resolved_ret_val.status
# assert resolved_ret_val.body == {
# "good": ["1001"],
# BuiltinConcepts.CHICKEN_AND_EGG: ["1002", "1003"]
# }
+4 -3
View File
@@ -4,6 +4,7 @@ import tests.parsers.parsers_utils
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, ConceptParts, DoNotResolve, CC, DEFINITION_TYPE_BNF
from core.global_symbols import NotInit
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
from core.sheerka.services.SheerkaExecute import ParserInput
from parsers.BaseNodeParser import CNC, UTN, CN
from parsers.BnfDefinitionParser import BnfDefinitionParser
@@ -833,7 +834,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
# every obvious cyclic recursion are removed from concept_by_first_keyword dict
parser.init_from_concepts(context, my_map.values())
assert sheerka.om.copy(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == expected
assert sheerka.om.copy(SheerkaConceptManager.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == expected
# get_parsing_expression() also returns CHICKEN_AND_EGG
parsing_expression = parser.get_parsing_expression(context, my_map["foo"])
@@ -858,7 +859,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
# every obvious cyclic recursion are removed from concept_by_first_keyword dict
parser.init_from_concepts(context, my_map.values())
assert sheerka.om.copy(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {}
assert sheerka.om.copy(SheerkaConceptManager.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {}
parsing_expression = parser.get_parsing_expression(context, my_map["foo"])
assert sheerka.isinstance(parsing_expression, BuiltinConcepts.CHICKEN_AND_EGG)
@@ -884,7 +885,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
# every obvious cyclic recursion are removed from concept_by_first_keyword dict
parser.init_from_concepts(context, my_map.values())
assert sheerka.om.copy(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {}
assert sheerka.om.copy(SheerkaConceptManager.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {}
parsing_expression = parser.get_parsing_expression(context, my_map["foo"])
assert sheerka.isinstance(parsing_expression, BuiltinConcepts.CHICKEN_AND_EGG)
+1 -1
View File
@@ -87,7 +87,7 @@ class TestRuleParser(TestUsingMemoryBasedSheerka):
assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT)
assert len(rules) == 1
assert rules[0].id == "xxx"
assert rules[0].metadata.action_type == "deferred"
assert rules[0].metadata.id_is_unresolved
@pytest.mark.parametrize("text", [
"r:|1:xxx",
+36 -3
View File
@@ -1,6 +1,8 @@
import pytest
import tests.parsers.parsers_utils
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, CIO, ALL_ATTRIBUTES, CMV
from core.concept import Concept, CIO, CMV
from core.global_symbols import CONCEPT_COMPARISON_CONTEXT
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Tokenizer
@@ -10,8 +12,7 @@ from parsers.BaseNodeParser import utnode, cnode, short_cnode, UnrecognizedToken
from parsers.PythonParser import PythonNode
from parsers.SyaNodeParser import SyaNodeParser, SyaConceptParserHelper, SyaAssociativity, \
NoneAssociativeSequenceError, TooManyParametersFoundError, InFixToPostFix, ParenthesisMismatchError
import tests.parsers.parsers_utils
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -1356,3 +1357,35 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
assert res.status
assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
assert lexer_nodes == [CN(cmap["suffixed"], 0, 6, source=text)]
class TestFileBaseSyaNodeParser(TestUsingFileBasedSheerka):
def test_i_can_parse_after_restart(self):
sheerka, context, one, two, plus = self.init_test().with_concepts("one",
"two",
Concept("a plus b").def_var("a").def_var("b"),
create_new=True).unpack()
sheerka.om.commit(context)
parser = SyaNodeParser()
# sanity check
# Remove this commented section to make sure that the nominal case still works
# res = parser.parse(context, ParserInput("one plus two"))
# assert res.status
# assert sheerka.isinstance(res.body.body[0].concept, plus.key)
sheerka = self.new_sheerka_instance(False)
context = self.get_context(sheerka)
res = parser.parse(context, ParserInput("one plus two"))
assert res.status
assert sheerka.isinstance(res.body.body[0].concept, plus.key)
# adds an ontology layer and make the test again
sheerka.push_ontology(context, "new ontology")
sheerka = self.new_sheerka_instance(False)
context = self.get_context(sheerka)
res = parser.parse(context, ParserInput("one plus two"))
assert res.status
assert sheerka.isinstance(res.body.body[0].concept, plus.key)