Added set of set handling (thru concept ISA)

This commit is contained in:
2020-02-17 21:07:06 +01:00
parent 7481b458e1
commit 86c2ff58d4
33 changed files with 635 additions and 232 deletions
+1 -1
View File
@@ -139,7 +139,7 @@ def concept_to_python(concept_node):
value = node.get_prop(field)
if isinstance(value, list) or isinstance(value, Concept) and value.key == str(BuiltinConcepts.LIST):
lst = []
for i in value:
for i in value.body:
lst.append(_transform(i))
setattr(ast_object, field, lst)
elif isinstance(value, NodeConcept):
+1 -3
View File
@@ -22,7 +22,7 @@ class ConceptNodeVisitor:
"""Called if no explicit visitor function exists for a node."""
for field, value in iter_props(node):
if isinstance(value, ListConcept):
for item in value:
for item in value.body:
if isinstance(item, NodeConcept):
self.visit(item)
elif isinstance(value, NodeConcept):
@@ -97,8 +97,6 @@ class ExtractPredicateVisitor(ConceptNodeVisitor):
self.variable_name = variable_name
def get_parents(node):
if node.parent is None:
return []
+17 -16
View File
@@ -52,6 +52,7 @@ class BuiltinConcepts(Enum):
NOT_A_SET = "not a set" # the concept has no entry in sets
WHERE_CLAUSE_FAILED = "where clause failed" # failed to validate where clause during evaluation
CHICKEN_AND_EGG = "chicken and egg" # infinite recursion when declaring concept
ISA = "is a" # builtin concept to express that a concept is an instance of another one
NODE = "node"
GENERIC_NODE = "generic node"
@@ -340,8 +341,8 @@ class EnumerationConcept(Concept):
self.set_metadata_value(ConceptParts.BODY, iteration)
self.metadata.is_evaluated = True
def __iter__(self):
return iter(self.body)
# def __iter__(self):
# return iter(self.body)
class ListConcept(Concept):
@@ -353,20 +354,20 @@ class ListConcept(Concept):
def append(self, obj):
self.body.append(obj)
def __len__(self):
return len(self.body)
def __getitem__(self, key):
return self.body[key]
def __setitem__(self, key, value):
self.body[key] = value
def __iter__(self):
return iter(self.body)
def __contains__(self, item):
return item in self.body
# def __len__(self):
# return len(self.body)
#
# def __getitem__(self, key):
# return self.body[key]
#
# def __setitem__(self, key, value):
# self.body[key] = value
#
# def __iter__(self):
# return iter(self.body)
#
# def __contains__(self, item):
# return item in self.body
class ConceptAlreadyInSet(Concept):
+1 -2
View File
@@ -7,7 +7,6 @@ from core.ast.visitors import UnreferencedNamesVisitor
from core.builtin_concepts import BuiltinConcepts
def is_same_success(sheerka, return_values):
"""
Returns True if all returns values are successful and have the same value
@@ -206,7 +205,7 @@ def _extract_predicates(sheerka, node, variables_to_include, variables_to_exclud
elif node.node_type == "BoolOp":
all_op = True
temp_res = []
for op in node.get_prop("values"):
for op in node.get_prop("values").body:
res = _extract_predicates(sheerka, op, variables_to_include, variables_to_exclude)
if len(res) == 0:
all_op = False
+15 -23
View File
@@ -47,6 +47,7 @@ class ConceptMetadata:
id: str # unique identifier for a concept. The id will never be modified (but the key can)
props: list # list properties, with their default values
is_evaluated: bool = False # True is the concept is evaluated by sheerka.eval_concept()
full_serialization: bool = False # If True, the full object will be serialized, rather than just the diff
simplec = namedtuple("concept", "name body") # for simple concept (tests purposes only)
@@ -163,10 +164,10 @@ class Concept:
name = self.name if 'metadata' in vars(self) else 'Concept'
raise AttributeError(f"'{name}' concept has no attribute '{item}'")
def def_prop(self, prop_name: str, default_value=None):
def def_prop(self, prop_name, default_value=None):
"""
Adds a property to the metadata
:param prop_name:
:param prop_name: name or concept
:param default_value:
:return:
"""
@@ -242,25 +243,6 @@ class Concept:
def body(self):
return self.values[ConceptParts.BODY] if ConceptParts.BODY in self.values else None
# def add_codes(self, codes):
# """
# Gets the ASTs for 'where', 'pre', 'post' and 'body'
# There ASTs are know when the concept is freshly parsed.
# So the values are kept in cache.
#
# For concepts loaded from sdp, these ASTs must be created again
# TODO : Seems to be a service method. Can be put somewhere else
# :param codes:
# :return:
# """
# if codes is None:
# return
#
# for key in codes:
# self.compiled[key] = codes[key]
#
# return self
def get_digest(self):
"""
Returns the digest of the event
@@ -321,12 +303,22 @@ class Concept:
return self
def set_prop(self, prop_name: str, prop_value):
"""Directly sets a value to a property"""
def set_prop(self, prop_name, prop_value):
"""
Set the value of a property (not the metadata)
:param prop_name: Name the property or another concept
:param prop_value:
:return:
"""
self.props[prop_name] = Property(prop_name, prop_value)
return self
def get_prop(self, prop_name: str):
"""
Gets the value of a property
:param prop_name: name or concept
:return:
"""
return self.props[prop_name].value
def set_metadata_value(self, metadata: ConceptParts, value):
@@ -59,6 +59,7 @@ class SheerkaCreateNewConcept:
return self.sheerka.ret(self.logger_name, False, ErrorConcept(init_ret_value.value))
# save the new concept in sdp
concept.metadata.full_serialization = True
try:
# TODO : needs to make these calls atomic (or at least one single call)
# save the new concept
@@ -90,6 +91,7 @@ class SheerkaCreateNewConcept:
error.args[0])
# Updates the caches
concept.metadata.full_serialization = False
self.sheerka.cache_by_key[concept.key] = self.sheerka.sdp.get_safe(self.sheerka.CONCEPTS_ENTRY, concept.key)
self.sheerka.cache_by_id[concept.id] = concept
if init_ret_value is not None and init_ret_value.status:
+4 -4
View File
@@ -31,6 +31,8 @@ class SheerkaDump:
def dump_desc(self, *concept_names, eval=False):
first = True
event = Event(f"Dumping description", "")
context = ExecutionContext("dump_desc", event, self.sheerka)
for concept_name in concept_names:
if isinstance(concept_name, Concept):
concepts = concept_name
@@ -45,8 +47,6 @@ class SheerkaDump:
for c in concepts:
if eval:
event = Event(f"Evaluating {c}", "")
context = ExecutionContext("dump_desc", event, self.sheerka)
evaluated = self.sheerka.evaluate_concept(context, c)
value = evaluated.body if evaluated.key == c.key else evaluated
@@ -60,8 +60,8 @@ class SheerkaDump:
self.sheerka.log.info(f"value : {value}")
self.sheerka.log.info(f"digest : {c.get_digest()}")
if self.sheerka.isaset(c):
items = self.sheerka.get_set_elements(c)
if self.sheerka.isaset(context, c):
items = self.sheerka.get_set_elements(context, c)
self.sheerka.log.info(f"elements : {items}")
first = False
@@ -235,6 +235,12 @@ class SheerkaEvaluateConcept:
concept.set_prop(prop_name, resolved)
else:
part_key = ConceptParts(metadata_to_eval)
# do not evaluate where when the body is a set
# Indeed, the way that the where clause is expressed is not a valid python or concept code
if part_key == ConceptParts.WHERE and self.sheerka.isaset(context, concept.body):
continue
if part_key in concept.compiled and concept.compiled[part_key] is not None:
metadata_ast = concept.compiled[part_key]
resolved = self.resolve(context, metadata_ast, part_key, concept, logger)
@@ -244,7 +250,7 @@ class SheerkaEvaluateConcept:
concept.values[part_key] = self.get_infinite_recursion_resolution(resolved) or resolved
# validate where clause
if concept.metadata.where is not None:
if ConceptParts.WHERE in concept.values:
where_value = concept.values[ConceptParts.WHERE]
if not (where_value is None or self.sheerka.value(where_value) is True):
return self.sheerka.new(BuiltinConcepts.WHERE_CLAUSE_FAILED, body=concept)
@@ -68,7 +68,7 @@ class SheerkaHistoryManager:
events = list(self.sheerka.sdp.load_events(depth_or_digest, start))
for event in events:
try:
result = self.sheerka.sdp.load_result(self.sheerka, event.get_digest())
result = self.sheerka.sdp.load_result(event.get_digest())
except (IOError, KeyError):
result = None
yield History(event, result)
@@ -0,0 +1,15 @@
from core.builtin_concepts import BuiltinConcepts
class SheerkaModifyConcept:
def __init__(self, sheerka):
self.sheerka = sheerka
self.logger_name = self.modify_concept.__name__
def modify_concept(self, context, concept, logger=None):
logger = logger or self.sheerka.log
self.sheerka.sdp.modify(context.event.get_digest(), self.sheerka.CONCEPTS_ENTRY, concept.key, concept)
ret = self.sheerka.ret(self.logger_name, True, self.sheerka.new(BuiltinConcepts.NEW_CONCEPT, body=concept))
return ret
+151 -14
View File
@@ -1,5 +1,7 @@
from core.ast.nodes import python_to_concept
from core.builtin_concepts import BuiltinConcepts, ErrorConcept
from core.concept import Concept
from core.concept import Concept, ConceptParts
import core.builtin_helpers
GROUP_PREFIX = 'All_'
@@ -9,6 +11,30 @@ class SheerkaSetsManager:
self.sheerka = sheerka
self.logger_name = self.add_concept_to_set.__name__
def set_isa(self, context, concept, concept_set, logger=None):
"""
Defines that concept a is b is another concept
:param context:
:param concept:
:param concept_set:
:param logger:
:return:
"""
logger = logger or self.sheerka.log
context.log(logger, f"Setting that concept {concept} is a {concept_set}", who=self.logger_name)
isa = [] if BuiltinConcepts.ISA not in concept.props else concept.get_prop(BuiltinConcepts.ISA)
if concept_set not in isa:
isa.append(concept_set)
concept.set_prop(BuiltinConcepts.ISA, isa)
res = self.sheerka.modify_concept(context, concept, logger)
if not res.status:
return res
return self.add_concept_to_set(context, concept, concept_set, logger)
def add_concept_to_set(self, context, concept, concept_set, logger=None):
"""
Add an entry in sdp to tell that concept isa concept_set
@@ -53,24 +79,51 @@ class SheerkaSetsManager:
context.log_error(logger, "Failed to add to set.", who=self.logger_name)
return self.sheerka.ret(self.logger_name, False, ErrorConcept(error), error.args[0])
def get_set_elements(self, concept):
def get_set_elements(self, context, concept, logger=None):
"""
Concept is supposed to be a set
Returns all elements if the set
:param context:
:param concept:
:param logger:
:return:
"""
assert concept.id
logger = logger or self.sheerka.log
ids = self.sheerka.sdp.get_safe(GROUP_PREFIX + concept.id)
if ids is None:
# noinspection PyShadowingNames
def _get_set_elements(context, concept, sub_concept):
if not (isinstance(sub_concept, Concept) and sub_concept.id):
return self.sheerka.new(BuiltinConcepts.NOT_A_SET, body=concept)
elements = [self.sheerka.get_by_id(element_id) for element_id in ids]
return elements
ids = self.sheerka.sdp.get_safe(GROUP_PREFIX + sub_concept.id)
if ids:
if concept.metadata.where:
new_condition = self._validate_where_clause(concept)
if not new_condition:
return self.sheerka.new(BuiltinConcepts.WHERE_CLAUSE_FAILED, body=concept)
else:
# This methods sucks, but I don't have enough tools (like proper AST manipulation functions)
# to do it properly now. It will be enhanced later
concepts = self._get_concepts(context, ids, True, logger)
globals_ = {"xx__concepts__xx": concepts, "sheerka": self.sheerka}
locals_ = {}
exec(new_condition, globals_, locals_)
return locals_["result"]
else:
return self._get_concepts(context, ids, False, logger)
def isa(self, a, b):
# it may be a concept that references a set
if not sub_concept.metadata.is_evaluated:
with context.push(desc=f"Evaluating concept {sub_concept}") as sub_context:
evaluated = self.sheerka.evaluate_concept(sub_context, sub_concept)
if evaluated.key != concept.key:
return False
return _get_set_elements(context, concept, sub_concept.body)
return _get_set_elements(context, concept, concept)
def isinset(self, a, b):
"""
return true if the concept a is a b
Will handle when the keyword isa will be implemented
@@ -82,17 +135,101 @@ class SheerkaSetsManager:
if isinstance(a, BuiltinConcepts): # common KSI error ;-)
raise SyntaxError("Remember that the first parameter of isinstance MUST be a concept")
assert isinstance(a, Concept)
assert isinstance(b, Concept)
if not (isinstance(a, Concept) and isinstance(b, Concept)):
return False
# TODO, first check the 'isa' property of a
if not (a.id and b.id):
return False
return self.sheerka.sdp.exists(GROUP_PREFIX + b.id, a.id)
if self.sheerka.sdp.exists(GROUP_PREFIX + b.id, a.id):
return True
def isaset(self, concept):
"""True if exists All_<concept_id> in sdp"""
if not concept.id:
return False
def isa(self, a, b):
if BuiltinConcepts.ISA not in a.props:
return False
for c in a.get_prop(BuiltinConcepts.ISA):
if c == b:
return True
if self.isa(c, b):
return True
return False
def isaset(self, context, concept, logger=None):
"""
True if exists All_<concept_id> in sdp or if concept references to a concept that has all_<concept_id>
:param context:
:param concept:
:param logger:
:return:
"""
""""""
logger = logger or self.sheerka.log
if not (isinstance(concept, Concept) and concept.id):
return None
# it may be a concept that references a set
if not concept.metadata.is_evaluated:
with context.push(desc=f"Evaluating concept {concept}") as sub_context:
evaluated = self.sheerka.evaluate_concept(sub_context, concept, logger)
if evaluated.key != concept.key:
return False
if concept.body:
return self.isaset(context, concept.body, logger)
res = self.sheerka.sdp.get_safe(GROUP_PREFIX + concept.id)
return res is not None
def _validate_where_clause(self, concept):
python_parser_result = [r for r in concept.compiled[ConceptParts.WHERE] if r.who == "parsers.Python"]
if not python_parser_result or not python_parser_result[0].status:
return None
ast_ = python_parser_result[0].body.body.ast_
ast_as_concepts = python_to_concept(ast_)
names = core.builtin_helpers.get_names(self.sheerka, ast_as_concepts)
if len(names) != 1 or names[0] != concept.metadata.body:
return None
condition = concept.metadata.where.replace(concept.metadata.body, "sheerka.value(x)")
expression = f"""
result=[]
for x in xx__concepts__xx:
try:
if {condition}:
result.append(x)
except Exception:
pass
"""
return expression
def _get_concepts(self, context, ids, evaluate, logger):
"""
Gets concepts from a list of concepts ids
:param ids:
:param evaluate: if True, all the elements are evaluated before returned
:return:
"""
if not ids:
return []
if not evaluate:
return [self.sheerka.get_by_id(element_id) for element_id in ids]
result = []
with context.push(desc=f"Evaluating concepts of a set") as sub_context:
for element_id in ids:
concept = self.sheerka.get_by_id(element_id)
evaluated = self.sheerka.evaluate_concept(context, concept, logger)
result.append(evaluated)
return result
+33 -8
View File
@@ -7,6 +7,7 @@ from core.sheerka.Services.SheerkaDump import SheerkaDump
from core.sheerka.Services.SheerkaEvaluateConcept import SheerkaEvaluateConcept
from core.sheerka.Services.SheerkaExecute import SheerkaExecute
from core.sheerka.Services.SheerkaHistoryManager import SheerkaHistoryManager
from core.sheerka.Services.SheerkaModifyConcept import SheerkaModifyConcept
from core.sheerka.Services.SheerkaSetsManager import SheerkaSetsManager
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event
import core.utils
@@ -81,12 +82,14 @@ class Sheerka(Concept):
self.execute_handler = SheerkaExecute(self)
self.create_new_concept_handler = SheerkaCreateNewConcept(self)
self.modify_concept_handler = SheerkaModifyConcept(self)
self.dump_handler = SheerkaDump(self)
self.sets_handler = SheerkaSetsManager(self)
self.evaluate_concept_handler = SheerkaEvaluateConcept(self)
self.history_handler = SheerkaHistoryManager(self)
self.during_restore = False
self._builtins_classes_cache = None
def initialize(self, root_folder: str = None):
"""
@@ -101,7 +104,7 @@ class Sheerka(Concept):
from sheerkapickle.sheerka_handlers import initialize_pickle_handlers
initialize_pickle_handlers()
self.sdp = SheerkaDataProvider(root_folder)
self.sdp = SheerkaDataProvider(root_folder, self)
if self.sdp.first_time:
self.sdp.set_key(self.USER_CONCEPTS_KEYS, 1000)
@@ -117,7 +120,7 @@ class Sheerka(Concept):
exec_context.add_values(return_values=res)
if not self.skip_builtins_in_db:
self.sdp.save_result(self, exec_context)
self.sdp.save_result(exec_context)
except IOError as e:
res = ReturnValueConcept(self, False, self.get(BuiltinConcepts.ERROR), e)
@@ -151,6 +154,7 @@ class Sheerka(Concept):
if from_db is None:
self.init_log.debug(f"'{concept.name}' concept is not found in db. Adding.")
self.set_id_if_needed(concept, True)
concept.metadata.full_serialization = True
self.sdp.add("init", self.CONCEPTS_ENTRY, concept, use_ref=True)
else:
self.init_log.debug(f"Found concept '{from_db}' in db. Updating.")
@@ -247,9 +251,9 @@ class Sheerka(Concept):
execution_context.add_values(return_values=ret)
if not self.skip_builtins_in_db:
self.sdp.save_result(self, execution_context)
self.sdp.save_result(execution_context)
# hack to save valid concept definition
# # hack to save valid concept definition
# if not self.during_restore:
# if len(ret) == 1 and ret[0].status and self.isinstance(ret[0].value, BuiltinConcepts.NEW_CONCEPT):
# with open(CONCEPTS_FILE, "a") as f:
@@ -294,6 +298,9 @@ class Sheerka(Concept):
return self.create_new_concept_handler.create_new_concept(context, concept, logger)
def modify_concept(self, context, concept: Concept, logger):
return self.modify_concept_handler.modify_concept(context, concept, logger)
def add_concept_to_set(self, context, concept, concept_set, logger=None):
"""
Add an entry in sdp to tell that concept isa concept_set
@@ -305,15 +312,27 @@ class Sheerka(Concept):
"""
return self.sets_handler.add_concept_to_set(context, concept, concept_set, logger)
def get_set_elements(self, concept):
def set_isa(self, context, concept, concept_set, logger=None):
"""
:param context:
:param concept:
:param concept_set:
:param logger:
:return:
"""
return self.sets_handler.set_isa(context, concept, concept_set, logger)
def get_set_elements(self, context, concept):
"""
Concept is supposed to be a set
Returns all elements if the set
:param context:
:param concept:
:return:
"""
return self.sets_handler.get_set_elements(concept)
return self.sets_handler.get_set_elements(context, concept)
def evaluate_concept(self, context, concept: Concept, logger=None):
"""
@@ -524,8 +543,11 @@ class Sheerka(Concept):
self.isinstance(objs, BuiltinConcepts.ENUMERATION)):
objs = [objs]
if isinstance(objs, list):
return (self.value(obj) for obj in objs)
return (self.value(obj) for obj in objs.body)
def is_success(self, obj):
if isinstance(obj, bool): # quick win
return obj
@@ -562,11 +584,14 @@ class Sheerka(Concept):
return a.key == b_key
def isinset(self, a, b):
return self.sets_handler.isinset(a, b)
def isa(self, a, b):
return self.sets_handler.isa(a, b)
def isaset(self, concept):
return self.sets_handler.isaset(concept)
def isaset(self, context, concept):
return self.sets_handler.isaset(context, concept)
def get_evaluator_name(self, name):
if self.evaluators_prefix is None:
+1 -1
View File
@@ -61,7 +61,7 @@ class AddConceptEvaluator(OneReturnValueEvaluator):
if not isinstance(part_ret_val, ReturnValueConcept) or not part_ret_val.status:
continue # Nothing to do is not initialized
# update the parts
# update the metadata
source = self.get_source(part_ret_val)
setattr(concept.metadata, prop, source)
+9 -1
View File
@@ -29,13 +29,21 @@ class EvalEvaluator(AllReturnValuesEvaluator):
for ret_val in return_values:
if ret_val.status and isinstance(ret_val.body, Concept) and ret_val.body.body:
context.log(self.verbose_log, f"Evaluating {ret_val}", who=self)
context.log(self.verbose_log, f"Evaluating {ret_val.body}", who=self)
result.append(sheerka.ret(self.name, True, ret_val.body.body, parents=[ret_val, self.eval_requested]))
elif ret_val.status and sheerka.isaset(context, ret_val.body):
context.log(self.verbose_log, f"Evaluating set {ret_val.body}", who=self)
result.append(sheerka.ret(
self.name,
True,
sheerka.get_set_elements(context, ret_val.body),
parents=[ret_val, self.eval_requested]))
if len(result) > 0:
return result
else:
# suppress the successful BuiltinConcepts.CONCEPT_EVAL_REQUESTED
# status of CONCEPT_EVAL_REQUESTED is now set to False
return sheerka.ret(
self.name,
False,
+10 -8
View File
@@ -42,17 +42,18 @@ class PythonEvaluator(OneReturnValueEvaluator):
return sheerka.ret(self.name, False, not_for_me, parents=[return_value])
# get locals
my_locals = self.get_locals(context, node)
context.log(self.verbose_log, f"locals={my_locals}", self.name)
my_globals = self.get_globals(context, node)
my_locals = {}
context.log(self.verbose_log, f"globals={my_globals}", self.name)
# eval
if isinstance(node.ast_, ast.Expression):
context.log(self.verbose_log, "Evaluating using 'eval'.", self.name)
compiled = compile(node.ast_, "<string>", "eval")
evaluated = eval(compiled, {}, my_locals)
evaluated = eval(compiled, my_globals, my_locals)
else:
context.log(self.verbose_log, "Evaluating using 'exec'.", self.name)
evaluated = self.exec_with_return(node.ast_, my_locals)
evaluated = self.exec_with_return(node.ast_, my_globals, my_locals)
context.log(self.verbose_log, f"{evaluated=}", self.name)
return sheerka.ret(self.name, True, evaluated, parents=[return_value])
@@ -62,7 +63,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
error = sheerka.new(BuiltinConcepts.ERROR, body=error)
return sheerka.ret(self.name, False, error, parents=[return_value])
def get_locals(self, context, node):
def get_globals(self, context, node):
my_locals = {
"sheerka": context.sheerka,
"desc": context.sheerka.dump_handler.dump_desc,
@@ -70,6 +71,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
"definitions": context.sheerka.dump_handler.dump_definitions,
"history": context.sheerka.dump_handler.dump_history,
"state": context.sheerka.dump_handler.dump_state,
"Concept": core.concept.Concept
}
if context.obj:
context.log(self.verbose_log,
@@ -189,7 +191,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
return result
def exec_with_return(self, code_ast, my_locals):
def exec_with_return(self, code_ast, my_globals, my_locals):
init_ast = copy.deepcopy(code_ast)
init_ast.body = code_ast.body[:-1]
@@ -199,6 +201,6 @@ class PythonEvaluator(OneReturnValueEvaluator):
exec(compile(init_ast, "<ast>", "exec"), {}, my_locals)
if type(last_ast.body[0]) == ast.Expr:
return eval(compile(self.expr_to_expression(last_ast.body[0]), "<ast>", "eval"), {}, my_locals)
return eval(compile(self.expr_to_expression(last_ast.body[0]), "<ast>", "eval"), my_globals, my_locals)
else:
exec(compile(last_ast, "<ast>", "exec"), {}, my_locals)
exec(compile(last_ast, "<ast>", "exec"), my_globals, my_locals)
+4 -2
View File
@@ -236,7 +236,8 @@ class BnfParser(BaseParser):
if token.type == TokenKind.CONCEPT:
self.next_token()
concept = self.sheerka.new((token.value[0], token.value[1]))
expr = ConceptGroupExpression(concept) if self.sheerka.isaset(concept) else ConceptExpression(concept)
expr = ConceptGroupExpression(concept) if self.sheerka.isaset(self.context, concept) \
else ConceptExpression(concept)
return self.eat_rule_name_if_needed(expr)
if token.type == TokenKind.IDENTIFIER:
@@ -260,7 +261,8 @@ class BnfParser(BaseParser):
body=("key", concept_name)))
return None
else:
expr = ConceptGroupExpression(concept) if self.sheerka.isaset(concept) else ConceptExpression(concept)
expr = ConceptGroupExpression(concept) if self.sheerka.isaset(self.context, concept) \
else ConceptExpression(concept)
expr.rule_name = concept.name
return expr
+2 -2
View File
@@ -318,7 +318,7 @@ class ConceptGroupExpression(ConceptExpression):
self.concept = to_match # Memoize
if to_match not in parser.concepts_grammars:
concepts_in_group = parser.sheerka.get_set_elements(self.concept)
concepts_in_group = parser.sheerka.get_set_elements(parser.context, self.concept)
nodes = [ConceptExpression(c, rule_name=c.name) for c in concepts_in_group]
expr = OrderedChoice(nodes)
expr.nodes = nodes
@@ -697,7 +697,7 @@ class ConceptLexerParser(BaseParser):
# A copy must be created
def inner_get_model(expression):
if isinstance(expression, Concept):
if self.sheerka.isaset(expression):
if self.sheerka.isaset(self.context, expression):
ret = ConceptGroupExpression(expression, rule_name=expression.name)
else:
ret = ConceptExpression(expression, rule_name=expression.name)
+1 -1
View File
@@ -246,7 +246,7 @@ class DefaultParser(BaseParser):
# the definition of a concept consists of several parts
# Keywords.CONCEPT to get the name of the concept
# Keywords.FROM [Keywords.REGEX] to get the definition of the concept
# Keywords.FROM [Keywords.BNF] to get the definition of the concept
# Keywords.AS to get the body
# Keywords.WHERE to get the conditions to recognize for the variables
# Keywords.PRE to know if the conditions to evaluate the concept
+15 -10
View File
@@ -294,16 +294,18 @@ class SheerkaDataProvider:
KeysFile = "keys"
REF_PREFIX = "##REF##:"
def __init__(self, root=None):
def __init__(self, root=None, sheerka=None):
self.log = get_logger(__name__)
self.init_log = get_logger("init." + __name__)
self.init_log.debug("Initializing sdp.")
self.sheerka = sheerka
self.io = SheerkaDataProviderIO.get(root)
self.first_time = self.io.first_time
self.serializer = Serializer()
@staticmethod
def get_obj_key(obj):
"""
@@ -729,13 +731,12 @@ class SheerkaDataProvider:
digest = event.parents[0]
count += 1
def save_result(self, sheerka, execution_context):
def save_result(self, execution_context):
"""
Save the execution context associated with an event
To make a long story short,
for every single user input, there is an event (which is the first thing that is created)
and a result (the ExecutionContext created by sheerka.evaluate_user_input()
:param sheerka:
:param execution_context:
:return:
"""
@@ -745,15 +746,15 @@ class SheerkaDataProvider:
if self.io.exists(target_path):
return digest
context = SerializerContext(sheerka=sheerka)
context = SerializerContext(sheerka=self.sheerka)
self.io.write_binary(target_path, self.serializer.serialize(execution_context, context).read())
return digest
def load_result(self, sheerka, digest):
def load_result(self, digest):
target_path = self.io.get_obj_path(SheerkaDataProvider.EventFolder, digest) + "_result"
with self.io.open(target_path, "rb") as f:
context = SerializerContext(sheerka=sheerka)
context = SerializerContext(sheerka=self.sheerka)
return self.serializer.deserialize(f, context)
def save_state(self, state: State):
@@ -763,7 +764,8 @@ class SheerkaDataProvider:
if self.io.exists(target_path):
return digest
self.io.write_binary(target_path, self.serializer.serialize(state, None).read())
context = SerializerContext(sheerka=self.sheerka)
self.io.write_binary(target_path, self.serializer.serialize(state, context).read())
return digest
def load_state(self, digest):
@@ -772,11 +774,13 @@ class SheerkaDataProvider:
target_path = self.io.get_obj_path(SheerkaDataProvider.StateFolder, digest)
with self.io.open(target_path, "rb") as f:
return self.serializer.deserialize(f, None)
context = SerializerContext(sheerka=self.sheerka)
return self.serializer.deserialize(f, context)
def save_obj(self, obj):
self.log.debug(f"Saving '{obj}' as reference...")
stream = self.serializer.serialize(obj, SerializerContext(user_name="kodjo"))
context = SerializerContext(user_name="kodjo", sheerka=self.sheerka)
stream = self.serializer.serialize(obj, context)
digest = obj.get_digest() if hasattr(obj, "get_digest") else self.get_stream_digest(stream)
target_path = self.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, digest)
@@ -798,7 +802,8 @@ class SheerkaDataProvider:
return None
with self.io.open(target_path, "rb") as f:
obj = self.serializer.deserialize(f, SerializerContext(origin=digest))
context = SerializerContext(origin=digest, sheerka=self.sheerka)
obj = self.serializer.deserialize(f, context)
# set the origin of the object
if add_origin:
+14 -3
View File
@@ -231,13 +231,24 @@ class StateSerializer(PickleSerializer):
1)
class ConceptSerializer(JsonSerializer):
class ConceptSerializer(BaseSerializer):
def __init__(self):
JsonSerializer.__init__(self, "core.concept.Concept", "C", 1)
BaseSerializer.__init__(self, "C", 1)
def matches(self, obj):
return isinstance(obj, Concept)
def dump(self, stream, obj, context):
stream.write(sheerkapickle.encode(context.sheerka, obj).encode("utf-8"))
stream.seek(0)
return stream
def load(self, stream, context):
json_stream = stream.read().decode("utf-8")
obj = sheerkapickle.decode(context.sheerka, json_stream)
return obj
class DictionarySerializer(BaseSerializer):
def __init__(self):
@@ -275,7 +286,7 @@ class ExecutionContextSerializer(BaseSerializer):
def load(self, stream, context):
json_stream = stream.read().decode("utf-8")
obj = sheerkapickle.decode(context.sheerka, json_stream)
#json_message = json.loads(json_stream)
# json_message = json.loads(json_stream)
return obj
#
+20 -27
View File
@@ -16,11 +16,11 @@ class ConceptHandler(BaseHandler):
pickler = self.context
sheerka = self.sheerka
if obj.id:
if obj.metadata.full_serialization:
ref = default_concept
else:
ref = sheerka.get_by_id(obj.id)
data[CONCEPT_ID] = (obj.key, obj.id)
else:
ref = default_concept
# transform metadata
for prop in CONCEPT_PROPERTIES_TO_SERIALIZE:
@@ -41,7 +41,7 @@ class ConceptHandler(BaseHandler):
if prop not in ref.props or value != ref.props[prop].value:
if "props" not in data:
data["props"] = []
data["props"].append((prop, pickler.flatten(value)))
data["props"].append((pickler.flatten(prop), pickler.flatten(value)))
return data
@@ -77,7 +77,7 @@ class ConceptHandler(BaseHandler):
return instance
class UserInputHandler(BaseHandler):
class UserInputHandler(ConceptHandler):
def flatten(self, obj: UserInputConcept, data):
data[CONCEPT_ID] = (obj.key, obj.id)
@@ -86,12 +86,12 @@ class UserInputHandler(BaseHandler):
return data
def new(self, data):
sheerka = self.sheerka
instance = sheerka.new(tuple(data[CONCEPT_ID]), body=data["text"], user_name=data["user_name"])
return instance
return UserInputConcept.__new__(UserInputConcept)
def restore(self, data, instance):
instance.__init__(data["text"], data["user_name"])
instance.metadata.key = data[CONCEPT_ID][0]
instance.metadata.id = data[CONCEPT_ID][1]
return instance
@@ -100,6 +100,7 @@ class ReturnValueHandler(BaseHandler):
def flatten(self, obj: ReturnValueConcept, data):
pickler = self.context
data[CONCEPT_ID] = (obj.key, obj.id)
data["who"] = f"c:{obj.who.id}:" if isinstance(obj.who, Concept) else \
obj.who.name if isinstance(obj.who, (BaseParser, BaseEvaluator)) else \
obj.who
@@ -110,38 +111,30 @@ class ReturnValueHandler(BaseHandler):
return data
def new(self, data):
sheerka = self.sheerka
instance = sheerka.ret(data["who"], data["status"], None)
return instance
return ReturnValueConcept.__new__(ReturnValueConcept)
def restore(self, data, instance):
pickler = self.context
instance.value = pickler.restore(data["value"])
instance.__init__(data["who"], data["status"], pickler.restore(data["value"]))
if "parents" in data:
instance.parents = pickler.restore(data["parents"])
instance.metadata.key = data[CONCEPT_ID][0]
instance.metadata.id = data[CONCEPT_ID][1]
return instance
# class BuiltinConceptsHandler(BaseHandler):
#
# def flatten(self, obj: BuiltinConcepts, data):
# return data
#
# def restore(self, obj):
# pass
class SheerkaHandler(ConceptHandler):
class SheerkaHandler(BaseHandler):
def flatten(self, obj: BuiltinConcepts, data):
return data
# def flatten(self, obj: BuiltinConcepts, data):
# return ConceptHandler().flatten()data
def new(self, data):
return self.sheerka
def restore(self, data, instance):
return instance
# def restore(self, data, instance):
# return instance
class ExecutionContextHandler(BaseHandler):
+26 -1
View File
@@ -3,11 +3,12 @@ import ast
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept
from core.concept import Concept
from core.sheerka.ExecutionContext import ExecutionContext
from parsers.BnfParser import BnfParser
from sdp.sheerkaDataProvider import Event
class BaseTest:
def get_sheerka(self):
def get_sheerka(self, **kwargs):
pass
def get_context(self, sheerka=None):
@@ -32,6 +33,30 @@ class BaseTest:
dump = dump.replace(to_remove, "")
return dump
def init_concepts(self, *concepts, **kwargs):
sheerka = self.get_sheerka(**kwargs)
context = self.get_context(sheerka)
result = []
for c in concepts:
if isinstance(c, str):
c = Concept(c)
c.init_key()
sheerka.set_id_if_needed(c, False)
# manage concepts with bnf definitions
if c.metadata.definition:
bnf_parser = BnfParser()
res = bnf_parser.parse(context, c.metadata.definition)
if res.status:
c.bnf = res.value.value
sheerka.create_new_concept(context, c)
sheerka.add_in_cache(c)
result.append(c)
return sheerka, context, *result
@staticmethod
def retval(obj, who="who", status=True):
"""ret_val"""
+3 -1
View File
@@ -26,7 +26,9 @@ class TestUsingFileBasedSheerka(BaseTest):
os.chdir(current_pwd)
def get_sheerka(self, use_dict=True, skip_builtins_in_db=True):
def get_sheerka(self, **kwargs):
use_dict = kwargs.get("use_dict", True)
skip_builtins_in_db = kwargs.get("skip_builtins_in_db", True)
root = "mem://" if use_dict else self.root_folder
sheerka = Sheerka(skip_builtins_in_db=skip_builtins_in_db)
sheerka.initialize(root)
+2 -1
View File
@@ -4,7 +4,8 @@ from tests.BaseTest import BaseTest
class TestUsingMemoryBasedSheerka(BaseTest):
def get_sheerka(self, skip_builtins_in_db=True):
def get_sheerka(self, **kwargs):
skip_builtins_in_db = kwargs.get("skip_builtins_in_db", True)
sheerka = Sheerka(skip_builtins_in_db=skip_builtins_in_db)
sheerka.initialize("mem://")
return sheerka
@@ -457,3 +457,4 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one)
assert evaluated.key == one.key
assert evaluated.body == 1
+174 -39
View File
@@ -6,41 +6,39 @@ from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
class TestSheerkaSetsManager(TestUsingFileBasedSheerka):
def init(self, use_dict, *concepts):
sheerka = self.get_sheerka(use_dict, True)
for c in concepts:
sheerka.set_id_if_needed(c, False)
sheerka.add_in_cache(c)
context = self.get_context(sheerka)
return sheerka, context
# def init(self, use_dict, *concepts):
# sheerka = self.get_sheerka(use_dict, True)
# for c in concepts:
# sheerka.set_id_if_needed(c, False)
# sheerka.add_in_cache(c)
#
# context = self.get_context(sheerka)
# return sheerka, context
def test_i_can_add_concept_to_set(self):
foo = Concept("foo")
all_foos = Concept("all_foos")
sheerka, context = self.init(False, foo, all_foos)
sheerka, context, foo, all_foos = self.init_concepts(Concept("foo"), Concept("all_foo"), use_dict=False)
res = sheerka.add_concept_to_set(context, foo, all_foos)
assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
all_entries = self.get_sheerka(False, True).sdp.get("All_" + all_foos.id, None, False)
all_entries = self.get_sheerka(use_dict=False).sdp.get("All_" + all_foos.id, None, False)
assert len(all_entries) == 1
assert foo.id in all_entries
def test_i_can_add_several_concepts_to_set(self):
foo1 = Concept("foo1")
foo2 = Concept("foo2")
all_foos = Concept("all_foos")
sheerka, context = self.init(False, foo1, foo2, all_foos)
sheerka, context, foo1, foo2, all_foos = self.init_concepts(
Concept("foo1"),
Concept("foo2"),
Concept("all_foo"), use_dict=False)
res = sheerka.sets_handler.add_concepts_to_set(context, (foo1, foo2), all_foos)
assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
all_entries = self.get_sheerka(False, False).sdp.get("All_" + all_foos.id, None, False)
all_entries = self.get_sheerka(use_dict=False).sdp.get("All_" + all_foos.id, None, False)
assert len(all_entries) == 2
assert foo1.id in all_entries
assert foo2.id in all_entries
@@ -57,7 +55,7 @@ class TestSheerkaSetsManager(TestUsingFileBasedSheerka):
assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
all_entries = self.get_sheerka(False, False).sdp.get("All_" + all_foos.id, None, False)
all_entries = self.get_sheerka(use_dict=False).sdp.get("All_" + all_foos.id, None, False)
assert len(all_entries) == 4
assert foo1.id in all_entries
assert foo2.id in all_entries
@@ -65,9 +63,7 @@ class TestSheerkaSetsManager(TestUsingFileBasedSheerka):
assert foo4.id in all_entries
def test_i_cannot_add_the_same_concept_twice_in_a_set(self):
foo = Concept("foo")
all_foos = Concept("all_foos")
sheerka, context = self.init(True, foo, all_foos)
sheerka, context, foo, all_foos = self.init_concepts(Concept("foo"), Concept("all_foos"))
sheerka.add_concept_to_set(context, foo, all_foos)
res = sheerka.add_concept_to_set(context, foo, all_foos)
@@ -80,40 +76,179 @@ class TestSheerkaSetsManager(TestUsingFileBasedSheerka):
assert foo.id in all_entries
def test_i_get_elements_from_a_set(self):
one = Concept("one")
two = Concept("two")
three = Concept("three")
number = Concept("number")
sheerka, context = self.init(True, one, two, three, number)
sheerka, context, one, two, three, number = self.init_concepts(
Concept("one"), Concept("two"), Concept("three"), Concept("number"))
for c in [one, two, three]:
sheerka.add_concept_to_set(context, c, number)
elements = sheerka.get_set_elements(number)
elements = sheerka.get_set_elements(context, number)
assert set(elements) == {one, two, three}
def test_i_cannot_get_elements_if_not_a_set(self):
one = Concept("one")
sheerka, context = self.init(True, one)
sheerka, context, one = self.init_concepts(Concept("one"))
error = sheerka.get_set_elements(one)
error = sheerka.get_set_elements(context, one)
assert sheerka.isinstance(error, BuiltinConcepts.NOT_A_SET)
assert error.body == one
def test_isa_and_isa_group(self):
group = Concept("group")
foo = Concept("foo")
sheerka, context = self.init(True, group, foo)
sheerka, context, group, foo = self.init_concepts(Concept("group"), Concept("foo"))
assert not sheerka.isaset(group)
assert not sheerka.isa(foo, group)
assert not sheerka.isaset(context, group)
assert not sheerka.isinset(foo, group)
context = self.get_context(sheerka)
sheerka.add_concept_to_set(context, foo, group)
assert sheerka.isaset(group)
assert sheerka.isa(foo, group)
assert sheerka.isaset(context, group)
assert sheerka.isinset(foo, group)
def test_i_can_a_multiples_concepts(self):
pass
def test_i_can_define_a_group_from_another_group(self):
sheerka, context, foo, bar, group1, group2 = self.init_concepts(
Concept("foo"), Concept("bar"), Concept("group1"), Concept("group2", body="group1"))
sheerka.sets_handler.add_concepts_to_set(context, [foo, bar], group1)
assert sheerka.isaset(context, group2)
assert sheerka.get_set_elements(context, group2) == [foo, bar]
def test_i_can_define_subset_of_another_group(self):
sheerka, context, one, two, three, four, five, number, sub_number = self.init_concepts(
Concept("one", body="1"),
Concept("two", body="2"),
Concept("three", body="3"),
Concept("four", body="4"),
Concept("five", body="5"),
Concept("number"),
Concept("sub_number", body="number", where="number < 4")
)
sheerka.sets_handler.add_concepts_to_set(context, [one, two, three, four, five], number)
assert sheerka.isaset(context, sub_number)
assert sheerka.get_set_elements(context, sub_number) == [one, two, three]
def test_i_can_define_subset_of_another_set_when_some_concept_dont_have_a_defined_body(self):
"""
Example
def concept unit from number where number <10
It implies that all elements in number have a (numeric) body
What if its not the case ?
:return:
"""
sheerka, context, one, two, three, four, five, number, sub_number = self.init_concepts(
Concept("one", body="1"),
Concept("two"),
Concept("three", body="3"),
Concept("four"),
Concept("five", body="5"),
Concept("number"),
Concept("sub_number", body="number", where="number < 4")
)
sheerka.sets_handler.add_concepts_to_set(context, [one, two, three, four, five], number)
assert sheerka.isaset(context, sub_number)
assert sheerka.get_set_elements(context, sub_number) == [one, three]
def test_i_can_define_subset_of_another_set_when_some_concept_are_bnf(self):
"""
Other case:
twenties isa number, but its body is a source code, not a constant numeric number
is it included ?
:return:
"""
sheerka, context, one, two, twenty, twenties, number, sub_number = self.init_concepts(
Concept("one", body="1"),
Concept("two", body="2"),
Concept("twenty", body="20"),
Concept("twenties", definition="twenty (one|two)=unit", body="twenty + unit"),
Concept("number"),
Concept("sub_number", body="number", where="number >= 20")
)
sheerka.sets_handler.add_concepts_to_set(context, [one, two, twenty, twenties], number)
assert sheerka.isaset(context, sub_number)
assert sheerka.get_set_elements(context, sub_number) == [twenty] # what is expected ?
def test_bnf_elements_can_be_part_of_a_set(self):
"""
The purpose of this test is
def concept twenties from bnf ...
twenties isa number
assert twenty two isa number
We want that all elements of the twenties are number
:return:
"""
sheerka, context, one, two, twenty, twenties, number = self.init_concepts(
Concept("one", body="1"),
Concept("two", body="2"),
Concept("twenty", body="20"),
Concept("twenties", definition="twenty (one|two)=unit", body="twenty + unit").def_prop("unit"),
Concept("number"),
)
sheerka.sets_handler.add_concepts_to_set(context, [one, two, twenty, twenties], number)
assert sheerka.isinset(twenties, number)
twenty_one = sheerka.evaluate_user_input("twenty one", "")[0].body
assert sheerka.isinset(twenty_one, number)
def test_i_can_set_isa(self):
sheerka, context, foo, all_foos = self.init_concepts(Concept("foo"), Concept("all_foo"), use_dict=False)
sheerka.create_new_concept(context, foo)
assert BuiltinConcepts.ISA not in foo.props
sheerka.set_isa(context, foo, all_foos)
assert foo.get_prop(BuiltinConcepts.ISA) == [all_foos]
assert sheerka.isa(foo, all_foos)
assert sheerka.isinset(foo, all_foos)
assert sheerka.isaset(context, all_foos)
def test_a_concept_can_be_in_multiple_sets(self):
sheerka, context, foo, all_foos, all_bars = self.init_concepts(
Concept("foo"),
Concept("all_foo"),
Concept("all_bar"),
use_dict=False)
sheerka.create_new_concept(context, foo)
sheerka.set_isa(context, foo, all_foos)
sheerka.set_isa(context, foo, all_bars)
assert foo.get_prop(BuiltinConcepts.ISA) == [all_foos, all_bars]
assert sheerka.isa(foo, all_foos)
assert sheerka.isa(foo, all_bars)
assert sheerka.isinset(foo, all_foos)
assert sheerka.isinset(foo, all_bars)
assert sheerka.isaset(context, all_foos)
assert sheerka.isaset(context, all_bars)
def test_i_can_manage_isa_transitivity(self):
"""
if foo isa bar and bar isa baz, then foo isa baz
:return:
"""
sheerka, context, foo, bar, baz = self.init_concepts(
Concept("foo"),
Concept("bar"),
Concept("baz"),
)
sheerka.create_new_concept(context, foo)
sheerka.create_new_concept(context, bar)
sheerka.create_new_concept(context, baz)
sheerka.set_isa(context, foo, bar)
sheerka.set_isa(context, bar, baz)
assert sheerka.isa(foo, bar)
assert sheerka.isa(bar, baz)
assert sheerka.isa(foo, baz)
+13 -13
View File
@@ -42,7 +42,7 @@ def my_function(a,b):
assert tree_as_concept.node_type == "Module"
assert sheerka.isinstance(tree_as_concept.get_prop("body"), BuiltinConcepts.LIST)
def_func = tree_as_concept.get_prop("body")[0]
def_func = tree_as_concept.get_prop("body").body[0]
assert sheerka.isinstance(def_func, BuiltinConcepts.GENERIC_NODE)
assert def_func.node_type == "FunctionDef"
assert def_func.parent == NodeParent(tree_as_concept, "body")
@@ -54,27 +54,27 @@ def my_function(a,b):
def_func_args_real_args = def_func_args.get_prop("args")
assert sheerka.isinstance(def_func_args_real_args, BuiltinConcepts.LIST)
assert len(def_func_args_real_args) == 2
assert len(def_func_args_real_args.body) == 2
assert sheerka.isinstance(def_func_args_real_args[0], BuiltinConcepts.GENERIC_NODE)
assert def_func_args_real_args[0].node_type == "arg"
assert def_func_args_real_args[0].parent == NodeParent(def_func_args, "args")
assert def_func_args_real_args[0].get_prop("arg") == "a"
assert sheerka.isinstance(def_func_args_real_args[1], BuiltinConcepts.GENERIC_NODE)
assert def_func_args_real_args[1].node_type == "arg"
assert def_func_args_real_args[1].parent == NodeParent(def_func_args, "args")
assert def_func_args_real_args[1].get_prop("arg") == "b"
assert sheerka.isinstance(def_func_args_real_args.body[0], BuiltinConcepts.GENERIC_NODE)
assert def_func_args_real_args.body[0].node_type == "arg"
assert def_func_args_real_args.body[0].parent == NodeParent(def_func_args, "args")
assert def_func_args_real_args.body[0].get_prop("arg") == "a"
assert sheerka.isinstance(def_func_args_real_args.body[1], BuiltinConcepts.GENERIC_NODE)
assert def_func_args_real_args.body[1].node_type == "arg"
assert def_func_args_real_args.body[1].parent == NodeParent(def_func_args, "args")
assert def_func_args_real_args.body[1].get_prop("arg") == "b"
def_fun_body = def_func.get_prop("body")
assert sheerka.isinstance(def_fun_body, BuiltinConcepts.LIST)
assert len(def_fun_body) == 2
assert len(def_fun_body.body) == 2
def_fun_body_for = def_fun_body[0]
def_fun_body_for = def_fun_body.body[0]
assert sheerka.isinstance(def_fun_body_for, BuiltinConcepts.GENERIC_NODE)
assert def_fun_body_for.node_type == "For"
assert def_fun_body_for.parent == NodeParent(def_func, "body")
def_fun_body_return = def_fun_body[1]
def_fun_body_return = def_fun_body.body[1]
assert sheerka.isinstance(def_fun_body_return, BuiltinConcepts.GENERIC_NODE)
assert def_fun_body_return.node_type == "Return"
assert def_fun_body_return.parent == NodeParent(def_func, "body")
+1
View File
@@ -134,6 +134,7 @@ class TestBuiltinHelpers(TestUsingMemoryBasedSheerka):
("a == 1 or b == 2", ["b"], [], ["b == 2"]),
("a == 1 or b == 2", ["a", "b"], [], ["a == 1 or b == 2"]),
("predicate(a,c) or predicate(b,c)", ["a", "b"], [], ["predicate(a,c) or predicate(b,c)"]),
("a < 1 and a > b", ["a"], [], ["a < 1 and a > b"]),
])
def test_i_can_extract_predicates(self, expression, vars_to_include, vars_to_exclude, expected_expr):
sheerka = self.get_sheerka()
+3 -3
View File
@@ -38,12 +38,12 @@ class TestSheerka(TestUsingFileBasedSheerka):
assert isinstance(sheerka.cache_by_key[key], concept_class)
def test_builtin_concepts_can_be_updated(self):
sheerka = self.get_sheerka(False, False)
sheerka = self.get_sheerka(use_dict=False, skip_builtins_in_db=False)
loaded_sheerka = sheerka.get(BuiltinConcepts.SHEERKA)
loaded_sheerka.metadata.desc = "I have a description"
sheerka.sdp.modify("Test", sheerka.CONCEPTS_ENTRY, loaded_sheerka.key, loaded_sheerka)
sheerka = self.get_sheerka(False, False)
sheerka = self.get_sheerka(use_dict=False, skip_builtins_in_db=False)
loaded_sheerka = sheerka.get(BuiltinConcepts.SHEERKA)
assert loaded_sheerka.metadata.desc == "I have a description"
@@ -233,7 +233,7 @@ class TestSheerka(TestUsingFileBasedSheerka):
assert sheerka.value(concept, reduce_simple_list) == expected
def test_list_of_concept_is_sorted_by_id(self):
sheerka = self.get_sheerka(False, False)
sheerka = self.get_sheerka(use_dict=False, skip_builtins_in_db=False)
concepts = sheerka.concepts()
assert concepts[0].id < concepts[-1].id
+18
View File
@@ -70,3 +70,21 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
False,
context.sheerka.new(BuiltinConcepts.CONCEPT_EVAL_REQUESTED))
assert evaluated.parents == [eval_requested]
def test_i_can_evaluate_sets(self):
sheerka, context, foo, bar, baz, number = self.init_concepts(
Concept("foo"),
Concept("bar"),
Concept("baz"),
Concept("number"))
sheerka.sets_handler.add_concepts_to_set(context, [foo, bar, baz], number)
return_values = [retval(number), eval_requested]
evaluator = EvalEvaluator()
evaluator.matches(context, return_values)
evaluated = evaluator.eval(context, return_values)
assert len(evaluated) == 1
assert evaluated[0].status
assert evaluated[0].body == [foo, bar, baz]
+5 -5
View File
@@ -255,7 +255,7 @@ as:
assert isinstance(res[0].value.body, list)
def test_i_can_create_concept_with_bnf_definition(self):
sheerka = self.get_sheerka(False, False)
sheerka = self.get_sheerka(use_dict=False, skip_builtins_in_db=False)
a = Concept("a")
sheerka.add_in_cache(a)
sheerka.concepts_definition_cache = {a: OrderedChoice("one", "two")}
@@ -317,10 +317,10 @@ as:
Same test then before,
but make sure that the BNF are correctly persisted and loaded
"""
sheerka = self.get_sheerka(False)
sheerka = self.get_sheerka(use_dict=False)
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' 'two'")[0].body.body
res = self.get_sheerka(False).evaluate_user_input("one two")
res = self.get_sheerka(use_dict=False).evaluate_user_input("one two")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a)
@@ -328,12 +328,12 @@ as:
# add another bnf definition
concept_b = sheerka.evaluate_user_input("def concept b from bnf a 'three'")[0].body.body
res = self.get_sheerka(False).evaluate_user_input("one two") # previous one still works
res = self.get_sheerka(use_dict=False).evaluate_user_input("one two") # previous one still works
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a)
res = self.get_sheerka(False).evaluate_user_input("one two three") # new one works
res = self.get_sheerka(use_dict=False).evaluate_user_input("one two three") # new one works
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_b)
@@ -151,15 +151,6 @@ class TestSheerkaPickler(TestUsingFileBasedSheerka):
decoded = SheerkaUnpickler(sheerka).restore(flatten)
assert decoded == obj
def test_serialize_concept(self):
sheerka = self.get_sheerka()
foo = Concept("doo")
flatten = SheerkaPickler(sheerka).flatten(foo)
restored = SheerkaUnpickler(sheerka).restore(flatten)
assert restored == foo
def test_i_do_not_encode_logger(self):
sheerka = self.get_sheerka()
+63 -30
View File
@@ -10,85 +10,98 @@ from sdp.sheerkaDataProvider import Event
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
def set_full_serialization(concept):
concept.metadata.full_serialization = True
return concept
class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
def test_i_can_encode_decode_unknown_concept_metadata(self):
sheerka = self.get_sheerka()
concept = Concept(name="foo", key="my_key")
concept = set_full_serialization(Concept(name="foo", key="my_key"))
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "meta.key": "my_key"}'
assert decoded == concept
concept = Concept("foo", is_builtin=True, is_unique=True)
concept = set_full_serialization(Concept("foo", is_builtin=True, is_unique=True))
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "meta.is_builtin": true, "meta.is_unique": true}'
concept = Concept("foo", body="my_body")
concept = set_full_serialization(Concept("foo", body="my_body"))
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "meta.body": "my_body"}'
concept = Concept("foo", pre="my_pre")
concept = set_full_serialization(Concept("foo", pre="my_pre"))
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "meta.pre": "my_pre"}'
concept = Concept("foo", post="my_post")
concept = set_full_serialization(Concept("foo", post="my_post"))
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "meta.post": "my_post"}'
concept = Concept("foo", where="my_where")
concept = set_full_serialization(Concept("foo", where="my_where"))
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "meta.where": "my_where"}'
concept = Concept("foo").def_prop("a", "value_a").def_prop("b", "value_b")
concept = set_full_serialization(Concept("foo").def_prop("a", "value_a").def_prop("b", "value_b"))
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
concept = Concept("foo").init_key()
sheerka.create_new_concept(self.get_context(sheerka), concept)
concept.metadata.full_serialization = True
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "meta.key": "foo", "meta.id": "1001"}'
def test_i_can_encode_decode_unknown_concept_values(self):
sheerka = self.get_sheerka()
concept = Concept("foo")
concept = set_full_serialization(Concept("foo"))
concept.values[ConceptParts.PRE] = 10 # an int
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "pre": 10}'
concept = Concept("foo")
concept.values[ConceptParts.POST] = 'a string' # an int
concept = set_full_serialization(Concept("foo"))
concept.values[ConceptParts.POST] = 'a string' # an string
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "post": "a string"}'
concept = Concept("foo")
concept = set_full_serialization(Concept("foo"))
concept.values[ConceptParts.WHERE] = ['a string', 3.14] # a list
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "where": ["a string", 3.14]}'
concept = Concept("foo")
concept = set_full_serialization(Concept("foo"))
concept.values[ConceptParts.WHERE] = ('a string', 3.14) # a tuple
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "where": {"_sheerka/tuple": ["a string", 3.14]}}'
concept = Concept("foo")
concept.values[ConceptParts.BODY] = Concept("foo", body="foo_body")
concept = set_full_serialization(Concept("foo"))
concept.values[ConceptParts.BODY] = set_full_serialization(Concept("foo", body="foo_body"))
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
@@ -97,28 +110,28 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
def test_i_can_encode_decode_unknown_concept_properties(self):
sheerka = self.get_sheerka()
concept = Concept("foo")
concept = set_full_serialization(Concept("foo"))
concept.set_prop("a", "value_a") # string
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "props": [["a", "value_a"]]}'
concept = Concept("foo")
concept = set_full_serialization(Concept("foo"))
concept.set_prop("a", 10) # int
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "props": [["a", 10]]}'
concept = Concept("foo")
concept.set_prop("a", Concept("bar")) # another concept
concept = set_full_serialization(Concept("foo"))
concept.set_prop("a", set_full_serialization(Concept("bar"))) # another concept
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "props": [["a", {"_sheerka/obj": "core.concept.Concept", "meta.name": "bar"}]]}'
concept = Concept("foo")
concept = set_full_serialization(Concept("foo"))
concept.set_prop("a", "a").set_prop("b", "b") # at least two props
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
@@ -138,19 +151,38 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
assert decoded == ref_concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "concept/id": ["my_key", "1001"]}'
# same test, modify a value and check if this modification is correctly saved
concept = Concept().update_from(sheerka.get_by_id(ref_concept.id))
concept.set_metadata_value(ConceptParts.BODY, Concept("bar"))
concept.set_metadata_value(ConceptParts.BODY, set_full_serialization(Concept("bar")))
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "concept/id": ["my_key", "1001"], "body": {"_sheerka/obj": "core.concept.Concept", "meta.name": "bar"}}'
def test_i_can_encode_decode_when_property_is_a_concept(self):
sheerka = self.get_sheerka()
foo = Concept("foo").init_key()
sheerka.create_new_concept(self.get_context(sheerka), foo)
concept = Concept("my_name").init_key()
sheerka.create_new_concept(self.get_context(sheerka), concept)
concept.def_prop(foo, "a value")
concept.metadata.full_serialization = True
to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "my_name", "meta.key": "my_name", ' + \
'"meta.props": [{"_sheerka/tuple": [{"_sheerka/obj": "core.concept.Concept", "concept/id": ["foo", "1001"]}, "a value"]}], ' + \
'"meta.id": "1002", "props": [[{"_sheerka/id": 1}, null]]}'
def test_i_can_manage_reference_of_the_same_object(self):
sheerka = self.get_sheerka()
concept_ref = Concept("foo")
concept_ref = set_full_serialization(Concept("foo"))
concept = Concept("bar")
concept = set_full_serialization(Concept("bar"))
concept.set_metadata_value(ConceptParts.PRE, concept_ref)
concept.set_metadata_value(ConceptParts.BODY, concept_ref)
@@ -189,7 +221,7 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
to_string = sheerkapickle.encode(sheerka, ret_val)
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == ret_val
assert to_string == '{"_sheerka/obj": "core.builtin_concepts.ReturnValueConcept", "who": "who", "status": true, "value": 10}'
assert to_string == '{"_sheerka/obj": "core.builtin_concepts.ReturnValueConcept", "concept/id": ["__RETURN_VALUE", null], "who": "who", "status": true, "value": 10}'
def test_i_can_encode_decode_return_value_with_parent(self):
sheerka = self.get_sheerka()
@@ -202,13 +234,14 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == ret_val
assert decoded.parents == ret_val.parents
parents_str = '[{"_sheerka/obj": "core.builtin_concepts.ReturnValueConcept", "who": "parent_who", "status": true, "value": "10"}, {"_sheerka/id": 1}]'
assert to_string == '{"_sheerka/obj": "core.builtin_concepts.ReturnValueConcept", "who": "who", "status": true, "value": 10, "parents": ' + parents_str + '}'
id_str = ', "concept/id": ["__RETURN_VALUE", null]'
parents_str = '[{"_sheerka/obj": "core.builtin_concepts.ReturnValueConcept"' + id_str + ', "who": "parent_who", "status": true, "value": "10"}, {"_sheerka/id": 1}]'
assert to_string == '{"_sheerka/obj": "core.builtin_concepts.ReturnValueConcept"' + id_str + ', "who": "who", "status": true, "value": 10, "parents": ' + parents_str + '}'
def test_i_can_encode_decode_return_values_with_complex_body(self):
sheerka = self.get_sheerka()
ret_val = sheerka.ret("who", True, Concept("foo", body="bar"))
ret_val = sheerka.ret("who", True, set_full_serialization(Concept("foo", body="bar")))
to_string = sheerkapickle.encode(sheerka, ret_val)
decoded = sheerkapickle.decode(sheerka, to_string)
@@ -239,9 +272,9 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
context = ExecutionContext("who", Event("xxx"), sheerka, "my desc")
input_list = [ReturnValueConcept("who", True, 10), ReturnValueConcept("who2", False, 20)]
context.inputs = {"a": input_list, "b": Concept("foo")}
context.values = {"c": input_list, "d": Concept("bar")}
context.obj = Concept("baz")
context.inputs = {"a": input_list, "b": set_full_serialization(Concept("foo"))}
context.values = {"c": input_list, "d": set_full_serialization(Concept("bar"))}
context.obj = set_full_serialization(Concept("baz"))
context.push("who3", "sub_child1")
context.push("who4", "sub_child2")
@@ -278,7 +311,7 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
def test_encode_simple_concept(self):
sheerka = self.get_sheerka()
foo = Concept("foo")
foo = set_full_serialization(Concept("foo"))
to_string = sheerkapickle.encode(sheerka, foo)
decoded = sheerkapickle.decode(sheerka, to_string)