Refactored Caching, Refactored BnfNodeParser, Introduced Sphinx

This commit is contained in:
2020-05-12 17:21:10 +02:00
parent 7d3a490bc5
commit 6e343ba996
110 changed files with 13865 additions and 7540 deletions
+129 -161
View File
@@ -1,15 +1,15 @@
import pytest
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, Property, simplec
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, simplec
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
from parsers.BaseNodeParser import SyaAssociativity
from parsers.BnfNodeParser import Sequence, StrMatch, OrderedChoice, Optional, ConceptExpression
from sdp.sheerkaDataProvider import SheerkaDataProvider
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestSheerkaNonReg(TestUsingFileBasedSheerka):
class TestSheerkaNonRegMemory(TestUsingMemoryBasedSheerka):
def init_scenario(self, init_expressions):
sheerka = self.get_sheerka()
@@ -105,10 +105,10 @@ as:
expected = self.get_default_concept()
expected.metadata.id = "1001"
expected.metadata.desc = None
expected.metadata.props = [("a", None), ("b", None)]
expected.metadata.variables = [("a", None), ("b", None)]
expected.init_key()
sheerka = self.get_sheerka()
sheerka = self.get_sheerka(cache_only=False)
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
@@ -120,21 +120,15 @@ as:
for prop in PROPERTIES_TO_SERIALIZE:
assert getattr(concept_saved.metadata, prop) == getattr(expected.metadata, prop)
assert concept_saved.key in sheerka.cache_by_key
assert concept_saved.id in sheerka.cache_by_id
assert sheerka.sdp.io.exists(
sheerka.sdp.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, concept_saved.get_origin()))
# cache is up to date
assert sheerka.has_key(concept_saved.key)
assert sheerka.has_id(concept_saved.id)
assert sheerka.has_name(concept_saved.name)
assert sheerka.has_hash(concept_saved.get_definition_hash())
assert sheerka.cache_manager.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {'+': ['1001']}
def test_i_can_def_several_concepts(self):
sheerka = self.get_sheerka(use_dict=False)
sheerka.evaluate_user_input("def concept foo")
sheerka = self.get_sheerka(use_dict=False)
res = sheerka.evaluate_user_input("def concept bar")
assert len(res) == 1
assert res[0].status
assert res[0].body.body.id == "1002"
# sdp is up to date
assert sheerka.sdp.exists(sheerka.CONCEPTS_BY_KEY_ENTRY, expected.key)
def test_i_can_evaluate_def_concept_part_when_one_part_is_a_ref_of_another_concept(self):
"""
@@ -145,11 +139,11 @@ as:
sheerka = self.get_sheerka()
# concept 'a plus b' is known
concept_a_plus_b = Concept(name="a plus b").def_prop("a").def_prop("b")
concept_a_plus_b = Concept(name="a plus b").def_var("a").def_var("b").init_key()
sheerka.add_in_cache(concept_a_plus_b)
res = sheerka.evaluate_user_input("def concept a xx b as a plus b")
expected = Concept(name="a xx b", body="a plus b").def_prop("a").def_prop("b").init_key()
expected = Concept(name="a xx b", body="a plus b").def_var("a").def_var("b").init_key()
expected.metadata.id = "1001"
assert len(res) == 1
@@ -161,10 +155,7 @@ as:
for prop in PROPERTIES_TO_SERIALIZE:
assert getattr(concept_saved.metadata, prop) == getattr(expected.metadata, prop)
assert concept_saved.key in sheerka.cache_by_key
assert concept_saved.id in sheerka.cache_by_id
assert sheerka.sdp.io.exists(
sheerka.sdp.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, concept_saved.get_origin()))
assert sheerka.has_key(concept_saved.key)
def test_i_cannot_evaluate_the_same_def_concept_twice(self):
text = """
@@ -202,7 +193,7 @@ as:
def test_i_can_recognize_concept_with_variable(self):
sheerka = self.get_sheerka()
concept_hello = Concept(name="hello a").def_prop("a")
concept_hello = Concept(name="hello a").def_var("a")
concept_foo = Concept(name="foo")
sheerka.add_in_cache(concept_hello)
sheerka.add_in_cache(concept_foo)
@@ -212,15 +203,15 @@ as:
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(return_value, concept_hello)
assert return_value.metadata.props[0] == ('a', "foo")
assert return_value.metadata.variables[0] == ('a', "foo")
# sanity check
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), return_value)
assert evaluated.props["a"].value == concept_foo
assert evaluated.get_value("a") == concept_foo
def test_i_can_recognize_concept_with_variable_and_python_as_body(self):
sheerka = self.get_sheerka()
hello_a = sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").def_prop("a"))
hello_a = sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").def_var("a"))
sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
res = sheerka.evaluate_user_input("hello foo")
@@ -232,15 +223,14 @@ as:
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value)
assert evaluated.body == "hello foo"
assert evaluated.metadata.is_evaluated
assert evaluated.props["a"].value == simplec("foo", "foo")
assert evaluated.props["a"].value.metadata.is_evaluated
assert evaluated.get_value("a") == simplec("foo", "foo")
assert evaluated.get_value("a").metadata.is_evaluated
def test_i_can_recognize_duplicate_concepts_with_same_value(self):
sheerka = self.get_sheerka()
sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").def_prop("a"))
sheerka.add_in_cache(Concept(name="hello foo", body="'hello foo'"))
sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
self.create_concept_lite(sheerka, Concept(name="hello a", body="'hello ' + a"), variables=["a"])
self.create_concept_lite(sheerka, Concept(name="hello foo", body="'hello foo'"))
self.create_concept_lite(sheerka, Concept(name="foo", body="'foo'"))
res = sheerka.evaluate_user_input("hello foo")
assert len(res) == 1
@@ -250,10 +240,9 @@ as:
def test_i_cannot_manage_duplicate_concepts_when_the_values_are_different(self):
sheerka = self.get_sheerka()
sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").def_prop("a"))
sheerka.add_in_cache(Concept(name="hello foo", body="'hello foo'"))
sheerka.add_in_cache(Concept(name="foo", body="'another value'"))
self.create_concept_lite(sheerka, Concept(name="hello a", body="'hello ' + a"), variables=["a"])
self.create_concept_lite(sheerka, Concept(name="hello foo", body="'hello foo'"))
self.create_concept_lite(sheerka, Concept(name="foo", body="'another value'"))
res = sheerka.evaluate_user_input("hello foo")
assert len(res) == 1
@@ -270,8 +259,8 @@ as:
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
sheerka.create_new_concept(context, Concept(name="hello a", body="'hello ' + a").def_prop("a"))
sheerka.create_new_concept(context, Concept(name="hello b", body="'hello ' + b").def_prop("b"))
sheerka.create_new_concept(context, Concept(name="hello a", body="'hello ' + a").def_var("a"))
sheerka.create_new_concept(context, Concept(name="hello b", body="'hello ' + b").def_var("b"))
res = sheerka.evaluate_user_input("hello 'foo'")
assert len(res) == 1
@@ -283,42 +272,12 @@ as:
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
sheerka.create_new_concept(context, Concept(name="concepts", body="sheerka.concepts()"))
sheerka.create_new_concept(context, Concept(name="concepts", body="sheerka.test()"))
res = sheerka.evaluate_user_input("eval concepts")
assert len(res) == 1
assert res[0].status
assert isinstance(res[0].value, list)
def test_i_can_create_concept_with_bnf_definition(self):
sheerka = self.get_sheerka(use_dict=False, skip_builtins_in_db=False)
a = Concept("a")
sheerka.add_in_cache(a)
sheerka.concepts_definition_cache = {a: OrderedChoice("one", "two")}
res = sheerka.evaluate_user_input("def concept plus from bnf a ('plus' plus)?")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
saved_concept = sheerka.sdp.get_safe(sheerka.CONCEPTS_ENTRY, "plus")
assert saved_concept.key == "plus"
assert saved_concept.metadata.definition == "a ('plus' plus)?"
assert "a" in saved_concept.props
assert "plus" in saved_concept.props
saved_definitions = sheerka.sdp.get_safe(sheerka.CONCEPTS_DEFINITIONS_ENTRY)
expected_bnf = Sequence(
ConceptExpression(a, rule_name="a"),
Optional(Sequence(StrMatch("plus"), ConceptExpression(saved_concept, rule_name="plus"))))
assert saved_definitions["c:plus|1001:"] == "(c:a:=a ('plus' c:plus|1001:=plus)?)"
new_concept = res[0].value.body
assert new_concept.metadata.name == "plus"
assert new_concept.metadata.definition == "a ('plus' plus)?"
assert new_concept.bnf == expected_bnf
assert "a" in new_concept.props
assert "plus" in new_concept.props
assert res[0].value == sheerka.test()
def test_i_can_recognize_bnf_definitions(self):
sheerka = self.get_sheerka()
@@ -344,41 +303,11 @@ as:
assert sheerka.isinstance(return_value, concept_b)
# sanity check
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), return_value)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka=sheerka, eval_body=True), return_value)
assert evaluated.body == "one three"
assert evaluated.metadata.is_evaluated
assert evaluated.props["a"] == Property("a", sheerka.new(concept_a.key, body="one").init_key())
assert evaluated.props["a"].value.metadata.is_evaluated
def test_i_can_recognize_bnf_definitions_from_separate_instances(self):
"""
Same test then before,
but make sure that the BNF are correctly persisted and loaded
"""
sheerka = self.get_sheerka(use_dict=False)
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' 'two'")[0].body.body
res = self.get_sheerka(use_dict=False).evaluate_user_input("one two")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a)
# add another bnf definition
concept_b = sheerka.evaluate_user_input("def concept b from bnf a 'three'")[0].body.body
res = self.get_sheerka(use_dict=False).evaluate_user_input("one two") # previous one still works
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a)
res = self.get_sheerka(use_dict=False).evaluate_user_input("one two three") # new one works
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_b)
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value)
assert evaluated.body == "one two three"
assert evaluated.props["a"] == Property("a", sheerka.new(concept_a.key, body="one two").init_key())
assert evaluated.get_value("a") == sheerka.new(concept_a.key, body="one").init_key()
assert evaluated.get_value("a").metadata.is_evaluated
@pytest.mark.parametrize("user_input", [
"def concept greetings from def hello a where a",
@@ -393,7 +322,7 @@ as:
assert res[0].status
concept_found = res[0].value
assert sheerka.isinstance(concept_found, greetings)
assert concept_found.get_prop("a") == "foo"
assert concept_found.get_value("a") == "foo"
assert concept_found.metadata.need_validation
res = sheerka.evaluate_user_input("greetings")
@@ -401,10 +330,9 @@ as:
assert res[0].status
concept_found = res[0].value
assert sheerka.isinstance(concept_found, greetings)
assert concept_found.get_prop("a") is None
assert concept_found.get_value("a") is None
assert not concept_found.metadata.need_validation
# @pytest.mark.xfail
@pytest.mark.parametrize("desc, definitions", [
("Simple form", [
"def concept one as 1",
@@ -452,7 +380,7 @@ as:
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, "twenties")
assert sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].body).body == 21
assert sheerka.evaluate_concept(self.get_context(sheerka=sheerka, eval_body=True), res[0].body).body == 21
res = sheerka.evaluate_user_input("twenty one + 1")
assert len(res) == 1
@@ -479,7 +407,6 @@ as:
assert res[0].status
assert res[0].body == 23
# @pytest.mark.xfail
def test_i_can_mix_bnf_and_isa(self):
"""
if 'one' isa 'number, twenty number should be recognized
@@ -497,7 +424,7 @@ as:
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, "twenties")
assert sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value).body == 21
assert sheerka.evaluate_concept(self.get_context(sheerka=sheerka, eval_body=True), res[0].value).body == 21
res = sheerka.evaluate_user_input("twenty one + 1")
assert len(res) == 1
@@ -524,7 +451,7 @@ as:
assert res[0].status
assert res[0].body == 23
def test_i_can_mix_bnf_and_isa_when_concept_other_case(self):
def test_i_can_mix_bnf_and_isa_2(self):
sheerka = self.get_sheerka()
init = [
@@ -544,7 +471,6 @@ as:
assert res[0].status
assert res[0].body == 21
# @pytest.mark.xfail
def test_i_can_use_concepts_defined_with_from(self):
sheerka = self.get_sheerka()
@@ -656,31 +582,6 @@ as:
assert res[0].status
assert res[0].body == 3
@pytest.mark.xfail
def test_i_can_recognize_composition_of_concept(self):
sheerka = self.get_sheerka()
definitions = [
"def concept little a where a",
"def concept blue a where a",
"def concept house"
]
for definition in definitions:
sheerka.evaluate_user_input(definition)
### CAUTION ####
# this test cannot work !!
# it is just to hint the result that I would like to achieve
res = sheerka.evaluate_user_input("little blue house")
assert len(res) == 2
assert res[0].status
assert res[0].body == "little(blue(house))"
assert res[1].status
assert res[1].body == "little blue(house)"
def test_i_can_say_that_a_concept_isa_another_concept(self):
sheerka = self.get_sheerka()
sheerka.evaluate_user_input("def concept foo")
@@ -779,36 +680,35 @@ as:
sheerka.evaluate_user_input(exp)
res = sheerka.evaluate_user_input("twenty one")
assert len(res) == 1 and res[0].status and sheerka.isinstance(res[0].body, "twenties")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, "twenties")
res = sheerka.evaluate_user_input("eval twenty one")
assert len(res) == 1 and res[0].status and res[0].body == 21
assert len(res) == 1
assert res[0].status
assert res[0].body == 21
res = sheerka.evaluate_user_input("twenty two")
assert len(res) == 1 and res[0].status and sheerka.isinstance(res[0].body, "twenties")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, "twenties")
res = sheerka.evaluate_user_input("eval twenty two")
assert len(res) == 1 and res[0].status and res[0].body == 22
assert len(res) == 1
assert res[0].status
assert res[0].body == 22
res = sheerka.evaluate_user_input("twenty three")
assert len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.WHERE_CLAUSE_FAILED)
assert sheerka.isinstance(res[0].body, BuiltinConcepts.MULTIPLE_ERRORS)
assert str(BuiltinConcepts.WHERE_CLAUSE_FAILED) in [error.key for error in sheerka.get_error(res[0].body.body)]
res = sheerka.evaluate_user_input("eval twenty three")
assert len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.WHERE_CLAUSE_FAILED)
# def test_i_can_detect_when_only_one_evaluator_is_in_error(self):
# sheerka = self.get_sheerka()
#
# sheerka.evaluate_user_input("def concept 1 as one")
# res = sheerka.evaluate_user_input("eval 1")
# assert len(res) == 1
# assert not res[0].status
# assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONCEPT_EVAL_ERROR)
assert str(BuiltinConcepts.WHERE_CLAUSE_FAILED) in [error.key for error in sheerka.get_error(res[0].body.body)]
def test_i_can_manage_some_type_of_infinite_recursion(self):
sheerka = self.get_sheerka()
@@ -862,7 +762,7 @@ as:
assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.WHERE_CLAUSE_FAILED)
@pytest.mark.xfail
@pytest.mark.skip("Not ready for that")
def test_i_can_manage_missing_variables_from_bnf_parsing(self):
definitions = [
"def concept one as 1",
@@ -894,8 +794,8 @@ as:
assert len(res) == 1
assert res[0].status
twenties = sheerka.get("twenties")
number = sheerka.get("number")
twenties = sheerka.get_by_key("twenties")
number = sheerka.get_by_key("number")
assert sheerka.isa(twenties, number)
def test_i_can_mix_sya_concepts_and_bnf_concept(self):
@@ -910,9 +810,9 @@ as:
sheerka = self.init_scenario(definitions)
context = self.get_context(sheerka)
sheerka.set_sya_def(context, [
(sheerka.get("mult").id, 20, SyaAssociativity.Right),
(sheerka.get("plus").id, 10, SyaAssociativity.Right),
sheerka.force_sya_def(context, [
(sheerka.get_by_name("mult").id, 20, SyaAssociativity.Right),
(sheerka.get_by_name("plus").id, 10, SyaAssociativity.Right),
])
res = sheerka.evaluate_user_input("eval one plus two mult three")
@@ -954,3 +854,71 @@ as:
assert len(res) == 1
assert res[0].status
assert res[0].body == 64
class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
def test_i_can_def_several_concepts(self):
sheerka = self.get_sheerka()
sheerka.evaluate_user_input("def concept foo")
sheerka = self.get_sheerka()
res = sheerka.evaluate_user_input("def concept bar")
assert len(res) == 1
assert res[0].status
assert res[0].body.body.id == "1002"
def test_i_can_create_concept_with_bnf_definition(self):
sheerka = self.get_sheerka()
concept_a = self.bnf_concept("a", expression=OrderedChoice(StrMatch("one"), StrMatch("two")))
sheerka.create_new_concept(self.get_context(sheerka), concept_a)
res = sheerka.evaluate_user_input("def concept plus from bnf a ('plus' plus)?")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
saved_concept = sheerka.sdp.get(sheerka.CONCEPTS_BY_KEY_ENTRY, "plus")
assert saved_concept.key == "plus"
assert saved_concept.metadata.definition == "a ('plus' plus)?"
assert "a" in saved_concept.values
assert "plus" in saved_concept.values
expected_bnf = Sequence(
ConceptExpression(concept_a, rule_name="a"),
Optional(Sequence(StrMatch("plus"), ConceptExpression("plus"))))
new_concept = res[0].value.body
assert new_concept.metadata.name == "plus"
assert new_concept.metadata.definition == "a ('plus' plus)?"
assert new_concept.bnf == expected_bnf
assert "a" in new_concept.values
assert "plus" in new_concept.values
def test_i_can_recognize_bnf_definitions_from_separate_instances(self):
sheerka = self.get_sheerka()
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' 'two'")[0].body.body
sheerka = self.get_sheerka()
res = sheerka.evaluate_user_input("one two")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a)
# add another bnf definition
concept_b = sheerka.evaluate_user_input("def concept b from bnf a 'three'")[0].body.body
sheerka = self.get_sheerka()
res = sheerka.evaluate_user_input("one two") # previous one still works
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a)
res = self.get_sheerka().evaluate_user_input("one two three") # new one works
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_b)
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value)
assert evaluated.body == "one two three"
assert evaluated.get_value("a") == sheerka.new(concept_a.key, body="one two").init_key()