Added set of set handling (thru concept ISA)
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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 []
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
#
|
||||
class SheerkaHandler(ConceptHandler):
|
||||
|
||||
# def flatten(self, obj: BuiltinConcepts, data):
|
||||
# return data
|
||||
#
|
||||
# def restore(self, obj):
|
||||
# pass
|
||||
|
||||
|
||||
class SheerkaHandler(BaseHandler):
|
||||
|
||||
def flatten(self, obj: BuiltinConcepts, data):
|
||||
return 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
@@ -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"""
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user