diff --git a/_concepts_default.txt b/_concepts_default.txt index 86d0145..d32868f 100644 --- a/_concepts_default.txt +++ b/_concepts_default.txt @@ -27,6 +27,15 @@ def concept x has a y as hasa(x,y) pre is_question() def concept x has an y as hasa(x,y) pre is_question() # no need to auto eval as it's a question +def concept x and y as x and y pre is_question() +set_is_lesser(__PRECEDENCE, c:x and y:, 'Sya') +set_is_less_than(__PRECEDENCE, c:q:, c:x and y:, 'Sya') + +def concept x or y as x or y pre is_question() +set_is_lesser(__PRECEDENCE, c:x or y:, 'Sya') +set_is_greater_than(__PRECEDENCE, c:x and y:, c:x or y:, 'Sya') +set_is_less_than(__PRECEDENCE, c:q:, c:x or y:, 'Sya') + # default def concept male def concept female diff --git a/src/core/builtin_helpers.py b/src/core/builtin_helpers.py index f77a82a..0a24050 100644 --- a/src/core/builtin_helpers.py +++ b/src/core/builtin_helpers.py @@ -18,6 +18,22 @@ EVAL_STEPS = PARSE_STEPS + [BuiltinConcepts.BEFORE_EVALUATION, BuiltinConcepts.E PARSERS = ["EmptyString", "ShortTermMemory", "Sequence", "Bnf", "Sya", "Python"] +def remove_python_nodes(context, return_values): + """ + Try to reduce the number of return_values by removing return values with python node + :param context: + :param return_values: + :return: + """ + res = [] + for ret_val in return_values: + value = context.sheerka.objvalue(ret_val) + if not hasattr(value, "get_python_node"): + res.append(ret_val) + + return res + + def is_same_success(context, return_values): """ Returns True if all returns values are successful and have the same value @@ -89,12 +105,25 @@ def expect_one(context, return_values): # too many winners, which one to choose ? if number_of_successful > 1: + # first, try to remove python node results. + # In case of conflict, the concept take precedence over the natural Python result + # as it is considered as an override (overload ?) + successful_results = remove_python_nodes(context, successful_results) + + if len(successful_results) == 1: + return sheerka.ret( + context.who, + True, + successful_results[0].body, + parents=return_values) + if is_same_success(context, successful_results): return sheerka.ret( context.who, True, successful_results[0].value, parents=return_values) + else: if context.logger and context.logger.isEnabledFor(logging.DEBUG): context.log(f"Too many successful results found by expect_one()", context.who) diff --git a/src/jupyter/install_kernel.md b/src/jupyter/install_kernel.md index 36a691d..eaa9065 100644 --- a/src/jupyter/install_kernel.md +++ b/src/jupyter/install_kernel.md @@ -1,12 +1,12 @@ To make Jupyter notebook recognize Sheerka, the file kernel.json must be copied where the kernels are declared - * First, open the kernel.json file and make sure that the path to SheerkaKernel is correct. + * First, open the kernel.json file and make sure that the path to SheerkaKernel.py is correct. * The copy it to the correct location * You can use the command 'jupyter kernelspec install ' - * or simply copy it using cp ;-) + * or simply copy 'Sheerka/kernel.json' into the folder 'kernels' (You may have to create it!) -Valid locations for kernel.json are +Valid locations for 'Sheerka/kernel.json' are | | Unix | Windows | |----|------| ---------------| diff --git a/src/sdp/sheerkaDataProvider.py b/src/sdp/sheerkaDataProvider.py index 4bffa6c..9f25c13 100644 --- a/src/sdp/sheerkaDataProvider.py +++ b/src/sdp/sheerkaDataProvider.py @@ -57,7 +57,7 @@ class Event(object): return self._digest if not isinstance(self.message, str): - raise NotImplementedError + raise NotImplementedError(f"message={self.message}") to_hash = f"Event:{self.user_id}{self.date}{self.message}{self.parents}".encode("utf-8") self._digest = hashlib.sha256(to_hash).hexdigest() diff --git a/tests/non_reg/test_sheerka_non_reg.py b/tests/non_reg/test_sheerka_non_reg.py index bcdbb30..aa0e548 100644 --- a/tests/non_reg/test_sheerka_non_reg.py +++ b/tests/non_reg/test_sheerka_non_reg.py @@ -1299,102 +1299,15 @@ as: assert sheerka.objvalue(res[0].body.get_value("qty")) == 2 + def test_i_can_implement_implement_the_concept_and(self): + init = [ + "def concept x and y as x and y", + "set_is_lesser(__PRECEDENCE, c:x and y:, 'Sya')", + ] + sheerka = self.init_scenario(init) -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") + res = sheerka.evaluate_user_input("def concept foo x y where x > 1 and y > 2") 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.om.current_sdp().get(SheerkaConceptManager.CONCEPTS_BY_KEY_ENTRY, "plus") - assert saved_concept.key == "plus" - assert saved_concept.get_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.get_metadata().name == "plus" - assert new_concept.get_metadata().definition == "a ('plus' plus)?" - assert new_concept.get_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 - - def test_i_can_pop_ontology_after_restart(self): - sheerka = self.get_sheerka() - sheerka.evaluate_user_input("push_ontology('test')") - - sheerka = self.new_sheerka_instance(False) - - res = sheerka.evaluate_user_input("pop_ontology()") - - assert len(res) == 1 - assert res[0].status - assert sheerka.isinstance(res[0].body, BuiltinConcepts.ONTOLOGY_REMOVED) diff --git a/tests/non_reg/test_sheerka_non_reg_file_based.py b/tests/non_reg/test_sheerka_non_reg_file_based.py new file mode 100644 index 0000000..049d84d --- /dev/null +++ b/tests/non_reg/test_sheerka_non_reg_file_based.py @@ -0,0 +1,104 @@ +from core.builtin_concepts_ids import BuiltinConcepts +from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager +from parsers.BnfNodeParser import OrderedChoice, StrMatch, Sequence, ConceptExpression, Optional +from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka + + +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.om.current_sdp().get(SheerkaConceptManager.CONCEPTS_BY_KEY_ENTRY, "plus") + assert saved_concept.key == "plus" + assert saved_concept.get_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.get_metadata().name == "plus" + assert new_concept.get_metadata().definition == "a ('plus' plus)?" + assert new_concept.get_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 + + def test_i_can_pop_ontology_after_restart(self): + sheerka = self.get_sheerka() + sheerka.evaluate_user_input("push_ontology('test')") + + sheerka = self.new_sheerka_instance(False) + + res = sheerka.evaluate_user_input("pop_ontology()") + + assert len(res) == 1 + assert res[0].status + assert sheerka.isinstance(res[0].body, BuiltinConcepts.ONTOLOGY_REMOVED)