Files
Sheerka-Old/tests/non_reg/test_sheerka_non_reg.py
T
kodjo 87cab44fb8 Fixed #125: SheerkaErrorManager
Fixed #135: Change services service priorities
Fixed #136: ErrorManager: Implement recognize_error
Fixed #137: BNFNodeParser : Error when parsing regex with sub parsers
Fixed #138: get_last_errors(): real errors sources are lost
Fixed #139: OneError return value removes the origin of the error
Fixed #140: Concept variables are not correctly handled when parsing sub expression
Fixed #143: Implement has_unknown_concepts()
2021-10-28 14:04:41 +02:00

1426 lines
52 KiB
Python

import pytest
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, PROPERTIES_TO_SERIALIZE
from core.global_symbols import NotInit
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
from evaluators.OneSuccessEvaluator import OneSuccessEvaluator
from evaluators.PythonEvaluator import PythonEvalError
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.parsers.parsers_utils import CB, CC, CMV, compare_with_test_object
class TestSheerkaNonRegMemory(TestUsingMemoryBasedSheerka):
@pytest.mark.parametrize("text, expected", [
("1 + 1", 2),
("sheerka.test()", 'I have access to Sheerka !')
])
def test_i_can_evaluate_python_expressions_with_no_variable(self, text, expected):
sheerka = self.get_sheerka()
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert res[0].status
assert res[0].value == expected
def test_i_can_recognize_concept_with_python_body(self):
sheerka = self.get_sheerka()
concept = Concept(name="one", body="1")
sheerka.test_only_add_in_cache(concept)
text = "one"
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert res[0].status
assert res[0].value == concept
# sanity check
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value)
compare_with_test_object(evaluated, CB("one", 1))
def test_i_can_recognize_concept_with_concept_body(self):
sheerka, context, concept_one, concept_un = self.init_concepts("one", Concept(name="un", body="one"))
res = sheerka.evaluate_user_input("un")
return_value = res[0].value
assert len(res) == 1
assert res[0].status
assert return_value == concept_un
# sanity check
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), return_value)
compare_with_test_object(evaluated, CB("un", CB("one", NotInit)))
def test_i_can_recognize_concept_with_no_body(self):
sheerka = self.get_sheerka()
concept = Concept(name="one")
sheerka.test_only_add_in_cache(concept)
text = "one"
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert res[0].status
assert res[0].value == concept
assert id(res[0].value) != id(concept)
def test_is_unique_property_is_used_when_evaluating(self):
sheerka = self.get_sheerka()
concept = Concept(name="one", is_unique=True)
sheerka.test_only_add_in_cache(concept)
text = "one"
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert res[0].status
assert res[0].value == concept
assert id(res[0].value) == id(concept)
def test_i_can_evaluate_def_concept_request(self):
text = """
def concept a + b
where isinstance(a, int) and isinstance(b, int)
pre isinstance(a, int) and isinstance(b, int)
post isinstance(res, int)
as:
def func(x,y):
return x+y
func(a,b)
"""
expected = self.get_default_concept()
expected.get_metadata().id = "1001"
expected.get_metadata().desc = None
expected.get_metadata().variables = [("a", None), ("b", None)]
expected.get_metadata().parameters = ["a", "b"]
expected.init_key()
sheerka = self.get_sheerka(cache_only=False)
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
concept_saved = res[0].value.body
for prop in PROPERTIES_TO_SERIALIZE:
assert getattr(concept_saved.get_metadata(), prop) == getattr(expected.get_metadata(), prop)
# cache is up to date
service = sheerka.services[SheerkaConceptManager.NAME]
assert service.has_key(concept_saved.key)
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(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)
def test_i_can_evaluate_def_concept_part_when_one_part_is_a_ref_of_another_concept(self):
"""
In this test, we test that the properties of 'concept a xx b' (which are 'a' and 'b')
are correctly detected, thanks to the source code 'a plus b' in its body
:return:
"""
sheerka = self.get_sheerka()
# concept 'a plus b' is known
concept_a_plus_b = Concept(name="a plus b").def_var("a").def_var("b").init_key()
sheerka.test_only_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_var("a").def_var("b").init_key()
expected.get_metadata().id = "1001"
expected.get_metadata().parameters = ["a", "b"]
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
concept_saved = res[0].value.body
for prop in PROPERTIES_TO_SERIALIZE:
assert getattr(concept_saved.get_metadata(), prop) == getattr(expected.get_metadata(), prop)
assert sheerka.services[SheerkaConceptManager.NAME].has_key(concept_saved.key)
def test_i_cannot_evaluate_the_same_def_concept_twice(self):
text = """
def concept a + b
where isinstance(a, int) and isinstance(b, int)
pre isinstance(a, int) and isinstance(b, int)
post isinstance(res, int)
as:
def func(x,y):
return x+y
func(a,b)
"""
sheerka = self.get_sheerka()
sheerka.evaluate_user_input(text)
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].value.value, BuiltinConcepts.CONCEPT_ALREADY_DEFINED)
@pytest.mark.parametrize("text", [
"",
" ",
"\n",
])
def test_i_can_recognize_a_empty_input(self, text):
sheerka = self.get_sheerka()
res = sheerka.evaluate_user_input(text)
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NOP)
def test_i_can_recognize_concept_with_variable(self):
sheerka, context, concept_foo, concept_hello = self.init_test().with_concepts(
"foo",
Concept(name="hello a").def_var("a"),
create_new=True).unpack()
res = sheerka.evaluate_user_input("hello foo")
return_value = res[0].value
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(return_value, concept_hello)
# sanity check
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), return_value)
assert evaluated.get_value("a") == concept_foo
def test_i_can_recognize_concept_with_variable_and_python_as_body(self):
sheerka, context, hello_a, foo = self.init_concepts(
Concept(name="hello a", body="'hello ' + a").def_var("a"),
Concept(name="foo", body="'foo'")
)
res = sheerka.evaluate_user_input("hello foo")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, hello_a)
# sanity check
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value)
assert evaluated.body == "hello foo"
assert evaluated.get_hints().is_evaluated
compare_with_test_object(evaluated.get_value("a"), CB("foo", "foo"))
assert evaluated.get_value("a").get_hints().is_evaluated
def test_i_can_recognize_duplicate_concepts_with_same_value(self):
# when multiple result, choose the one that is the more specific (that has the less variables)
sheerka = self.get_sheerka()
self.create_and_add_in_cache_concept(sheerka, Concept(name="hello a", body="'hello ' + a"), variables=["a"])
self.create_and_add_in_cache_concept(sheerka, Concept(name="hello foo", body="'hello foo'"))
self.create_and_add_in_cache_concept(sheerka, Concept(name="foo", body="'foo'"))
res = sheerka.evaluate_user_input("hello foo")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, "hello foo")
assert res[0].value.body == NotInit
assert res[0].who == sheerka.get_evaluator_name(OneSuccessEvaluator.NAME)
def test_i_cannot_manage_duplicate_concepts_when_the_values_are_different(self):
sheerka = self.get_sheerka()
self.create_and_add_in_cache_concept(sheerka, Concept(name="hello a", body="'hello ' + a").def_var("a"))
self.create_and_add_in_cache_concept(sheerka, Concept(name="hello b", body="'hello you ' + b").def_var("b"))
self.create_and_add_in_cache_concept(sheerka, Concept(name="foo", body="'another value'"))
res = sheerka.evaluate_user_input("eval hello foo")
assert len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].value, BuiltinConcepts.TOO_MANY_SUCCESS)
concepts = res[0].value.body
assert len(concepts) == 2
sorted_values = sorted(concepts, key=lambda x: x.value)
assert sorted_values[0].value == "hello another value"
assert sorted_values[1].value == "hello you another value"
def test_i_can_manage_concepts_with_the_same_key_when_values_are_the_same(self):
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
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("eval hello 'foo'")
assert len(res) == 1
assert res[0].status
assert res[0].value == "hello foo" # I don't know yet the one to choose
assert res[0].who == sheerka.get_evaluator_name(MultipleSameSuccessEvaluator.NAME)
def test_i_can_create_concepts_with_python_code_as_body(self):
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
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 res[0].value == sheerka.test()
def test_i_can_recognize_bnf_definitions(self):
sheerka = self.get_sheerka()
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' | 'two'")[0].body.body
res = sheerka.evaluate_user_input("one")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a)
def test_i_can_recognize_bnf_definitions_with_variables(self):
sheerka = self.get_sheerka()
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' | 'two'")[0].body.body
concept_b = sheerka.evaluate_user_input("def concept b from bnf a 'three'")[0].body.body
res = sheerka.evaluate_user_input("one three")
assert len(res) == 1
assert res[0].status
return_value = res[0].value
assert sheerka.isinstance(return_value, concept_b)
# sanity check
evaluated = sheerka.evaluate_concept(self.get_context(sheerka=sheerka, eval_body=True), return_value)
assert evaluated.body == "one three"
assert evaluated.get_hints().is_evaluated
assert evaluated.get_value("a") == sheerka.new(concept_a.key, body="one").init_key()
assert evaluated.get_value("a").get_hints().is_evaluated
@pytest.mark.parametrize("user_input", [
"def concept greetings from def hello a where a",
"def concept greetings from hello a where a"])
def test_i_can_recognize_a_concept_defined_using_from_def(self, user_input):
sheerka = self.get_sheerka()
greetings = sheerka.evaluate_user_input(user_input)[0].body.body
res = sheerka.evaluate_user_input("hello 'foo'")
assert len(res) == 1
assert res[0].status
concept_found = res[0].value
assert sheerka.isinstance(concept_found, greetings)
assert concept_found.get_value("a") == "foo"
assert concept_found.get_hints().need_validation
res = sheerka.evaluate_user_input("greetings")
assert len(res) == 1
assert res[0].status
concept_found = res[0].value
assert sheerka.isinstance(concept_found, greetings)
assert concept_found.get_value("a") == NotInit
assert not concept_found.get_hints().need_validation
@pytest.mark.parametrize("desc, definitions", [
("Simple form", [
"def concept one as 1",
"def concept two as 2",
"def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit"
]),
("When twenty is a concept", [
"def concept one as 1",
"def concept two as 2",
"def concept twenty as 20",
"def concept twenties from bnf twenty (one|two)=unit as twenty + unit"
]),
("When digit is a concept", [
"def concept one as 1",
"def concept two as 2",
"def concept twenty as 20",
"def concept digit from bnf one|two",
"def concept twenties from bnf twenty digit as twenty + digit"
]),
("When using isa and concept twenty", [
"def concept one as 1",
"def concept two as 2",
"def concept number",
"set_isa(one, number)",
"set_isa(two, number)",
"def concept twenties from bnf 'twenty' number as 20 + number"
]),
("When using isa and concept twenty", [
"def concept one as 1",
"def concept two as 2",
"def concept twenty as 20",
"def concept number",
"set_isa(one, number)",
"set_isa(two, number)",
"def concept twenties from bnf twenty number as 20 + number"
]),
])
def test_i_can_mix_concept_with_python_to_define_numbers(self, desc, definitions):
sheerka = self.get_sheerka()
sheerka.add_to_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
for definition in definitions:
sheerka.evaluate_user_input(definition)
res = sheerka.evaluate_user_input("twenty one")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, "twenties")
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
assert res[0].status
assert res[0].body == 22
res = sheerka.evaluate_user_input("twenty one + one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 22
res = sheerka.evaluate_user_input("twenty one + twenty two")
assert len(res) == 1
assert res[0].status
assert res[0].body == 43
res = sheerka.evaluate_user_input("1 + twenty one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 22
res = sheerka.evaluate_user_input("1 + 1 + twenty one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 23
sheerka.remove_fom_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
def test_i_can_mix_bnf_and_isa(self):
"""
if 'one' isa 'number, twenty number should be recognized
:return:
"""
sheerka = self.get_sheerka()
sheerka.evaluate_user_input("def concept one as 1")
sheerka.evaluate_user_input("def concept two as 2")
sheerka.evaluate_user_input("def concept number")
sheerka.evaluate_user_input("global_truth(set_isa(one, number))")
sheerka.evaluate_user_input("global_truth(set_isa(two, number))")
sheerka.evaluate_user_input("def concept twenties from bnf 'twenty' number as 20 + number")
res = sheerka.evaluate_user_input("twenty one")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, "twenties")
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
assert res[0].status
assert res[0].body == 22
res = sheerka.evaluate_user_input("twenty one + one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 22
res = sheerka.evaluate_user_input("twenty one + twenty two")
assert len(res) == 1
assert res[0].status
assert res[0].body == 43
res = sheerka.evaluate_user_input("1 + twenty one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 22
res = sheerka.evaluate_user_input("1 + 1 + twenty one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 23
def test_i_can_mix_bnf_and_isa_2(self):
sheerka = self.get_sheerka()
sheerka.add_to_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
init = [
"def concept one as 1",
"def concept twenty as 20",
"def concept number",
"set_isa(one, number)",
"set_isa(twenty, number)",
"def concept twenties from bnf twenty number as twenty + number"
]
for exp in init:
sheerka.evaluate_user_input(exp)
res = sheerka.evaluate_user_input("eval twenty one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 21
sheerka.remove_fom_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
def test_i_can_use_concepts_defined_with_from(self):
sheerka = self.get_sheerka()
init = [
"def concept plus from a plus b as a + b",
"def concept one as 1",
]
for exp in init:
sheerka.evaluate_user_input(exp)
res = sheerka.evaluate_user_input("eval one plus one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 2
res = sheerka.evaluate_user_input("eval 1 plus one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 2
res = sheerka.evaluate_user_input("eval one plus 1")
assert len(res) == 1
assert res[0].status
assert res[0].body == 2
res = sheerka.evaluate_user_input("eval 1 plus 2")
assert len(res) == 1
assert res[0].status
assert res[0].body == 3
res = sheerka.evaluate_user_input("eval 1 plus 1")
assert len(res) == 1
assert res[0].status
assert res[0].body == 2
def test_i_can_mix_bnf_concept_and_concept(self):
definitions = [
"def concept one as 1",
"def concept two as 2",
"def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit",
"def concept a plus b as a + b"
]
sheerka = self.init_scenario(definitions)
res = sheerka.evaluate_user_input("eval 1 plus 2")
assert len(res) == 1
assert res[0].status
assert res[0].body == 3
res = sheerka.evaluate_user_input("eval 1 plus one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 2
res = sheerka.evaluate_user_input("eval 1 + 1 plus 1")
assert len(res) == 1
assert res[0].status
assert res[0].body == 3
res = sheerka.evaluate_user_input("eval 1 plus twenty one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 22
res = sheerka.evaluate_user_input("eval one plus 1")
assert len(res) == 1
assert res[0].status
assert res[0].body == 2
res = sheerka.evaluate_user_input("eval one plus two")
assert len(res) == 1
assert res[0].status
assert res[0].body == 3
res = sheerka.evaluate_user_input("eval one plus twenty one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 22
res = sheerka.evaluate_user_input("eval twenty one plus 1")
assert len(res) == 1
assert res[0].status
assert res[0].body == 22
res = sheerka.evaluate_user_input("eval twenty one plus one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 22
res = sheerka.evaluate_user_input("eval twenty one plus twenty two")
assert len(res) == 1
assert res[0].status
assert res[0].body == 43
def test_i_can_use_bnf_alias(self):
definitions = [
"def concept two as 2",
"def concept number",
"set_isa(two, number)",
"def concept plus_one from bnf number=n1 'plus_one' as n1 + 1",
]
sheerka = self.init_scenario(definitions, global_truth=True)
res = sheerka.evaluate_user_input("eval two plus_one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 3
def test_eval_does_not_break_valid_result(self):
sheerka = self.get_sheerka()
sheerka.evaluate_user_input("def concept one as 1")
sheerka.evaluate_user_input("def concept two as 2")
res = sheerka.evaluate_user_input("one + two")
assert len(res) == 1
assert res[0].status
assert res[0].body == 3
res = sheerka.evaluate_user_input("eval one + two")
assert len(res) == 1
assert res[0].status
assert res[0].body == 3
@pytest.mark.parametrize("text", [
"'hello",
'"foo" + "string',
"c::",
"c:foo\nbar:",
"c:foo",
"def concept 'name",
"def concept name from bnf 'name"
])
def test_i_can_manage_tokenizer_error(self, text):
sheerka = self.get_sheerka()
sheerka.test_only_add_in_cache(Concept("foo"))
res = sheerka.evaluate_user_input(text)
assert len(res) > 1
for r in [r for r in res if r.who.startswith("parsers.")]:
assert not r.status
def test_i_can_recognize_concept_from_string(self):
sheerka = self.get_sheerka()
sheerka.test_only_add_in_cache(Concept("one", body="1"))
res = sheerka.evaluate_user_input("'one'")
assert len(res) == 1
assert res[0].status
assert res[0].body == "one"
res = sheerka.evaluate_user_input("eval 'one'")
assert len(res) == 1
assert res[0].status
assert res[0].body == "one"
@pytest.mark.parametrize("expression", [
"def concept twenties from bnf 'twenty' (one | two)=unit as 20 + unit",
"def concept twenties from bnf 'twenty' (one | two)=unit as twenty + unit",
"def concept twenties from bnf twenty (one | two)=unit as 20 + unit",
"def concept twenties from bnf twenty (one | two)=unit as twenty + unit",
])
def test_i_can_evaluate_bnf_concepts(self, expression):
sheerka = self.get_sheerka()
sheerka.evaluate_user_input("def concept one as 1")
sheerka.evaluate_user_input("def concept two as 2")
sheerka.evaluate_user_input("def concept twenty as 20")
sheerka.evaluate_user_input(expression)
res = sheerka.evaluate_user_input("eval twenty one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 21
def test_i_can_use_where_in_bnf(self):
init = [
"def concept one as 1",
"def concept two as 2",
"def concept three as 3",
"def concept twenty as 20",
"def concept number",
"set_isa(one, number)",
"set_isa(two, number)",
"set_isa(three, number)",
"def concept twenties from bnf twenty number where number <= 2 as twenty + number"
]
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("twenty one")
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
assert res[0].status
assert res[0].body == 21
res = sheerka.evaluate_user_input("twenty two")
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
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
res = sheerka.evaluate_user_input("eval twenty three")
assert len(res) == 1
assert not res[0].status
def test_i_can_manage_some_type_of_infinite_recursion(self):
sheerka = self.get_sheerka()
sheerka.evaluate_user_input("def concept one as 1")
sheerka.evaluate_user_input("def concept 1 as one")
res = sheerka.evaluate_user_input("one + 1")
assert len(res) == 1
assert res[0].status
assert res[0].body == 2
res = sheerka.evaluate_user_input("1 + 1")
assert len(res) == 1
assert res[0].status
assert res[0].body == 2
def test_i_can_evaluate_bnf_concept_with_where_clause(self):
sheerka = self.get_sheerka()
sheerka.evaluate_user_input("def concept a from bnf 'bar' | 'baz'")
sheerka.evaluate_user_input("def concept b as 'hello world'")
sheerka.evaluate_user_input("def concept foobar from bnf 'foo' a where a=='bar' as b")
res = sheerka.evaluate_user_input("foo bar")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, "foobar")
assert res[0].body.body == NotInit
res = sheerka.evaluate_user_input("eval foo bar")
assert len(res) == 1
assert res[0].status
assert res[0].body == "hello world"
res = sheerka.evaluate_user_input("foo baz")
assert sheerka.has_error(self.get_context(sheerka), res, __type=BuiltinConcepts.CONDITION_FAILED)
res = sheerka.evaluate_user_input("eval foo baz")
assert sheerka.has_error(self.get_context(sheerka), res, __type=BuiltinConcepts.CONDITION_FAILED)
res = sheerka.evaluate_user_input("c:foobar:") # where clause must not be evaluated
assert len(res) == 1
assert res[0].status
res = sheerka.evaluate_user_input("foobar") # where clause must not be evaluated
assert len(res) == 1
assert res[0].status
res = sheerka.evaluate_user_input("eval foobar") # where clause is forced
assert len(res) == 1 # error
assert not res[0].status
assert sheerka.isinstance(res[0].body.value, BuiltinConcepts.CONDITION_FAILED)
@pytest.mark.skip("Not ready for that")
def test_i_can_manage_missing_variables_from_bnf_parsing(self):
definitions = [
"def concept one as 1",
"def concept number",
"set_isa(one, number)",
"def concept hundreds from bnf number=n1 'hundred' ('and' number=n2)? where n1<10 and n2<100 as n1 * 100 + n2",
]
sheerka = self.init_scenario(definitions)
res = sheerka.evaluate_user_input("one hundred")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, "hundreds")
res = sheerka.evaluate_user_input("eval one hundred")
assert len(res) == 1
assert res[0].status
assert res[0].body == "100"
def test_i_can_say_than_bnf_concept_isa_another_concept(self):
sheerka = self.get_sheerka()
sheerka.evaluate_user_input("def concept number")
sheerka.evaluate_user_input("def concept one as 1")
sheerka.evaluate_user_input("def concept two as 2")
sheerka.evaluate_user_input("def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit")
res = sheerka.evaluate_user_input("global_truth(set_isa(twenties, number))")
assert len(res) == 1
assert res[0].status
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):
definitions = [
"def concept one as 1",
"def concept two as 2",
"def concept three as 3",
"def concept plus from a plus b as a + b",
"def concept mult from a mult b as a * b",
"def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit",
"set_is_greater_than(BuiltinConcepts.PRECEDENCE, mult, plus, 'Sya')"
]
sheerka = self.init_scenario(definitions)
res = sheerka.evaluate_user_input("eval one plus two mult three")
assert len(res) == 1
assert res[0].status
assert res[0].body == 7
res = sheerka.evaluate_user_input("eval two mult three plus one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 7
res = sheerka.evaluate_user_input("eval 1 plus two mult 3")
assert len(res) == 1
assert res[0].status
assert res[0].body == 7
res = sheerka.evaluate_user_input("eval 2 mult 3 plus one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 7
res = sheerka.evaluate_user_input("eval twenty two plus 1")
assert len(res) == 1
assert res[0].status
assert res[0].body == 23
res = sheerka.evaluate_user_input("eval 1 plus twenty two")
assert len(res) == 1
assert res[0].status
assert res[0].body == 23
res = sheerka.evaluate_user_input("eval twenty one plus twenty two")
assert len(res) == 1
assert res[0].status
assert res[0].body == 43
res = sheerka.evaluate_user_input("eval twenty two plus twenty one mult two")
assert len(res) == 1
assert res[0].status
assert res[0].body == 64
def test_concepts_parsed_by_atom_parser_must_not_be_evaluated(self):
definitions = [
"def concept mult from a mult b as a * b",
]
sheerka = self.init_scenario(definitions)
res = sheerka.evaluate_user_input("eval mult")
assert res[0].status
assert isinstance(res[0].body, Concept)
@pytest.mark.skip("Need to be fixed")
def test_concepts_parsed_by_atom_parser_must_not_be_evaluated_2(self):
definitions = [
"def concept a mult b as a * b",
]
sheerka = self.init_scenario(definitions)
res = sheerka.evaluate_user_input("eval a mult b")
assert res[0].status
assert isinstance(res[0].body, Concept)
def test_i_can_express_comparison(self):
definitions = [
"def concept one",
"def concept two",
"def concept three",
"def concept four",
]
sheerka = self.init_scenario(definitions)
res = sheerka.evaluate_user_input("set_is_greater_than('some_prop', two, one)")
assert res[0].status
res = sheerka.evaluate_user_input("set_is_less_than('some_prop', two, three)")
assert res[0].status
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}
# test i use a concept to define relation
sheerka.evaluate_user_input("def concept a > b as set_is_greater_than('some_prop', a, b)")
res = sheerka.evaluate_user_input("eval four > three")
assert res[0].status
assert sheerka.get_weights("some_prop") == {'c:one|1001:': 1,
'c:two|1002:': 2,
'c:three|1003:': 3,
'c:four|1004:': 4}
def test_i_can_evaluate_expression_when_using_token_concept(self):
sheerka, context, one, two, three, is_less_than = self.init_concepts(
Concept("one", body="1"),
Concept("two", body="2"),
Concept("three", body="3"),
self.from_def_concept("<", "a < b", ["a", "b"], body="set_is_less_than('some_prop', a, b)")
)
expression = "c:one: < c:two:"
res = sheerka.evaluate_user_input(expression)
assert res[0].status
compare_with_test_object(res[0].body, CMV(is_less_than, a="c:one:", b="c:two:"))
assert res[0].body.a == NotInit # concept is not evaluated
assert res[0].body.b == NotInit # concept is not evaluated
expression = "eval c:one: < c:two:"
res = sheerka.evaluate_user_input(expression)
assert res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.SUCCESS)
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_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(
Concept("foo", body="'string'"),
Concept("a plus one", body="a + 1").def_var("a")
)
res = sheerka.evaluate_user_input("eval foo plus one")
assert not res[0].status
assert context.sheerka.isinstance(res[0].body.body, BuiltinConcepts.CONCEPT_EVAL_ERROR)
assert context.sheerka.isinstance(res[0].body.body.body, BuiltinConcepts.ERROR)
error0 = res[0].body.body.body.body[0]
assert isinstance(error0, PythonEvalError)
assert isinstance(error0.error, TypeError)
assert error0.error.args[0] == "unsupported operand type(s) for +: 'Concept' and 'int'"
error1 = res[0].body.body.body.body[1]
assert isinstance(error1, PythonEvalError)
assert isinstance(error1.error, TypeError)
assert error1.error.args[0] == 'can only concatenate str (not "int") to str'
def test_i_can_evaluate_bnf_concept_defined_with_group_after_restart(self):
"""
BNF Concepts defined with group and being themselves part a s group get messed up after restart
:return:
"""
init = [
"def concept one as 1",
"def concept two as 2",
"def concept twenty as 20",
"def concept number",
"set_isa(one, number)",
"set_isa(two, number)",
"set_isa(twenty, number)",
"def concept twenties from bnf twenty number where number < 10 as twenty + number",
"set_isa(twenties, number)",
]
sheerka = self.init_scenario(init, global_truth=True)
# simulate that sheerka was stopped and restarted
sheerka.clear_bnf_definition()
sheerka.om.get(SheerkaConceptManager.CONCEPTS_BY_KEY_ENTRY, "twenties").set_compiled({})
res = sheerka.evaluate_user_input("eval twenty one")
assert res[0].status
assert res[0].body == 21
def test_i_can_use_last_created_concept_to_define_set(self):
init = [
"def concept number",
"def concept one",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("set_isa(last_created_concept(), number)")
assert res[0].status
assert sheerka.isinstance(res[0].body, "one")
assert sheerka.isa(res[0].body, sheerka.new("number"))
def test_i_can_evaluate_sya_and_ret_concepts(self):
init = [
"def concept one as 1",
"def concept plus from a plus b as a + b",
"def concept the a ret a"
]
sheerka = self.init_scenario(init)
the = sheerka.get_by_name("the a")
res = sheerka.evaluate_user_input("one plus the one")
assert res[0].status
plus = res[0].body
assert isinstance(plus, Concept)
assert plus.name == "plus"
assert plus.get_compiled()["a"] == sheerka.new("one")
compare_with_test_object(plus.get_compiled()["b"], CC(the, a=sheerka.new("one")))
res = sheerka.evaluate_user_input("eval one plus the one")
assert res[0].status
assert res[0].body == 2
def test_i_can_evaluate_command(self):
init = [
"def concept command as 'Executed !'",
"set_isa(c:command:, __AUTO_EVAL)",
]
# Since command is a __COMMAND, the body is auto evaluated
# and we return the body, not the concept
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("command")
assert res[0].status
assert res[0].body == "Executed !"
def test_i_can_manage_question(self):
init = [
"def concept one",
"def concept foo",
"def concept number",
"set_isa(one, number)",
"def concept x is a y as isa(x,y) pre in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)",
"def concept x is a y as set_isa(x,y)",
]
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("question(one is a number)") # automatically evaluated
assert len(res) == 1
assert res[0].status
assert res[0].body
res = sheerka.evaluate_user_input("question(foo is a number)") # automatically evaluated
assert len(res) == 1
assert res[0].status
assert not res[0].body
def test_where_clause_implicitly_infer_to_question(self):
init = [
"def concept one as 1",
"def concept number",
"set_isa(one, number)",
"def concept one as 10", # to make sure that it won't be rejected because of the cast
"def concept x is a y as isa(x,y) pre in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)",
"def concept x is a y as set_isa(x,y)",
]
# Explanations
# There are two concepts 'one'. The first one is tagged as a number while the second one is not
# So the first one should be picked.
# the second concept 'one' 's value is an integer, to make sure that it won't be rejected because of its type
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("def concept x plus y where x is a number as x + y")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.NEW_CONCEPT)
# Let's check that the concept is correctly understood
res = sheerka.evaluate_user_input("eval one plus 2")
assert len(res) == 1
assert res[0].status
assert res[0].body == 3 # it means that the first 'one' was chosen
def test_i_can_manage_concept_that_refers_to_question(self):
init = [
"def concept one",
"def concept foo",
"def concept number",
"set_isa(one, number)",
"def concept q from q ? as question(q) auto_eval True",
"def concept is_a from x is a y as isa(x,y) pre in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)",
"set_is_greater_than(BuiltinConcepts.PRECEDENCE, c:is_a:, c:q:, 'Sya')",
]
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("one is a number ?") # automatically evaluated
assert len(res) == 1
assert res[0].status
assert isinstance(res[0].body, bool) and res[0].body # the body MUST be a boolean
res = sheerka.evaluate_user_input("foo is a number ?") # automatically evaluated
assert len(res) == 1
assert res[0].status
assert isinstance(res[0].body, bool) and not res[0].body # the body MUST be a boolean
# x is a y is supposed to be a question. It cannot be used if not in a context of a question
res = sheerka.evaluate_user_input("one is a number")
assert sheerka.has_error(self.get_context(sheerka), res, __type=BuiltinConcepts.CONDITION_FAILED)
def test_i_can_evaluate_source_code_with_concept(self):
init = [
"def concept the a ret a",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("desc(c:the a:)")
assert len(res) == 1
assert res[0].status
def test_i_can_parse_concept_with_variables_using_short_name(self):
init = [
"def concept foo from a foo b where a,b",
"def concept bar from bar a where a",
"def concept baz from a baz where a",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("desc(foo)")
assert len(res) == 1
assert res[0].status
res = sheerka.evaluate_user_input("desc(bar)")
assert len(res) == 1
assert res[0].status
res = sheerka.evaluate_user_input("desc(baz)")
assert len(res) == 1
assert res[0].status
def test_i_can_define_a_concept_when_where_clause_contains_the_name_of_the_variable(self):
init = [
"def concept x is a y as isa(x,y) pre is_question()",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("def concept a x b where a is a number as a + b")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.NEW_CONCEPT)
def test_bnf_node_parsers_are_updated_when_concepts_are_modified(self):
init = [
"def concept number",
"def concept one",
"def concept twenties from bnf 'twenty' number as 20 + number",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("twenty one")
assert len(res) > 1 # not recognized
sheerka.evaluate_user_input("global_truth(set_isa(one, number))")
res = sheerka.evaluate_user_input("twenty one")
assert len(res) == 1
assert res[0].status
def test_i_can_set_attribute(self):
init = [
"def concept size",
"def concept adjective",
"def concept beautiful",
"def concept little",
"def concept house",
"def concept little x as set_attr(x, size, little) ret x",
"def concept beautiful x as set_attr(x, adjective, beautiful) ret x",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("eval beautiful little house")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, "house")
assert sheerka.get_attr(res[0].body, sheerka.new("size")) == sheerka.new("little")
assert sheerka.get_attr(res[0].body, sheerka.new("adjective")) == sheerka.new("beautiful")
def test_i_can_display_multiple_concepts_using_desc_command(self):
init = [
"def concept foo as 1",
"def concept foo as 2",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("desc(foo)")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.TO_MULTI)
def test_i_can_evaluate_pseudo_recursive_definition(self):
init = [
"def concept a + b as a + b",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("eval 1 + 1")
assert len(res) == 1
assert res[0].status
assert res[0].body == 2
def test_i_can_parse_when_multiple_ontology_layers(self):
init = [
"def concept one as 1",
"def concept two as 2",
"def concept a plus b as a + b", # sya node
"def concept twenties from bnf 'twenty' (one | two)=unit as 20 + unit", # bnf node
]
sheerka = self.init_scenario(init)
sheerka.push_ontology(self.get_context(sheerka), "new ontology")
res = sheerka.evaluate_user_input("eval one")
assert len(res) == 1
assert res[0].status
assert res[0].body == 1
res = sheerka.evaluate_user_input("eval one plus two")
assert len(res) == 1
assert res[0].status
assert res[0].body == 3
res = sheerka.evaluate_user_input("eval twenty one")
assert len(res) == 1
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_format_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
def test_i_can_get_history_after_def_rule_parser(self):
sheerka = self.get_sheerka()
sheerka.save_execution_context = True
sheerka.evaluate_user_input("when True then answer('that is true')")
res = sheerka.evaluate_user_input("history()")
assert len(res) == 1
assert res[0].status
l = list(res[0].body.body)
assert len(l) > 0
sheerka.save_execution_context = False
def test_i_can_define_a_regex_concept_and_parse_it(self):
sheerka, context = self.init_test().unpack()
res = sheerka.evaluate_user_input("def concept binary from bnf r'[01]+'")
assert len(res) == 1
assert res[0].status
res = sheerka.evaluate_user_input("01001")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, "binary")
def test_parsing_expression_are_dynamic(self):
init = [
"def concept two",
"def concept number",
"def concept nb times from bnf number 'times'",
"set_isa(two, number)", # defined after 'nb times'
]
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("two times")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, "nb times")
def test_i_can_evaluate_when_body_is_a_function_that_references_inner_variables(self):
init = [
"def concept two as 2",
"def concept number",
"set_isa(two, number)",
"def concept cars",
"def concept quantify x from bnf number x as set_attr(x, 'qty', number) ret x"
]
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("eval two cars")
assert len(res) == 1
assert res[0].status
assert sheerka.objvalue(res[0].body.get_value("qty")) == 2
def test_i_can_evaluate_when_body_is_a_function_that_references_inner_variables_using_alias(self):
init = [
"def concept two as 2",
"def concept number",
"set_isa(two, number)",
"def concept cars",
"def concept quantify x from bnf number=n1 x as set_attr(x, 'qty', n1) ret x"
]
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("eval two cars")
assert len(res) == 1
assert res[0].status
assert sheerka.objvalue(res[0].body.get_value("qty")) == 2
def test_i_can_implement_the_concept_and(self):
# Normally, redefining 'and' leads to a circular ref between the concept and the python
init = [
"def concept x and y as x and y",
"set_is_lesser(__PRECEDENCE, c:x and y:, 'Sya')",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("def concept foo x y where x > 1 and y > 2")
assert len(res) == 1
assert res[0].status
def test_i_can_use_result_from_memory_filtering(self):
init = [
"def concept female",
"def concept girl",
"set_isa(girl, female)",
"def concept she ret memory('isa(self, female)')",
"girl"
]
sheerka = self.init_scenario(init, global_truth=True)
context = self.get_context(sheerka)
res = sheerka.evaluate_user_input("set_attr(she, 'my_attr', 'my value')")
assert len(res) == 1
assert res[0].status
girl_from_memory = sheerka.get_last_from_memory(context, "girl")
assert girl_from_memory.obj.get_value("my_attr") == "my value"
def test_i_can_use_result_from_memory_filtering_within_other_concept(self):
init = [
"def concept female",
"def concept girl",
"set_isa(girl, female)",
"def concept she ret memory('isa(self, female)')",
"def concept x attribute y equals z as set_attr(x, y, z)",
"girl"
]
sheerka = self.init_scenario(init, global_truth=True)
context = self.get_context(sheerka)
res = sheerka.evaluate_user_input("eval she attribute 'my_attr' equals 'my value'")
assert len(res) == 1
assert res[0].status
girl_from_memory = sheerka.get_last_from_memory(context, "girl")
assert girl_from_memory.obj.get_value("my_attr") == "my value"
def test_i_cannot_use_method_that_alter_the_global_state_within_question(self):
init = [
"def concept foo as question(set_debug(True))",
]
sheerka = self.init_scenario(init)
context = self.get_context(sheerka)
res = sheerka.evaluate_user_input("question(set_debug(True))")
assert sheerka.has_error(context, res, __type="MethodAccessError")
res = sheerka.evaluate_user_input("eval foo")
assert sheerka.has_error(context, res, __type="MethodAccessError")
def test_i_can_use_function_parser_and_complex_concept(self):
init = [
"def concept the x ret x",
"def concept foo",
"def concept bar",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("smart_get_attr(the foo, bar)")
assert len(res) == 1
assert res[0].status
def test_i_can_get_smart_get_attr_for_complex_concepts(self):
init = [
"def concept q from q ? as question(q) auto_eval True",
"set_is_lesser(__PRECEDENCE, q, 'Sya')",
"def concept a x ret x where isinstance(x, Concept)",
"def concept the x ret memory(x)",
"def concept short",
"def concept color",
"def concept red",
"def concept blue",
"def concept adjective",
"set_isa(red, color)",
"set_isa(blue, color)",
"set_isa(color, adjective)",
"def concept what is the x of y pre is_question() as smart_get_attr(y, x)",
"def concept qualify x from bnf adjective x as set_attr(x, c:adjective:, adjective) ret x",
]
sheerka = self.init_scenario(init, global_truth=True)
res = sheerka.evaluate_user_input("eval a red short")
res = sheerka.evaluate_user_input("what is the color of the short ?")
assert len(res) == 1
assert res[0].status
assert res[0].value == "red"
sheerka.evaluate_user_input("eval a blue short")
res = sheerka.evaluate_user_input("what is the color of the short ?")
assert len(res) == 1
assert res[0].status
assert res[0].value == "blue"
def test_i_can_access_a_concept_after_a_global_set_attr(self):
init = [
"def concept foo",
"def concept color",
"def concept red",
"global_truth(set_attr(foo, color, red))"
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("inspect(foo)")
assert len(res) == 1
assert res[0].status