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) value = node.get_prop(field)
if isinstance(value, list) or isinstance(value, Concept) and value.key == str(BuiltinConcepts.LIST): if isinstance(value, list) or isinstance(value, Concept) and value.key == str(BuiltinConcepts.LIST):
lst = [] lst = []
for i in value: for i in value.body:
lst.append(_transform(i)) lst.append(_transform(i))
setattr(ast_object, field, lst) setattr(ast_object, field, lst)
elif isinstance(value, NodeConcept): elif isinstance(value, NodeConcept):
+1 -3
View File
@@ -22,7 +22,7 @@ class ConceptNodeVisitor:
"""Called if no explicit visitor function exists for a node.""" """Called if no explicit visitor function exists for a node."""
for field, value in iter_props(node): for field, value in iter_props(node):
if isinstance(value, ListConcept): if isinstance(value, ListConcept):
for item in value: for item in value.body:
if isinstance(item, NodeConcept): if isinstance(item, NodeConcept):
self.visit(item) self.visit(item)
elif isinstance(value, NodeConcept): elif isinstance(value, NodeConcept):
@@ -97,8 +97,6 @@ class ExtractPredicateVisitor(ConceptNodeVisitor):
self.variable_name = variable_name self.variable_name = variable_name
def get_parents(node): def get_parents(node):
if node.parent is None: if node.parent is None:
return [] 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 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 WHERE_CLAUSE_FAILED = "where clause failed" # failed to validate where clause during evaluation
CHICKEN_AND_EGG = "chicken and egg" # infinite recursion when declaring concept 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" NODE = "node"
GENERIC_NODE = "generic node" GENERIC_NODE = "generic node"
@@ -340,8 +341,8 @@ class EnumerationConcept(Concept):
self.set_metadata_value(ConceptParts.BODY, iteration) self.set_metadata_value(ConceptParts.BODY, iteration)
self.metadata.is_evaluated = True self.metadata.is_evaluated = True
def __iter__(self): # def __iter__(self):
return iter(self.body) # return iter(self.body)
class ListConcept(Concept): class ListConcept(Concept):
@@ -353,20 +354,20 @@ class ListConcept(Concept):
def append(self, obj): def append(self, obj):
self.body.append(obj) self.body.append(obj)
def __len__(self): # def __len__(self):
return len(self.body) # return len(self.body)
#
def __getitem__(self, key): # def __getitem__(self, key):
return self.body[key] # return self.body[key]
#
def __setitem__(self, key, value): # def __setitem__(self, key, value):
self.body[key] = value # self.body[key] = value
#
def __iter__(self): # def __iter__(self):
return iter(self.body) # return iter(self.body)
#
def __contains__(self, item): # def __contains__(self, item):
return item in self.body # return item in self.body
class ConceptAlreadyInSet(Concept): class ConceptAlreadyInSet(Concept):
+1 -2
View File
@@ -7,7 +7,6 @@ from core.ast.visitors import UnreferencedNamesVisitor
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
def is_same_success(sheerka, return_values): def is_same_success(sheerka, return_values):
""" """
Returns True if all returns values are successful and have the same value 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": elif node.node_type == "BoolOp":
all_op = True all_op = True
temp_res = [] 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) res = _extract_predicates(sheerka, op, variables_to_include, variables_to_exclude)
if len(res) == 0: if len(res) == 0:
all_op = False 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) 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 props: list # list properties, with their default values
is_evaluated: bool = False # True is the concept is evaluated by sheerka.eval_concept() 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) 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' name = self.name if 'metadata' in vars(self) else 'Concept'
raise AttributeError(f"'{name}' concept has no attribute '{item}'") 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 Adds a property to the metadata
:param prop_name: :param prop_name: name or concept
:param default_value: :param default_value:
:return: :return:
""" """
@@ -242,25 +243,6 @@ class Concept:
def body(self): def body(self):
return self.values[ConceptParts.BODY] if ConceptParts.BODY in self.values else None 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): def get_digest(self):
""" """
Returns the digest of the event Returns the digest of the event
@@ -321,12 +303,22 @@ class Concept:
return self return self
def set_prop(self, prop_name: str, prop_value): def set_prop(self, prop_name, prop_value):
"""Directly sets a value to a property""" """
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) self.props[prop_name] = Property(prop_name, prop_value)
return self return self
def get_prop(self, prop_name: str): 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 return self.props[prop_name].value
def set_metadata_value(self, metadata: ConceptParts, 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)) return self.sheerka.ret(self.logger_name, False, ErrorConcept(init_ret_value.value))
# save the new concept in sdp # save the new concept in sdp
concept.metadata.full_serialization = True
try: try:
# TODO : needs to make these calls atomic (or at least one single call) # TODO : needs to make these calls atomic (or at least one single call)
# save the new concept # save the new concept
@@ -90,6 +91,7 @@ class SheerkaCreateNewConcept:
error.args[0]) error.args[0])
# Updates the caches # 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_key[concept.key] = self.sheerka.sdp.get_safe(self.sheerka.CONCEPTS_ENTRY, concept.key)
self.sheerka.cache_by_id[concept.id] = concept self.sheerka.cache_by_id[concept.id] = concept
if init_ret_value is not None and init_ret_value.status: 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): def dump_desc(self, *concept_names, eval=False):
first = True first = True
event = Event(f"Dumping description", "")
context = ExecutionContext("dump_desc", event, self.sheerka)
for concept_name in concept_names: for concept_name in concept_names:
if isinstance(concept_name, Concept): if isinstance(concept_name, Concept):
concepts = concept_name concepts = concept_name
@@ -45,8 +47,6 @@ class SheerkaDump:
for c in concepts: for c in concepts:
if eval: if eval:
event = Event(f"Evaluating {c}", "")
context = ExecutionContext("dump_desc", event, self.sheerka)
evaluated = self.sheerka.evaluate_concept(context, c) evaluated = self.sheerka.evaluate_concept(context, c)
value = evaluated.body if evaluated.key == c.key else evaluated 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"value : {value}")
self.sheerka.log.info(f"digest : {c.get_digest()}") self.sheerka.log.info(f"digest : {c.get_digest()}")
if self.sheerka.isaset(c): if self.sheerka.isaset(context, c):
items = self.sheerka.get_set_elements(c) items = self.sheerka.get_set_elements(context, c)
self.sheerka.log.info(f"elements : {items}") self.sheerka.log.info(f"elements : {items}")
first = False first = False
@@ -235,6 +235,12 @@ class SheerkaEvaluateConcept:
concept.set_prop(prop_name, resolved) concept.set_prop(prop_name, resolved)
else: else:
part_key = ConceptParts(metadata_to_eval) 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: if part_key in concept.compiled and concept.compiled[part_key] is not None:
metadata_ast = concept.compiled[part_key] metadata_ast = concept.compiled[part_key]
resolved = self.resolve(context, metadata_ast, part_key, concept, logger) 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 concept.values[part_key] = self.get_infinite_recursion_resolution(resolved) or resolved
# validate where clause # validate where clause
if concept.metadata.where is not None: if ConceptParts.WHERE in concept.values:
where_value = concept.values[ConceptParts.WHERE] where_value = concept.values[ConceptParts.WHERE]
if not (where_value is None or self.sheerka.value(where_value) is True): if not (where_value is None or self.sheerka.value(where_value) is True):
return self.sheerka.new(BuiltinConcepts.WHERE_CLAUSE_FAILED, body=concept) 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)) events = list(self.sheerka.sdp.load_events(depth_or_digest, start))
for event in events: for event in events:
try: try:
result = self.sheerka.sdp.load_result(self.sheerka, event.get_digest()) result = self.sheerka.sdp.load_result(event.get_digest())
except (IOError, KeyError): except (IOError, KeyError):
result = None result = None
yield History(event, result) 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.builtin_concepts import BuiltinConcepts, ErrorConcept
from core.concept import Concept from core.concept import Concept, ConceptParts
import core.builtin_helpers
GROUP_PREFIX = 'All_' GROUP_PREFIX = 'All_'
@@ -9,6 +11,30 @@ class SheerkaSetsManager:
self.sheerka = sheerka self.sheerka = sheerka
self.logger_name = self.add_concept_to_set.__name__ 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): def add_concept_to_set(self, context, concept, concept_set, logger=None):
""" """
Add an entry in sdp to tell that concept isa concept_set 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) 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]) 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 Concept is supposed to be a set
Returns all elements if the set Returns all elements if the set
:param context:
:param concept: :param concept:
:param logger:
:return: :return:
""" """
assert concept.id logger = logger or self.sheerka.log
ids = self.sheerka.sdp.get_safe(GROUP_PREFIX + concept.id) # noinspection PyShadowingNames
if ids is None: 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) return self.sheerka.new(BuiltinConcepts.NOT_A_SET, body=concept)
elements = [self.sheerka.get_by_id(element_id) for element_id in ids] ids = self.sheerka.sdp.get_safe(GROUP_PREFIX + sub_concept.id)
return elements 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 return true if the concept a is a b
Will handle when the keyword isa will be implemented Will handle when the keyword isa will be implemented
@@ -82,17 +135,101 @@ class SheerkaSetsManager:
if isinstance(a, BuiltinConcepts): # common KSI error ;-) if isinstance(a, BuiltinConcepts): # common KSI error ;-)
raise SyntaxError("Remember that the first parameter of isinstance MUST be a concept") raise SyntaxError("Remember that the first parameter of isinstance MUST be a concept")
assert isinstance(a, Concept) if not (isinstance(a, Concept) and isinstance(b, Concept)):
assert isinstance(b, Concept) return False
# TODO, first check the 'isa' property of a # 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): return False
"""True if exists All_<concept_id> in sdp"""
if not concept.id: 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 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) res = self.sheerka.sdp.get_safe(GROUP_PREFIX + concept.id)
return res is not None 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.SheerkaEvaluateConcept import SheerkaEvaluateConcept
from core.sheerka.Services.SheerkaExecute import SheerkaExecute from core.sheerka.Services.SheerkaExecute import SheerkaExecute
from core.sheerka.Services.SheerkaHistoryManager import SheerkaHistoryManager from core.sheerka.Services.SheerkaHistoryManager import SheerkaHistoryManager
from core.sheerka.Services.SheerkaModifyConcept import SheerkaModifyConcept
from core.sheerka.Services.SheerkaSetsManager import SheerkaSetsManager from core.sheerka.Services.SheerkaSetsManager import SheerkaSetsManager
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event from sdp.sheerkaDataProvider import SheerkaDataProvider, Event
import core.utils import core.utils
@@ -81,12 +82,14 @@ class Sheerka(Concept):
self.execute_handler = SheerkaExecute(self) self.execute_handler = SheerkaExecute(self)
self.create_new_concept_handler = SheerkaCreateNewConcept(self) self.create_new_concept_handler = SheerkaCreateNewConcept(self)
self.modify_concept_handler = SheerkaModifyConcept(self)
self.dump_handler = SheerkaDump(self) self.dump_handler = SheerkaDump(self)
self.sets_handler = SheerkaSetsManager(self) self.sets_handler = SheerkaSetsManager(self)
self.evaluate_concept_handler = SheerkaEvaluateConcept(self) self.evaluate_concept_handler = SheerkaEvaluateConcept(self)
self.history_handler = SheerkaHistoryManager(self) self.history_handler = SheerkaHistoryManager(self)
self.during_restore = False self.during_restore = False
self._builtins_classes_cache = None
def initialize(self, root_folder: str = None): def initialize(self, root_folder: str = None):
""" """
@@ -101,7 +104,7 @@ class Sheerka(Concept):
from sheerkapickle.sheerka_handlers import initialize_pickle_handlers from sheerkapickle.sheerka_handlers import initialize_pickle_handlers
initialize_pickle_handlers() initialize_pickle_handlers()
self.sdp = SheerkaDataProvider(root_folder) self.sdp = SheerkaDataProvider(root_folder, self)
if self.sdp.first_time: if self.sdp.first_time:
self.sdp.set_key(self.USER_CONCEPTS_KEYS, 1000) self.sdp.set_key(self.USER_CONCEPTS_KEYS, 1000)
@@ -117,7 +120,7 @@ class Sheerka(Concept):
exec_context.add_values(return_values=res) exec_context.add_values(return_values=res)
if not self.skip_builtins_in_db: if not self.skip_builtins_in_db:
self.sdp.save_result(self, exec_context) self.sdp.save_result(exec_context)
except IOError as e: except IOError as e:
res = ReturnValueConcept(self, False, self.get(BuiltinConcepts.ERROR), e) res = ReturnValueConcept(self, False, self.get(BuiltinConcepts.ERROR), e)
@@ -151,6 +154,7 @@ class Sheerka(Concept):
if from_db is None: if from_db is None:
self.init_log.debug(f"'{concept.name}' concept is not found in db. Adding.") self.init_log.debug(f"'{concept.name}' concept is not found in db. Adding.")
self.set_id_if_needed(concept, True) self.set_id_if_needed(concept, True)
concept.metadata.full_serialization = True
self.sdp.add("init", self.CONCEPTS_ENTRY, concept, use_ref=True) self.sdp.add("init", self.CONCEPTS_ENTRY, concept, use_ref=True)
else: else:
self.init_log.debug(f"Found concept '{from_db}' in db. Updating.") 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) execution_context.add_values(return_values=ret)
if not self.skip_builtins_in_db: 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 not self.during_restore:
# if len(ret) == 1 and ret[0].status and self.isinstance(ret[0].value, BuiltinConcepts.NEW_CONCEPT): # if len(ret) == 1 and ret[0].status and self.isinstance(ret[0].value, BuiltinConcepts.NEW_CONCEPT):
# with open(CONCEPTS_FILE, "a") as f: # 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) 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): def add_concept_to_set(self, context, concept, concept_set, logger=None):
""" """
Add an entry in sdp to tell that concept isa concept_set 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) 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 Concept is supposed to be a set
Returns all elements if the set Returns all elements if the set
:param context:
:param concept: :param concept:
:return: :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): def evaluate_concept(self, context, concept: Concept, logger=None):
""" """
@@ -524,8 +543,11 @@ class Sheerka(Concept):
self.isinstance(objs, BuiltinConcepts.ENUMERATION)): self.isinstance(objs, BuiltinConcepts.ENUMERATION)):
objs = [objs] objs = [objs]
if isinstance(objs, list):
return (self.value(obj) for obj in objs) return (self.value(obj) for obj in objs)
return (self.value(obj) for obj in objs.body)
def is_success(self, obj): def is_success(self, obj):
if isinstance(obj, bool): # quick win if isinstance(obj, bool): # quick win
return obj return obj
@@ -562,11 +584,14 @@ class Sheerka(Concept):
return a.key == b_key return a.key == b_key
def isinset(self, a, b):
return self.sets_handler.isinset(a, b)
def isa(self, a, b): def isa(self, a, b):
return self.sets_handler.isa(a, b) return self.sets_handler.isa(a, b)
def isaset(self, concept): def isaset(self, context, concept):
return self.sets_handler.isaset(concept) return self.sets_handler.isaset(context, concept)
def get_evaluator_name(self, name): def get_evaluator_name(self, name):
if self.evaluators_prefix is None: 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: if not isinstance(part_ret_val, ReturnValueConcept) or not part_ret_val.status:
continue # Nothing to do is not initialized continue # Nothing to do is not initialized
# update the parts # update the metadata
source = self.get_source(part_ret_val) source = self.get_source(part_ret_val)
setattr(concept.metadata, prop, source) setattr(concept.metadata, prop, source)
+9 -1
View File
@@ -29,13 +29,21 @@ class EvalEvaluator(AllReturnValuesEvaluator):
for ret_val in return_values: for ret_val in return_values:
if ret_val.status and isinstance(ret_val.body, Concept) and ret_val.body.body: 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])) 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: if len(result) > 0:
return result return result
else: else:
# suppress the successful BuiltinConcepts.CONCEPT_EVAL_REQUESTED # suppress the successful BuiltinConcepts.CONCEPT_EVAL_REQUESTED
# status of CONCEPT_EVAL_REQUESTED is now set to False
return sheerka.ret( return sheerka.ret(
self.name, self.name,
False, False,
+10 -8
View File
@@ -42,17 +42,18 @@ class PythonEvaluator(OneReturnValueEvaluator):
return sheerka.ret(self.name, False, not_for_me, parents=[return_value]) return sheerka.ret(self.name, False, not_for_me, parents=[return_value])
# get locals # get locals
my_locals = self.get_locals(context, node) my_globals = self.get_globals(context, node)
context.log(self.verbose_log, f"locals={my_locals}", self.name) my_locals = {}
context.log(self.verbose_log, f"globals={my_globals}", self.name)
# eval # eval
if isinstance(node.ast_, ast.Expression): if isinstance(node.ast_, ast.Expression):
context.log(self.verbose_log, "Evaluating using 'eval'.", self.name) context.log(self.verbose_log, "Evaluating using 'eval'.", self.name)
compiled = compile(node.ast_, "<string>", "eval") compiled = compile(node.ast_, "<string>", "eval")
evaluated = eval(compiled, {}, my_locals) evaluated = eval(compiled, my_globals, my_locals)
else: else:
context.log(self.verbose_log, "Evaluating using 'exec'.", self.name) 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) context.log(self.verbose_log, f"{evaluated=}", self.name)
return sheerka.ret(self.name, True, evaluated, parents=[return_value]) return sheerka.ret(self.name, True, evaluated, parents=[return_value])
@@ -62,7 +63,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
error = sheerka.new(BuiltinConcepts.ERROR, body=error) error = sheerka.new(BuiltinConcepts.ERROR, body=error)
return sheerka.ret(self.name, False, error, parents=[return_value]) return sheerka.ret(self.name, False, error, parents=[return_value])
def get_locals(self, context, node): def get_globals(self, context, node):
my_locals = { my_locals = {
"sheerka": context.sheerka, "sheerka": context.sheerka,
"desc": context.sheerka.dump_handler.dump_desc, "desc": context.sheerka.dump_handler.dump_desc,
@@ -70,6 +71,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
"definitions": context.sheerka.dump_handler.dump_definitions, "definitions": context.sheerka.dump_handler.dump_definitions,
"history": context.sheerka.dump_handler.dump_history, "history": context.sheerka.dump_handler.dump_history,
"state": context.sheerka.dump_handler.dump_state, "state": context.sheerka.dump_handler.dump_state,
"Concept": core.concept.Concept
} }
if context.obj: if context.obj:
context.log(self.verbose_log, context.log(self.verbose_log,
@@ -189,7 +191,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
return result 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 = copy.deepcopy(code_ast)
init_ast.body = code_ast.body[:-1] init_ast.body = code_ast.body[:-1]
@@ -199,6 +201,6 @@ class PythonEvaluator(OneReturnValueEvaluator):
exec(compile(init_ast, "<ast>", "exec"), {}, my_locals) exec(compile(init_ast, "<ast>", "exec"), {}, my_locals)
if type(last_ast.body[0]) == ast.Expr: 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: 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: if token.type == TokenKind.CONCEPT:
self.next_token() self.next_token()
concept = self.sheerka.new((token.value[0], token.value[1])) 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) return self.eat_rule_name_if_needed(expr)
if token.type == TokenKind.IDENTIFIER: if token.type == TokenKind.IDENTIFIER:
@@ -260,7 +261,8 @@ class BnfParser(BaseParser):
body=("key", concept_name))) body=("key", concept_name)))
return None return None
else: 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 expr.rule_name = concept.name
return expr return expr
+2 -2
View File
@@ -318,7 +318,7 @@ class ConceptGroupExpression(ConceptExpression):
self.concept = to_match # Memoize self.concept = to_match # Memoize
if to_match not in parser.concepts_grammars: 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] nodes = [ConceptExpression(c, rule_name=c.name) for c in concepts_in_group]
expr = OrderedChoice(nodes) expr = OrderedChoice(nodes)
expr.nodes = nodes expr.nodes = nodes
@@ -697,7 +697,7 @@ class ConceptLexerParser(BaseParser):
# A copy must be created # A copy must be created
def inner_get_model(expression): def inner_get_model(expression):
if isinstance(expression, Concept): if isinstance(expression, Concept):
if self.sheerka.isaset(expression): if self.sheerka.isaset(self.context, expression):
ret = ConceptGroupExpression(expression, rule_name=expression.name) ret = ConceptGroupExpression(expression, rule_name=expression.name)
else: else:
ret = ConceptExpression(expression, rule_name=expression.name) 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 # the definition of a concept consists of several parts
# Keywords.CONCEPT to get the name of the concept # 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.AS to get the body
# Keywords.WHERE to get the conditions to recognize for the variables # Keywords.WHERE to get the conditions to recognize for the variables
# Keywords.PRE to know if the conditions to evaluate the concept # Keywords.PRE to know if the conditions to evaluate the concept
+15 -10
View File
@@ -294,16 +294,18 @@ class SheerkaDataProvider:
KeysFile = "keys" KeysFile = "keys"
REF_PREFIX = "##REF##:" REF_PREFIX = "##REF##:"
def __init__(self, root=None): def __init__(self, root=None, sheerka=None):
self.log = get_logger(__name__) self.log = get_logger(__name__)
self.init_log = get_logger("init." + __name__) self.init_log = get_logger("init." + __name__)
self.init_log.debug("Initializing sdp.") self.init_log.debug("Initializing sdp.")
self.sheerka = sheerka
self.io = SheerkaDataProviderIO.get(root) self.io = SheerkaDataProviderIO.get(root)
self.first_time = self.io.first_time self.first_time = self.io.first_time
self.serializer = Serializer() self.serializer = Serializer()
@staticmethod @staticmethod
def get_obj_key(obj): def get_obj_key(obj):
""" """
@@ -729,13 +731,12 @@ class SheerkaDataProvider:
digest = event.parents[0] digest = event.parents[0]
count += 1 count += 1
def save_result(self, sheerka, execution_context): def save_result(self, execution_context):
""" """
Save the execution context associated with an event Save the execution context associated with an event
To make a long story short, To make a long story short,
for every single user input, there is an event (which is the first thing that is created) 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() and a result (the ExecutionContext created by sheerka.evaluate_user_input()
:param sheerka:
:param execution_context: :param execution_context:
:return: :return:
""" """
@@ -745,15 +746,15 @@ class SheerkaDataProvider:
if self.io.exists(target_path): if self.io.exists(target_path):
return digest return digest
context = SerializerContext(sheerka=sheerka) context = SerializerContext(sheerka=self.sheerka)
self.io.write_binary(target_path, self.serializer.serialize(execution_context, context).read()) self.io.write_binary(target_path, self.serializer.serialize(execution_context, context).read())
return digest return digest
def load_result(self, sheerka, digest): def load_result(self, digest):
target_path = self.io.get_obj_path(SheerkaDataProvider.EventFolder, digest) + "_result" target_path = self.io.get_obj_path(SheerkaDataProvider.EventFolder, digest) + "_result"
with self.io.open(target_path, "rb") as f: with self.io.open(target_path, "rb") as f:
context = SerializerContext(sheerka=sheerka) context = SerializerContext(sheerka=self.sheerka)
return self.serializer.deserialize(f, context) return self.serializer.deserialize(f, context)
def save_state(self, state: State): def save_state(self, state: State):
@@ -763,7 +764,8 @@ class SheerkaDataProvider:
if self.io.exists(target_path): if self.io.exists(target_path):
return digest 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 return digest
def load_state(self, digest): def load_state(self, digest):
@@ -772,11 +774,13 @@ class SheerkaDataProvider:
target_path = self.io.get_obj_path(SheerkaDataProvider.StateFolder, digest) target_path = self.io.get_obj_path(SheerkaDataProvider.StateFolder, digest)
with self.io.open(target_path, "rb") as f: 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): def save_obj(self, obj):
self.log.debug(f"Saving '{obj}' as reference...") 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) 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) target_path = self.io.get_obj_path(SheerkaDataProvider.ObjectsFolder, digest)
@@ -798,7 +802,8 @@ class SheerkaDataProvider:
return None return None
with self.io.open(target_path, "rb") as f: 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 # set the origin of the object
if add_origin: if add_origin:
+13 -2
View File
@@ -231,13 +231,24 @@ class StateSerializer(PickleSerializer):
1) 1)
class ConceptSerializer(JsonSerializer): class ConceptSerializer(BaseSerializer):
def __init__(self): def __init__(self):
JsonSerializer.__init__(self, "core.concept.Concept", "C", 1) BaseSerializer.__init__(self, "C", 1)
def matches(self, obj): def matches(self, obj):
return isinstance(obj, Concept) 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): class DictionarySerializer(BaseSerializer):
def __init__(self): def __init__(self):
+20 -27
View File
@@ -16,11 +16,11 @@ class ConceptHandler(BaseHandler):
pickler = self.context pickler = self.context
sheerka = self.sheerka sheerka = self.sheerka
if obj.id: if obj.metadata.full_serialization:
ref = default_concept
else:
ref = sheerka.get_by_id(obj.id) ref = sheerka.get_by_id(obj.id)
data[CONCEPT_ID] = (obj.key, obj.id) data[CONCEPT_ID] = (obj.key, obj.id)
else:
ref = default_concept
# transform metadata # transform metadata
for prop in CONCEPT_PROPERTIES_TO_SERIALIZE: 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 prop not in ref.props or value != ref.props[prop].value:
if "props" not in data: if "props" not in data:
data["props"] = [] data["props"] = []
data["props"].append((prop, pickler.flatten(value))) data["props"].append((pickler.flatten(prop), pickler.flatten(value)))
return data return data
@@ -77,7 +77,7 @@ class ConceptHandler(BaseHandler):
return instance return instance
class UserInputHandler(BaseHandler): class UserInputHandler(ConceptHandler):
def flatten(self, obj: UserInputConcept, data): def flatten(self, obj: UserInputConcept, data):
data[CONCEPT_ID] = (obj.key, obj.id) data[CONCEPT_ID] = (obj.key, obj.id)
@@ -86,12 +86,12 @@ class UserInputHandler(BaseHandler):
return data return data
def new(self, data): def new(self, data):
sheerka = self.sheerka return UserInputConcept.__new__(UserInputConcept)
instance = sheerka.new(tuple(data[CONCEPT_ID]), body=data["text"], user_name=data["user_name"])
return instance
def restore(self, data, instance): 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 return instance
@@ -100,6 +100,7 @@ class ReturnValueHandler(BaseHandler):
def flatten(self, obj: ReturnValueConcept, data): def flatten(self, obj: ReturnValueConcept, data):
pickler = self.context pickler = self.context
data[CONCEPT_ID] = (obj.key, obj.id)
data["who"] = f"c:{obj.who.id}:" if isinstance(obj.who, Concept) else \ 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.name if isinstance(obj.who, (BaseParser, BaseEvaluator)) else \
obj.who obj.who
@@ -110,38 +111,30 @@ class ReturnValueHandler(BaseHandler):
return data return data
def new(self, data): def new(self, data):
sheerka = self.sheerka return ReturnValueConcept.__new__(ReturnValueConcept)
instance = sheerka.ret(data["who"], data["status"], None)
return instance
def restore(self, data, instance): def restore(self, data, instance):
pickler = self.context pickler = self.context
instance.value = pickler.restore(data["value"]) instance.__init__(data["who"], data["status"], pickler.restore(data["value"]))
if "parents" in data: if "parents" in data:
instance.parents = pickler.restore(data["parents"]) instance.parents = pickler.restore(data["parents"])
instance.metadata.key = data[CONCEPT_ID][0]
instance.metadata.id = data[CONCEPT_ID][1]
return instance return instance
# class BuiltinConceptsHandler(BaseHandler): class SheerkaHandler(ConceptHandler):
#
# def flatten(self, obj: BuiltinConcepts, data): # def flatten(self, obj: BuiltinConcepts, data):
# return data # return ConceptHandler().flatten()data
#
# def restore(self, obj):
# pass
class SheerkaHandler(BaseHandler):
def flatten(self, obj: BuiltinConcepts, data):
return data
def new(self, data): def new(self, data):
return self.sheerka return self.sheerka
def restore(self, data, instance): # def restore(self, data, instance):
return instance # return instance
class ExecutionContextHandler(BaseHandler): class ExecutionContextHandler(BaseHandler):
+26 -1
View File
@@ -3,11 +3,12 @@ import ast
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept from core.builtin_concepts import ReturnValueConcept, ParserResultConcept
from core.concept import Concept from core.concept import Concept
from core.sheerka.ExecutionContext import ExecutionContext from core.sheerka.ExecutionContext import ExecutionContext
from parsers.BnfParser import BnfParser
from sdp.sheerkaDataProvider import Event from sdp.sheerkaDataProvider import Event
class BaseTest: class BaseTest:
def get_sheerka(self): def get_sheerka(self, **kwargs):
pass pass
def get_context(self, sheerka=None): def get_context(self, sheerka=None):
@@ -32,6 +33,30 @@ class BaseTest:
dump = dump.replace(to_remove, "") dump = dump.replace(to_remove, "")
return dump 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 @staticmethod
def retval(obj, who="who", status=True): def retval(obj, who="who", status=True):
"""ret_val""" """ret_val"""
+3 -1
View File
@@ -26,7 +26,9 @@ class TestUsingFileBasedSheerka(BaseTest):
os.chdir(current_pwd) 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 root = "mem://" if use_dict else self.root_folder
sheerka = Sheerka(skip_builtins_in_db=skip_builtins_in_db) sheerka = Sheerka(skip_builtins_in_db=skip_builtins_in_db)
sheerka.initialize(root) sheerka.initialize(root)
+2 -1
View File
@@ -4,7 +4,8 @@ from tests.BaseTest import BaseTest
class TestUsingMemoryBasedSheerka(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 = Sheerka(skip_builtins_in_db=skip_builtins_in_db)
sheerka.initialize("mem://") sheerka.initialize("mem://")
return sheerka return sheerka
@@ -457,3 +457,4 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one) evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one)
assert evaluated.key == one.key assert evaluated.key == one.key
assert evaluated.body == 1 assert evaluated.body == 1
+174 -39
View File
@@ -6,41 +6,39 @@ from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
class TestSheerkaSetsManager(TestUsingFileBasedSheerka): class TestSheerkaSetsManager(TestUsingFileBasedSheerka):
def init(self, use_dict, *concepts): # def init(self, use_dict, *concepts):
sheerka = self.get_sheerka(use_dict, True) # sheerka = self.get_sheerka(use_dict, True)
for c in concepts: # for c in concepts:
sheerka.set_id_if_needed(c, False) # sheerka.set_id_if_needed(c, False)
sheerka.add_in_cache(c) # sheerka.add_in_cache(c)
#
context = self.get_context(sheerka) # context = self.get_context(sheerka)
return sheerka, context # return sheerka, context
def test_i_can_add_concept_to_set(self): def test_i_can_add_concept_to_set(self):
foo = Concept("foo") sheerka, context, foo, all_foos = self.init_concepts(Concept("foo"), Concept("all_foo"), use_dict=False)
all_foos = Concept("all_foos")
sheerka, context = self.init(False, foo, all_foos)
res = sheerka.add_concept_to_set(context, foo, all_foos) res = sheerka.add_concept_to_set(context, foo, all_foos)
assert res.status assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS) 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 len(all_entries) == 1
assert foo.id in all_entries assert foo.id in all_entries
def test_i_can_add_several_concepts_to_set(self): def test_i_can_add_several_concepts_to_set(self):
foo1 = Concept("foo1") sheerka, context, foo1, foo2, all_foos = self.init_concepts(
foo2 = Concept("foo2") Concept("foo1"),
all_foos = Concept("all_foos") Concept("foo2"),
sheerka, context = self.init(False, foo1, foo2, all_foos) Concept("all_foo"), use_dict=False)
res = sheerka.sets_handler.add_concepts_to_set(context, (foo1, foo2), all_foos) res = sheerka.sets_handler.add_concepts_to_set(context, (foo1, foo2), all_foos)
assert res.status assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS) 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 len(all_entries) == 2
assert foo1.id in all_entries assert foo1.id in all_entries
assert foo2.id in all_entries assert foo2.id in all_entries
@@ -57,7 +55,7 @@ class TestSheerkaSetsManager(TestUsingFileBasedSheerka):
assert res.status assert res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS) 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 len(all_entries) == 4
assert foo1.id in all_entries assert foo1.id in all_entries
assert foo2.id in all_entries assert foo2.id in all_entries
@@ -65,9 +63,7 @@ class TestSheerkaSetsManager(TestUsingFileBasedSheerka):
assert foo4.id in all_entries assert foo4.id in all_entries
def test_i_cannot_add_the_same_concept_twice_in_a_set(self): def test_i_cannot_add_the_same_concept_twice_in_a_set(self):
foo = Concept("foo") sheerka, context, foo, all_foos = self.init_concepts(Concept("foo"), Concept("all_foos"))
all_foos = Concept("all_foos")
sheerka, context = self.init(True, foo, all_foos)
sheerka.add_concept_to_set(context, foo, all_foos) sheerka.add_concept_to_set(context, foo, all_foos)
res = 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 assert foo.id in all_entries
def test_i_get_elements_from_a_set(self): def test_i_get_elements_from_a_set(self):
one = Concept("one") sheerka, context, one, two, three, number = self.init_concepts(
two = Concept("two") Concept("one"), Concept("two"), Concept("three"), Concept("number"))
three = Concept("three")
number = Concept("number")
sheerka, context = self.init(True, one, two, three, number)
for c in [one, two, three]: for c in [one, two, three]:
sheerka.add_concept_to_set(context, c, number) 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} assert set(elements) == {one, two, three}
def test_i_cannot_get_elements_if_not_a_set(self): def test_i_cannot_get_elements_if_not_a_set(self):
one = Concept("one") sheerka, context, one = self.init_concepts(Concept("one"))
sheerka, context = self.init(True, one)
error = sheerka.get_set_elements(one) error = sheerka.get_set_elements(context, one)
assert sheerka.isinstance(error, BuiltinConcepts.NOT_A_SET) assert sheerka.isinstance(error, BuiltinConcepts.NOT_A_SET)
assert error.body == one assert error.body == one
def test_isa_and_isa_group(self): def test_isa_and_isa_group(self):
group = Concept("group") sheerka, context, group, foo = self.init_concepts(Concept("group"), Concept("foo"))
foo = Concept("foo")
sheerka, context = self.init(True, group, foo)
assert not sheerka.isaset(group) assert not sheerka.isaset(context, group)
assert not sheerka.isa(foo, group) assert not sheerka.isinset(foo, group)
context = self.get_context(sheerka) context = self.get_context(sheerka)
sheerka.add_concept_to_set(context, foo, group) sheerka.add_concept_to_set(context, foo, group)
assert sheerka.isaset(group) assert sheerka.isaset(context, group)
assert sheerka.isa(foo, group) assert sheerka.isinset(foo, group)
def test_i_can_a_multiples_concepts(self): def test_i_can_define_a_group_from_another_group(self):
pass 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 tree_as_concept.node_type == "Module"
assert sheerka.isinstance(tree_as_concept.get_prop("body"), BuiltinConcepts.LIST) 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 sheerka.isinstance(def_func, BuiltinConcepts.GENERIC_NODE)
assert def_func.node_type == "FunctionDef" assert def_func.node_type == "FunctionDef"
assert def_func.parent == NodeParent(tree_as_concept, "body") 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") def_func_args_real_args = def_func_args.get_prop("args")
assert sheerka.isinstance(def_func_args_real_args, BuiltinConcepts.LIST) 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 sheerka.isinstance(def_func_args_real_args.body[0], BuiltinConcepts.GENERIC_NODE)
assert def_func_args_real_args[0].node_type == "arg" assert def_func_args_real_args.body[0].node_type == "arg"
assert def_func_args_real_args[0].parent == NodeParent(def_func_args, "args") assert def_func_args_real_args.body[0].parent == NodeParent(def_func_args, "args")
assert def_func_args_real_args[0].get_prop("arg") == "a" assert def_func_args_real_args.body[0].get_prop("arg") == "a"
assert sheerka.isinstance(def_func_args_real_args[1], BuiltinConcepts.GENERIC_NODE) assert sheerka.isinstance(def_func_args_real_args.body[1], BuiltinConcepts.GENERIC_NODE)
assert def_func_args_real_args[1].node_type == "arg" assert def_func_args_real_args.body[1].node_type == "arg"
assert def_func_args_real_args[1].parent == NodeParent(def_func_args, "args") assert def_func_args_real_args.body[1].parent == NodeParent(def_func_args, "args")
assert def_func_args_real_args[1].get_prop("arg") == "b" assert def_func_args_real_args.body[1].get_prop("arg") == "b"
def_fun_body = def_func.get_prop("body") def_fun_body = def_func.get_prop("body")
assert sheerka.isinstance(def_fun_body, BuiltinConcepts.LIST) 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 sheerka.isinstance(def_fun_body_for, BuiltinConcepts.GENERIC_NODE)
assert def_fun_body_for.node_type == "For" assert def_fun_body_for.node_type == "For"
assert def_fun_body_for.parent == NodeParent(def_func, "body") 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 sheerka.isinstance(def_fun_body_return, BuiltinConcepts.GENERIC_NODE)
assert def_fun_body_return.node_type == "Return" assert def_fun_body_return.node_type == "Return"
assert def_fun_body_return.parent == NodeParent(def_func, "body") 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", ["b"], [], ["b == 2"]),
("a == 1 or b == 2", ["a", "b"], [], ["a == 1 or 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)"]), ("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): def test_i_can_extract_predicates(self, expression, vars_to_include, vars_to_exclude, expected_expr):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
+3 -3
View File
@@ -38,12 +38,12 @@ class TestSheerka(TestUsingFileBasedSheerka):
assert isinstance(sheerka.cache_by_key[key], concept_class) assert isinstance(sheerka.cache_by_key[key], concept_class)
def test_builtin_concepts_can_be_updated(self): 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 = sheerka.get(BuiltinConcepts.SHEERKA)
loaded_sheerka.metadata.desc = "I have a description" loaded_sheerka.metadata.desc = "I have a description"
sheerka.sdp.modify("Test", sheerka.CONCEPTS_ENTRY, loaded_sheerka.key, loaded_sheerka) 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) loaded_sheerka = sheerka.get(BuiltinConcepts.SHEERKA)
assert loaded_sheerka.metadata.desc == "I have a description" assert loaded_sheerka.metadata.desc == "I have a description"
@@ -233,7 +233,7 @@ class TestSheerka(TestUsingFileBasedSheerka):
assert sheerka.value(concept, reduce_simple_list) == expected assert sheerka.value(concept, reduce_simple_list) == expected
def test_list_of_concept_is_sorted_by_id(self): 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() concepts = sheerka.concepts()
assert concepts[0].id < concepts[-1].id assert concepts[0].id < concepts[-1].id
+18
View File
@@ -70,3 +70,21 @@ class TestEvalEvaluator(TestUsingMemoryBasedSheerka):
False, False,
context.sheerka.new(BuiltinConcepts.CONCEPT_EVAL_REQUESTED)) context.sheerka.new(BuiltinConcepts.CONCEPT_EVAL_REQUESTED))
assert evaluated.parents == [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) assert isinstance(res[0].value.body, list)
def test_i_can_create_concept_with_bnf_definition(self): 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") a = Concept("a")
sheerka.add_in_cache(a) sheerka.add_in_cache(a)
sheerka.concepts_definition_cache = {a: OrderedChoice("one", "two")} sheerka.concepts_definition_cache = {a: OrderedChoice("one", "two")}
@@ -317,10 +317,10 @@ as:
Same test then before, Same test then before,
but make sure that the BNF are correctly persisted and loaded 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 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 len(res) == 1
assert res[0].status assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a) assert sheerka.isinstance(res[0].value, concept_a)
@@ -328,12 +328,12 @@ as:
# add another bnf definition # add another bnf definition
concept_b = sheerka.evaluate_user_input("def concept b from bnf a 'three'")[0].body.body 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 len(res) == 1
assert res[0].status assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a) 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 len(res) == 1
assert res[0].status assert res[0].status
assert sheerka.isinstance(res[0].value, concept_b) assert sheerka.isinstance(res[0].value, concept_b)
@@ -151,15 +151,6 @@ class TestSheerkaPickler(TestUsingFileBasedSheerka):
decoded = SheerkaUnpickler(sheerka).restore(flatten) decoded = SheerkaUnpickler(sheerka).restore(flatten)
assert decoded == obj 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): def test_i_do_not_encode_logger(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
+63 -30
View File
@@ -10,85 +10,98 @@ from sdp.sheerkaDataProvider import Event
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
def set_full_serialization(concept):
concept.metadata.full_serialization = True
return concept
class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka): class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
def test_i_can_encode_decode_unknown_concept_metadata(self): def test_i_can_encode_decode_unknown_concept_metadata(self):
sheerka = self.get_sheerka() 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) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "meta.key": "my_key"}' assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "meta.key": "my_key"}'
assert decoded == concept 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) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "meta.is_builtin": true, "meta.is_unique": true}' 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) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "meta.body": "my_body"}' 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) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "meta.pre": "my_pre"}' 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) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "meta.post": "my_post"}' 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) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "meta.where": "my_where"}' 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) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept 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): def test_i_can_encode_decode_unknown_concept_values(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept = Concept("foo") concept = set_full_serialization(Concept("foo"))
concept.values[ConceptParts.PRE] = 10 # an int concept.values[ConceptParts.PRE] = 10 # an int
to_string = sheerkapickle.encode(sheerka, concept) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "pre": 10}' assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "pre": 10}'
concept = Concept("foo") concept = set_full_serialization(Concept("foo"))
concept.values[ConceptParts.POST] = 'a string' # an int concept.values[ConceptParts.POST] = 'a string' # an string
to_string = sheerkapickle.encode(sheerka, concept) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "post": "a string"}' 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 concept.values[ConceptParts.WHERE] = ['a string', 3.14] # a list
to_string = sheerkapickle.encode(sheerka, concept) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "where": ["a string", 3.14]}' 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 concept.values[ConceptParts.WHERE] = ('a string', 3.14) # a tuple
to_string = sheerkapickle.encode(sheerka, concept) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "where": {"_sheerka/tuple": ["a string", 3.14]}}' assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "where": {"_sheerka/tuple": ["a string", 3.14]}}'
concept = Concept("foo") concept = set_full_serialization(Concept("foo"))
concept.values[ConceptParts.BODY] = Concept("foo", body="foo_body") concept.values[ConceptParts.BODY] = set_full_serialization(Concept("foo", body="foo_body"))
to_string = sheerkapickle.encode(sheerka, concept) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept assert decoded == concept
@@ -97,28 +110,28 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
def test_i_can_encode_decode_unknown_concept_properties(self): def test_i_can_encode_decode_unknown_concept_properties(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
concept = Concept("foo") concept = set_full_serialization(Concept("foo"))
concept.set_prop("a", "value_a") # string concept.set_prop("a", "value_a") # string
to_string = sheerkapickle.encode(sheerka, concept) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "props": [["a", "value_a"]]}' 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 concept.set_prop("a", 10) # int
to_string = sheerkapickle.encode(sheerka, concept) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "props": [["a", 10]]}' assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "props": [["a", 10]]}'
concept = Concept("foo") concept = set_full_serialization(Concept("foo"))
concept.set_prop("a", Concept("bar")) # another concept concept.set_prop("a", set_full_serialization(Concept("bar"))) # another concept
to_string = sheerkapickle.encode(sheerka, concept) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept assert decoded == concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "meta.name": "foo", "props": [["a", {"_sheerka/obj": "core.concept.Concept", "meta.name": "bar"}]]}' 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 concept.set_prop("a", "a").set_prop("b", "b") # at least two props
to_string = sheerkapickle.encode(sheerka, concept) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
@@ -138,19 +151,38 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
assert decoded == ref_concept assert decoded == ref_concept
assert to_string == '{"_sheerka/obj": "core.concept.Concept", "concept/id": ["my_key", "1001"]}' 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 = 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) to_string = sheerkapickle.encode(sheerka, concept)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == concept 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"}}' 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): def test_i_can_manage_reference_of_the_same_object(self):
sheerka = self.get_sheerka() 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.PRE, concept_ref)
concept.set_metadata_value(ConceptParts.BODY, concept_ref) concept.set_metadata_value(ConceptParts.BODY, concept_ref)
@@ -189,7 +221,7 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
to_string = sheerkapickle.encode(sheerka, ret_val) to_string = sheerkapickle.encode(sheerka, ret_val)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == ret_val 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): def test_i_can_encode_decode_return_value_with_parent(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
@@ -202,13 +234,14 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
assert decoded == ret_val assert decoded == ret_val
assert decoded.parents == ret_val.parents assert decoded.parents == ret_val.parents
parents_str = '[{"_sheerka/obj": "core.builtin_concepts.ReturnValueConcept", "who": "parent_who", "status": true, "value": "10"}, {"_sheerka/id": 1}]' id_str = ', "concept/id": ["__RETURN_VALUE", null]'
assert to_string == '{"_sheerka/obj": "core.builtin_concepts.ReturnValueConcept", "who": "who", "status": true, "value": 10, "parents": ' + parents_str + '}' 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): def test_i_can_encode_decode_return_values_with_complex_body(self):
sheerka = self.get_sheerka() 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) to_string = sheerkapickle.encode(sheerka, ret_val)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)
@@ -239,9 +272,9 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
context = ExecutionContext("who", Event("xxx"), sheerka, "my desc") context = ExecutionContext("who", Event("xxx"), sheerka, "my desc")
input_list = [ReturnValueConcept("who", True, 10), ReturnValueConcept("who2", False, 20)] input_list = [ReturnValueConcept("who", True, 10), ReturnValueConcept("who2", False, 20)]
context.inputs = {"a": input_list, "b": Concept("foo")} context.inputs = {"a": input_list, "b": set_full_serialization(Concept("foo"))}
context.values = {"c": input_list, "d": Concept("bar")} context.values = {"c": input_list, "d": set_full_serialization(Concept("bar"))}
context.obj = Concept("baz") context.obj = set_full_serialization(Concept("baz"))
context.push("who3", "sub_child1") context.push("who3", "sub_child1")
context.push("who4", "sub_child2") context.push("who4", "sub_child2")
@@ -278,7 +311,7 @@ class TestSheerkaPickleHandler(TestUsingMemoryBasedSheerka):
def test_encode_simple_concept(self): def test_encode_simple_concept(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
foo = Concept("foo") foo = set_full_serialization(Concept("foo"))
to_string = sheerkapickle.encode(sheerka, foo) to_string = sheerkapickle.encode(sheerka, foo)
decoded = sheerkapickle.decode(sheerka, to_string) decoded = sheerkapickle.decode(sheerka, to_string)