First but not optimized version of AstFormatDict
This commit is contained in:
@@ -105,6 +105,7 @@ class BuiltinConcepts:
|
|||||||
|
|
||||||
# formatting
|
# formatting
|
||||||
TO_LIST = "__TO_LIST"
|
TO_LIST = "__TO_LIST"
|
||||||
|
TO_DICT = "__TO_DICT"
|
||||||
|
|
||||||
|
|
||||||
AllBuiltinConcepts = [v for n, v in BuiltinConcepts.__dict__.items() if not n.startswith("__")]
|
AllBuiltinConcepts = [v for n, v in BuiltinConcepts.__dict__.items() if not n.startswith("__")]
|
||||||
@@ -176,6 +177,7 @@ BuiltinContainers = [
|
|||||||
BuiltinConcepts.FILTERED,
|
BuiltinConcepts.FILTERED,
|
||||||
BuiltinConcepts.EXPLANATION,
|
BuiltinConcepts.EXPLANATION,
|
||||||
BuiltinConcepts.TO_LIST,
|
BuiltinConcepts.TO_LIST,
|
||||||
|
BuiltinConcepts.TO_DICT,
|
||||||
]
|
]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -113,7 +113,8 @@ class Sheerka(Concept):
|
|||||||
self.methods_with_context = {"test_using_context"} # only the names, the method is defined in sheerka_methods
|
self.methods_with_context = {"test_using_context"} # only the names, the method is defined in sheerka_methods
|
||||||
self.sheerka_methods = {
|
self.sheerka_methods = {
|
||||||
"test": SheerkaMethod(self.test, False),
|
"test": SheerkaMethod(self.test, False),
|
||||||
"test_using_context": SheerkaMethod(self.test_using_context, False)
|
"test_using_context": SheerkaMethod(self.test_using_context, False),
|
||||||
|
"test_dict": SheerkaMethod(self.test_dict, False)
|
||||||
}
|
}
|
||||||
self.sheerka_pipeables = {}
|
self.sheerka_pipeables = {}
|
||||||
|
|
||||||
@@ -1028,6 +1029,20 @@ class Sheerka(Concept):
|
|||||||
# uncomment the following line to enable colors
|
# uncomment the following line to enable colors
|
||||||
# logging.StreamHandler.emit = add_coloring_to_emit_ansi(logging.StreamHandler.emit)
|
# logging.StreamHandler.emit = add_coloring_to_emit_ansi(logging.StreamHandler.emit)
|
||||||
|
|
||||||
|
def test_dict(self):
|
||||||
|
bag2 = {
|
||||||
|
"alpha": "value4",
|
||||||
|
"beta": ["item1", "item2", "item3", ]
|
||||||
|
}
|
||||||
|
bag = {
|
||||||
|
"a": "value1",
|
||||||
|
"baba": "value2",
|
||||||
|
"c": "value1",
|
||||||
|
"de": ["item1", "item2", "item3", ],
|
||||||
|
"e": bag2
|
||||||
|
}
|
||||||
|
return self.new(BuiltinConcepts.TO_DICT, body=bag)
|
||||||
|
|
||||||
|
|
||||||
def to_profile():
|
def to_profile():
|
||||||
sheerka = Sheerka()
|
sheerka = Sheerka()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import time
|
|||||||
from os import path
|
from os import path
|
||||||
|
|
||||||
from core.builtin_concepts import BuiltinConcepts, BuiltinContainers
|
from core.builtin_concepts import BuiltinConcepts, BuiltinContainers
|
||||||
|
from core.builtin_helpers import ensure_concept
|
||||||
from core.concept import Concept
|
from core.concept import Concept
|
||||||
from core.sheerka.services.sheerka_service import BaseService
|
from core.sheerka.services.sheerka_service import BaseService
|
||||||
|
|
||||||
@@ -22,6 +23,7 @@ class SheerkaAdmin(BaseService):
|
|||||||
self.sheerka.bind_service_method(self.cache, False)
|
self.sheerka.bind_service_method(self.cache, False)
|
||||||
self.sheerka.bind_service_method(self.restore, True)
|
self.sheerka.bind_service_method(self.restore, True)
|
||||||
self.sheerka.bind_service_method(self.concepts, False)
|
self.sheerka.bind_service_method(self.concepts, False)
|
||||||
|
self.sheerka.bind_service_method(self.desc, False)
|
||||||
self.sheerka.bind_service_method(self.last_created_concept, False)
|
self.sheerka.bind_service_method(self.last_created_concept, False)
|
||||||
self.sheerka.bind_service_method(self.last_ret, False)
|
self.sheerka.bind_service_method(self.last_ret, False)
|
||||||
self.sheerka.bind_service_method(self.last_error_ret, False)
|
self.sheerka.bind_service_method(self.last_error_ret, False)
|
||||||
@@ -122,6 +124,28 @@ class SheerkaAdmin(BaseService):
|
|||||||
def concepts(self):
|
def concepts(self):
|
||||||
return self.sheerka.new(BuiltinConcepts.TO_LIST, body=self.sheerka.sdp.list(self.sheerka.CONCEPTS_BY_ID_ENTRY))
|
return self.sheerka.new(BuiltinConcepts.TO_LIST, body=self.sheerka.sdp.list(self.sheerka.CONCEPTS_BY_ID_ENTRY))
|
||||||
|
|
||||||
|
def desc(self, *concepts):
|
||||||
|
ensure_concept(*concepts)
|
||||||
|
res = []
|
||||||
|
for c in concepts:
|
||||||
|
bag = {
|
||||||
|
"id": c.id,
|
||||||
|
"name": c.name,
|
||||||
|
"key": c.key,
|
||||||
|
"definition": c.get_metadata().definition,
|
||||||
|
"type": c.get_metadata().definition_type,
|
||||||
|
"body": c.get_metadata().body,
|
||||||
|
"where": c.get_metadata().where,
|
||||||
|
"pre": c.get_metadata().pre,
|
||||||
|
"post": c.get_metadata().post,
|
||||||
|
"ret": c.get_metadata().ret,
|
||||||
|
"vars": c.get_metadata().variables,
|
||||||
|
"props": c.get_metadata().props,
|
||||||
|
}
|
||||||
|
res.append(self.sheerka.new(BuiltinConcepts.TO_DICT, body=bag))
|
||||||
|
|
||||||
|
return res[0] if len(res) == 1 else self.sheerka.new(BuiltinConcepts.TO_LIST, body=res)
|
||||||
|
|
||||||
def format_rules(self):
|
def format_rules(self):
|
||||||
return self.sheerka.new(BuiltinConcepts.TO_LIST, items=self.sheerka.get_format_rules())
|
return self.sheerka.new(BuiltinConcepts.TO_LIST, items=self.sheerka.get_format_rules())
|
||||||
|
|
||||||
|
|||||||
@@ -34,13 +34,16 @@ class BaseDebugLogger:
|
|||||||
def debug_entering(self, **kwargs):
|
def debug_entering(self, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def debug_var(self, name, value, is_error=False):
|
def debug_var(self, name, value, is_error=False, hint=None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def debug_rule(self, rule, results):
|
def debug_rule(self, rule, results):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def debug_log(self, text):
|
def debug_log(self, text, is_error=False):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def is_enabled(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@@ -48,6 +51,9 @@ class NullDebugLogger(BaseDebugLogger):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def is_enabled(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class ConsoleDebugLogger(BaseDebugLogger):
|
class ConsoleDebugLogger(BaseDebugLogger):
|
||||||
|
|
||||||
@@ -60,6 +66,9 @@ class ConsoleDebugLogger(BaseDebugLogger):
|
|||||||
self.debug_id = debug_id
|
self.debug_id = debug_id
|
||||||
self.is_highlighted = ""
|
self.is_highlighted = ""
|
||||||
|
|
||||||
|
def is_enabled(self):
|
||||||
|
return True
|
||||||
|
|
||||||
def debug_entering(self, **kwargs):
|
def debug_entering(self, **kwargs):
|
||||||
super().debug_entering(**kwargs)
|
super().debug_entering(**kwargs)
|
||||||
|
|
||||||
@@ -71,17 +80,18 @@ class ConsoleDebugLogger(BaseDebugLogger):
|
|||||||
self.debug_manager.debug(self.prefix() + str_text)
|
self.debug_manager.debug(self.prefix() + str_text)
|
||||||
self.debug_manager.debug(self.prefix() + str_vars)
|
self.debug_manager.debug(self.prefix() + str_vars)
|
||||||
|
|
||||||
def debug_var(self, name, value, is_error=False):
|
def debug_var(self, name, value, is_error=False, hint=None):
|
||||||
enabled = self.debug_manager.compute_var_debug(self.service_name,
|
enabled = is_error or self.debug_manager.compute_var_debug(self.service_name,
|
||||||
self.method_name,
|
self.method_name,
|
||||||
self.context_id,
|
self.context_id,
|
||||||
name,
|
name,
|
||||||
self.context_id)
|
self.context_id)
|
||||||
if enabled == False:
|
if enabled == False:
|
||||||
return
|
return
|
||||||
|
|
||||||
color = 'red' if is_error else 'green'
|
color = 'red' if is_error else 'green'
|
||||||
str_text = f"{CCM[color]}..{name}={CCM['reset']}"
|
hint_str = f"({hint})" if hint is not None else ""
|
||||||
|
str_text = f"{CCM[color]}..{name}{hint_str}={CCM['reset']}"
|
||||||
str_vars = "" if isinstance(enabled, str) else pp.pformat(value)
|
str_vars = "" if isinstance(enabled, str) else pp.pformat(value)
|
||||||
if "\n" not in str(str_vars):
|
if "\n" not in str(str_vars):
|
||||||
self.debug_manager.debug(self.prefix() + str_text + str_vars)
|
self.debug_manager.debug(self.prefix() + str_text + str_vars)
|
||||||
@@ -101,8 +111,9 @@ class ConsoleDebugLogger(BaseDebugLogger):
|
|||||||
self.debug_manager.debug(self.prefix() + str_text)
|
self.debug_manager.debug(self.prefix() + str_text)
|
||||||
self.debug_manager.debug(self.prefix() + str_vars)
|
self.debug_manager.debug(self.prefix() + str_vars)
|
||||||
|
|
||||||
def debug_log(self, text):
|
def debug_log(self, text, is_error=False):
|
||||||
self.debug_manager.debug(self.prefix() + f"{CCM['blue']}..{text}{CCM['reset']}")
|
color = 'red' if is_error else 'blue'
|
||||||
|
self.debug_manager.debug(self.prefix() + f"{CCM[color]}..{text}{CCM['reset']}")
|
||||||
|
|
||||||
def prefix(self):
|
def prefix(self):
|
||||||
return f"[{self.context_id:2}][{self.debug_id:2}] {self.is_highlighted}"
|
return f"[{self.context_id:2}][{self.debug_id:2}] {self.is_highlighted}"
|
||||||
@@ -271,12 +282,8 @@ class SheerkaDebugManager(BaseService):
|
|||||||
res = {}
|
res = {}
|
||||||
for prop in props:
|
for prop in props:
|
||||||
res[prop] = evaluate_expression(prop, bag)
|
res[prop] = evaluate_expression(prop, bag)
|
||||||
# res = {
|
|
||||||
# "return_values": to_inspect.values.get("return_values", None)
|
|
||||||
# }
|
|
||||||
|
|
||||||
pp.pprint(res)
|
return self.sheerka.new(BuiltinConcepts.TO_DICT, body=res)
|
||||||
return None
|
|
||||||
|
|
||||||
def debug(self, *args, **kwargs):
|
def debug(self, *args, **kwargs):
|
||||||
print(*args, **kwargs)
|
print(*args, **kwargs)
|
||||||
@@ -437,4 +444,4 @@ class SheerkaDebugManager(BaseService):
|
|||||||
return self.sheerka.ret(SheerkaDebugManager.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
|
return self.sheerka.ret(SheerkaDebugManager.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
|
||||||
|
|
||||||
def get_debug_settings(self):
|
def get_debug_settings(self):
|
||||||
return self.debug_vars_settings
|
return self.sheerka.new(BuiltinConcepts.TO_LIST, body=self.debug_vars_settings)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class SheerkaDump(BaseService):
|
|||||||
super().__init__(sheerka)
|
super().__init__(sheerka)
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.sheerka.bind_service_method(self.dump_desc, True, "desc") # has_side_effect 'cause concept is evaluated
|
self.sheerka.bind_service_method(self.dump_desc, True, "old_desc") # has_side_effect 'cause concept is evaluated
|
||||||
self.sheerka.bind_service_method(self.dump_sdp, False, "dump_sdp")
|
self.sheerka.bind_service_method(self.dump_sdp, False, "dump_sdp")
|
||||||
|
|
||||||
def dump_desc(self, *concept_names, eval=False):
|
def dump_desc(self, *concept_names, eval=False):
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ class SheerkaOut(BaseService):
|
|||||||
self.sheerka.bind_service_method(self.process_return_values, False)
|
self.sheerka.bind_service_method(self.process_return_values, False)
|
||||||
|
|
||||||
def create_out_tree(self, context, obj):
|
def create_out_tree(self, context, obj):
|
||||||
return self.create_out_tree_recursive(context, {'__obj': obj}, DeveloperVisitor(self, set(), 0))
|
debugger = context.get_debugger("Out.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):
|
def create_out_tree_recursive(self, context, bag, visitor):
|
||||||
debugger = context.get_debugger(SheerkaOut.NAME, "create_out_tree")
|
debugger = context.get_debugger(SheerkaOut.NAME, "create_out_tree")
|
||||||
@@ -40,8 +41,7 @@ class SheerkaOut(BaseService):
|
|||||||
visitor.already_seen.add(rule.id)
|
visitor.already_seen.add(rule.id)
|
||||||
|
|
||||||
bag.update(as_bag(current_obj)) # update with the current obj attributes
|
bag.update(as_bag(current_obj)) # update with the current obj attributes
|
||||||
visitor.visit(context, rule.compiled_action, bag)
|
res = visitor.visit(context, rule.compiled_action, bag)
|
||||||
res = visitor.get_result()
|
|
||||||
|
|
||||||
if res is None:
|
if res is None:
|
||||||
debugger.debug_log(f"No matching rule.")
|
debugger.debug_log(f"No matching rule.")
|
||||||
@@ -67,9 +67,7 @@ class SheerkaOut(BaseService):
|
|||||||
|
|
||||||
if out_tree:
|
if out_tree:
|
||||||
for visitor in self.out_visitors:
|
for visitor in self.out_visitors:
|
||||||
visitor.visit(context, out_tree, None)
|
visitor.visit(out_tree)
|
||||||
if hasattr(visitor, "finalize"):
|
|
||||||
visitor.finalize()
|
|
||||||
|
|
||||||
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
|
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
|
||||||
return self.sheerka.ret(self.NAME, False, self.sheerka.new(BuiltinConcepts.NO_RESULT))
|
return self.sheerka.ret(self.NAME, False, self.sheerka.new(BuiltinConcepts.NO_RESULT))
|
||||||
|
|||||||
@@ -63,6 +63,15 @@ class FormatAstNode:
|
|||||||
|
|
||||||
return ", ".join(repr(item) for item in items)
|
return ", ".join(repr(item) for item in items)
|
||||||
|
|
||||||
|
def clone(self, instance, props, **kwargs):
|
||||||
|
for prop_name in props:
|
||||||
|
setattr(instance, prop_name, getattr(self, prop_name))
|
||||||
|
|
||||||
|
for k, v in kwargs.items():
|
||||||
|
setattr(instance, k, v)
|
||||||
|
|
||||||
|
return instance
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FormatAstRawText(FormatAstNode):
|
class FormatAstRawText(FormatAstNode):
|
||||||
@@ -73,9 +82,15 @@ class FormatAstRawText(FormatAstNode):
|
|||||||
class FormatAstVariable(FormatAstNode):
|
class FormatAstVariable(FormatAstNode):
|
||||||
name: str
|
name: str
|
||||||
format: Union[str, None] = None
|
format: Union[str, None] = None
|
||||||
|
debug: bool = False
|
||||||
value: object = None
|
value: object = None
|
||||||
index: object = None
|
index: object = None
|
||||||
|
|
||||||
|
def clone(self, **kwargs):
|
||||||
|
return super().clone(FormatAstVariable(self.name),
|
||||||
|
("format", "debug", "value", "index"),
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FormatAstVariableNotFound(FormatAstNode):
|
class FormatAstVariableNotFound(FormatAstNode):
|
||||||
@@ -93,29 +108,50 @@ class FormatAstList(FormatAstNode):
|
|||||||
items_prop: str = None # where to search the list if variable does not resolve to an iterable
|
items_prop: str = None # where to search the list if variable does not resolve to an iterable
|
||||||
recurse_on: str = None
|
recurse_on: str = None
|
||||||
recursion_depth: int = 0
|
recursion_depth: int = 0
|
||||||
|
debug: bool = False
|
||||||
|
prefix: str = None
|
||||||
|
suffix: str = None
|
||||||
|
show_index: bool = False
|
||||||
|
|
||||||
items: object = None
|
items: object = None
|
||||||
|
|
||||||
|
def clone(self, **kwargs):
|
||||||
|
return super().clone(
|
||||||
|
FormatAstList(self.variable),
|
||||||
|
("items_prop", "recurse_on", "recursion_depth", "debug", "prefix", "suffix", "show_index", "items"),
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class FormatAstDict(FormatAstNode):
|
||||||
|
variable: str
|
||||||
|
items_prop: str = None # where to search the dict if variable does not resolve to an iterable
|
||||||
|
debug: bool = False
|
||||||
|
prefix: str = None
|
||||||
|
suffix: str = None
|
||||||
|
|
||||||
|
items: object = None
|
||||||
|
|
||||||
|
def clone(self, **kwargs):
|
||||||
|
return super().clone(
|
||||||
|
FormatAstDict(self.variable),
|
||||||
|
("items_prop", "debug", "prefix", "suffix", "items"),
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FormatAstColor(FormatAstNode):
|
class FormatAstColor(FormatAstNode):
|
||||||
def __init__(self, color, format_ast):
|
color: str
|
||||||
self.color = color
|
format_ast: FormatAstNode
|
||||||
self.format_ast = format_ast
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"{self.color}({self.format_ast})"
|
return f"{self.color}({self.format_ast})"
|
||||||
|
|
||||||
def __eq__(self, other):
|
def clone(self, **kwargs):
|
||||||
if id(self) == id(other):
|
return super().clone(
|
||||||
return True
|
FormatAstColor(self.color, self.format_ast),
|
||||||
|
(),
|
||||||
if not isinstance(other, FormatAstColor):
|
**kwargs)
|
||||||
return False
|
|
||||||
|
|
||||||
return self.color == other.color and self.format_ast == other.format_ast
|
|
||||||
|
|
||||||
def __hash__(self):
|
|
||||||
return hash((self.color, self.format_ast))
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -125,21 +161,19 @@ class FormatAstFunction(FormatAstNode):
|
|||||||
kwargs: dict = None
|
kwargs: dict = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
class FormatAstSequence(FormatAstNode):
|
class FormatAstSequence(FormatAstNode):
|
||||||
def __init__(self, items):
|
items: list
|
||||||
self.items = items
|
debug: bool = False
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "FormatAstSequence(" + self.repr_value(self.items) + ")"
|
return "FormatAstSequence(" + self.repr_value(self.items) + ")"
|
||||||
|
|
||||||
def __eq__(self, other):
|
def clone(self, **kwargs):
|
||||||
if id(self) == id(other):
|
return super().clone(
|
||||||
return True
|
FormatAstSequence(self.items),
|
||||||
|
("debug",),
|
||||||
if not isinstance(other, FormatAstSequence):
|
**kwargs)
|
||||||
return False
|
|
||||||
|
|
||||||
return self.items == other.items
|
|
||||||
|
|
||||||
|
|
||||||
class FormatRuleParser(IterParser):
|
class FormatRuleParser(IterParser):
|
||||||
@@ -170,6 +204,9 @@ class FormatRuleParser(IterParser):
|
|||||||
if value[0] in ("'", '"'):
|
if value[0] in ("'", '"'):
|
||||||
return value[1:-1]
|
return value[1:-1]
|
||||||
|
|
||||||
|
if value in ("True", "False"):
|
||||||
|
return bool(value)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return int(value)
|
return int(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@@ -278,6 +315,8 @@ class FormatRuleParser(IterParser):
|
|||||||
return self.return_color(func_name.value, args, kwargs)
|
return self.return_color(func_name.value, args, kwargs)
|
||||||
elif func_name.value == "list":
|
elif func_name.value == "list":
|
||||||
return self.return_list(args, kwargs)
|
return self.return_list(args, kwargs)
|
||||||
|
elif func_name.value == "dict":
|
||||||
|
return self.return_dict(args, kwargs)
|
||||||
|
|
||||||
return FormatAstFunction(func_name.value, self.to_text(args), self.to_text(kwargs))
|
return FormatAstFunction(func_name.value, self.to_text(args), self.to_text(kwargs))
|
||||||
|
|
||||||
@@ -347,13 +386,19 @@ class FormatRuleParser(IterParser):
|
|||||||
return FormatAstColor(color, FormatAstVariable(variable, vformat))
|
return FormatAstColor(color, FormatAstVariable(variable, vformat))
|
||||||
|
|
||||||
def return_list(self, args, kwargs):
|
def return_list(self, args, kwargs):
|
||||||
|
"""
|
||||||
|
Looking for variable_name, [recurse_on], [recursion_depth], [items_prop]
|
||||||
|
:param args:
|
||||||
|
:param kwargs:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
len_args = len(args)
|
len_args = len(args)
|
||||||
if len_args < 1:
|
if len_args < 1:
|
||||||
self.error_sink = FormatRuleSyntaxError("variable name not found", None)
|
self.error_sink = FormatRuleSyntaxError("variable name not found", None)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if len_args > 3:
|
if len_args > 4:
|
||||||
self.error_sink = FormatRuleSyntaxError("too many positional arguments", args[3][0])
|
self.error_sink = FormatRuleSyntaxError("too many positional arguments", args[4][0])
|
||||||
return None
|
return None
|
||||||
|
|
||||||
variable_name = get_text_from_tokens(args[0])
|
variable_name = get_text_from_tokens(args[0])
|
||||||
@@ -364,6 +409,10 @@ class FormatRuleParser(IterParser):
|
|||||||
elif len_args == 3:
|
elif len_args == 3:
|
||||||
recursion_depth = self.to_value(args[1])
|
recursion_depth = self.to_value(args[1])
|
||||||
recurse_on = self.to_value(args[2])
|
recurse_on = self.to_value(args[2])
|
||||||
|
elif len_args == 4:
|
||||||
|
recursion_depth = self.to_value(args[1])
|
||||||
|
recurse_on = self.to_value(args[2])
|
||||||
|
items_prop = self.to_value(args[3])
|
||||||
|
|
||||||
if "recurse_on" in kwargs:
|
if "recurse_on" in kwargs:
|
||||||
recurse_on = self.to_value(kwargs["recurse_on"])
|
recurse_on = self.to_value(kwargs["recurse_on"])
|
||||||
@@ -383,6 +432,34 @@ class FormatRuleParser(IterParser):
|
|||||||
|
|
||||||
return FormatAstList(variable_name, items_prop, recurse_on, recursion_depth)
|
return FormatAstList(variable_name, items_prop, recurse_on, recursion_depth)
|
||||||
|
|
||||||
|
def return_dict(self, args, kwargs):
|
||||||
|
len_args = len(args)
|
||||||
|
if len_args < 1:
|
||||||
|
self.error_sink = FormatRuleSyntaxError("variable name not found", None)
|
||||||
|
return None
|
||||||
|
|
||||||
|
if len_args > 1:
|
||||||
|
self.error_sink = FormatRuleSyntaxError("too many positional arguments", args[1][0])
|
||||||
|
return None
|
||||||
|
|
||||||
|
variable_name = get_text_from_tokens(args[0])
|
||||||
|
|
||||||
|
kwargs_parameters = {}
|
||||||
|
for prop in ("items_prop", "prefix", "suffix", "debug"):
|
||||||
|
if prop in kwargs:
|
||||||
|
kwargs_parameters[prop] = self.to_value(kwargs[prop])
|
||||||
|
|
||||||
|
if "debug" in kwargs_parameters:
|
||||||
|
if "prefix" not in kwargs_parameters:
|
||||||
|
kwargs_parameters["prefix"] = "{"
|
||||||
|
if "suffix" not in kwargs_parameters:
|
||||||
|
kwargs_parameters["suffix"] = "}"
|
||||||
|
|
||||||
|
if self.error_sink:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return FormatAstDict(variable_name, **kwargs_parameters)
|
||||||
|
|
||||||
|
|
||||||
@dataclass()
|
@dataclass()
|
||||||
class RulePredicate:
|
class RulePredicate:
|
||||||
@@ -556,6 +633,9 @@ class SheerkaRuleManager(BaseService):
|
|||||||
Rule("print", "Display formatted list",
|
Rule("print", "Display formatted list",
|
||||||
"isinstance(__ret_container, BuiltinConcepts.TO_LIST)",
|
"isinstance(__ret_container, BuiltinConcepts.TO_LIST)",
|
||||||
"list(__ret_container)"),
|
"list(__ret_container)"),
|
||||||
|
Rule("print", "Display formatted dict",
|
||||||
|
"isinstance(__ret_container, BuiltinConcepts.TO_DICT)",
|
||||||
|
"dict(__ret_container)"),
|
||||||
]
|
]
|
||||||
|
|
||||||
for r in rules:
|
for r in rules:
|
||||||
|
|||||||
+10
-1
@@ -2,11 +2,11 @@ import ast
|
|||||||
import importlib
|
import importlib
|
||||||
import inspect
|
import inspect
|
||||||
import pkgutil
|
import pkgutil
|
||||||
import re
|
|
||||||
|
|
||||||
from cache.Cache import Cache
|
from cache.Cache import Cache
|
||||||
from core.ast_helpers import ast_to_props
|
from core.ast_helpers import ast_to_props
|
||||||
from core.tokenizer import TokenKind, Tokenizer
|
from core.tokenizer import TokenKind, Tokenizer
|
||||||
|
from pyparsing import *
|
||||||
|
|
||||||
default_debug_name = "*default*"
|
default_debug_name = "*default*"
|
||||||
debug_activated = set()
|
debug_activated = set()
|
||||||
@@ -38,6 +38,15 @@ PRIMITIVES_TYPES = (str, bool, type(None), int, float, list, dict, set, bytes, t
|
|||||||
|
|
||||||
expressions_cache = Cache()
|
expressions_cache = Cache()
|
||||||
|
|
||||||
|
ESC = Literal('\x1b')
|
||||||
|
integer = Word(nums)
|
||||||
|
escapeSeq = Combine(ESC + '[' + Optional(delimitedList(integer, ';')) +
|
||||||
|
oneOf(list(alphas)))
|
||||||
|
|
||||||
|
|
||||||
|
def no_color_str(text):
|
||||||
|
return Suppress(escapeSeq).transformString(str(text))
|
||||||
|
|
||||||
|
|
||||||
def my_debug(*args, check_started=None):
|
def my_debug(*args, check_started=None):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -129,12 +129,14 @@ class DefConceptEvaluator(OneReturnValueEvaluator):
|
|||||||
This function can only be a draft, as there may be tons of different situations
|
This function can only be a draft, as there may be tons of different situations
|
||||||
I guess that it can only be complete when will we have access to Sheerka memory
|
I guess that it can only be complete when will we have access to Sheerka memory
|
||||||
"""
|
"""
|
||||||
|
debugger = context.get_debugger(DefConceptEvaluator.NAME, "get_variables")
|
||||||
#
|
#
|
||||||
# Case of NameNode
|
# Case of NameNode
|
||||||
#
|
#
|
||||||
if isinstance(ret_value, NameNode):
|
if isinstance(ret_value, NameNode):
|
||||||
names = [str(t.value) for t in ret_value.tokens if t.type in (
|
names = [str(t.value) for t in ret_value.tokens if t.type in (
|
||||||
TokenKind.IDENTIFIER, TokenKind.STRING, TokenKind.KEYWORD)]
|
TokenKind.IDENTIFIER, TokenKind.STRING, TokenKind.KEYWORD)]
|
||||||
|
debugger.debug_var("names", names, hint="from NameNode")
|
||||||
return set(filter(lambda x: x in concept_name and context.sheerka.not_is_variable(x), names))
|
return set(filter(lambda x: x in concept_name and context.sheerka.not_is_variable(x), names))
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -143,6 +145,7 @@ class DefConceptEvaluator(OneReturnValueEvaluator):
|
|||||||
if isinstance(ret_value.value, ParserResultConcept) and isinstance(ret_value.value.value, ParsingExpression):
|
if isinstance(ret_value.value, ParserResultConcept) and isinstance(ret_value.value.value, ParsingExpression):
|
||||||
visitor = ConceptOrRuleNameVisitor()
|
visitor = ConceptOrRuleNameVisitor()
|
||||||
visitor.visit(ret_value.value.value)
|
visitor.visit(ret_value.value.value)
|
||||||
|
debugger.debug_var("names", visitor.names, hint="from BNF")
|
||||||
return set(visitor.names)
|
return set(visitor.names)
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -152,6 +155,7 @@ class DefConceptEvaluator(OneReturnValueEvaluator):
|
|||||||
if len(concept_name) > 1:
|
if len(concept_name) > 1:
|
||||||
visitor = UnreferencedVariablesVisitor(context)
|
visitor = UnreferencedVariablesVisitor(context)
|
||||||
names = visitor.get_names(python_node.ast_)
|
names = visitor.get_names(python_node.ast_)
|
||||||
|
debugger.debug_var("names", names, hint="from python node")
|
||||||
return set(filter(lambda x: x in concept_name and context.sheerka.not_is_variable(x), names))
|
return set(filter(lambda x: x in concept_name and context.sheerka.not_is_variable(x), names))
|
||||||
else:
|
else:
|
||||||
return set()
|
return set()
|
||||||
@@ -168,6 +172,7 @@ class DefConceptEvaluator(OneReturnValueEvaluator):
|
|||||||
for identifier in [i for i in concept_name if str(i).isalnum()]:
|
for identifier in [i for i in concept_name if str(i).isalnum()]:
|
||||||
if identifier in tokens:
|
if identifier in tokens:
|
||||||
variables.add(identifier)
|
variables.add(identifier)
|
||||||
|
debugger.debug_var("names", variables, hint="from concept")
|
||||||
return variables
|
return variables
|
||||||
|
|
||||||
return set()
|
return set()
|
||||||
|
|||||||
@@ -92,6 +92,9 @@ class PythonEvaluator(OneReturnValueEvaluator):
|
|||||||
|
|
||||||
debugger = context.get_debugger(PythonEvaluator.NAME, "eval")
|
debugger = context.get_debugger(PythonEvaluator.NAME, "eval")
|
||||||
debugger.debug_entering(node=node)
|
debugger.debug_entering(node=node)
|
||||||
|
exception_debugger = context.get_debugger("Exceptions", PythonEvaluator.NAME + ".eval")
|
||||||
|
get_trace_back = context.debug_enabled or exception_debugger.is_enabled()
|
||||||
|
|
||||||
context.log(f"Evaluating python node {node}.", self.name)
|
context.log(f"Evaluating python node {node}.", self.name)
|
||||||
|
|
||||||
# If we evaluate a Concept metadata which is NOT the body ex (pre, post, where...)
|
# If we evaluate a Concept metadata which is NOT the body ex (pre, post, where...)
|
||||||
@@ -136,9 +139,12 @@ class PythonEvaluator(OneReturnValueEvaluator):
|
|||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
if concepts_entries is None:
|
if concepts_entries is None:
|
||||||
concepts_entries = self.get_concepts_entries_from_globals(my_globals)
|
concepts_entries = self.get_concepts_entries_from_globals(my_globals)
|
||||||
errors.append(PythonEvalError(ex,
|
eval_error = PythonEvalError(ex,
|
||||||
traceback.format_exc() if context.debug_enabled else None,
|
traceback.format_exc() if get_trace_back else None,
|
||||||
self.get_concepts_values_from_globals(globals_, concepts_entries)))
|
self.get_concepts_values_from_globals(globals_, concepts_entries))
|
||||||
|
errors.append(eval_error)
|
||||||
|
exception_debugger.debug_var("exception", eval_error.error, is_error=True)
|
||||||
|
exception_debugger.debug_var("trace", eval_error.traceback, is_error=True)
|
||||||
|
|
||||||
if evaluated == NotInit:
|
if evaluated == NotInit:
|
||||||
if len(errors) == 1:
|
if len(errors) == 1:
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
from IPython.core.display import JSON
|
||||||
from core.sheerka.Sheerka import Sheerka
|
from core.sheerka.Sheerka import Sheerka
|
||||||
from ipykernel.ipkernel import IPythonKernel
|
from ipykernel.ipkernel import IPythonKernel
|
||||||
from ipykernel.kernelapp import IPKernelApp
|
from ipykernel.kernelapp import IPKernelApp
|
||||||
from sheerkapickle import encode
|
from sheerkapickle.SheerkaPickler import SheerkaPickler
|
||||||
|
|
||||||
|
|
||||||
class SheerkaKernel(IPythonKernel):
|
class SheerkaKernel(IPythonKernel):
|
||||||
@@ -25,12 +26,19 @@ class SheerkaKernel(IPythonKernel):
|
|||||||
|
|
||||||
def do_execute(self, code, silent, store_history=True, user_expressions=None, allow_stdin=False):
|
def do_execute(self, code, silent, store_history=True, user_expressions=None, allow_stdin=False):
|
||||||
result = self.sheerka.evaluate_user_input(code)
|
result = self.sheerka.evaluate_user_input(code)
|
||||||
|
# md = Markdown(f'<span style="color: {hexcolor}">{input_data}</span>')
|
||||||
|
as_json = JSON(SheerkaPickler(self.sheerka).flatten(result))
|
||||||
|
a = {
|
||||||
|
"a": "value1",
|
||||||
|
"b": "value2",
|
||||||
|
}
|
||||||
|
|
||||||
if not silent:
|
if not silent:
|
||||||
display_data_content = {
|
display_data_content = {
|
||||||
'data': {
|
'data': {
|
||||||
'text/plain': str(result),
|
# 'text/plain': str(result),
|
||||||
'application/json': encode(self.sheerka, result)
|
# "text/markdown": md._repr_markdown_(),
|
||||||
|
'application/json': JSON(a)._repr_json_(),
|
||||||
},
|
},
|
||||||
'metadata': {
|
'metadata': {
|
||||||
'application/json': {'expanded': True}
|
'application/json': {'expanded': True}
|
||||||
@@ -38,9 +46,8 @@ class SheerkaKernel(IPythonKernel):
|
|||||||
'execution_count': self.sheerka.execution_count,
|
'execution_count': self.sheerka.execution_count,
|
||||||
|
|
||||||
}
|
}
|
||||||
stream_content = {'name': 'stdout', 'text': display_data_content}
|
|
||||||
# self.send_response(self.iopub_socket, "stream", stream_content)
|
self.send_response(self.iopub_socket, "display_data", display_data_content)
|
||||||
self.send_response(self.iopub_socket, "execute_result", display_data_content)
|
|
||||||
|
|
||||||
return {'status': 'ok',
|
return {'status': 'ok',
|
||||||
# The base class increments the execution count
|
# The base class increments the execution count
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
from core.sheerka.services.SheerkaRuleManager import FormatAstNode
|
||||||
|
from core.utils import CONSOLE_COLORS_MAP as CCM, no_color_str
|
||||||
|
from out.OutVisitor import OutVisitor
|
||||||
|
|
||||||
|
get_start = re.compile(r"^([\(\{\[]\w*)")
|
||||||
|
|
||||||
|
|
||||||
|
class AsStrVisitor(OutVisitor):
|
||||||
|
|
||||||
|
def __init__(self, expand=False):
|
||||||
|
self.expand = expand
|
||||||
|
|
||||||
|
def visit_FormatAstRawText(self, format_ast):
|
||||||
|
return str(format_ast.text)
|
||||||
|
|
||||||
|
def visit_FormatAstVariable(self, format_ast):
|
||||||
|
if isinstance(format_ast.value, FormatAstNode):
|
||||||
|
value = self.visit(format_ast.value)
|
||||||
|
else:
|
||||||
|
value = format_ast.value
|
||||||
|
|
||||||
|
if format_ast.debug and isinstance(value, str):
|
||||||
|
value = "'" + str(value).translate(str.maketrans({"'": r"\'"})) + "'"
|
||||||
|
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
def visit_FormatAstVariableNotFound(self, format_ast):
|
||||||
|
return CCM["red"] + format_ast.name + CCM["reset"]
|
||||||
|
|
||||||
|
def visit_FormatAstColor(self, format_ast):
|
||||||
|
return CCM[format_ast.color] + self.visit(format_ast.format_ast) + CCM["reset"]
|
||||||
|
|
||||||
|
def visit_FormatAstSequence(self, format_ast):
|
||||||
|
return "".join([self.visit(item) for item in format_ast.items])
|
||||||
|
|
||||||
|
def visit_FormatAstList(self, format_ast):
|
||||||
|
first = True
|
||||||
|
result = ""
|
||||||
|
if format_ast.prefix:
|
||||||
|
result += format_ast.prefix
|
||||||
|
|
||||||
|
sep = ",\n" if self.expand else ", " if format_ast.debug else "\n"
|
||||||
|
|
||||||
|
for item in format_ast.items:
|
||||||
|
if not first:
|
||||||
|
result += sep
|
||||||
|
if format_ast.show_index:
|
||||||
|
result += f"[{item.index}] "
|
||||||
|
result += self.visit(item)
|
||||||
|
first = False
|
||||||
|
if format_ast.suffix:
|
||||||
|
result += format_ast.suffix
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def visit_FormatAstDict(self, format_ast):
|
||||||
|
first = True
|
||||||
|
result = ""
|
||||||
|
|
||||||
|
keys_values = []
|
||||||
|
max_len = 0
|
||||||
|
for k, v in format_ast.items:
|
||||||
|
value = self.visit(k)
|
||||||
|
len_value = len(no_color_str(value))
|
||||||
|
if len_value > max_len:
|
||||||
|
max_len = len_value
|
||||||
|
keys_values.append(value)
|
||||||
|
|
||||||
|
if format_ast.prefix:
|
||||||
|
result += format_ast.prefix
|
||||||
|
|
||||||
|
sep = ",\n" if self.expand else ", " if format_ast.debug else "\n"
|
||||||
|
|
||||||
|
for i, (k, v) in enumerate(format_ast.items):
|
||||||
|
start = "" if first else sep
|
||||||
|
|
||||||
|
key = f"{keys_values[i]:<{max_len}}" if (self.expand or not format_ast.debug) else keys_values[i]
|
||||||
|
colon = ": "
|
||||||
|
indent = len(no_color_str(key)) + len(colon)
|
||||||
|
value = self.visit(v)
|
||||||
|
if self.expand:
|
||||||
|
if m := get_start.match(no_color_str(value)):
|
||||||
|
indent += len(m.group(1))
|
||||||
|
value = value.replace("\n", "\n" + " " * indent)
|
||||||
|
first = False
|
||||||
|
|
||||||
|
result += start + key + colon + value
|
||||||
|
|
||||||
|
if format_ast.suffix:
|
||||||
|
result += format_ast.suffix
|
||||||
|
return result
|
||||||
+28
-40
@@ -1,55 +1,43 @@
|
|||||||
from out.OutVisitor import OutVisitor
|
from out.AsStrVisitor import AsStrVisitor
|
||||||
from core.sheerka.services.SheerkaRuleManager import FormatAstNode
|
|
||||||
|
|
||||||
|
|
||||||
class ConsoleVisitor(OutVisitor):
|
class ConsoleVisitor(AsStrVisitor):
|
||||||
"""
|
"""
|
||||||
Prints to the console
|
Prints to the console
|
||||||
"""
|
"""
|
||||||
COLORS = {
|
|
||||||
"reset": "\u001b[0m",
|
|
||||||
"black": "\u001b[30m",
|
|
||||||
"red": "\u001b[31m",
|
|
||||||
"green": "\u001b[32m",
|
|
||||||
"yellow": "\u001b[33m",
|
|
||||||
"blue": "\u001b[34m",
|
|
||||||
"magenta": "\u001b[35m",
|
|
||||||
"cyan": "\u001b[36m",
|
|
||||||
"white": "\u001b[37m",
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, expand_mode="auto"):
|
||||||
|
super().__init__()
|
||||||
self.out = print
|
self.out = print
|
||||||
|
self.expand_mode = expand_mode
|
||||||
|
|
||||||
def finalize(self):
|
def visit_FormatAstRawText(self, format_ast):
|
||||||
self.out("")
|
self.out(super().visit_FormatAstRawText(format_ast))
|
||||||
|
|
||||||
def visit_FormatAstRawText(self, context, format_ast, bag):
|
def visit_FormatAstVariable(self, format_ast):
|
||||||
self.out(format_ast.text, end="")
|
self.out(super().visit_FormatAstVariable(format_ast))
|
||||||
|
|
||||||
def visit_FormatAstVariable(self, context, format_ast, bag):
|
def visit_FormatAstVariableNotFound(self, format_ast):
|
||||||
if isinstance(format_ast.value, FormatAstNode):
|
self.out(super().visit_FormatAstVariableNotFound(format_ast))
|
||||||
self.visit(context, format_ast.value, bag)
|
|
||||||
return
|
|
||||||
self.out(format_ast.value, end="")
|
|
||||||
|
|
||||||
def visit_FormatAstVariableNotFound(self, context, format_ast, bag):
|
def visit_FormatAstColor(self, format_ast):
|
||||||
self.out(self.COLORS["red"] + format_ast.name + self.COLORS["reset"], end="")
|
self.out(super().visit_FormatAstColor(format_ast))
|
||||||
|
|
||||||
def visit_FormatAstSequence(self, context, format_ast, bag):
|
def visit_FormatAstSequence(self, format_ast):
|
||||||
for item in format_ast.items:
|
visitor = AsStrVisitor()
|
||||||
self.visit(context, item, bag)
|
self.out(visitor.visit_FormatAstSequence(format_ast))
|
||||||
|
|
||||||
def visit_FormatAstList(self, context, format_ast, bag):
|
def visit_FormatAstList(self, format_ast):
|
||||||
first = True
|
visitor = AsStrVisitor()
|
||||||
for item in format_ast.items:
|
res = visitor.visit_FormatAstList(format_ast)
|
||||||
if not first:
|
self.out(res)
|
||||||
self.out("") # print new line
|
|
||||||
self.visit(context, item, bag)
|
|
||||||
first = False
|
|
||||||
|
|
||||||
def visit_FormatAstColor(self, context, format_ast, bag):
|
def visit_FormatAstDict(self, format_ast):
|
||||||
self.out(self.COLORS[format_ast.color], end="")
|
if self.expand_mode == "always":
|
||||||
self.visit(context, format_ast.format_ast, bag)
|
expand = True
|
||||||
self.out(self.COLORS["reset"], end="")
|
else:
|
||||||
|
expand = False
|
||||||
|
|
||||||
|
visitor = AsStrVisitor(expand)
|
||||||
|
res = visitor.visit_FormatAstDict(format_ast)
|
||||||
|
self.out(res)
|
||||||
|
|||||||
+101
-46
@@ -1,31 +1,43 @@
|
|||||||
from core.sheerka.services.SheerkaRuleManager import FormatAstVariable, FormatAstVariableNotFound, FormatAstSequence, \
|
from core.sheerka.services.SheerkaRuleManager import FormatAstVariable, FormatAstVariableNotFound, FormatAstColor, \
|
||||||
FormatAstColor, FormatAstList, FormatAstRawText
|
FormatAstList, FormatAstRawText, FormatAstDict
|
||||||
from core.utils import evaluate_expression, as_bag
|
from core.utils import evaluate_expression, as_bag
|
||||||
from out.OutVisitor import OutVisitor
|
|
||||||
|
|
||||||
fstring = compile('f"{value:{format}}"', "DeveloperVisitor.fstring", mode="eval")
|
fstring = compile('f"{value:{format}}"', "DeveloperVisitor.fstring", mode="eval")
|
||||||
|
|
||||||
|
|
||||||
class DeveloperVisitor(OutVisitor):
|
class DeveloperVisitor:
|
||||||
"""
|
"""
|
||||||
This visitor is used to resolve all the variables as well as all the lists
|
This visitor is used to resolve all the variables as well as all the lists
|
||||||
Once completed, it will be passed to the ConsoleVisitor for console print
|
Once completed, it will be passed to the ConsoleVisitor for console print
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, sheerka_out, already_seen, list_recursion_depth):
|
def __init__(self, sheerka_out, debugger, already_seen, list_recursion_depth):
|
||||||
self._result = None
|
self._result = None
|
||||||
self.sheerka_out = sheerka_out
|
self.sheerka_out = sheerka_out
|
||||||
|
self.debugger = debugger
|
||||||
self.already_seen = already_seen
|
self.already_seen = already_seen
|
||||||
self.list_recursion_depth = list_recursion_depth
|
self.list_recursion_depth = list_recursion_depth
|
||||||
|
|
||||||
|
def visit(self, context, format_ast, bag):
|
||||||
|
name = format_ast.__class__.__name__
|
||||||
|
|
||||||
|
method = 'visit_' + name
|
||||||
|
visit_method = getattr(self, method, self.generic_visit)
|
||||||
|
return visit_method(context, format_ast, bag)
|
||||||
|
|
||||||
|
def generic_visit(self, context, format_ast, bag):
|
||||||
|
pass
|
||||||
|
|
||||||
def visit_FormatAstRawText(self, context, format_ast, bag):
|
def visit_FormatAstRawText(self, context, format_ast, bag):
|
||||||
if context.debug_enabled:
|
if self.debugger.is_enabled():
|
||||||
context.debug_entering("DeveloperVisitor", "visit_FormatAstRawText", format_ast=format_ast, bag=bag)
|
debug_bag = {"format_ast": format_ast, "bag": bag}
|
||||||
return self.set_result(format_ast)
|
self.debugger.debug_log(f"Entering visit_FormatAstRawText with {debug_bag}")
|
||||||
|
return format_ast
|
||||||
|
|
||||||
def visit_FormatAstVariable(self, context, format_ast, bag):
|
def visit_FormatAstVariable(self, context, format_ast, bag):
|
||||||
if context.debug_enabled:
|
if self.debugger.is_enabled():
|
||||||
context.debug_entering("DeveloperVisitor", "visit_FormatAstVariable", format_ast=format_ast, bag=bag)
|
debug_bag = {"format_ast": format_ast, "bag": bag}
|
||||||
|
self.debugger.debug_log(f"Entering visit_FormatAstVariable with {debug_bag}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
value = evaluate_expression(format_ast.name, bag)
|
value = evaluate_expression(format_ast.name, bag)
|
||||||
@@ -33,6 +45,8 @@ class DeveloperVisitor(OutVisitor):
|
|||||||
"__obj": value,
|
"__obj": value,
|
||||||
format_ast.name: value
|
format_ast.name: value
|
||||||
}
|
}
|
||||||
|
# create a bag entry with the last part of the variable
|
||||||
|
# eg: for __ret.status, creates an entry status
|
||||||
try:
|
try:
|
||||||
index = format_ast.name.rindex(".")
|
index = format_ast.name.rindex(".")
|
||||||
sub_bag[format_ast.name[index + 1:]] = value
|
sub_bag[format_ast.name[index + 1:]] = value
|
||||||
@@ -43,32 +57,31 @@ class DeveloperVisitor(OutVisitor):
|
|||||||
if format_ast.format:
|
if format_ast.format:
|
||||||
res = eval(fstring, {"value": res, "format": format_ast.format})
|
res = eval(fstring, {"value": res, "format": format_ast.format})
|
||||||
|
|
||||||
return self.set_result(FormatAstVariable(format_ast.name,
|
return format_ast.clone(value=res)
|
||||||
format_ast.format,
|
|
||||||
res,
|
|
||||||
format_ast.index))
|
|
||||||
|
|
||||||
except NameError as error:
|
except NameError as error:
|
||||||
context.debug("DeveloperVisitor", "visit_FormatAstList", "evaluate_expression", error, is_error=True)
|
context.debug("DeveloperVisitor", "visit_FormatAstList", "evaluate_expression", error, is_error=True)
|
||||||
return self.set_result(FormatAstVariableNotFound(format_ast.name))
|
return FormatAstVariableNotFound(format_ast.name)
|
||||||
|
|
||||||
def visit_FormatAstSequence(self, context, format_ast, bag):
|
def visit_FormatAstSequence(self, context, format_ast, bag):
|
||||||
if context.debug_enabled:
|
if self.debugger.is_enabled():
|
||||||
context.debug_entering("DeveloperVisitor", "visit_FormatAstSequence", format_ast=format_ast, bag=bag)
|
debug_bag = {"format_ast": format_ast, "bag": bag}
|
||||||
return self.set_result(FormatAstSequence([self.visit(context, item, bag) for item in format_ast.items]))
|
self.debugger.debug_log(f"Entering visit_FormatAstSequence with {debug_bag}")
|
||||||
|
return format_ast.clone(items=[self.visit(context, item, bag) for item in format_ast.items])
|
||||||
|
|
||||||
def visit_FormatAstColor(self, context, format_ast, bag):
|
def visit_FormatAstColor(self, context, format_ast, bag):
|
||||||
if context.debug_enabled:
|
if self.debugger.is_enabled():
|
||||||
context.debug_entering("DeveloperVisitor", "visit_FormatAstColor", format_ast=format_ast, bag=bag)
|
debug_bag = {"format_ast": format_ast, "bag": bag}
|
||||||
return self.set_result(FormatAstColor(format_ast.color, self.visit(context, format_ast.format_ast, bag)))
|
self.debugger.debug_log(f"Entering visit_FormatAstColor with {debug_bag}")
|
||||||
|
return format_ast.clone(format_ast=self.visit(context, format_ast.format_ast, bag))
|
||||||
|
|
||||||
def visit_FormatAstList(self, context, format_ast, bag):
|
def visit_FormatAstList(self, context, format_ast, bag):
|
||||||
if context.debug_enabled:
|
if self.debugger.is_enabled():
|
||||||
context.debug_entering("DeveloperVisitor", "visit_FormatAstList", format_ast=format_ast, bag=bag)
|
debug_bag = {"format_ast": format_ast, "bag": bag}
|
||||||
|
self.debugger.debug_log(f"Entering visit_FormatAstList with {debug_bag}")
|
||||||
try:
|
try:
|
||||||
value = evaluate_expression(format_ast.variable, bag)
|
value = evaluate_expression(format_ast.variable, bag)
|
||||||
if value is None:
|
if value is None:
|
||||||
return self.set_result(FormatAstVariable(format_ast.variable, format_ast.format, None))
|
return FormatAstVariable(format_ast.variable, format_ast.format, value=None)
|
||||||
|
|
||||||
if hasattr(value, "__iter__"):
|
if hasattr(value, "__iter__"):
|
||||||
items = value
|
items = value
|
||||||
@@ -78,22 +91,29 @@ class DeveloperVisitor(OutVisitor):
|
|||||||
items = evaluate_expression(f"self.{items_props}", {"self": value})
|
items = evaluate_expression(f"self.{items_props}", {"self": value})
|
||||||
if not hasattr(items, "__iter__"):
|
if not hasattr(items, "__iter__"):
|
||||||
# Definition error ? No list found
|
# Definition error ? No list found
|
||||||
return self.set_result(FormatAstVariable(format_ast.variable, None, value))
|
return FormatAstVariable(format_ast.variable, value=value)
|
||||||
|
|
||||||
recursion_depth, recurse_on = self.get_recurse_info(value, format_ast.recursion_depth, format_ast.recurse_on)
|
recursion_depth, recurse_on = self.get_recurse_info(value, format_ast.recursion_depth,
|
||||||
|
format_ast.recurse_on)
|
||||||
|
|
||||||
result = [] # TODO change into generator
|
result = [] # TODO change into generator
|
||||||
for i, item in enumerate(items):
|
for i, item in enumerate(items):
|
||||||
bag["__item"] = item
|
bag["__item"] = item
|
||||||
sub_visitor = DeveloperVisitor(self.sheerka_out, set(), self.list_recursion_depth)
|
sub_visitor = DeveloperVisitor(self.sheerka_out, self.debugger, set(), self.list_recursion_depth)
|
||||||
result.append(sub_visitor.visit(context, FormatAstVariable("__item", None, item, i), bag))
|
result.append(sub_visitor.visit(context, FormatAstVariable("__item",
|
||||||
|
debug=format_ast.debug,
|
||||||
|
value=item,
|
||||||
|
index=i), bag))
|
||||||
|
|
||||||
# recursion management
|
# recursion management
|
||||||
recursion_depth, recurse_on = self.get_recurse_info(item, recursion_depth, recurse_on)
|
recursion_depth, recurse_on = self.get_recurse_info(item, recursion_depth, recurse_on)
|
||||||
if recursion_depth > 0:
|
if recursion_depth > 0:
|
||||||
sub_items = evaluate_expression(recurse_on, as_bag(item))
|
sub_items = evaluate_expression(recurse_on, as_bag(item))
|
||||||
if sub_items and hasattr(sub_items, "__iter__"):
|
if sub_items and hasattr(sub_items, "__iter__"):
|
||||||
sub_visitor = DeveloperVisitor(self.sheerka_out, set(), self.list_recursion_depth + 1)
|
sub_visitor = DeveloperVisitor(self.sheerka_out,
|
||||||
|
self.debugger,
|
||||||
|
set(),
|
||||||
|
self.list_recursion_depth + 1)
|
||||||
bag[f"__{recurse_on}"] = sub_items
|
bag[f"__{recurse_on}"] = sub_items
|
||||||
|
|
||||||
sub_items = sub_visitor.visit(context, FormatAstList(f"__{recurse_on}",
|
sub_items = sub_visitor.visit(context, FormatAstList(f"__{recurse_on}",
|
||||||
@@ -102,29 +122,64 @@ class DeveloperVisitor(OutVisitor):
|
|||||||
recursion_depth - 1), bag)
|
recursion_depth - 1), bag)
|
||||||
result.append(sub_items)
|
result.append(sub_items)
|
||||||
|
|
||||||
return self.set_result(FormatAstList(variable=format_ast.variable,
|
return format_ast.clone(recurse_on=recurse_on, recursion_depth=recursion_depth, items=result)
|
||||||
items_prop=format_ast.items_prop,
|
|
||||||
recurse_on=recurse_on,
|
|
||||||
recursion_depth=recursion_depth,
|
|
||||||
items=result))
|
|
||||||
except NameError as error:
|
except NameError as error:
|
||||||
context.debug("DeveloperVisitor", "visit_FormatAstList", "evaluate_expression", error, is_error=True)
|
self.debugger.debug_log(error, is_error=True)
|
||||||
var_name = format_ast.variable if error.args[0] == format_ast.variable else \
|
var_name = format_ast.variable if error.args[0] == format_ast.variable else \
|
||||||
format_ast.variable + "." + error.args[0]
|
format_ast.variable + "." + error.args[0]
|
||||||
return self.set_result(FormatAstVariableNotFound(var_name))
|
return FormatAstVariableNotFound(var_name)
|
||||||
|
|
||||||
def visit_FormatAstFunction(self, context, format_ast, bag):
|
def visit_FormatAstFunction(self, context, format_ast, bag):
|
||||||
if context.debug_enabled:
|
if self.debugger.is_enabled():
|
||||||
context.debug_entering("DeveloperVisitor", "visit_FormatAstFunction", format_ast=format_ast, bag=bag)
|
debug_bag = {"format_ast": format_ast, "bag": bag}
|
||||||
unknown = FormatAstColor("red", FormatAstRawText(f"function '{format_ast.name}' is unknown"))
|
self.debugger.debug_log(f"Entering visit_FormatAstFunction with {debug_bag}")
|
||||||
return self.set_result(unknown)
|
return FormatAstColor("red", FormatAstRawText(f"function '{format_ast.name}' is unknown"))
|
||||||
|
|
||||||
def set_result(self, result):
|
def visit_FormatAstDict(self, context, format_ast, bag):
|
||||||
self._result = result
|
if self.debugger.is_enabled():
|
||||||
return result
|
debug_bag = {"format_ast": format_ast, "bag": bag}
|
||||||
|
self.debugger.debug_log(f"Entering visit_FormatAstDict with {debug_bag}")
|
||||||
|
|
||||||
def get_result(self):
|
try:
|
||||||
return self._result
|
result = []
|
||||||
|
|
||||||
|
value = evaluate_expression(format_ast.variable, bag)
|
||||||
|
if value is None:
|
||||||
|
return FormatAstVariable(format_ast.variable, format_ast.format, value=None)
|
||||||
|
|
||||||
|
if isinstance(value, dict):
|
||||||
|
items = value
|
||||||
|
else:
|
||||||
|
# the variable does not resolve to a dictionary, let's look at one of its attribute
|
||||||
|
items_props = format_ast.items_prop or "body"
|
||||||
|
items = evaluate_expression(f"self.{items_props}", {"self": value})
|
||||||
|
if not isinstance(items, dict):
|
||||||
|
# Definition error ? No Dictionary found
|
||||||
|
return FormatAstVariable(format_ast.variable, value=value)
|
||||||
|
|
||||||
|
for i, (k, v) in enumerate(items.items()):
|
||||||
|
bag["__key"] = k
|
||||||
|
key_visitor = DeveloperVisitor(self.sheerka_out, self.debugger, set(), self.list_recursion_depth)
|
||||||
|
key_res = key_visitor.visit(context,
|
||||||
|
FormatAstVariable("__key", value=k, index=i, debug=format_ast.debug),
|
||||||
|
bag)
|
||||||
|
|
||||||
|
bag["__value"] = v
|
||||||
|
value_visitor = DeveloperVisitor(self.sheerka_out, self.debugger, set(), self.list_recursion_depth)
|
||||||
|
to_visit = FormatAstDict("__value", debug=True, prefix='{', suffix='}') if isinstance(v, dict) else \
|
||||||
|
FormatAstList("__value", debug=True, prefix='[', suffix=']') if isinstance(v, list) else \
|
||||||
|
FormatAstVariable("__value", value=v, index=k, debug=format_ast.debug)
|
||||||
|
|
||||||
|
value_res = value_visitor.visit(context, to_visit, bag)
|
||||||
|
|
||||||
|
result.append((key_res, value_res))
|
||||||
|
|
||||||
|
return format_ast.clone(items=result)
|
||||||
|
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
|
@staticmethod
|
||||||
def get_recurse_info(obj, recursion_depth, recurse_on):
|
def get_recurse_info(obj, recursion_depth, recurse_on):
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
class OutVisitor:
|
class OutVisitor:
|
||||||
def visit(self, context, format_ast, bag):
|
def visit(self, format_ast):
|
||||||
name = format_ast.__class__.__name__
|
name = format_ast.__class__.__name__
|
||||||
|
|
||||||
method = 'visit_' + name
|
method = 'visit_' + name
|
||||||
visit_method = getattr(self, method, self.generic_visit)
|
visit_method = getattr(self, method, self.generic_visit)
|
||||||
return visit_method(context, format_ast, bag)
|
return visit_method(format_ast)
|
||||||
|
|
||||||
def generic_visit(self, context, format_ast, bag):
|
def generic_visit(self, format_ast):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -37,10 +37,15 @@ class PythonNode(Node):
|
|||||||
|
|
||||||
def __init__(self, source, ast_=None, objects=None):
|
def __init__(self, source, ast_=None, objects=None):
|
||||||
self.source = source
|
self.source = source
|
||||||
self.ast_ = ast_ if ast_ else ast.parse(source, mode="eval") if source else None
|
self.ast_ = ast_ # if ast_ else ast.parse(source, mode="eval") if source else None
|
||||||
self.objects = objects or {} # when objects (mainly concepts or rules) are recognized in the expression
|
self.objects = objects or {} # when objects (mainly concepts or rules) are recognized in the expression
|
||||||
self.compiled = None
|
self.compiled = None
|
||||||
|
|
||||||
|
def init_ast(self):
|
||||||
|
if self.ast_ is None and self.source:
|
||||||
|
self.ast_ = ast.parse(self.source, mode="eval")
|
||||||
|
return self
|
||||||
|
|
||||||
def get_compiled(self):
|
def get_compiled(self):
|
||||||
if self.compiled is None:
|
if self.compiled is None:
|
||||||
self.compiled = compile(self.ast_, "<string>", "eval")
|
self.compiled = compile(self.ast_, "<string>", "eval")
|
||||||
@@ -60,10 +65,12 @@ class PythonNode(Node):
|
|||||||
if self.source != other.source:
|
if self.source != other.source:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self_dump = self.get_dump(self.ast_)
|
if self.ast_ and other.ast_:
|
||||||
other_dump = self.get_dump(other.ast_)
|
self_dump = self.get_dump(self.ast_)
|
||||||
|
other_dump = self.get_dump(other.ast_)
|
||||||
|
return self_dump == other_dump
|
||||||
|
|
||||||
return self_dump == other_dump
|
return True
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash((self.source, self.ast_.hash))
|
return hash((self.source, self.ast_.hash))
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
|||||||
def test_i_can_evaluate_when_compiled_is_set_up_with_return_value(self):
|
def test_i_can_evaluate_when_compiled_is_set_up_with_return_value(self):
|
||||||
sheerka = self.get_sheerka()
|
sheerka = self.get_sheerka()
|
||||||
|
|
||||||
python_node = PythonNode("1 +1 ")
|
python_node = PythonNode("1 +1 ").init_ast()
|
||||||
parser_result = ParserResultConcept(parser="who", value=python_node)
|
parser_result = ParserResultConcept(parser="who", value=python_node)
|
||||||
|
|
||||||
concept = Concept("to_eval").def_var("prop")
|
concept = Concept("to_eval").def_var("prop")
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from core.global_symbols import RULE_COMPARISON_CONTEXT
|
|||||||
from core.rule import Rule
|
from core.rule import Rule
|
||||||
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, FormatRuleParser, \
|
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, FormatRuleParser, \
|
||||||
FormatAstRawText, FormatAstVariable, FormatAstSequence, FormatAstFunction, \
|
FormatAstRawText, FormatAstVariable, FormatAstSequence, FormatAstFunction, \
|
||||||
FormatRuleSyntaxError, FormatAstList, UnexpectedEof, FormatAstColor, RulePredicate
|
FormatRuleSyntaxError, FormatAstList, UnexpectedEof, FormatAstColor, RulePredicate, FormatAstDict
|
||||||
from core.tokenizer import Token, TokenKind
|
from core.tokenizer import Token, TokenKind
|
||||||
from parsers.BaseNodeParser import SourceCodeWithConceptNode, SourceCodeNode
|
from parsers.BaseNodeParser import SourceCodeWithConceptNode, SourceCodeNode
|
||||||
from parsers.PythonParser import PythonNode
|
from parsers.PythonParser import PythonNode
|
||||||
@@ -102,8 +102,8 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
|
|||||||
('green("")', FormatAstColor("green", raw(""))),
|
('green("")', FormatAstColor("green", raw(""))),
|
||||||
("list(var_name, 2, 'children')", FormatAstList("var_name", recurse_on="children", recursion_depth=2)),
|
("list(var_name, 2, 'children')", FormatAstList("var_name", recurse_on="children", recursion_depth=2)),
|
||||||
("list(var_name, recursion_depth=2, recurse_on='children')", FormatAstList("var_name",
|
("list(var_name, recursion_depth=2, recurse_on='children')", FormatAstList("var_name",
|
||||||
recurse_on="children",
|
recurse_on="children",
|
||||||
recursion_depth=2)),
|
recursion_depth=2)),
|
||||||
("list(var_name, recursion_depth=2, 'children')", FormatAstList("var_name", recursion_depth=2)),
|
("list(var_name, recursion_depth=2, 'children')", FormatAstList("var_name", recursion_depth=2)),
|
||||||
("list(var_name, 'children', recursion_depth=2)", FormatAstList("var_name", recursion_depth=2)),
|
("list(var_name, 'children', recursion_depth=2)", FormatAstList("var_name", recursion_depth=2)),
|
||||||
("list(var_name)", FormatAstList("var_name")),
|
("list(var_name)", FormatAstList("var_name")),
|
||||||
@@ -112,6 +112,9 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
|
|||||||
("{variable:format}", FormatAstVariable("variable", "format")),
|
("{variable:format}", FormatAstVariable("variable", "format")),
|
||||||
("{variable:3}", FormatAstVariable("variable", "3")),
|
("{variable:3}", FormatAstVariable("variable", "3")),
|
||||||
(r"\not_a_function(a={var})", seq([raw("not_a_function(a="), var("var"), raw(")")])),
|
(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="}"))
|
||||||
])
|
])
|
||||||
def test_i_can_parse_format_rule(self, text, expected):
|
def test_i_can_parse_format_rule(self, text, expected):
|
||||||
assert FormatRuleParser(text).parse() == expected
|
assert FormatRuleParser(text).parse() == expected
|
||||||
@@ -129,10 +132,11 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
|
|||||||
("red(xy {v})", FormatRuleSyntaxError("Invalid identifier", None)),
|
("red(xy {v})", FormatRuleSyntaxError("Invalid identifier", None)),
|
||||||
("list()", FormatRuleSyntaxError("variable name not found", None)),
|
("list()", FormatRuleSyntaxError("variable name not found", None)),
|
||||||
("list(recursion_depth=2)", FormatRuleSyntaxError("variable name not found", None)),
|
("list(recursion_depth=2)", FormatRuleSyntaxError("variable name not found", None)),
|
||||||
("list(a,b,c,d)", FormatRuleSyntaxError("too many positional arguments",
|
("list(a,b,c,d,e)", FormatRuleSyntaxError("too many positional arguments",
|
||||||
Token(TokenKind.IDENTIFIER, "d", 11, 1, 12))),
|
Token(TokenKind.IDENTIFIER, "e", 13, 1, 14))),
|
||||||
("list(a, recursion_depth=hello)", FormatRuleSyntaxError("'hello' is not numeric", None)),
|
("list(a, recursion_depth=hello)", FormatRuleSyntaxError("'hello' is not numeric", None)),
|
||||||
("list(a, recursion_depth='hello')", FormatRuleSyntaxError("'recursion_depth' must be an integer", None)),
|
("list(a, recursion_depth='hello')", FormatRuleSyntaxError("'recursion_depth' must be an integer", None)),
|
||||||
|
("dict()", FormatRuleSyntaxError("variable name not found", None)),
|
||||||
])
|
])
|
||||||
def test_i_cannot_parse_invalid_format(self, text, expected_error):
|
def test_i_cannot_parse_invalid_format(self, text, expected_error):
|
||||||
parser = FormatRuleParser(text)
|
parser = FormatRuleParser(text)
|
||||||
|
|||||||
@@ -0,0 +1,168 @@
|
|||||||
|
import pytest
|
||||||
|
from core.sheerka.services.SheerkaRuleManager import FormatAstRawText, FormatAstVariable, FormatAstVariableNotFound, \
|
||||||
|
FormatAstSequence, FormatAstList, FormatAstDict
|
||||||
|
from out.AsStrVisitor import AsStrVisitor
|
||||||
|
|
||||||
|
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||||
|
|
||||||
|
|
||||||
|
class TestAsStrVisitor(TestUsingMemoryBasedSheerka):
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("format_text, expected", [
|
||||||
|
(FormatAstRawText("hello word"), "hello word"),
|
||||||
|
(FormatAstVariable('xxx', value="hello word"), "hello word"),
|
||||||
|
(FormatAstVariable('xxx', value=1), "1"),
|
||||||
|
(FormatAstVariable('xxx', value=1.5), "1.5"),
|
||||||
|
(FormatAstVariable('xxx', value="hello word", debug=True), "'hello word'"),
|
||||||
|
(FormatAstVariable('xxx', value=1, debug=True), "1"),
|
||||||
|
(FormatAstVariable('xxx', value=1.5, debug=True), "1.5"),
|
||||||
|
(FormatAstVariable('xxx', value=False, debug=True), "False"),
|
||||||
|
(FormatAstVariableNotFound('va_name'), "\x1b[31mva_name\x1b[0m"),
|
||||||
|
])
|
||||||
|
def test_i_can_print_simple_ast(self, format_text, expected):
|
||||||
|
visitor = AsStrVisitor()
|
||||||
|
|
||||||
|
res = visitor.visit(format_text)
|
||||||
|
assert res == expected
|
||||||
|
|
||||||
|
def test_i_can_print_sequence(self, capsys):
|
||||||
|
visitor = AsStrVisitor()
|
||||||
|
sequence = FormatAstSequence([
|
||||||
|
FormatAstRawText("hello word"),
|
||||||
|
FormatAstVariable('xxx', value=1),
|
||||||
|
FormatAstVariableNotFound('va_name'),
|
||||||
|
FormatAstVariable('xxx', value="hello word", debug=True)
|
||||||
|
])
|
||||||
|
|
||||||
|
res = visitor.visit(sequence)
|
||||||
|
|
||||||
|
assert res == "hello word1\x1b[31mva_name\x1b[0m'hello word'"
|
||||||
|
|
||||||
|
def test_i_can_print_list(self, capsys):
|
||||||
|
visitor = AsStrVisitor()
|
||||||
|
lst = FormatAstList("xxx", items=[
|
||||||
|
FormatAstVariable('__item', index=0, value="first element"),
|
||||||
|
FormatAstVariable('__item', index=1, value="second element", debug=True),
|
||||||
|
])
|
||||||
|
|
||||||
|
res = visitor.visit(lst)
|
||||||
|
|
||||||
|
assert res == "first element\n'second element'"
|
||||||
|
|
||||||
|
def test_i_can_print_list_with_sub_items(self, capsys):
|
||||||
|
visitor = AsStrVisitor()
|
||||||
|
lst = FormatAstList("xxx", items=[
|
||||||
|
FormatAstVariable('__item', index=0, value="first element"),
|
||||||
|
FormatAstList("__sub", items=[
|
||||||
|
FormatAstVariable('__item', index=0, value="sub item 1"),
|
||||||
|
FormatAstVariable('__item', index=1, value="sub item 2"),
|
||||||
|
]),
|
||||||
|
FormatAstVariable('__item', index=1, value="second element", debug=True),
|
||||||
|
])
|
||||||
|
|
||||||
|
res = visitor.visit(lst)
|
||||||
|
|
||||||
|
assert res == "first element\nsub item 1\nsub item 2\n'second element'"
|
||||||
|
|
||||||
|
def test_i_can_print_list_in_debug_mode(self, capsys):
|
||||||
|
visitor = AsStrVisitor()
|
||||||
|
lst = FormatAstList("xxx", debug=True, prefix="[", suffix="]", items=[
|
||||||
|
FormatAstVariable('__item', index=0, value="first element", debug=True),
|
||||||
|
FormatAstVariable('__item', index=1, value="second element", debug=True),
|
||||||
|
])
|
||||||
|
|
||||||
|
res = visitor.visit(lst)
|
||||||
|
|
||||||
|
assert res == "['first element', 'second element']"
|
||||||
|
|
||||||
|
def test_i_can_print_expanded_list_in_debug_mode(self):
|
||||||
|
visitor = AsStrVisitor(expand=True)
|
||||||
|
lst = FormatAstList("xxx", debug=True, prefix="[", suffix="]", items=[
|
||||||
|
FormatAstVariable('__item', index=0, value="first element", debug=True),
|
||||||
|
FormatAstVariable('__item', index=1, value="second element", debug=True),
|
||||||
|
])
|
||||||
|
|
||||||
|
res = visitor.visit(lst)
|
||||||
|
|
||||||
|
assert res == "['first element',\n'second element']"
|
||||||
|
|
||||||
|
def test_i_can_print_list_with_index(self):
|
||||||
|
visitor = AsStrVisitor()
|
||||||
|
lst = FormatAstList("xxx", show_index=True, items=[
|
||||||
|
FormatAstVariable('__item', index=0, value="first element"),
|
||||||
|
FormatAstVariable('__item', index=1, value="second element", debug=True),
|
||||||
|
])
|
||||||
|
|
||||||
|
res = visitor.visit(lst)
|
||||||
|
|
||||||
|
assert res == "[0] first element\n[1] 'second element'"
|
||||||
|
|
||||||
|
def test_i_can_print_dict(self, capsys):
|
||||||
|
visitor = AsStrVisitor()
|
||||||
|
bag = FormatAstDict("xxx", items=[
|
||||||
|
(FormatAstVariable('__key', index=0, value="key1"),
|
||||||
|
FormatAstVariable('__value', index="key1", value=1)),
|
||||||
|
(FormatAstVariable('__key', index=1, value="long_key2"),
|
||||||
|
FormatAstVariable('__value', index="key2", value="value2")),
|
||||||
|
])
|
||||||
|
|
||||||
|
res = visitor.visit(bag)
|
||||||
|
|
||||||
|
assert res == "key1 : 1\nlong_key2: value2"
|
||||||
|
|
||||||
|
def test_i_can_print_dict_in_debug_mode(self, capsys):
|
||||||
|
visitor = AsStrVisitor()
|
||||||
|
bag = FormatAstDict("xxx", debug=True, prefix="{", suffix="}", items=[
|
||||||
|
(FormatAstVariable('__key', index=0, value="key1", debug=True),
|
||||||
|
FormatAstVariable('__value', index="key1", value=1, debug=True)),
|
||||||
|
(FormatAstVariable('__key', index=1, value="long_key2", debug=True),
|
||||||
|
FormatAstVariable('__value', index="key2", value="value2", debug=True)),
|
||||||
|
])
|
||||||
|
|
||||||
|
res = visitor.visit(bag)
|
||||||
|
|
||||||
|
assert res == "{'key1': 1, 'long_key2': 'value2'}"
|
||||||
|
|
||||||
|
def test_i_can_print_expanded_dict_in_debug_mode(self):
|
||||||
|
visitor = AsStrVisitor(expand=True)
|
||||||
|
bag = FormatAstDict("xxx", debug=True, prefix="{", suffix="}", items=[
|
||||||
|
(FormatAstVariable('__key', index=0, value="key1", debug=True),
|
||||||
|
FormatAstVariable('__value', index="key1", value=1, debug=True)),
|
||||||
|
(FormatAstVariable('__key', index=1, value="long_key2", debug=True),
|
||||||
|
FormatAstVariable('__value', index="key2", value="value2", debug=True)),
|
||||||
|
])
|
||||||
|
|
||||||
|
res = visitor.visit(bag)
|
||||||
|
|
||||||
|
assert res == "{'key1' : 1,\n'long_key2': 'value2'}"
|
||||||
|
|
||||||
|
def test_i_can_print_sub_level_of_dict_in_expand_mode(self):
|
||||||
|
visitor = AsStrVisitor(expand=True)
|
||||||
|
bag = FormatAstDict("xxx", debug=True, prefix="{", suffix="}", items=[
|
||||||
|
(FormatAstVariable('__key', index=0, value="key1", debug=True),
|
||||||
|
FormatAstVariable('__value', index="key1", value=1, debug=True)),
|
||||||
|
|
||||||
|
(FormatAstVariable('__key', index=0, value="key2", debug=True),
|
||||||
|
FormatAstDict("__value", debug=True, prefix="{", suffix="}", items=[
|
||||||
|
(FormatAstVariable('__key', index=0, value="sub_key1", debug=True),
|
||||||
|
FormatAstVariable('__value', index="sub_key1", value=1, debug=True)),
|
||||||
|
(FormatAstVariable('__key', index=1, value="sub_long_key2", debug=True),
|
||||||
|
FormatAstDict("__value", debug=True, prefix="{", suffix="}", items=[
|
||||||
|
(FormatAstVariable('__key', index=0, value="sub_sub_key1", debug=True),
|
||||||
|
FormatAstVariable('__value', index="sub_sub_key1", value=1, debug=True)),
|
||||||
|
(FormatAstVariable('__key', index=1, value="sub_sub_key2", debug=True),
|
||||||
|
FormatAstVariable('__value', index="sub_sub_key2", value="sub_sub_value", debug=True)),
|
||||||
|
])),
|
||||||
|
])),
|
||||||
|
|
||||||
|
(FormatAstVariable('__key', index=1, value="long_key3", debug=True),
|
||||||
|
FormatAstVariable('__value', index="key2", value="value2", debug=True)),
|
||||||
|
])
|
||||||
|
|
||||||
|
res = visitor.visit(bag)
|
||||||
|
|
||||||
|
assert res == """{'key1' : 1,
|
||||||
|
'key2' : {'sub_key1' : 1,
|
||||||
|
'sub_long_key2': {'sub_sub_key1': 1,
|
||||||
|
'sub_sub_key2': 'sub_sub_value'}},
|
||||||
|
'long_key3': 'value2'}"""
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
import pytest
|
||||||
|
from core.sheerka.services.SheerkaRuleManager import FormatAstRawText, FormatAstVariable, FormatAstVariableNotFound, \
|
||||||
|
FormatAstSequence, FormatAstList, FormatAstDict
|
||||||
|
from out.ConsoleVisistor import ConsoleVisitor
|
||||||
|
|
||||||
|
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||||
|
|
||||||
|
|
||||||
|
class TestConsoleVisitor(TestUsingMemoryBasedSheerka):
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("format_text, expected", [
|
||||||
|
(FormatAstRawText("hello word"), "hello word"),
|
||||||
|
(FormatAstVariable('xxx', value="hello word"), "hello word"),
|
||||||
|
(FormatAstVariable('xxx', value=1), "1"),
|
||||||
|
(FormatAstVariable('xxx', value=1.5), "1.5"),
|
||||||
|
(FormatAstVariable('xxx', value="hello word", debug=True), "'hello word'"),
|
||||||
|
(FormatAstVariable('xxx', value=1, debug=True), "1"),
|
||||||
|
(FormatAstVariable('xxx', value=1.5, debug=True), "1.5"),
|
||||||
|
(FormatAstVariable('xxx', value=False, debug=True), "False"),
|
||||||
|
(FormatAstVariableNotFound('va_name'), "\x1b[31mva_name\x1b[0m"),
|
||||||
|
])
|
||||||
|
def test_i_can_print_simple_ast(self, format_text, expected, capsys):
|
||||||
|
visitor = ConsoleVisitor()
|
||||||
|
|
||||||
|
visitor.visit(format_text)
|
||||||
|
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert captured.out == expected + "\n"
|
||||||
|
|
||||||
|
def test_i_can_print_sequence(self, capsys):
|
||||||
|
visitor = ConsoleVisitor()
|
||||||
|
sequence = FormatAstSequence([
|
||||||
|
FormatAstRawText("hello word"),
|
||||||
|
FormatAstVariable('xxx', value=1),
|
||||||
|
FormatAstVariableNotFound('va_name'),
|
||||||
|
FormatAstVariable('xxx', value="hello word", debug=True)
|
||||||
|
])
|
||||||
|
|
||||||
|
visitor.visit(sequence)
|
||||||
|
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert captured.out == "hello word1\x1b[31mva_name\x1b[0m'hello word'\n"
|
||||||
|
|
||||||
|
def test_i_can_print_list(self, capsys):
|
||||||
|
visitor = ConsoleVisitor()
|
||||||
|
lst = FormatAstList("xxx", items=[
|
||||||
|
FormatAstVariable('__item', index=0, value="first element"),
|
||||||
|
FormatAstVariable('__item', index=1, value="second element", debug=True),
|
||||||
|
])
|
||||||
|
|
||||||
|
visitor.visit(lst)
|
||||||
|
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert captured.out == "first element\n'second element'\n"
|
||||||
|
|
||||||
|
def test_i_can_print_list_with_sub_items(self, capsys):
|
||||||
|
visitor = ConsoleVisitor()
|
||||||
|
lst = FormatAstList("xxx", items=[
|
||||||
|
FormatAstVariable('__item', index=0, value="first element"),
|
||||||
|
FormatAstList("__sub", items=[
|
||||||
|
FormatAstVariable('__item', index=0, value="sub item 1"),
|
||||||
|
FormatAstVariable('__item', index=1, value="sub item 2"),
|
||||||
|
]),
|
||||||
|
FormatAstVariable('__item', index=1, value="second element", debug=True),
|
||||||
|
])
|
||||||
|
|
||||||
|
visitor.visit(lst)
|
||||||
|
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert captured.out == "first element\nsub item 1\nsub item 2\n'second element'\n"
|
||||||
|
|
||||||
|
def test_i_can_print_list_in_debug_mode(self, capsys):
|
||||||
|
visitor = ConsoleVisitor()
|
||||||
|
lst = FormatAstList("xxx", debug=True, prefix="[", suffix="]", items=[
|
||||||
|
FormatAstVariable('__item', index=0, value="first element", debug=True),
|
||||||
|
FormatAstVariable('__item', index=1, value="second element", debug=True),
|
||||||
|
])
|
||||||
|
|
||||||
|
visitor.visit(lst)
|
||||||
|
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert captured.out == "['first element', 'second element']\n"
|
||||||
|
|
||||||
|
def test_i_can_print_dict(self, capsys):
|
||||||
|
visitor = ConsoleVisitor()
|
||||||
|
bag = FormatAstDict("xxx", items=[
|
||||||
|
(FormatAstVariable('__key', index=0, value="key1"),
|
||||||
|
FormatAstVariable('__value', index="key1", value=1)),
|
||||||
|
(FormatAstVariable('__key', index=1, value="long_key2"),
|
||||||
|
FormatAstVariable('__value', index="key2", value="value2")),
|
||||||
|
])
|
||||||
|
|
||||||
|
visitor.visit(bag)
|
||||||
|
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert captured.out == "key1 : 1\nlong_key2: value2\n"
|
||||||
|
|
||||||
|
def test_i_can_print_dict_in_debug_mode(self, capsys):
|
||||||
|
visitor = ConsoleVisitor()
|
||||||
|
bag = FormatAstDict("xxx", debug=True, prefix="{", suffix="}", items=[
|
||||||
|
(FormatAstVariable('__key', index=0, value="key1", debug=True),
|
||||||
|
FormatAstVariable('__value', index="key1", value=1, debug=True)),
|
||||||
|
(FormatAstVariable('__key', index=1, value="long_key2", debug=True),
|
||||||
|
FormatAstVariable('__value', index="key2", value="value2", debug=True)),
|
||||||
|
])
|
||||||
|
|
||||||
|
visitor.visit(bag)
|
||||||
|
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert captured.out == "{'key1': 1, 'long_key2': 'value2'}\n"
|
||||||
|
|
||||||
|
def test_i_can_print_sub_level_of_dict_in_expand_mode(self, capsys):
|
||||||
|
visitor = ConsoleVisitor(expand_mode='always')
|
||||||
|
bag = FormatAstDict("xxx", debug=True, prefix="{", suffix="}", items=[
|
||||||
|
(FormatAstVariable('__key', index=0, value="key1", debug=True),
|
||||||
|
FormatAstVariable('__value', index="key1", value=1, debug=True)),
|
||||||
|
|
||||||
|
(FormatAstVariable('__key', index=0, value="key2", debug=True),
|
||||||
|
FormatAstDict("__value", debug=True, prefix="{", suffix="}", items=[
|
||||||
|
(FormatAstVariable('__key', index=0, value="sub_key1", debug=True),
|
||||||
|
FormatAstVariable('__value', index="sub_key1", value=1, debug=True)),
|
||||||
|
(FormatAstVariable('__key', index=1, value="sub_long_key2", debug=True),
|
||||||
|
FormatAstDict("__value", debug=True, prefix="{", suffix="}", items=[
|
||||||
|
(FormatAstVariable('__key', index=0, value="sub_sub_key1", debug=True),
|
||||||
|
FormatAstVariable('__value', index="sub_sub_key1", value=1, debug=True)),
|
||||||
|
(FormatAstVariable('__key', index=1, value="sub_sub_key2", debug=True),
|
||||||
|
FormatAstVariable('__value', index="sub_sub_key2", value="sub_sub_value", debug=True)),
|
||||||
|
])),
|
||||||
|
])),
|
||||||
|
|
||||||
|
(FormatAstVariable('__key', index=1, value="long_key3", debug=True),
|
||||||
|
FormatAstVariable('__value', index="key2", value="value2", debug=True)),
|
||||||
|
])
|
||||||
|
|
||||||
|
visitor.visit(bag)
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
|
||||||
|
assert captured.out == """{'key1' : 1,
|
||||||
|
'key2' : {'sub_key1' : 1,
|
||||||
|
'sub_long_key2': {'sub_sub_key1': 1,
|
||||||
|
'sub_sub_key2': 'sub_sub_value'}},
|
||||||
|
'long_key3': 'value2'}
|
||||||
|
"""
|
||||||
+127
-57
@@ -1,10 +1,12 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
|
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
|
||||||
from core.concept import Concept
|
from core.concept import Concept
|
||||||
from core.rule import Rule
|
from core.rule import Rule
|
||||||
from core.sheerka.services.SheerkaOut import SheerkaOut
|
from core.sheerka.services.SheerkaOut import SheerkaOut
|
||||||
from core.sheerka.services.SheerkaRuleManager import FormatAstRawText, FormatAstVariable, FormatAstSequence, \
|
from core.sheerka.services.SheerkaRuleManager import FormatAstRawText, FormatAstVariable, FormatAstSequence, \
|
||||||
FormatAstColor, FormatAstVariableNotFound, FormatAstList
|
FormatAstColor, FormatAstVariableNotFound, FormatAstList, FormatAstDict
|
||||||
from core.utils import flatten_all_children
|
from core.utils import flatten_all_children
|
||||||
|
|
||||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||||
@@ -14,6 +16,12 @@ raw = FormatAstRawText
|
|||||||
var = FormatAstVariable
|
var = FormatAstVariable
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DummyObj:
|
||||||
|
prop_1: float
|
||||||
|
prop_2: str
|
||||||
|
|
||||||
|
|
||||||
class TestSheerkaOut(TestUsingMemoryBasedSheerka):
|
class TestSheerkaOut(TestUsingMemoryBasedSheerka):
|
||||||
|
|
||||||
def init_service_with_rules(self, *rules, **kwargs):
|
def init_service_with_rules(self, *rules, **kwargs):
|
||||||
@@ -24,20 +32,20 @@ class TestSheerkaOut(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
@pytest.mark.parametrize("rule, expected", [
|
@pytest.mark.parametrize("rule, expected", [
|
||||||
(("__ret", "hello world"), FormatAstRawText("hello world")),
|
(("__ret", "hello world"), FormatAstRawText("hello world")),
|
||||||
(("__ret", "{__ret_value}"), FormatAstVariable("__ret_value", None, 1)),
|
(("__ret", "{__ret_value}"), FormatAstVariable("__ret_value", value=1)),
|
||||||
(("__ret", "{status}"), FormatAstVariable("status", None, True)),
|
(("__ret", "{status}"), FormatAstVariable("status", value=True)),
|
||||||
(("__ret", "{foo}"), FormatAstVariableNotFound("foo")),
|
(("__ret", "{foo}"), FormatAstVariableNotFound("foo")),
|
||||||
(("__ret", "hello world {__ret_value} !"), seq([FormatAstRawText("hello world "),
|
(("__ret", "hello world {__ret_value} !"), seq([FormatAstRawText("hello world "),
|
||||||
FormatAstVariable("__ret_value", None, 1),
|
FormatAstVariable("__ret_value", value=1),
|
||||||
FormatAstRawText(" !")])),
|
FormatAstRawText(" !")])),
|
||||||
(("__ret", "red(__ret_value)"), FormatAstColor("red", FormatAstVariable("__ret_value", None, 1))),
|
(("__ret", "red(__ret_value)"), FormatAstColor("red", FormatAstVariable("__ret_value", value=1))),
|
||||||
(("__ret", "blue('hello world {__ret_value} !')"), FormatAstColor("blue",
|
(("__ret", "blue('hello world {__ret_value} !')"), FormatAstColor("blue",
|
||||||
seq([FormatAstRawText("hello world "),
|
seq([FormatAstRawText("hello world "),
|
||||||
FormatAstVariable("__ret_value", None,
|
FormatAstVariable("__ret_value",
|
||||||
1),
|
value=1),
|
||||||
FormatAstRawText(" !")]))),
|
FormatAstRawText(" !")]))),
|
||||||
(("__ret", "list(foo)"), FormatAstVariableNotFound("foo")),
|
(("__ret", "list(foo)"), FormatAstVariableNotFound("foo")),
|
||||||
(("__ret", "{__ret_value:3}"), FormatAstVariable("__ret_value", "3", " 1"))
|
(("__ret", "{__ret_value:3}"), FormatAstVariable("__ret_value", "3", value=" 1"))
|
||||||
])
|
])
|
||||||
def test_i_can_develop_when_simple_rules(self, rule, expected):
|
def test_i_can_develop_when_simple_rules(self, rule, expected):
|
||||||
sheerka, context, service, rule = self.init_service_with_rules(rule)
|
sheerka, context, service, rule = self.init_service_with_rules(rule)
|
||||||
@@ -59,14 +67,14 @@ class TestSheerkaOut(TestUsingMemoryBasedSheerka):
|
|||||||
res = service.create_out_tree(context, ret)
|
res = service.create_out_tree(context, ret)
|
||||||
|
|
||||||
assert res == seq([FormatAstRawText("status: "),
|
assert res == seq([FormatAstRawText("status: "),
|
||||||
FormatAstVariable("status", None, True),
|
FormatAstVariable("status", value=True),
|
||||||
FormatAstRawText(", value: "),
|
FormatAstRawText(", value: "),
|
||||||
FormatAstVariable("__ret_value", None, seq([FormatAstVariable("id", None, "1001"),
|
FormatAstVariable("__ret_value", value=seq([FormatAstVariable("id", value="1001"),
|
||||||
FormatAstRawText("-"),
|
FormatAstRawText("-"),
|
||||||
FormatAstVariable("name", None, "foo"),
|
FormatAstVariable("name", value="foo"),
|
||||||
FormatAstRawText(":"),
|
FormatAstRawText(":"),
|
||||||
FormatAstVariable("body", None,
|
FormatAstVariable("body",
|
||||||
"hello world")]))])
|
value="hello world")]))])
|
||||||
|
|
||||||
@pytest.mark.parametrize('second_rule', [
|
@pytest.mark.parametrize('second_rule', [
|
||||||
("__ret.body", "{id}-{name}:{body}"),
|
("__ret.body", "{id}-{name}:{body}"),
|
||||||
@@ -84,23 +92,32 @@ class TestSheerkaOut(TestUsingMemoryBasedSheerka):
|
|||||||
res = service.create_out_tree(context, ret)
|
res = service.create_out_tree(context, ret)
|
||||||
|
|
||||||
assert res == seq([FormatAstRawText("status: "),
|
assert res == seq([FormatAstRawText("status: "),
|
||||||
FormatAstVariable("status", None, True),
|
FormatAstVariable("status", value=True),
|
||||||
FormatAstRawText(", value: "),
|
FormatAstRawText(", value: "),
|
||||||
FormatAstVariable("__ret.body", None, seq([FormatAstVariable("id", None, "1001"),
|
FormatAstVariable("__ret.body", value=seq([FormatAstVariable("id", value="1001"),
|
||||||
FormatAstRawText("-"),
|
FormatAstRawText("-"),
|
||||||
FormatAstVariable("name", None, "foo"),
|
FormatAstVariable("name", value="foo"),
|
||||||
FormatAstRawText(":"),
|
FormatAstRawText(":"),
|
||||||
FormatAstVariable("body", None,
|
FormatAstVariable("body",
|
||||||
"hello world")]))])
|
value="hello world")]))])
|
||||||
|
|
||||||
|
def test_i_can_develop_using_variable_properties(self):
|
||||||
|
sheerka, context, service, *rules = self.init_service_with_rules(
|
||||||
|
("isinstance(__obj, Concept)", "{__obj.body}"),
|
||||||
|
)
|
||||||
|
obj = Concept("bar", body="value for bar").auto_init()
|
||||||
|
|
||||||
|
res = service.create_out_tree(context, obj)
|
||||||
|
assert res == FormatAstVariable("__obj.body", value="value for bar")
|
||||||
|
|
||||||
def test_i_can_develop_list(self):
|
def test_i_can_develop_list(self):
|
||||||
sheerka, context, service, *rules = self.init_service_with_rules(("isinstance(__obj, list)", "list(__obj)"))
|
sheerka, context, service, *rules = self.init_service_with_rules(("isinstance(__obj, list)", "list(__obj)"))
|
||||||
lst = list(flatten_all_children(context, lambda item: item.achildren))[:3]
|
lst = list(flatten_all_children(context, lambda item: item.achildren))[:3]
|
||||||
|
|
||||||
res = service.create_out_tree(context, lst)
|
res = service.create_out_tree(context, lst)
|
||||||
assert res == FormatAstList(variable="__obj", items=[FormatAstVariable("__item", None, lst[0], 0),
|
assert res == FormatAstList(variable="__obj", items=[FormatAstVariable("__item", value=lst[0], index=0),
|
||||||
FormatAstVariable("__item", None, lst[1], 1),
|
FormatAstVariable("__item", value=lst[1], index=1),
|
||||||
FormatAstVariable("__item", None, lst[2], 2)])
|
FormatAstVariable("__item", value=lst[2], index=2)])
|
||||||
|
|
||||||
def test_i_can_develop_list_using_the_default_items_prop(self):
|
def test_i_can_develop_list_using_the_default_items_prop(self):
|
||||||
sheerka, context, service, *rules = self.init_service_with_rules(("isinstance(__obj, 'foo')", "list(__obj)"))
|
sheerka, context, service, *rules = self.init_service_with_rules(("isinstance(__obj, 'foo')", "list(__obj)"))
|
||||||
@@ -108,9 +125,9 @@ class TestSheerkaOut(TestUsingMemoryBasedSheerka):
|
|||||||
foo = Concept("foo", body=lst, key="foo").auto_init()
|
foo = Concept("foo", body=lst, key="foo").auto_init()
|
||||||
|
|
||||||
res = service.create_out_tree(context, foo)
|
res = service.create_out_tree(context, foo)
|
||||||
assert res == FormatAstList(variable="__obj", items=[FormatAstVariable("__item", None, lst[0], 0),
|
assert res == FormatAstList(variable="__obj", items=[FormatAstVariable("__item", value=lst[0], index=0),
|
||||||
FormatAstVariable("__item", None, lst[1], 1),
|
FormatAstVariable("__item", value=lst[1], index=1),
|
||||||
FormatAstVariable("__item", None, lst[2], 2)])
|
FormatAstVariable("__item", value=lst[2], index=2)])
|
||||||
|
|
||||||
def test_i_can_develop_list_using_the_custom_items_prop(self):
|
def test_i_can_develop_list_using_the_custom_items_prop(self):
|
||||||
sheerka, context, service, *rules = self.init_service_with_rules(
|
sheerka, context, service, *rules = self.init_service_with_rules(
|
||||||
@@ -121,16 +138,16 @@ class TestSheerkaOut(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
res = service.create_out_tree(context, foo)
|
res = service.create_out_tree(context, foo)
|
||||||
assert res == FormatAstList(variable="__obj", items_prop='custom',
|
assert res == FormatAstList(variable="__obj", items_prop='custom',
|
||||||
items=[FormatAstVariable("__item", None, lst[0], 0),
|
items=[FormatAstVariable("__item", value=lst[0], index=0),
|
||||||
FormatAstVariable("__item", None, lst[1], 1),
|
FormatAstVariable("__item", value=lst[1], index=1),
|
||||||
FormatAstVariable("__item", None, lst[2], 2)])
|
FormatAstVariable("__item", value=lst[2], index=2)])
|
||||||
|
|
||||||
def test_not_a_list_are_resolved_into_variable_ast(self):
|
def test_not_a_list_are_resolved_into_variable_ast(self):
|
||||||
sheerka, context, service, *rules = self.init_service_with_rules(("isinstance(__obj, 'foo')", "list(__obj)"))
|
sheerka, context, service, *rules = self.init_service_with_rules(("isinstance(__obj, 'foo')", "list(__obj)"))
|
||||||
foo = Concept("foo", key="foo")
|
foo = Concept("foo", key="foo")
|
||||||
|
|
||||||
res = service.create_out_tree(context, foo)
|
res = service.create_out_tree(context, foo)
|
||||||
assert res == FormatAstVariable("__obj", None, foo)
|
assert res == FormatAstVariable("__obj", value=foo)
|
||||||
|
|
||||||
def test_i_can_develop_list_of_return_values(self):
|
def test_i_can_develop_list_of_return_values(self):
|
||||||
sheerka, context, service, *rules = self.init_service_with_rules(("__rets", "list(__rets)"))
|
sheerka, context, service, *rules = self.init_service_with_rules(("__rets", "list(__rets)"))
|
||||||
@@ -140,9 +157,9 @@ class TestSheerkaOut(TestUsingMemoryBasedSheerka):
|
|||||||
]
|
]
|
||||||
|
|
||||||
res = service.create_out_tree(context, lst)
|
res = service.create_out_tree(context, lst)
|
||||||
assert res == FormatAstList(variable="__rets", items=[FormatAstVariable("__item", None, lst[0], 0),
|
assert res == FormatAstList(variable="__rets", items=[FormatAstVariable("__item", value=lst[0], index=0),
|
||||||
FormatAstVariable("__item", None, lst[1], 1),
|
FormatAstVariable("__item", value=lst[1], index=1),
|
||||||
FormatAstVariable("__item", None, lst[2], 2)])
|
FormatAstVariable("__item", value=lst[2], index=2)])
|
||||||
|
|
||||||
def test_rules_are_correctly_reset_when_list(self):
|
def test_rules_are_correctly_reset_when_list(self):
|
||||||
sheerka, context, service, *rules = self.init_service_with_rules(
|
sheerka, context, service, *rules = self.init_service_with_rules(
|
||||||
@@ -156,8 +173,8 @@ class TestSheerkaOut(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
res = service.create_out_tree(context, lst)
|
res = service.create_out_tree(context, lst)
|
||||||
assert res == FormatAstList(variable="__rets", items=[
|
assert res == FormatAstList(variable="__rets", items=[
|
||||||
FormatAstVariable("__item", None, FormatAstColor("red", FormatAstVariable("__ret", None, lst[0])), 0),
|
FormatAstVariable("__item", value=FormatAstColor("red", FormatAstVariable("__ret", value=lst[0])), index=0),
|
||||||
FormatAstVariable("__item", None, FormatAstColor("red", FormatAstVariable("__ret", None, lst[1])), 1),
|
FormatAstVariable("__item", value=FormatAstColor("red", FormatAstVariable("__ret", value=lst[1])), index=1),
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_i_can_develop_list_with_recurse(self):
|
def test_i_can_develop_list_with_recurse(self):
|
||||||
@@ -174,15 +191,15 @@ class TestSheerkaOut(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
res = service.create_out_tree(context, lst)
|
res = service.create_out_tree(context, lst)
|
||||||
assert res == FormatAstList(variable="__rets", recurse_on='parents', recursion_depth=2, items=[
|
assert res == FormatAstList(variable="__rets", recurse_on='parents', recursion_depth=2, items=[
|
||||||
FormatAstVariable("__item", None, r1, 0),
|
FormatAstVariable("__item", value=r1, index=0),
|
||||||
FormatAstList(variable="__parents", recurse_on='parents', recursion_depth=1, items=[
|
FormatAstList(variable="__parents", recurse_on='parents', recursion_depth=1, items=[
|
||||||
FormatAstVariable("__item", None, r11, 0),
|
FormatAstVariable("__item", value=r11, index=0),
|
||||||
FormatAstList(variable="__parents", recurse_on='parents', recursion_depth=0, items=[
|
FormatAstList(variable="__parents", recurse_on='parents', recursion_depth=0, items=[
|
||||||
FormatAstVariable("__item", None, r111, 0)])
|
FormatAstVariable("__item", value=r111, index=0)])
|
||||||
]),
|
]),
|
||||||
FormatAstVariable("__item", None, r2, 1),
|
FormatAstVariable("__item", value=r2, index=1),
|
||||||
FormatAstList(variable="__parents", recurse_on='parents', recursion_depth=1, items=[
|
FormatAstList(variable="__parents", recurse_on='parents', recursion_depth=1, items=[
|
||||||
FormatAstVariable("__item", None, r22, 0)]),
|
FormatAstVariable("__item", value=r22, index=0)]),
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_i_can_develop_list_with_recurse_using_container_format_instr(self):
|
def test_i_can_develop_list_with_recurse_using_container_format_instr(self):
|
||||||
@@ -200,29 +217,53 @@ class TestSheerkaOut(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
res = service.create_out_tree(context, foo)
|
res = service.create_out_tree(context, foo)
|
||||||
assert res == FormatAstList(variable="__obj", recurse_on='parents', recursion_depth=2, items=[
|
assert res == FormatAstList(variable="__obj", recurse_on='parents', recursion_depth=2, items=[
|
||||||
FormatAstVariable("__item", None, r1, 0),
|
FormatAstVariable("__item", value=r1, index=0),
|
||||||
FormatAstList(variable="__parents", recurse_on='parents', recursion_depth=1, items=[
|
FormatAstList(variable="__parents", recurse_on='parents', recursion_depth=1, items=[
|
||||||
FormatAstVariable("__item", None, r11, 0),
|
FormatAstVariable("__item", value=r11, index=0),
|
||||||
FormatAstList(variable="__parents", recurse_on='parents', recursion_depth=0, items=[
|
FormatAstList(variable="__parents", recurse_on='parents', recursion_depth=0, items=[
|
||||||
FormatAstVariable("__item", None, r111, 0)])
|
FormatAstVariable("__item", value=r111, index=0)])
|
||||||
]),
|
]),
|
||||||
FormatAstVariable("__item", None, r2, 1),
|
FormatAstVariable("__item", value=r2, index=1),
|
||||||
FormatAstList(variable="__parents", recurse_on='parents', recursion_depth=1, items=[
|
FormatAstList(variable="__parents", recurse_on='parents', recursion_depth=1, items=[
|
||||||
FormatAstVariable("__item", None, r22, 0)]),
|
FormatAstVariable("__item", value=r22, index=0)]),
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_i_can_develop_using_variable_properties(self):
|
def test_i_can_develop_dict(self):
|
||||||
sheerka, context, service, *rules = self.init_service_with_rules(
|
sheerka, context, service, *rules = self.init_service_with_rules(("isinstance(__obj, dict)", "dict(__obj)"))
|
||||||
("isinstance(__obj, Concept)", "{__obj.body}"),
|
obj = {
|
||||||
)
|
"key1": "value1",
|
||||||
lst = Concept("bar", body="value for bar").auto_init()
|
"key2": "value2",
|
||||||
|
}
|
||||||
|
|
||||||
res = service.create_out_tree(context, lst)
|
res = service.create_out_tree(context, obj)
|
||||||
assert res == FormatAstVariable("__obj.body", None, "value for bar")
|
assert res == FormatAstDict(variable="__obj", items=[
|
||||||
|
(FormatAstVariable("__key", value="key1", index=0),
|
||||||
|
FormatAstVariable("__value", value="value1", index="key1")),
|
||||||
|
(FormatAstVariable("__key", value="key2", index=1),
|
||||||
|
FormatAstVariable("__value", value="value2", index="key2")),
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_i_can_develop_dict_with_list(self):
|
||||||
|
sheerka, context, service, *rules = self.init_service_with_rules(("isinstance(__obj, dict)", "dict(__obj)"))
|
||||||
|
obj = {
|
||||||
|
"key1": "value1",
|
||||||
|
"key2": ["item1", "item2"],
|
||||||
|
}
|
||||||
|
|
||||||
|
res = service.create_out_tree(context, obj)
|
||||||
|
assert res == FormatAstDict(variable="__obj", items=[
|
||||||
|
(FormatAstVariable("__key", value="key1", index=0),
|
||||||
|
FormatAstVariable("__value", value="value1", index="key1")),
|
||||||
|
(FormatAstVariable("__key", value="key2", index=1),
|
||||||
|
FormatAstList(variable='__value', debug=True, prefix='[', suffix=']', items=[
|
||||||
|
FormatAstVariable("__item", debug=True, value="item1", index=0),
|
||||||
|
FormatAstVariable("__item", debug=True, value="item2", index=1),
|
||||||
|
])),
|
||||||
|
])
|
||||||
|
|
||||||
@pytest.mark.parametrize("rule, expected", [
|
@pytest.mark.parametrize("rule, expected", [
|
||||||
(("__ret", "red('hello world')"), FormatAstColor("red", FormatAstRawText("hello world"))),
|
(("__ret", "red('hello world')"), FormatAstColor("red", FormatAstRawText("hello world"))),
|
||||||
(("__ret", "blue(__ret_value)"), FormatAstColor("blue", FormatAstVariable("__ret_value", None, 1))),
|
(("__ret", "blue(__ret_value)"), FormatAstColor("blue", FormatAstVariable("__ret_value", value=1))),
|
||||||
])
|
])
|
||||||
def test_i_can_develop_color(self, rule, expected):
|
def test_i_can_develop_color(self, rule, expected):
|
||||||
sheerka, context, service, rule = self.init_service_with_rules(rule)
|
sheerka, context, service, rule = self.init_service_with_rules(rule)
|
||||||
@@ -233,12 +274,10 @@ class TestSheerkaOut(TestUsingMemoryBasedSheerka):
|
|||||||
assert res == expected
|
assert res == expected
|
||||||
|
|
||||||
@pytest.mark.parametrize("rule, expected", [
|
@pytest.mark.parametrize("rule, expected", [
|
||||||
(("__ret", "{__ret}"), FormatAstVariable("__ret", None,
|
(("__ret", "{__ret}"), FormatAstVariable("__ret", value=ReturnValueConcept(who="Test", status=True, value=1))),
|
||||||
ReturnValueConcept(who="Test", status=True, value=1))),
|
|
||||||
(("__ret", "magenta(__ret)"),
|
(("__ret", "magenta(__ret)"),
|
||||||
FormatAstColor("magenta",
|
FormatAstColor("magenta",
|
||||||
FormatAstVariable("__ret", None,
|
FormatAstVariable("__ret", value=ReturnValueConcept(who="Test", status=True, value=1)))),
|
||||||
ReturnValueConcept(who="Test", status=True, value=1)))),
|
|
||||||
])
|
])
|
||||||
def test_i_can_manage_infinite_recursion(self, rule, expected):
|
def test_i_can_manage_infinite_recursion(self, rule, expected):
|
||||||
sheerka, context, service, rule = self.init_service_with_rules(rule)
|
sheerka, context, service, rule = self.init_service_with_rules(rule)
|
||||||
@@ -258,8 +297,8 @@ class TestSheerkaOut(TestUsingMemoryBasedSheerka):
|
|||||||
res = service.create_out_tree(context, ret)
|
res = service.create_out_tree(context, ret)
|
||||||
|
|
||||||
assert res == FormatAstColor("white",
|
assert res == FormatAstColor("white",
|
||||||
FormatAstVariable("__ret", None,
|
FormatAstVariable("__ret",
|
||||||
FormatAstVariable("__ret.value", None, "hello world!")))
|
value=FormatAstVariable("__ret.value", value="hello world!")))
|
||||||
|
|
||||||
def test_i_can_print_out_the_result(self, capsys):
|
def test_i_can_print_out_the_result(self, capsys):
|
||||||
sheerka, context, service, *rules = self.init_service_with_rules(
|
sheerka, context, service, *rules = self.init_service_with_rules(
|
||||||
@@ -379,3 +418,34 @@ ReturnValue(who=Test, status=True, value=r2, message=None)
|
|||||||
service.process_return_values(context, ret)
|
service.process_return_values(context, ret)
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
assert captured.out == "status: \x1b[32mTrue\x1b[0m, \x1b[34mvalue: (1001)foo\x1b[0m\n"
|
assert captured.out == "status: \x1b[32mTrue\x1b[0m, \x1b[34mvalue: (1001)foo\x1b[0m\n"
|
||||||
|
|
||||||
|
def test_i_can_print_out_dict(self, capsys):
|
||||||
|
sheerka, context, service, *rules = self.init_service_with_rules(
|
||||||
|
("isinstance(__obj, dict)", "dict(__obj)"),
|
||||||
|
("__key=='key1'", "green(__key)")
|
||||||
|
)
|
||||||
|
obj = {
|
||||||
|
"key1": "value1",
|
||||||
|
"key2": "value2",
|
||||||
|
}
|
||||||
|
service.process_return_values(context, obj)
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert captured.out == """\x1b[32mkey1\x1b[0m: value1
|
||||||
|
key2: value2
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_i_can_print_out_dict_in_debug_mode(self, capsys):
|
||||||
|
sheerka, context, service, *rules = self.init_service_with_rules(
|
||||||
|
("isinstance(__obj, dict)", "dict(__obj, debug=True)"),
|
||||||
|
("__key=='key1'", "green(__key)")
|
||||||
|
)
|
||||||
|
obj = {
|
||||||
|
"key1": "value1",
|
||||||
|
"key2": 1,
|
||||||
|
"key3": DummyObj(3.15, "a string"),
|
||||||
|
"key4": ["alpha", 0]
|
||||||
|
}
|
||||||
|
service.process_return_values(context, obj)
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert captured.out == """{'\x1b[32mkey1\x1b[0m': 'value1', 'key2': 1, 'key3': DummyObj(prop_1=3.15, prop_2='a string'), 'key4': ['alpha', 0]}
|
||||||
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user