Files
Sheerka-Old/tests/non_reg/test_sheerka_non_reg.py
T

1250 lines
46 KiB
Python

import pytest
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, simplec, CMV, NotInit, CC
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
from evaluators.OneSuccessEvaluator import OneSuccessEvaluator
from evaluators.PythonEvaluator import PythonEvalError
from parsers.BaseNodeParser import SyaAssociativity
from parsers.BnfNodeParser import Sequence, StrMatch, OrderedChoice, Optional, ConceptExpression
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
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.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)
assert evaluated == simplec("one", 1)
def test_i_can_recognize_concept_with_concept_body(self):
sheerka = self.get_sheerka()
concept_one = Concept(name="one")
concept_un = Concept(name="un", body="one")
sheerka.add_in_cache(concept_one)
sheerka.add_in_cache(concept_un)
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)
assert evaluated == simplec("un", simplec("one", BuiltinConcepts.NOT_INITIALIZED))
def test_i_can_recognize_concept_with_no_body(self):
sheerka = self.get_sheerka()
concept = Concept(name="one")
sheerka.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.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.metadata.id = "1001"
expected.metadata.desc = None
expected.metadata.variables = [("a", None), ("b", None)]
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.metadata, prop) == getattr(expected.metadata, prop)
# 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']}
# 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):
"""
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.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.metadata.id = "1001"
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.metadata, prop) == getattr(expected.metadata, prop)
assert sheerka.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, BuiltinConcepts.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_concepts(
"foo",
Concept(name="hello a").def_var("a"),
create_new=True)
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 = self.get_sheerka()
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")
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.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):
# 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 == BuiltinConcepts.NOT_INITIALIZED
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.metadata.is_evaluated
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",
"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.metadata.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.metadata.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()
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
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("set_isa(one, number)")
sheerka.evaluate_user_input("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()
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
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)
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.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.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):
sheerka = self.get_sheerka()
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"
]
for exp in init:
sheerka.evaluate_user_input(exp)
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
assert sheerka.isinstance(res[0].body, BuiltinConcepts.MULTIPLE_ERRORS)
assert str(BuiltinConcepts.CONDITION_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 str(BuiltinConcepts.CONDITION_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()
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 == BuiltinConcepts.NOT_INITIALIZED
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 len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONDITION_FAILED)
res = sheerka.evaluate_user_input("eval foo baz")
assert len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONDITION_FAILED)
res = sheerka.evaluate_user_input("foobar")
assert len(res) == 1
assert res[0].status
res = sheerka.evaluate_user_input("eval foobar")
assert len(res) == 1 # error
assert not res[0].status
assert sheerka.isinstance(res[0].body, 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("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",
]
sheerka = self.init_scenario(definitions)
context = self.get_context(sheerka)
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")
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",
"def concept 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)
# 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_concepts_weights('some_prop')")
assert res[0].status
assert res[0].body == {'1001': 1, '1002': 2, '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_concepts_weights("some_prop") == {'1001': 1, '1002': 2, '1003': 3, '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
assert 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_concepts_weights("some_prop") == {'1001': 1, '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") == {'1001': 1, '1002': 2, '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, BuiltinConcepts.CONCEPT_EVAL_ERROR)
assert context.sheerka.isinstance(res[0].body.body, BuiltinConcepts.TOO_MANY_ERRORS)
error0 = res[0].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[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)
# simulate that sheerka was stopped and restarted
sheerka.cache_manager.clear(sheerka.CONCEPTS_GRAMMARS_ENTRY)
sheerka.cache_manager.get(sheerka.CONCEPTS_BY_KEY_ENTRY, "twenties").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.isa(sheerka.new("one"), 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.compiled["a"] == sheerka.new("one")
assert plus.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)
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)
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)
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)",
"set_auto_eval(q)",
"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:)",
]
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("one is a number ?") # automatically evaluated
assert len(res) == 1
assert res[0].status
assert res[0].body == True # 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 res[0].body == False # 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 len(res) == 1
assert not res[0].status
assert sheerka.isinstance(res[0].body, 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(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
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("desc(bar)")
assert len(res) == 1
assert res[0].status
sheerka = self.init_scenario(init)
res = sheerka.evaluate_user_input("desc(baz)")
assert len(res) == 1
assert res[0].status
def test_i_can_eval_concepts_fed_with_functions(self):
init = [
"def concept inc a as a + 1",
"def concept one as 1"
]
def times_five(i):
return i * 5
sheerka = self.init_scenario(init)
sheerka.locals["times_five"] = times_five
res = sheerka.evaluate_user_input("eval inc times_five(one)")
assert len(res) == 1
assert res[0].status
assert res[0].body == 6
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
sheerka.evaluate_user_input("set_isa(one, number)")
res = sheerka.evaluate_user_input("twenty one")
assert len(res) == 1
assert res[0].status
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()
def test_i_can_eval_sophisticated_bnf_concepts_after_restart(self):
self.init_scenario([
"def concept one as 1",
"def concept number",
"set_isa(one, number)",
"def concept twenty as 20",
"set_isa(twenty, number)",
"def concept twenties from bnf twenty number where number < 10 as twenty + number",
"set_isa(twenties, number)",
"def concept thirty as 30",
"set_isa(thirty, number)",
"def concept thirties from bnf thirty number where number < 10 as thirty + number",
"set_isa(thirties, number)",
])
sheerka = self.get_sheerka() # another instance
assert sheerka.evaluate_user_input("eval twenty one")[0].body == 21
assert sheerka.evaluate_user_input("eval thirty one")[0].body == 31