Fixed #61 : SheerkaDebugManager: Add get_value()

Fixed #60 : Hash error when ReturnValue is a list of list
Fixed #59 : Implement smart_get()
Fixed #58 : SheerkaPromptCompleter: Cannot parse concept token
Fixed #57 : SheerkaPrompt: Add concept autocompletion
Fixed #56 : automatically backup command
Fixed #54 : I can record execution status
Fixed #53 : ConceptManager: modify_concept fails
This commit is contained in:
2021-04-09 15:47:32 +02:00
parent 6cda2686fb
commit dd3d8f4abe
37 changed files with 1055 additions and 191 deletions
+2 -1
View File
@@ -25,7 +25,8 @@ class TestUsingMemoryBasedSheerka(BaseTest):
sheerka.initialize("mem://",
save_execution_context=False,
enable_process_return_values=False,
enable_process_rules=False)
enable_process_rules=False,
enable_commands_backup=False)
return sheerka
def get_sheerka(self, **kwargs) -> Sheerka:
+169 -1
View File
@@ -840,7 +840,8 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
assert sheerka.get_property(foo_instance, BuiltinConcepts.ASSOCIATIVITY) == SyaAssociativity.Left
res = sheerka.set_property(context, foo_instance, sheerka.new(BuiltinConcepts.ASSOCIATIVITY), SyaAssociativity.Right)
res = sheerka.set_property(context, foo_instance, sheerka.new(BuiltinConcepts.ASSOCIATIVITY),
SyaAssociativity.Right)
assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
assert sheerka.get_property(foo_instance, BuiltinConcepts.ASSOCIATIVITY) == SyaAssociativity.Right
@@ -1235,6 +1236,173 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
assert sheerka.chicken_and_eggs.get(two.id) == {one.id, two.id, three.id}
assert sheerka.chicken_and_eggs.get(three.id) == {one.id, two.id, three.id}
def test_i_can_smart_get_attr_when_the_value_is_known(self):
sheerka, context = self.init_concepts()
foo = Concept("foo")
prop = Concept("property")
bar = Concept("bar")
sheerka.set_attr(foo, prop, bar)
assert sheerka.smart_get_attr(foo, prop) == bar
def test_i_can_smart_get_attr_when_simple_isa(self):
sheerka, context, adjective, color, red, table = self.init_concepts("adjective",
"color",
"red",
"table",
create_new=True)
sheerka.set_isa(context, color, adjective)
sheerka.set_isa(context, red, color)
color_instance = sheerka.new(color, body=red)
adjective_instance = sheerka.new(adjective, body=color_instance)
table_instance = sheerka.new(table)
sheerka.set_attr(table_instance, adjective, adjective_instance)
assert sheerka.smart_get_attr(table_instance, color) == color_instance
assert sheerka.objvalue(sheerka.smart_get_attr(table_instance, color)) == red
def test_i_can_smart_get_when_multiple_levels_of_isa(self):
sheerka, context, adjective, color, reddish, red, table = self.init_concepts("adjective",
"color",
"reddish",
"red",
"table",
create_new=True)
sheerka.set_isa(context, color, adjective)
sheerka.set_isa(context, reddish, color)
sheerka.set_isa(context, red, reddish)
reddish_instance = sheerka.new(reddish, body=red)
color_instance = sheerka.new(color, body=reddish_instance)
adjective_instance = sheerka.new(adjective, body=color_instance)
table_instance = sheerka.new(table)
sheerka.set_attr(table_instance, adjective, adjective_instance)
assert sheerka.smart_get_attr(table_instance, reddish_instance) == reddish_instance
assert sheerka.objvalue(sheerka.smart_get_attr(table_instance, color)) == red
def test_i_can_smart_get_when_multiple_values(self):
sheerka, context, adjective, color, red, blue, table = self.init_concepts("adjective",
"color",
"red",
"blue",
"table",
create_new=True)
sheerka.set_isa(context, color, adjective)
sheerka.set_isa(context, red, color)
sheerka.set_isa(context, blue, color)
table_instance = sheerka.new(table)
# add red color
red_color_instance = sheerka.new(color, body=red)
red_adjective_instance = sheerka.new(adjective, body=red_color_instance)
sheerka.set_attr(table_instance, adjective, red_adjective_instance)
# add blue color
blue_color_instance = sheerka.new(color, body=blue)
blue_adjective_instance = sheerka.new(adjective, body=blue_color_instance)
sheerka.set_attr(table_instance, adjective, blue_adjective_instance)
res = sheerka.smart_get_attr(table_instance, color)
assert res == [red_color_instance, blue_color_instance]
def test_i_can_smart_get_when_ancestor_is_asked(self):
sheerka, context, adjective, color, red, table = self.init_concepts("adjective",
"color",
"red",
"table",
create_new=True)
sheerka.set_isa(context, color, adjective)
sheerka.set_isa(context, red, color)
color_instance = sheerka.new(color, body=red)
table_instance = sheerka.new(table)
sheerka.set_attr(table_instance, color, color_instance)
assert sheerka.smart_get_attr(table_instance, adjective) == color_instance
def test_i_can_smart_get_when_ancestor_is_asked_and_multiple_values(self):
sheerka, context, adjective, color, red, size, large, table = self.init_concepts("adjective",
"color",
"red",
"size",
"large",
"table",
create_new=True)
sheerka.set_isa(context, color, adjective)
sheerka.set_isa(context, red, color)
sheerka.set_isa(context, size, adjective)
sheerka.set_isa(context, large, size)
table_instance = sheerka.new(table)
color_instance = sheerka.new(color, body=red)
sheerka.set_attr(table_instance, color, color_instance)
size_instance = sheerka.new(size, body=large)
sheerka.set_attr(table_instance, size, size_instance)
assert sheerka.smart_get_attr(table_instance, adjective) == [color_instance, size_instance]
def test_i_can_smart_get_when_direct_value_takes_precedence_over_child_value(self):
sheerka, context, adjective, color, red, blue, table = self.init_concepts("adjective",
"color",
"red",
"blue",
"table",
create_new=True)
sheerka.set_isa(context, color, adjective)
sheerka.set_isa(context, red, color)
color_instance = sheerka.new(color, body=red)
adjective_instance = sheerka.new(adjective, body=color_instance)
table_instance = sheerka.new(table)
sheerka.set_attr(table_instance, adjective, adjective_instance)
sheerka.set_attr(table_instance, color, blue) # set direct color value
assert sheerka.smart_get_attr(table_instance, color) == blue
def test_i_can_smart_get_when_direct_value_takes_precedence_over_ancestor_value(self):
sheerka, context, adjective, color, red, blue, table = self.init_concepts("adjective",
"color",
"red",
"blue",
"table",
create_new=True)
sheerka.set_isa(context, color, adjective)
sheerka.set_isa(context, red, color)
color_instance = sheerka.new(color, body=red)
table_instance = sheerka.new(table)
sheerka.set_attr(table_instance, color, color_instance)
sheerka.set_attr(table_instance, adjective, blue) # set direct color value
assert sheerka.smart_get_attr(table_instance, adjective) == blue
def test_i_cannot_smart_get_attr_if_value_is_unknown_and_attribute_not_a_concept(self):
sheerka, context = self.init_concepts()
foo = Concept("foo")
res = sheerka.smart_get_attr(foo, "attribute")
assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND)
def test_i_cannot_smart_get_attr_if_value_is_unknown_and_no_isa(self):
sheerka, context, adjective, color, red, table = self.init_concepts("adjective",
"color",
"red",
"table",
create_new=True)
# sheerka.set_isa(context, color, adjective) # color is not defined as an adjective
sheerka.set_isa(context, red, color)
color_instance = sheerka.new(color, body=red)
adjective_instance = sheerka.new(adjective, body=color_instance)
table_instance = sheerka.new(table)
sheerka.set_attr(table_instance, adjective, adjective_instance)
res = sheerka.smart_get_attr(table_instance, color)
assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND)
class TestSheerkaConceptManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
def test_i_can_add_several_concepts(self):
+12
View File
@@ -15,3 +15,15 @@ class TestSheerkaHasAManager(TestUsingMemoryBasedSheerka):
# check that the definition of the concept has been updated
assert sheerka.hasa(sheerka.new("king"), kingdom)
def test_i_cannot_set_the_same_attribute_twice(self):
sheerka, context, king, kingdom = self.init_concepts("king", "kingdom")
sheerka.set_hasa(context, sheerka.new("king"), kingdom)
res = sheerka.set_hasa(context, sheerka.new("king"), kingdom)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.PROPERTY_ALREADY_DEFINED)
assert res.body.property_name == BuiltinConcepts.HASA
assert res.body.property_value == kingdom
assert res.body.concept == sheerka.new("king")
+49
View File
@@ -3,6 +3,10 @@ import types
import pytest
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from core.global_symbols import EVENT_CONCEPT_CREATED, EVENT_CONCEPT_MODIFIED, EVENT_CONCEPT_PRECEDENCE_MODIFIED, \
EVENT_RULE_PRECEDENCE_MODIFIED
from core.rule import Rule, ACTION_TYPE_EXEC
from core.sheerka.ExecutionContext import ExecutionContext
from core.sheerka.SheerkaOntologyManager import SheerkaOntologyManager
from core.sheerka.services.SheerkaResultManager import SheerkaResultManager
@@ -400,6 +404,51 @@ class TestSheerkaResultManager(TestUsingMemoryBasedSheerka):
assert service.last_error_event_id is None
assert sheerka.get_last_error() == self.sheerka.new(BuiltinConcepts.NOT_FOUND, body={"query": "get_last_error"})
@pytest.mark.parametrize("event_id, event_args", [
(EVENT_CONCEPT_CREATED, Concept("foo")),
(EVENT_CONCEPT_MODIFIED, {"old": Concept("foo"), "new": Concept("bar")}),
(EVENT_CONCEPT_PRECEDENCE_MODIFIED, None),
(EVENT_RULE_PRECEDENCE_MODIFIED, None),
])
def test_i_can_detect_when_the_global_state_has_change(self, event_id, event_args):
sheerka, context = self.init_test().unpack()
assert not context.is_state_modified()
if event_args:
sheerka.publish(context, event_id, event_args)
else:
sheerka.publish(context, event_id)
assert context.is_state_modified()
def test_i_can_detect_when_the_global_state_has_change_when_a_concept_is_deleted(self):
sheerka, context, foo = self.init_concepts("foo", create_new=True)
del context.values["is_state_modified"]
assert not context.is_state_modified()
with context.push("Testing state", None) as sub_context:
sheerka.remove_concept(sub_context, foo)
assert context.is_state_modified()
def test_i_can_detect_when_the_global_state_has_change_when_a_rule_is_created(self):
sheerka, context = self.init_test().unpack()
rule = Rule(ACTION_TYPE_EXEC, "testing state has change", "True", "'hello world'")
with context.push("Testing state", None) as sub_context:
sheerka.create_new_rule(sub_context, rule)
assert context.is_state_modified()
def test_i_can_detect_when_the_global_state_has_change_when_a_rule_is_deleted(self):
sheerka, context, rule = self.init_exec_rules(("testing state has change", "True", "'hello world'"))
del context.values["is_state_modified"]
assert not context.is_state_modified()
with context.push("Testing state", None) as sub_context:
sheerka.remove_rule(sub_context, rule)
assert context.is_state_modified()
class TestSheerkaResultManagerFileBased(TestUsingFileBasedSheerka):
@classmethod
+13
View File
@@ -430,6 +430,19 @@ def test_i_can_deep_copy_a_custom_type():
assert core.utils.sheerka_deepcopy(Removed) is Removed
def test_i_can_deep_copy_concepts_than_look_the_same():
foo = Concept("foo")
foo2 = Concept().update_from(foo)
foo2.set_value("prop_name", "prop_value")
assert foo != foo2
copied_foo = core.utils.sheerka_deepcopy(foo)
copied_foo2 = core.utils.sheerka_deepcopy(foo2)
assert copied_foo != copied_foo2
assert len({copied_foo, copied_foo2}) == 2
@pytest.mark.parametrize("expression1, expression2, expected", [
("foo bar baz", "foo bar baz", True),
("foo()", " foo ( ) ", True),
+195 -34
View File
@@ -1,9 +1,10 @@
import pytest
from core.sheerka.services.SheerkaFunctionsParametersHistory import SheerkaFunctionsParametersHistory
from prompt_toolkit.completion import CompleteEvent
from prompt_toolkit.document import Document
from repl.SheerkaPromptCompleter import SheerkaPromptCompleter, FuncFound
from core.concept import Concept
from core.tokenizer import TokenKind
from repl.SheerkaPromptCompleter import SheerkaPromptCompleter, FuncFound, ConceptCompleterHelper
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -38,41 +39,180 @@ class TestSheerkaPromptCompleter(TestUsingMemoryBasedSheerka):
assert as_dict["quit"].display_text == "quit"
assert as_dict["quit"].display_meta_text == "command"
@pytest.mark.parametrize("text, expected", [
("func(", ["10", "20", "30"]),
("func(1", ["10"]),
("func( 1", ["10"]),
("func( 10, ", ["'hello'"]),
("func( 10, v", []),
("func( 10, 'hel", ["'hello'"]),
('func( 10, "hel', []),
("func('hell,,', func2(2,4), 'w", ["'world'"]),
@pytest.mark.parametrize("concept_name", [
"foo",
"a long name",
])
def test_i_can_complete_function_parameters(self, text, expected):
sheerka = self.get_sheerka()
context = self.get_context(sheerka)
params_history_service = sheerka.services[SheerkaFunctionsParametersHistory.NAME]
params_history_service.record_function_parameter(context, "func", 0, "10")
params_history_service.record_function_parameter(context, "func", 0, "20")
params_history_service.record_function_parameter(context, "func", 0, "30")
params_history_service.record_function_parameter(context, "func", 1, "'hello'")
params_history_service.record_function_parameter(context, "func", 2, "'world'")
def test_i_can_complete_concept(self, concept_name):
sheerka, context, foo = self.init_concepts(Concept(concept_name), create_new=True)
completer = SheerkaPromptCompleter(sheerka)
completer.complete_commands = False
completer.complete_builtins = False
document = Document(text)
completions = SheerkaPromptCompleter(sheerka).get_completions(document, CompleteEvent())
as_list = [c.display_text for c in completions]
assert as_list == expected
for i in range(1, len(concept_name)):
before_cursor = concept_name[:i]
completions = list(completer.get_completions(Document(before_cursor), CompleteEvent()))
as_dict = {c.display_text: c for c in completions}
assert concept_name in as_dict, f"{i=}, {before_cursor=}"
@pytest.mark.parametrize("text, pos, expected", [
("", 0, ""),
("foo", 3, "foo"),
("foo ", 4, "foo "),
("foo", 2, "fo"),
("foo bar", 7, "bar"),
("foo bar", 4, "foo "),
])
def test_last_word(self, text, pos, expected):
assert SheerkaPromptCompleter.last_word(text, pos) == expected
def test_i_can_complete_sya_concept_with_variable(self):
sheerka, context, foo, something, bar = self.init_concepts(
Concept("if true x then do y else do z end").def_var("x").def_var("y").def_var("z"),
Concept("something"),
Concept("bar"),
create_new=True)
completer = SheerkaPromptCompleter(sheerka)
completer.complete_commands = False
completer.complete_builtins = False
text = "if true some cond then do some thing else do something else end"
# i 0123456789012345678901234567890123456789012345678901234567890123
# 0 1 2 3 4 5 6
for i in range(1, len(text) + 1):
before_cursor = text[:i]
d, c = Document(before_cursor), CompleteEvent()
completions = list(completer.get_completions(d, c))
display_as_dict = {(c.display_text, c.start_position): c for c in completions}
if i == 0:
assert len(completer.concepts_candidates) == 3
assert (foo.name, 0) in display_as_dict
assert display_as_dict[(foo.name, 0)].text == "if true "
assert (something.name, 0) in display_as_dict
assert (bar.name, 0) in display_as_dict
if i in range(1, 8): # 'if true'
assert len(completer.concepts_candidates) == 1
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 0
assert display_as_dict[(foo.name, -i)].text == "if true "
assert len(display_as_dict) == 1
if i == 8: # 'if true '
assert len(completer.concepts_candidates) == 1
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 1
assert display_as_dict[(foo.name, -i)].text == "if true "
assert len(display_as_dict) == 1
elif i in range(9, 13): # 'some'
assert len(completer.concepts_candidates) == 2
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 1
assert display_as_dict[(foo.name, -i)].text == before_cursor.rstrip() + " then do "
assert (something.name, 8 - i) in display_as_dict
assert display_as_dict[(something.name, 8 - i)].text == "something"
elif i in range(13, 18): # ' cond'
assert len(completer.concepts_candidates) == 2, f"{i=}, {before_cursor=}"
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 1
assert display_as_dict[(foo.name, -i)].text == before_cursor.rstrip() + " then do "
elif i == 18: # 'cond '
assert len(completer.concepts_candidates) == 2, f"{i=}, {before_cursor=}"
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 1
assert display_as_dict[(foo.name, -i)].text == before_cursor.rstrip() + " then do "
elif i in range(19, 26): # 'then do'
assert len(completer.concepts_candidates) == 2, f"{i=}, {before_cursor=}"
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 2
assert display_as_dict[(foo.name, -i)].text == "if true some cond then do "
elif i == 26: # 'then do '
assert len(completer.concepts_candidates) == 2, f"{i=}, {before_cursor=}"
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 3
assert display_as_dict[(foo.name, -i)].text == "if true some cond then do "
elif i in range(27, 31): # 'some'
assert len(completer.concepts_candidates) == 3, f"{i=}, {before_cursor=}"
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 3
assert display_as_dict[(foo.name, -i)].text == before_cursor.rstrip() + " else do "
assert (something.name, 26 - i) in display_as_dict
assert display_as_dict[(something.name, 26 - i)].text == "something"
elif i in range(31, 38): # ' thing '
assert len(completer.concepts_candidates) == 3, f"{i=}, {before_cursor=}"
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 3
assert display_as_dict[(foo.name, -i)].text == before_cursor.rstrip() + " else do "
elif i in range(38, 45): # 'else do'
assert len(completer.concepts_candidates) == 3, f"{i=}, {before_cursor=}"
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 4
assert display_as_dict[(foo.name, -i)].text == "if true some cond then do some thing else do "
elif i == 45: # 'else do '
assert len(completer.concepts_candidates) == 3, f"{i=}, {before_cursor=}"
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 5
assert display_as_dict[(foo.name, -i)].text == "if true some cond then do some thing else do "
elif i in range(46, 54): # 'something'
assert len(completer.concepts_candidates) == 4, f"{i=}, {before_cursor=}"
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 5
assert display_as_dict[(foo.name, -i)].text == before_cursor.rstrip() + " end"
assert (something.name, 45 - i) in display_as_dict
assert display_as_dict[(something.name, 45 - i)].text == "something"
elif i == 54: # 'g' from 'something'
assert len(completer.concepts_candidates) == 4, f"{i=}, {before_cursor=}"
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 5
assert display_as_dict[(foo.name, -i)].text == before_cursor.rstrip() + " end"
elif i == 55: # ' ' before 'else '
assert len(completer.concepts_candidates) == 7, f"{i=}, {before_cursor=}"
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 5
assert display_as_dict[(foo.name, -i)].text == before_cursor.rstrip() + " end"
elif i == 56: # 'e' from 'else '
assert len(completer.concepts_candidates) == 7, f"{i=}, {before_cursor=}"
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 6
assert display_as_dict[(foo.name, -i)].text == "if true some cond then do some thing else do something end"
elif i in range(57, 60): # 'lse '
assert len(completer.concepts_candidates) == 7, f"{i=}, {before_cursor=}"
assert (foo.name, -i) in display_as_dict
assert completer.concepts_candidates[(foo.id, 1)].last_part_index == 5
assert display_as_dict[(foo.name, -i)].text == before_cursor.rstrip() + " end"
# @pytest.mark.parametrize("text, expected", [
# ("func(", ["10", "20", "30"]),
# ("func(1", ["10"]),
# ("func( 1", ["10"]),
# ("func( 10, ", ["'hello'"]),
# ("func( 10, v", []),
# ("func( 10, 'hel", ["'hello'"]),
# ('func( 10, "hel', []),
# ("func('hell,,', func2(2,4), 'w", ["'world'"]),
# ])
# def test_i_can_complete_function_parameters(self, text, expected):
# sheerka = self.get_sheerka()
# context = self.get_context(sheerka)
# params_history_service = sheerka.services[SheerkaFunctionsParametersHistory.NAME]
# params_history_service.record_function_parameter(context, "func", 0, "10")
# params_history_service.record_function_parameter(context, "func", 0, "20")
# params_history_service.record_function_parameter(context, "func", 0, "30")
# params_history_service.record_function_parameter(context, "func", 1, "'hello'")
# params_history_service.record_function_parameter(context, "func", 2, "'world'")
#
# document = Document(text)
# completions = SheerkaPromptCompleter(sheerka).get_completions(document, CompleteEvent())
# as_list = [c.display_text for c in completions]
# assert as_list == expected
@pytest.mark.parametrize("text, pos, expected", [
("", 0, None),
@@ -104,6 +244,27 @@ class TestSheerkaPromptCompleter(TestUsingMemoryBasedSheerka):
def test_get_param_number(self, text, expected_param_number, expected_comma_index):
assert SheerkaPromptCompleter.get_param_number(text) == (expected_param_number, expected_comma_index)
@pytest.mark.parametrize("concept, expected_parts", [
(Concept("if true x then do y else do z end").def_var("x").def_var("y").def_var("z"), [
"if true ",
TokenKind.VAR_DEF,
"then do ",
TokenKind.VAR_DEF,
"else do ",
TokenKind.VAR_DEF,
"end"
]),
(Concept("x something y").def_var("x").def_var("y"), ["something ", TokenKind.VAR_DEF]),
(Concept("foo x y").def_var("x").def_var("y"), ["foo ", TokenKind.VAR_DEF]),
(Concept("foo x y bar").def_var("x").def_var("y"), ["foo ", TokenKind.VAR_DEF, "bar"]),
(Concept("x y foo").def_var("x").def_var("y"), ["foo"]),
])
def test_i_can_initialize_concept_parts(self, concept, expected_parts):
concept.init_key()
parts = ConceptCompleterHelper.initialize_parts(concept)
assert parts == expected_parts
# def test_jedi_infer(self):
# sheerka = self.get_sheerka()
#