From d364878ddb638732b825ca920b3c2afa7c102b82 Mon Sep 17 00:00:00 2001 From: Kodjo Sossouvi Date: Fri, 4 Dec 2020 17:37:06 +0100 Subject: [PATCH] Fixed error when desc() returns multiple results --- _concepts_default.txt | 11 ++++ src/core/builtin_concepts.py | 8 +++ src/core/sheerka/Sheerka.py | 13 +++++ .../sheerka/services/SheerkaDebugManager.py | 47 ++++++++++++--- src/core/sheerka/services/SheerkaOut.py | 2 +- .../sheerka/services/SheerkaRuleManager.py | 58 ++++++++++++++++++- src/evaluators/MultipleOutEvaluator.py | 44 ++++++++++++++ src/out/AsStrVisitor.py | 3 + src/out/ConsoleVisistor.py | 3 + src/out/DeveloperVisitor.py | 24 ++++++++ tests/core/test_SheerkaRuleManager.py | 5 +- tests/evaluators/EvaluatorTestsUtils.py | 50 ++++++++++++++++ tests/evaluators/test_MultipleOutEvaluator.py | 55 ++++++++++++++++++ tests/non_reg/test_sheerka_display.py | 38 ++++++++++++ tests/non_reg/test_sheerka_non_reg.py | 13 +++++ tests/out/test_DeveloperVisitor.py | 53 ++++++++++++++--- 16 files changed, 408 insertions(+), 19 deletions(-) create mode 100644 src/evaluators/MultipleOutEvaluator.py create mode 100644 tests/evaluators/EvaluatorTestsUtils.py create mode 100644 tests/evaluators/test_MultipleOutEvaluator.py diff --git a/_concepts_default.txt b/_concepts_default.txt index 8e1e3ad..c5c8212 100644 --- a/_concepts_default.txt +++ b/_concepts_default.txt @@ -25,3 +25,14 @@ def concept x has a y as hasa(x,y) pre is_question() # no need to auto eval as it's a question def concept x has an y as hasa(x,y) pre is_question() # no need to auto eval as it's a question + +# default +def concept male +def concept female +def concept man +man is a male +def concept woman +woman is a female +def concept human +man is a human +woman is a human diff --git a/src/core/builtin_concepts.py b/src/core/builtin_concepts.py index cedd395..3184f60 100644 --- a/src/core/builtin_concepts.py +++ b/src/core/builtin_concepts.py @@ -106,6 +106,7 @@ class BuiltinConcepts: # formatting TO_LIST = "__TO_LIST" TO_DICT = "__TO_DICT" + TO_MULTI = "__TO_MULTI" # used when there are multiple output to display AllBuiltinConcepts = [v for n, v in BuiltinConcepts.__dict__.items() if not n.startswith("__")] @@ -178,6 +179,13 @@ BuiltinContainers = [ BuiltinConcepts.EXPLANATION, BuiltinConcepts.TO_LIST, BuiltinConcepts.TO_DICT, + BuiltinConcepts.TO_MULTI, +] + +BuiltinOutConcepts = [ + BuiltinConcepts.TO_LIST, + BuiltinConcepts.TO_DICT, + BuiltinConcepts.TO_MULTI, ] """ diff --git a/src/core/sheerka/Sheerka.py b/src/core/sheerka/Sheerka.py index c50f343..e6319f7 100644 --- a/src/core/sheerka/Sheerka.py +++ b/src/core/sheerka/Sheerka.py @@ -916,6 +916,19 @@ class Sheerka(Concept): return a.key == b_key + @staticmethod + def isin(a, b): + """ + True if the concept is the list + :param a: + :param b: + :return: + """ + if not isinstance(a, Concept): + return False + + return a.key in b + @staticmethod def get_unknown(metadata): """ diff --git a/src/core/sheerka/services/SheerkaDebugManager.py b/src/core/sheerka/services/SheerkaDebugManager.py index c33e7c6..87b0573 100644 --- a/src/core/sheerka/services/SheerkaDebugManager.py +++ b/src/core/sheerka/services/SheerkaDebugManager.py @@ -8,6 +8,7 @@ from core.sheerka.ExecutionContext import ExecutionContext from core.sheerka.services.sheerka_service import BaseService from core.utils import CONSOLE_COLORS_MAP as CCM, CONSOLE_COLUMNS, PRIMITIVES_TYPES from core.utils import evaluate_expression, as_bag +from parsers.BaseNodeParser import SourceCodeWithConceptNode, UnrecognizedTokensNode pp = pprint.PrettyPrinter(indent=2, width=CONSOLE_COLUMNS) @@ -15,7 +16,7 @@ NotFound = "** Not Found **" class ConceptDebugObj: - def __init__(self, concept): + def __init__(self, concept, **kwargs): self.concept = concept self.attrs = concept.as_debug_bag(lambda x: ConceptDebugObj(x), True) @@ -46,12 +47,37 @@ class ConceptDebugObj: class ConceptNodeDebugObj: - def __init__(self, concept_node): + def __init__(self, concept_node, **kwargs): self.concept_node = concept_node self.concept_debug = ConceptDebugObj(concept_node.concept) def __repr__(self): - return f"ConceptNode({self.concept_debug.concept_repr()})" + return f"ConceptNodeDbg({self.concept_debug.concept_repr()})" + + +class SourceCodeWithConceptNodeDebugObj: + def __init__(self, source_code_node, **kwargs): + self.source_code_node = source_code_node + + def __repr__(self): + debug_repr = SheerkaDebugManager.get_debug_repr + res = f"SourceCodeNodeDbg('{debug_repr(self.source_code_node.first, inside_source_code=True)}' " + first = True + for node in self.source_code_node.nodes: + res += (", " if not first else "") + str(debug_repr(node)) + first = False + return res + f" '{debug_repr(self.source_code_node.last, inside_source_code=True)}')" + + +class UnrecognizedTokensNodeDebugOjb: + def __init__(self, unrec_node, **kwargs): + self.unrec_node = unrec_node + self.inside_source_code = kwargs.get("inside_source_code", False) + + def __repr__(self): + if self.inside_source_code: + return self.unrec_node.source + return f"UnrecNodeDbg('{self.unrec_node.source}')" class BaseDebugLogger: @@ -678,16 +704,21 @@ class SheerkaDebugManager(BaseService): return self.get_inner_values(obj.body, **kwargs) - def get_debug_repr(self, obj, **kwargs): + @staticmethod + def get_debug_repr(obj, **kwargs): if kwargs.get("as_bag", False): - forced_props = self.get_concept_forced_props(obj) if isinstance(obj, Concept) else None - return self.as_debug_bag(obj, True, forced_props) + forced_props = SheerkaDebugManager.get_concept_forced_props(obj) if isinstance(obj, Concept) else None + return SheerkaDebugManager.as_debug_bag(obj, True, forced_props) from parsers.BaseNodeParser import ConceptNode if isinstance(obj, Concept): - return ConceptDebugObj(obj) + return ConceptDebugObj(obj, **kwargs) elif isinstance(obj, ConceptNode): - return ConceptNodeDebugObj(obj) + return ConceptNodeDebugObj(obj, **kwargs) + elif isinstance(obj, SourceCodeWithConceptNode): + return SourceCodeWithConceptNodeDebugObj(obj, **kwargs) + elif isinstance(obj, UnrecognizedTokensNode): + return UnrecognizedTokensNodeDebugOjb(obj, **kwargs) else: return obj diff --git a/src/core/sheerka/services/SheerkaOut.py b/src/core/sheerka/services/SheerkaOut.py index 2db4bb7..56e623d 100644 --- a/src/core/sheerka/services/SheerkaOut.py +++ b/src/core/sheerka/services/SheerkaOut.py @@ -16,7 +16,7 @@ class SheerkaOut(BaseService): self.sheerka.bind_service_method(self.process_return_values, False) def create_out_tree(self, context, obj): - debugger = context.get_debugger("Out.visitor", "create_out_tree") + debugger = context.get_debugger("Visitor", "create_out_tree") return self.create_out_tree_recursive(context, {'__obj': obj}, DeveloperVisitor(self, debugger, set(), 0)) def create_out_tree_recursive(self, context, bag, visitor): diff --git a/src/core/sheerka/services/SheerkaRuleManager.py b/src/core/sheerka/services/SheerkaRuleManager.py index 99d5b83..e951df9 100644 --- a/src/core/sheerka/services/SheerkaRuleManager.py +++ b/src/core/sheerka/services/SheerkaRuleManager.py @@ -119,7 +119,9 @@ class FormatAstList(FormatAstNode): def clone(self, **kwargs): return super().clone( FormatAstList(self.variable), - ("items_prop", "recurse_on", "recursion_depth", "debug", "prefix", "suffix", "show_index", "index", "items"), + ( + "items_prop", "recurse_on", "recursion_depth", "debug", "prefix", "suffix", "show_index", "index", + "items"), **kwargs) @@ -177,6 +179,25 @@ class FormatAstSequence(FormatAstNode): **kwargs) +@dataclass +class FormatAstMulti(FormatAstNode): + """ + Used when there are multiple out to print, but they are not related + Just print them one by one + """ + variable: str + items: list = None + + def __repr__(self): + return f"FormatAstMulti({self.variable}, items={self.items})" + + def clone(self, **kwargs): + return super().clone( + FormatAstMulti(self.variable), + ("items",), + **kwargs) + + class FormatRuleParser(IterParser): @staticmethod @@ -318,6 +339,8 @@ class FormatRuleParser(IterParser): return self.return_list(args, kwargs) elif func_name.value == "dict": return self.return_dict(args, kwargs) + elif func_name.value == "multi": + return self.return_multi(args, kwargs) return FormatAstFunction(func_name.value, self.to_text(args), self.to_text(kwargs)) @@ -461,6 +484,17 @@ class FormatRuleParser(IterParser): return FormatAstDict(variable_name, **kwargs_parameters) + def return_multi(self, args, kwargs): + if len(kwargs) > 0: + self.error_sink = FormatRuleSyntaxError("keyword arguments are not supported", None) + return None + + if len(args) > 1: + self.error_sink = FormatRuleSyntaxError("too many positional arguments", args[1][0]) + return None + + return FormatAstMulti(get_text_from_tokens(args[0])) + @dataclass() class RulePredicate: @@ -620,25 +654,43 @@ class SheerkaRuleManager(BaseService): def init_builtin_rules(self, context): # self.sheerka.init_log.debug("Initializing default rules") rules = [ + # [0] Rule #1 Rule #2 in debug Rule("print", "Print return values", "__rets", "list(__rets)"), + + # [1] Rule #2 in debug Rule("print", "Print ReturnValue", "__ret", "\\ReturnValue(who={__ret.who}, status={__ret.status}, value={__ret.value})"), + + # [2] Rule #3 in debug Rule("print", "Failed ReturnValue in red", "__ret and not __ret.status", "red(__ret)"), + + # [3] Rule #4 in debug Rule("print", "List explanations", "isinstance(__ret_container, BuiltinConcepts.EXPLANATION)", "blue(__ret_container.digest) : {__ret_container.command}\nlist(__ret_container)"), + + # [4] Rule #5 in debug Rule("print", "Print ExecutionContext", "isinstance(__obj, ExecutionContext)", "[{id:3}] {__tab}{desc} ({status})"), + + # [6] Rule #7 in debug Rule("print", "Display formatted list", "isinstance(__ret_container, BuiltinConcepts.TO_LIST)", "list(__ret_container)"), + + # [7] Rule #8 in debug Rule("print", "Display formatted dict", "isinstance(__ret_container, BuiltinConcepts.TO_DICT)", "dict(__ret_container)"), + + # [8] Rule #9 in debug + Rule("print", "Display multiple outputs", + "isinstance(__ret_container, BuiltinConcepts.TO_MULTI)", + "multi(__ret_container)"), ] for r in rules: @@ -648,6 +700,10 @@ class SheerkaRuleManager(BaseService): self.sheerka.set_is_less_than(context, BuiltinConcepts.PRECEDENCE, rules[1], rules[3], RULE_COMPARISON_CONTEXT) self.sheerka.set_is_less_than(context, BuiltinConcepts.PRECEDENCE, rules[1], rules[5], RULE_COMPARISON_CONTEXT) self.sheerka.set_is_less_than(context, BuiltinConcepts.PRECEDENCE, rules[1], rules[6], RULE_COMPARISON_CONTEXT) + self.sheerka.set_is_greater_than(context, BuiltinConcepts.PRECEDENCE, rules[7], rules[6], + RULE_COMPARISON_CONTEXT) + self.sheerka.set_is_greater_than(context, BuiltinConcepts.PRECEDENCE, rules[7], rules[5], + RULE_COMPARISON_CONTEXT) self.sheerka.set_is_greatest(context, BuiltinConcepts.PRECEDENCE, rules[0], RULE_COMPARISON_CONTEXT) def get_rule_by_id(self, rule_id): diff --git a/src/evaluators/MultipleOutEvaluator.py b/src/evaluators/MultipleOutEvaluator.py new file mode 100644 index 0000000..ef9875e --- /dev/null +++ b/src/evaluators/MultipleOutEvaluator.py @@ -0,0 +1,44 @@ +from core.builtin_concepts import BuiltinConcepts, BuiltinOutConcepts +from evaluators.BaseEvaluator import AllReturnValuesEvaluator +from parsers.BaseParser import BaseParser + + +class MultipleOutEvaluator(AllReturnValuesEvaluator): + """ + Used to filter the responses + when too many success but these success are different output to print + """ + + NAME = "MultipleOut" + + def __init__(self): + super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 61) + self.success = [] + + def reset(self): + super().reset() + self.success.clear() + + def matches(self, context, return_values): + to_process = False + + for ret in return_values: + if ret.status and ret.who.startswith(BaseParser.PREFIX): + return False + elif ret.status and context.sheerka.isinstance(ret.body, BuiltinConcepts.REDUCE_REQUESTED): + to_process = True + self.eaten.append(ret) + elif ret.status and ret.who.startswith(self.PREFIX): + if context.sheerka.isin(ret.body, BuiltinOutConcepts): + self.success.append(ret) + self.eaten.append(ret) + else: + return False + elif not ret.status: + self.eaten.append(ret) + + return to_process and len(self.success) > 1 + + def eval(self, context, return_values): + to_multi = context.sheerka.new(BuiltinConcepts.TO_MULTI, body=[r.body for r in self.success]) + return context.sheerka.ret(self.name, True, to_multi, parents=self.eaten) diff --git a/src/out/AsStrVisitor.py b/src/out/AsStrVisitor.py index 52a4dbb..251d997 100644 --- a/src/out/AsStrVisitor.py +++ b/src/out/AsStrVisitor.py @@ -100,6 +100,9 @@ class AsStrVisitor(OutVisitor): result += format_ast.suffix return result + def visit_FormatAstMulti(self, format_ast): + return "\n".join(self.visit(item) for item in format_ast.items) + @staticmethod def debug_activated(node): return isinstance(node, FormatAstNode) and hasattr(node, "debug") and node.debug diff --git a/src/out/ConsoleVisistor.py b/src/out/ConsoleVisistor.py index 4a78006..83a473e 100644 --- a/src/out/ConsoleVisistor.py +++ b/src/out/ConsoleVisistor.py @@ -51,3 +51,6 @@ class ConsoleVisitor(AsStrVisitor): visitor = AsStrVisitor(expand, width=self.console_width) res = visitor.visit_FormatAstDict(format_ast) self.out(res) + + def visit_FormatAstMulti(self, format_ast): + self.out(super().visit_FormatAstMulti(format_ast)) diff --git a/src/out/DeveloperVisitor.py b/src/out/DeveloperVisitor.py index 0065f04..b3dadca 100644 --- a/src/out/DeveloperVisitor.py +++ b/src/out/DeveloperVisitor.py @@ -26,6 +26,8 @@ class DeveloperVisitor: return visit_method(context, format_ast, bag) def generic_visit(self, context, format_ast, bag): + name = format_ast.__class__.__name__ + self.debugger.debug_log(f"method '{name}' is not implemented", is_error=True) pass def visit_FormatAstRawText(self, context, format_ast, bag): @@ -191,6 +193,28 @@ class DeveloperVisitor: format_ast.variable + "." + error.args[0] return FormatAstVariableNotFound(var_name) + def visit_FormatAstMulti(self, context, format_ast, bag): + if self.debugger.is_enabled(): + debug_bag = {"format_ast": format_ast, "bag": bag} + self.debugger.debug_log(f"Entering visit_FormatAstMulti with {debug_bag}") + + try: + value = evaluate_expression(format_ast.variable, bag) + res = [] + for item in value.body: + sub_bag = {"__obj": item, format_ast.variable: item} + visitor = DeveloperVisitor(self.sheerka_out, self.debugger, set(), self.list_recursion_depth) + res.append(self.sheerka_out.create_out_tree_recursive(context, sub_bag, visitor)) + + format_ast.items = res + return format_ast + + except NameError as error: + self.debugger.debug_log(error, is_error=True) + var_name = format_ast.variable if error.args[0] == format_ast.variable else \ + format_ast.variable + "." + error.args[0] + return FormatAstVariableNotFound(var_name) + @staticmethod def get_recurse_info(obj, recursion_depth, recurse_on): depth, on = 0, None diff --git a/tests/core/test_SheerkaRuleManager.py b/tests/core/test_SheerkaRuleManager.py index 416f1c9..3fe2358 100644 --- a/tests/core/test_SheerkaRuleManager.py +++ b/tests/core/test_SheerkaRuleManager.py @@ -7,7 +7,7 @@ from core.global_symbols import RULE_COMPARISON_CONTEXT from core.rule import Rule from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, FormatRuleParser, \ FormatAstRawText, FormatAstVariable, FormatAstSequence, FormatAstFunction, \ - FormatRuleSyntaxError, FormatAstList, UnexpectedEof, FormatAstColor, RulePredicate, FormatAstDict + FormatRuleSyntaxError, FormatAstList, UnexpectedEof, FormatAstColor, RulePredicate, FormatAstDict, FormatAstMulti from core.tokenizer import Token, TokenKind from parsers.BaseNodeParser import SourceCodeWithConceptNode, SourceCodeNode from parsers.PythonParser import PythonNode @@ -114,7 +114,8 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka): (r"\not_a_function(a={var})", seq([raw("not_a_function(a="), var("var"), raw(")")])), ("dict(var_name)", FormatAstDict("var_name")), ("dict(var_name, items_prop='props')", FormatAstDict("var_name", items_prop='props')), - ("dict(var_name, debug=True)", FormatAstDict("var_name", debug=True, prefix="{", suffix="}")) + ("dict(var_name, debug=True)", FormatAstDict("var_name", debug=True, prefix="{", suffix="}")), + ("multi(var_name)", FormatAstMulti("var_name")), ]) def test_i_can_parse_format_rule(self, text, expected): assert FormatRuleParser(text).parse() == expected diff --git a/tests/evaluators/EvaluatorTestsUtils.py b/tests/evaluators/EvaluatorTestsUtils.py new file mode 100644 index 0000000..7a2c38f --- /dev/null +++ b/tests/evaluators/EvaluatorTestsUtils.py @@ -0,0 +1,50 @@ +from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts +from core.concept import Concept +from evaluators.BaseEvaluator import BaseEvaluator +from parsers.BaseParser import BaseParser + +reduced_requested = ReturnValueConcept("Sheerka", True, Concept(name=BuiltinConcepts.REDUCE_REQUESTED, + key=BuiltinConcepts.REDUCE_REQUESTED)) + + +def ret_val(value="value", who="who", status=True): + return ReturnValueConcept(who, status, value) + + +def p_ret_val(value="value", parser="parser", status=True): + return ReturnValueConcept(BaseParser.PREFIX + parser, status, value) + + +def e_ret_val(value="value", evaluator="evaluator", status=True): + return ReturnValueConcept(BaseEvaluator.PREFIX + evaluator, status, value) + + +def p_ret_val_false(value="value", parser="parser"): + return p_ret_val(value, parser, status=False) + + +def p_ret_val_true(value="value", parser="parser"): + return p_ret_val(value, parser, status=True) + + +def e_ret_val_false(value="value", parser="parser"): + return e_ret_val(value, parser, status=False) + + +def e_ret_val_true(value="value", parser="parser"): + return e_ret_val(value, parser, status=True) + + +def e_ret_val_new(key, evaluator="evaluator", status=True, **kwargs): + body = new_concept(key, **kwargs) + return e_ret_val(body, evaluator, status) + + +def new_concept(key, **kwargs): + res = Concept(key=key, name=key, is_builtin=False, is_unique=False) + for k, v in kwargs.items(): + to_use = "#" + k + "#" if k in ("body", "pre", "post", "ret") else k + res.set_value(to_use, v) + + res.get_metadata().is_evaluated = True + return res diff --git a/tests/evaluators/test_MultipleOutEvaluator.py b/tests/evaluators/test_MultipleOutEvaluator.py new file mode 100644 index 0000000..bd29537 --- /dev/null +++ b/tests/evaluators/test_MultipleOutEvaluator.py @@ -0,0 +1,55 @@ +import pytest +from core.builtin_concepts import BuiltinConcepts +from evaluators.MultipleOutEvaluator import MultipleOutEvaluator + +from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka +from tests.evaluators.EvaluatorTestsUtils import reduced_requested, e_ret_val_new, p_ret_val_false, p_ret_val_true, \ + e_ret_val_false, e_ret_val + + +class TestMultipleOutEvaluator(TestUsingMemoryBasedSheerka): + + @pytest.mark.parametrize("return_values, expected", [ + ([reduced_requested, + e_ret_val_new(BuiltinConcepts.TO_DICT, body={}), + e_ret_val_new(BuiltinConcepts.TO_DICT, body={}), + p_ret_val_false("value"), + e_ret_val_false()], True), + + # only one to_dict + ([reduced_requested, e_ret_val_new(BuiltinConcepts.TO_DICT, body={})], False), + + # reduce request missing + ([e_ret_val_new(BuiltinConcepts.TO_DICT, body={}), e_ret_val_new(BuiltinConcepts.TO_DICT, body={})], False), + + # parser result not evaluated + ([reduced_requested, + e_ret_val_new(BuiltinConcepts.TO_DICT, body={}), + e_ret_val_new(BuiltinConcepts.TO_DICT, body={}), + p_ret_val_true("value")], False), + ]) + def test_i_can_match(self, return_values, expected): + sheerka, context = self.init_concepts() + evaluator = MultipleOutEvaluator() + + assert evaluator.matches(context, return_values) == expected + + def test_i_can_eval(self): + sheerka, context = self.init_concepts() + evaluator = MultipleOutEvaluator() + + first_out = sheerka.new(BuiltinConcepts.TO_DICT, body={"a": 1}) + second_out = sheerka.new(BuiltinConcepts.TO_DICT, body={"b": 1}) + + return_values = [reduced_requested, + e_ret_val(first_out), + e_ret_val(second_out), + p_ret_val_false("value"), + e_ret_val_false()] + + evaluator.matches(context, return_values) + res = evaluator.eval(context, return_values) + + assert sheerka.isinstance(res, BuiltinConcepts.RETURN_VALUE) + assert res.body == sheerka.new(BuiltinConcepts.TO_MULTI, body=[first_out, second_out]) + assert res.parents == return_values diff --git a/tests/non_reg/test_sheerka_display.py b/tests/non_reg/test_sheerka_display.py index 88a3eac..a71027f 100644 --- a/tests/non_reg/test_sheerka_display.py +++ b/tests/non_reg/test_sheerka_display.py @@ -14,3 +14,41 @@ class TestSheerkaNonRegDisplay(TestUsingMemoryBasedSheerka): captured = capsys.readouterr() assert captured.out == "ReturnValue(who=evaluators.OneSuccess, status=True, value=(1001)one)\n" + + def test_i_can_display_multiple_concepts_description(self, capsys): + init = [ + "def concept foo as 1", + "def concept foo as 2", + ] + sheerka = self.init_scenario(init) + capsys.readouterr() + + sheerka.enable_process_return_values = True + sheerka.evaluate_user_input("desc(foo)") + + captured = capsys.readouterr() + assert captured.out == """id : 1001 +name : foo +key : foo +definition: None +type : None +body : 1 +where : None +pre : None +post : None +ret : None +vars : [] +props : {} +id : 1002 +name : foo +key : foo +definition: None +type : None +body : 2 +where : None +pre : None +post : None +ret : None +vars : [] +props : {} +""" diff --git a/tests/non_reg/test_sheerka_non_reg.py b/tests/non_reg/test_sheerka_non_reg.py index f25c7f1..990a5a4 100644 --- a/tests/non_reg/test_sheerka_non_reg.py +++ b/tests/non_reg/test_sheerka_non_reg.py @@ -1183,6 +1183,19 @@ as: 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) + class TestSheerkaNonRegFile(TestUsingFileBasedSheerka): def test_i_can_def_several_concepts(self): diff --git a/tests/out/test_DeveloperVisitor.py b/tests/out/test_DeveloperVisitor.py index 12c8a58..853f0d7 100644 --- a/tests/out/test_DeveloperVisitor.py +++ b/tests/out/test_DeveloperVisitor.py @@ -1,6 +1,7 @@ +from core.builtin_concepts import BuiltinConcepts from core.sheerka.services.SheerkaDebugManager import NullDebugLogger from core.sheerka.services.SheerkaOut import SheerkaOut -from core.sheerka.services.SheerkaRuleManager import FormatAstList, FormatAstVariable +from core.sheerka.services.SheerkaRuleManager import FormatAstList, FormatAstVariable, FormatAstDict, FormatAstMulti from out.DeveloperVisitor import DeveloperVisitor from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka @@ -12,10 +13,10 @@ class TestDeveloperVisitor(TestUsingMemoryBasedSheerka): service_out = sheerka.services[SheerkaOut.NAME] dev_visitor = DeveloperVisitor(service_out, NullDebugLogger(), set(), 0) - bag = {"a": ["a", "b", "c"]} + bag = {"to_format": ["a", "b", "c"]} - res = dev_visitor.visit(context, FormatAstList("a"), bag) - assert res == FormatAstList(variable="a", items=[ + res = dev_visitor.visit(context, FormatAstList("to_format"), bag) + assert res == FormatAstList(variable="to_format", items=[ FormatAstVariable(name="__item", index=0, value="a"), FormatAstVariable(name="__item", index=1, value="b"), FormatAstVariable(name="__item", index=2, value="c"), @@ -26,10 +27,10 @@ class TestDeveloperVisitor(TestUsingMemoryBasedSheerka): service_out = sheerka.services[SheerkaOut.NAME] dev_visitor = DeveloperVisitor(service_out, NullDebugLogger(), set(), 0) - bag = {"a": [["a1", "a2"], ["b1"]]} + bag = {"to_format": [["a1", "a2"], ["b1"]]} - res = dev_visitor.visit(context, FormatAstList("a"), bag) - assert res == FormatAstList(variable="a", items=[ + res = dev_visitor.visit(context, FormatAstList("to_format"), bag) + assert res == FormatAstList(variable="to_format", items=[ FormatAstList(variable="__item", index=0, debug=True, prefix='[', suffix=']', items=[ FormatAstVariable(name="__item", index=0, debug=True, value="a1"), FormatAstVariable(name="__item", index=1, debug=True, value="a2"), @@ -38,3 +39,41 @@ class TestDeveloperVisitor(TestUsingMemoryBasedSheerka): FormatAstVariable(name="__item", index=0, debug=True, value="b1"), ]), ]) + + def test_i_can_develop_dict(self): + sheerka, context = self.init_concepts() + service_out = sheerka.services[SheerkaOut.NAME] + dev_visitor = DeveloperVisitor(service_out, NullDebugLogger(), set(), 0) + + bag = {"to_format": {"a": "value1", "b": 3.14}} + + res = dev_visitor.visit(context, FormatAstDict("to_format"), bag) + + assert res == FormatAstDict(variable='to_format', items=[ + (FormatAstVariable(name='__key', index=0, value='a'), + FormatAstVariable(name='__value', index='a', value='value1')), + (FormatAstVariable(name='__key', index=1, value='b'), + FormatAstVariable(name='__value', index='b', value=3.14))]) + + def test_i_can_develop_multi(self): + sheerka, context, *rules = self.init_format_rules( + ("isinstance(to_format, BuiltinConcepts.TO_DICT)", "dict(to_format)")) + service_out = sheerka.services[SheerkaOut.NAME] + dev_visitor = DeveloperVisitor(service_out, NullDebugLogger(), set(), 0) + + item1 = sheerka.new(BuiltinConcepts.TO_DICT, body={"a1": "value1"}) + item2 = sheerka.new(BuiltinConcepts.TO_DICT, body={"a2": "value2"}) + + bag = {"to_format": sheerka.new(BuiltinConcepts.TO_MULTI, body=[item1, item2])} + + res = dev_visitor.visit(context, FormatAstMulti("to_format"), bag) + + assert res == FormatAstMulti("to_format", items=[ + FormatAstDict(variable='to_format', items=[ + (FormatAstVariable(name='__key', index=0, value='a1'), + FormatAstVariable(name='__value', index='a1', value='value1'))]), + + FormatAstDict(variable='to_format', items=[ + (FormatAstVariable(name='__key', index=0, value='a2'), + FormatAstVariable(name='__value', index='a2', value='value2'))]) + ])