Refactored Concept class for better separation of metadata, compiled and values

This commit is contained in:
2020-01-17 17:27:54 +01:00
parent 3789ef25d1
commit a7b239c167
27 changed files with 614 additions and 349 deletions
+4 -1
View File
@@ -86,7 +86,7 @@ class CallNodeConcept(NodeConcept):
super().__init__(BuiltinConcepts.IDENTIFIER_NODE, "Call", parent) super().__init__(BuiltinConcepts.IDENTIFIER_NODE, "Call", parent)
def get_args_names(self, sheerka): def get_args_names(self, sheerka):
return sheerka.values(self.get_prop("args")) return sheerka.get_values(self.get_prop("args"))
def python_to_concept(python_node): def python_to_concept(python_node):
@@ -105,6 +105,7 @@ def python_to_concept(python_node):
continue continue
value = getattr(node, field) value = getattr(node, field)
concept.def_prop(field)
if isinstance(value, list): if isinstance(value, list):
lst = ListConcept().init_key() lst = ListConcept().init_key()
for i in value: for i in value:
@@ -114,6 +115,8 @@ def python_to_concept(python_node):
concept.set_prop(field, _transform(value, NodeParent(concept, field))) concept.set_prop(field, _transform(value, NodeParent(concept, field)))
else: else:
concept.set_prop(field, value) concept.set_prop(field, value)
concept.metadata.is_evaluated = True
return concept return concept
return _transform(python_node, None) return _transform(python_node, None)
+1 -1
View File
@@ -84,7 +84,7 @@ class UnreferencedNamesVisitor(ConceptNodeVisitor):
if node.get_node_type() == "FunctionDef": if node.get_node_type() == "FunctionDef":
# variable defined as a function parameter # variable defined as a function parameter
args = node.get_prop("args") args = node.get_prop("args")
args_values = list(self.sheerka.values(args.get_prop("args"))) args_values = list(self.sheerka.get_values(args.get_prop("args")))
if variable_name in args_values: if variable_name in args_values:
return True return True
+32 -15
View File
@@ -1,6 +1,6 @@
from enum import Enum from enum import Enum
from core.concept import Concept from core.concept import Concept, ConceptParts
class BuiltinConcepts(Enum): class BuiltinConcepts(Enum):
@@ -97,8 +97,10 @@ It's mainly to ease the usage
class UserInputConcept(Concept): class UserInputConcept(Concept):
def __init__(self, text=None, user_name=None): def __init__(self, text=None, user_name=None):
super().__init__(BuiltinConcepts.USER_INPUT, True, False, BuiltinConcepts.USER_INPUT, text) super().__init__(BuiltinConcepts.USER_INPUT, True, False, BuiltinConcepts.USER_INPUT)
self.set_metadata_value(ConceptParts.BODY, text)
self.set_prop("user_name", user_name) self.set_prop("user_name", user_name)
self.metadata.is_evaluated = True
@property @property
def text(self): def text(self):
@@ -114,7 +116,9 @@ class UserInputConcept(Concept):
class ErrorConcept(Concept): class ErrorConcept(Concept):
def __init__(self, error=None): def __init__(self, error=None):
super().__init__(BuiltinConcepts.ERROR, True, False, BuiltinConcepts.ERROR, error) super().__init__(BuiltinConcepts.ERROR, True, False, BuiltinConcepts.ERROR)
self.set_metadata_value(ConceptParts.BODY, error)
self.metadata.is_evaluated = True
def __repr__(self): def __repr__(self):
return f"({self.id}){self.name}: {self.body}" return f"({self.id}){self.name}: {self.body}"
@@ -127,11 +131,13 @@ class ReturnValueConcept(Concept):
""" """
def __init__(self, who=None, status=None, value=None, message=None, parents=None): def __init__(self, who=None, status=None, value=None, message=None, parents=None):
super().__init__(BuiltinConcepts.RETURN_VALUE, True, False, BuiltinConcepts.RETURN_VALUE, value) super().__init__(BuiltinConcepts.RETURN_VALUE, True, False, BuiltinConcepts.RETURN_VALUE)
self.set_metadata_value(ConceptParts.BODY, value)
self.set_prop("who", who) self.set_prop("who", who)
self.set_prop("status", status) self.set_prop("status", status)
self.set_prop("message", message) self.set_prop("message", message)
self.set_prop("parents", parents) self.set_prop("parents", parents)
self.metadata.is_evaluated = True
@property @property
def who(self): def who(self):
@@ -155,7 +161,7 @@ class ReturnValueConcept(Concept):
@value.setter @value.setter
def value(self, value): def value(self, value):
self.metadata.body = value self.set_metadata_value(ConceptParts.BODY, value)
@property @property
def message(self): def message(self):
@@ -200,8 +206,10 @@ class UnknownPropertyConcept(Concept):
""" """
def __init__(self, property_name=None, concept=None): def __init__(self, property_name=None, concept=None):
super().__init__(BuiltinConcepts.UNKNOWN_PROPERTY, True, False, BuiltinConcepts.UNKNOWN_PROPERTY, property_name) super().__init__(BuiltinConcepts.UNKNOWN_PROPERTY, True, False, BuiltinConcepts.UNKNOWN_PROPERTY)
self.set_metadata_value(ConceptParts.BODY, property_name)
self.set_prop("concept", concept) self.set_prop("concept", concept)
self.metadata.is_evaluated = True
def __repr__(self): def __repr__(self):
return f"UnknownProperty(property={self.property_name}, concept={self.concept})" return f"UnknownProperty(property={self.property_name}, concept={self.concept})"
@@ -221,10 +229,12 @@ class ParserResultConcept(Concept):
""" """
def __init__(self, parser=None, source=None, value=None, try_parsed=None): def __init__(self, parser=None, source=None, value=None, try_parsed=None):
super().__init__(BuiltinConcepts.PARSER_RESULT, True, False, BuiltinConcepts.PARSER_RESULT, value) super().__init__(BuiltinConcepts.PARSER_RESULT, True, False, BuiltinConcepts.PARSER_RESULT)
self.set_metadata_value(ConceptParts.BODY, value)
self.set_prop("parser", parser) self.set_prop("parser", parser)
self.set_prop("source", source) self.set_prop("source", source)
self.set_prop("try_parsed", try_parsed) # in case of error, what was found before the error self.set_prop("try_parsed", try_parsed) # in case of error, what was found before the error
self.metadata.is_evaluated = True
def __repr__(self): def __repr__(self):
text = f"ParserResult(parser={self.props['parser'].value}" text = f"ParserResult(parser={self.props['parser'].value}"
@@ -273,9 +283,10 @@ class InvalidReturnValueConcept(Concept):
BuiltinConcepts.INVALID_RETURN_VALUE, BuiltinConcepts.INVALID_RETURN_VALUE,
True, True,
False, False,
BuiltinConcepts.INVALID_RETURN_VALUE, BuiltinConcepts.INVALID_RETURN_VALUE)
return_value) self.set_metadata_value(ConceptParts.BODY, return_value)
self.set_prop("evaluator", evaluator) self.set_prop("evaluator", evaluator)
self.metadata.is_evaluated = True
class ConceptEvalError(Concept): class ConceptEvalError(Concept):
@@ -283,10 +294,11 @@ class ConceptEvalError(Concept):
super().__init__(BuiltinConcepts.CONCEPT_EVAL_ERROR, super().__init__(BuiltinConcepts.CONCEPT_EVAL_ERROR,
True, True,
False, False,
BuiltinConcepts.CONCEPT_EVAL_ERROR, BuiltinConcepts.CONCEPT_EVAL_ERROR)
error) self.set_metadata_value(ConceptParts.BODY, error)
self.set_prop("concept", concept) self.set_prop("concept", concept)
self.set_prop("property_name", property_name) self.set_prop("property_name", property_name)
self.metadata.is_evaluated = True
def __repr__(self): def __repr__(self):
return f"ConceptEvalError(error={self.error}, concept={self.concept}, property={self.property_name})" return f"ConceptEvalError(error={self.error}, concept={self.concept}, property={self.property_name})"
@@ -306,7 +318,9 @@ class ConceptEvalError(Concept):
class EnumerationConcept(Concept): class EnumerationConcept(Concept):
def __init__(self, iteration=None): def __init__(self, iteration=None):
super().__init__(BuiltinConcepts.ENUMERATION, True, False, BuiltinConcepts.ENUMERATION, iteration) super().__init__(BuiltinConcepts.ENUMERATION, True, False, BuiltinConcepts.ENUMERATION)
self.set_metadata_value(ConceptParts.BODY, iteration)
self.metadata.is_evaluated = True
def __iter__(self): def __iter__(self):
return iter(self.body) return iter(self.body)
@@ -314,7 +328,9 @@ class EnumerationConcept(Concept):
class ListConcept(Concept): class ListConcept(Concept):
def __init__(self, items=None): def __init__(self, items=None):
super().__init__(BuiltinConcepts.LIST, True, False, BuiltinConcepts.LIST, items or []) super().__init__(BuiltinConcepts.LIST, True, False, BuiltinConcepts.LIST)
self.set_metadata_value(ConceptParts.BODY, items or [])
self.metadata.is_evaluated = True
def append(self, obj): def append(self, obj):
self.body.append(obj) self.body.append(obj)
@@ -340,9 +356,10 @@ class ConceptAlreadyInSet(Concept):
super().__init__(BuiltinConcepts.CONCEPT_ALREADY_IN_SET, super().__init__(BuiltinConcepts.CONCEPT_ALREADY_IN_SET,
True, True,
False, False,
BuiltinConcepts.CONCEPT_ALREADY_IN_SET, BuiltinConcepts.CONCEPT_ALREADY_IN_SET)
concept) self.set_metadata_value(ConceptParts.BODY, concept)
self.set_prop("concept_set", concept_set) self.set_prop("concept_set", concept_set)
self.metadata.is_evaluated = True
def __repr__(self): def __repr__(self):
return f"ConceptAlreadyInSet(concept={self.concept}, concept_set={self.concept_set})" return f"ConceptAlreadyInSet(concept={self.concept}, concept_set={self.concept_set})"
+4 -3
View File
@@ -121,10 +121,11 @@ def get_names(sheerka, concept_node):
def extract_predicates(sheerka, expression, variables_to_include, variables_to_exclude): def extract_predicates(sheerka, expression, variables_to_include, variables_to_exclude):
""" """
from expression, tries to find all the predicates referencing a variable, and the variable only from a given expression and a variable (or list of variables)
tries to find out all the predicates referencing the(se) variable(s), and the(se) variable(s) solely
for example for example
exp : isinstance(a, int) and isinstance(b, str) exp : isinstance(a, int) and isinstance(b, str)
will return 'isinstance(a, int)' if variable_name == 'a' will return 'isinstance(a, int)' if variable_name == 'a'
:param sheerka: :param sheerka:
:param expression: :param expression:
:param variables_to_include: :param variables_to_include:
+126 -29
View File
@@ -1,5 +1,6 @@
import hashlib import hashlib
from dataclasses import dataclass from collections import namedtuple
from dataclasses import dataclass, field
from enum import Enum from enum import Enum
from core.sheerka_logger import get_logger from core.sheerka_logger import get_logger
@@ -10,7 +11,7 @@ PROPERTIES_FOR_DIGEST = ("name", "key",
"definition", "definition_type", "definition", "definition_type",
"is_builtin", "is_unique", "is_builtin", "is_unique",
"where", "pre", "post", "body", "where", "pre", "post", "body",
"desc") "desc", "props")
PROPERTIES_TO_SERIALIZE = PROPERTIES_FOR_DIGEST + tuple(["id"]) PROPERTIES_TO_SERIALIZE = PROPERTIES_FOR_DIGEST + tuple(["id"])
PROPERTIES_FOR_NEW = ("where", "pre", "post", "body", "desc") PROPERTIES_FOR_NEW = ("where", "pre", "post", "body", "desc")
VARIABLE_PREFIX = "__var__" VARIABLE_PREFIX = "__var__"
@@ -44,9 +45,13 @@ class ConceptMetadata:
definition_type: str # definition can be done with something else than regex definition_type: str # definition can be done with something else than regex
desc: str # possible description for the concept desc: str # possible description for the concept
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
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()
simplec = namedtuple("concept", "name body") # for simple concept (tests purposes only)
class Concept: class Concept:
""" """
Default concept object Default concept object
@@ -65,7 +70,8 @@ class Concept:
definition=None, definition=None,
definition_type=None, definition_type=None,
desc=None, desc=None,
id=None): id=None,
props=None):
metadata = ConceptMetadata( metadata = ConceptMetadata(
str(name) if name else None, str(name) if name else None,
@@ -79,12 +85,14 @@ class Concept:
definition, definition,
definition_type, definition_type,
desc, desc,
id id,
props or []
) )
self.metadata = metadata self.metadata = metadata
self.props = {} # list of Property for this concept self.compiled = {} # cached ast for the where, pre, post and body parts
self.cached_asts = {} # cached ast for the where, pre, post and body parts self.values = {} # values of metadata once resolved
self.props = {} # resolved properties of this concept
self.bnf = None self.bnf = None
self.log = get_logger("core." + self.__class__.__name__) self.log = get_logger("core." + self.__class__.__name__)
self.init_log = get_logger("init.core." + self.__class__.__name__) self.init_log = get_logger("init.core." + self.__class__.__name__)
@@ -93,10 +101,17 @@ class Concept:
return f"({self.metadata.id}){self.metadata.name}" return f"({self.metadata.id}){self.metadata.name}"
def __eq__(self, other): def __eq__(self, other):
if isinstance(other, simplec):
return self.name == other.name and self.body == other.body
if id(self) == id(other):
return True
if not isinstance(other, Concept): if not isinstance(other, Concept):
return False return False
# check the attributes # check the metadata
for prop in PROPERTIES_TO_SERIALIZE: for prop in PROPERTIES_TO_SERIALIZE:
# print(prop) # use full to know which id does not match # print(prop) # use full to know which id does not match
my_value = getattr(self.metadata, prop) my_value = getattr(self.metadata, prop)
@@ -119,9 +134,19 @@ class Concept:
if my_value != other_value: if my_value != other_value:
return False return False
# check the props (Concept variables) # checks the values
for var_name, p in self.props.items(): if len(self.values) != len(other.values):
if p != other.props[var_name]: return False
for metadata in self.values:
if self.get_metadata_value(metadata) != other.get_metadata_value(metadata):
return False
if len(self.props) != len(other.props):
return False
for prop in self.props:
if self.get_prop(prop) != other.get_prop(prop):
return False return False
return True return True
@@ -138,6 +163,33 @@ 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):
"""
Adds a property to the metadata
:param prop_name:
:param default_value:
:return:
"""
assert default_value is None or isinstance(default_value, str) # default properties will have to be evaluated
self.metadata.props.append((prop_name, default_value))
self.props[prop_name] = Property(prop_name, None) # do not set the default value
# why not setting props to the default values ?
# Because it may not be the real values, as metadata.props need to be evaluated
return self
def def_prop_by_index(self, index: int, value):
"""
Re-assign a value to a property (mainly used by ExactConceptParser)
:param index:
:param value:
:return:
"""
assert value is None or isinstance(value, str) # default properties will have to be evaluated
prop = self.metadata.props[index]
self.metadata.props[index] = (prop[0], value)
return self
@property @property
def name(self): def name(self):
return self.metadata.name return self.metadata.name
@@ -165,7 +217,7 @@ class Concept:
if tokens is None: if tokens is None:
tokens = list(Tokenizer(self.metadata.name)) tokens = list(Tokenizer(self.metadata.name))
variables = list(self.props.keys()) if len(core.utils.strip_tokens(tokens, True)) > 1 else [] variables = [p[0] for p in self.metadata.props] if len(core.utils.strip_tokens(tokens, True)) > 1 else []
key = "" key = ""
first = True first = True
@@ -175,8 +227,8 @@ class Concept:
if token.type == TokenKind.WHITESPACE: if token.type == TokenKind.WHITESPACE:
continue continue
if not first: if not first:
key += " " # spaces are normalized key += " " # spaces are normalized
if variables is not None and token.value in variables: if token.value in variables:
key += VARIABLE_PREFIX + str(variables.index(token.value)) key += VARIABLE_PREFIX + str(variables.index(token.value))
else: else:
key += token.value[1:-1] if token.type == TokenKind.STRING else token.value key += token.value[1:-1] if token.type == TokenKind.STRING else token.value
@@ -187,7 +239,7 @@ class Concept:
@property @property
def body(self): def body(self):
return self.metadata.body return self.values[ConceptParts.BODY] if ConceptParts.BODY in self.values else None
def add_codes(self, codes): def add_codes(self, codes):
""" """
@@ -204,7 +256,7 @@ class Concept:
return return
for key in codes: for key in codes:
self.cached_asts[key] = codes[key] self.compiled[key] = codes[key]
return self return self
@@ -224,7 +276,6 @@ class Concept:
props_to_use = props_to_use or PROPERTIES_TO_SERIALIZE props_to_use = props_to_use or PROPERTIES_TO_SERIALIZE
props_as_dict = dict((prop, getattr(self.metadata, prop)) for prop in props_to_use) props_as_dict = dict((prop, getattr(self.metadata, prop)) for prop in props_to_use)
props_as_dict["props"] = [(p, self.props[p].value) for p in self.props]
return props_as_dict return props_as_dict
def from_dict(self, as_dict): def from_dict(self, as_dict):
@@ -235,10 +286,11 @@ class Concept:
""" """
for prop in PROPERTIES_TO_SERIALIZE: for prop in PROPERTIES_TO_SERIALIZE:
if prop in as_dict: if prop in as_dict:
setattr(self.metadata, prop, as_dict[prop]) if prop == "props":
if "props" in as_dict: for name, value in as_dict[prop]:
for n, v in as_dict["props"]: self.def_prop(name, value)
self.set_prop(n, v) else:
setattr(self.metadata, prop, as_dict[prop])
return self return self
def update_from(self, other): def update_from(self, other):
@@ -252,24 +304,69 @@ class Concept:
if other is None: if other is None:
return self return self
if id(other) == id(self):
return self
# update metadata
self.from_dict(other.to_dict()) self.from_dict(other.to_dict())
# for prop in self.props_to_serialize:
# setattr(self, prop, getattr(other, prop)) # update values
for k, v in other.values.items():
self.values[k] = v
# update properties
for k, v in other.props.items():
self.set_prop(k, v.value)
return self return self
def set_prop(self, prop_name: str, prop_value=None): def set_prop(self, prop_name: str, prop_value):
self.props[prop_name] = Property(prop_name, prop_value) # Python 3.x order is kept in dictionaries """Directly sets a value to a property"""
return self
def set_prop_by_index(self, index: int, prop_value):
prop_name = list(self.props.keys())[index]
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):
return self.props[prop_name].value return self.props[prop_name].value
def set_metadata_value(self, metadata: ConceptParts, value):
"""
Set the resolved value of a metadata (not the metadata itself)
:param metadata:
:param value:
:return:
"""
self.values[metadata] = value
def get_metadata_value(self, metadata: ConceptParts):
"""
Gets the resolved value of a metadata
:param metadata:
:return:
"""
return self.values[metadata]
def auto_init(self):
"""
Sometimes (for tests purposes)
You don't need the full process of evaluation to to get the values of the concept
Directly use the values of the metadata
:return:
"""
if self.metadata.is_evaluated:
return self
for metadata in ConceptParts:
value = getattr(self.metadata, metadata.value)
if value is not None:
self.values[metadata] = value
for prop, value in self.metadata.props:
self.set_prop(prop, value)
self.metadata.is_evaluated = True
return self
class Property: class Property:
""" """
@@ -303,6 +400,6 @@ class DoNotResolve:
For example, if you want to set a value to the BODY that will not change when For example, if you want to set a value to the BODY that will not change when
when the concept will be evaluated, when the concept will be evaluated,
set concept.cached_asts[BODY] to DoNotResolve(value) set concept.compiled[BODY] to DoNotResolve(value)
""" """
value: object value: object
+44 -37
View File
@@ -571,40 +571,41 @@ class Sheerka(Concept):
""" """
steps = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING] steps = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING]
for part_key in ConceptParts: for part_key in ConceptParts:
if part_key in concept.cached_asts: if part_key in concept.compiled:
continue continue
source = getattr(concept.metadata, part_key.value) source = getattr(concept.metadata, part_key.value)
if source is None or not isinstance(source, str) or source == "": if source is None or not isinstance(source, str):
# the only sources that I am sure to parse are strings
# I refuse empty strings for performance matters, I don't want to handle useless NOPConcepts
continue continue
if source.strip() == "":
concept.compiled[part_key] = DoNotResolve(source)
else: else:
with context.push(desc=f"Initializing AST for {part_key}") as sub_context: with context.push(desc=f"Initializing compiled for {part_key}") as sub_context:
sub_context.log_new(logger) sub_context.log_new(logger)
sub_context.add_inputs(source=source)
to_parse = self.ret(context.who, True, self.new(BuiltinConcepts.USER_INPUT, body=source)) to_parse = self.ret(context.who, True, self.new(BuiltinConcepts.USER_INPUT, body=source))
res = self.execute(sub_context, to_parse, steps, logger) res = self.execute(sub_context, to_parse, steps, logger)
concept.cached_asts[part_key] = res concept.compiled[part_key] = res
sub_context.add_values(return_values=res) sub_context.add_values(return_values=res)
for prop in concept.props: for prop, default_value in concept.metadata.props:
if prop in concept.cached_asts: if prop in concept.compiled:
continue continue
value = concept.props[prop].value if default_value is None or not isinstance(default_value, str):
if value: continue
if isinstance(value, Concept):
concept.cached_asts[prop] = value if default_value.strip() == "":
else: concept.compiled[prop] = DoNotResolve(default_value)
to_parse = self.ret( else:
context.who, with context.push(desc=f"Initializing AST for property {prop}") as sub_context:
True, sub_context.log_new(logger)
self.new(BuiltinConcepts.USER_INPUT, body=value)) sub_context.add_inputs(source=default_value)
with context.push(desc=f"Initializing AST for property {prop}") as sub_context: to_parse = self.ret(context.who, True, self.new(BuiltinConcepts.USER_INPUT, body=default_value))
sub_context.log_new(logger) res = self.execute(context, to_parse, steps)
res = self.execute(context, to_parse, steps) concept.compiled[prop] = res
concept.cached_asts[prop] = res sub_context.add_values(return_values=res)
sub_context.add_values(return_values=res)
# Updates the cache of concepts when possible # Updates the cache of concepts when possible
if concept.key in self.concepts_cache: if concept.key in self.concepts_cache:
@@ -613,7 +614,7 @@ class Sheerka(Concept):
# TODO : manage when there are multiple entries # TODO : manage when there are multiple entries
pass pass
else: else:
self.concepts_cache[concept.key].cached_asts = concept.cached_asts self.concepts_cache[concept.key].compiled = concept.compiled
def evaluate_concept(self, context, concept: Concept, logger=None): def evaluate_concept(self, context, concept: Concept, logger=None):
""" """
@@ -706,8 +707,8 @@ class Sheerka(Concept):
for metadata_to_eval in all_metadata_to_eval: for metadata_to_eval in all_metadata_to_eval:
if metadata_to_eval == "props": if metadata_to_eval == "props":
for prop_name in (p for p in concept.props if p in concept.cached_asts): for prop_name in (p for p in concept.props if p in concept.compiled):
prop_ast = concept.cached_asts[prop_name] prop_ast = concept.compiled[prop_name]
if isinstance(prop_ast, list): if isinstance(prop_ast, list):
resolved = _resolve_list(context.sheerka, prop_ast, prop_name, None) resolved = _resolve_list(context.sheerka, prop_ast, prop_name, None)
@@ -719,13 +720,13 @@ class Sheerka(Concept):
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)
if part_key in concept.cached_asts and concept.cached_asts[part_key] is not None: if part_key in concept.compiled and concept.compiled[part_key] is not None:
metadata_ast = concept.cached_asts[part_key] metadata_ast = concept.compiled[part_key]
resolved = _resolve(metadata_ast, part_key, concept) resolved = _resolve(metadata_ast, part_key, concept)
if context.sheerka.isinstance(resolved, BuiltinConcepts.CONCEPT_EVAL_ERROR): if context.sheerka.isinstance(resolved, BuiltinConcepts.CONCEPT_EVAL_ERROR):
return resolved return resolved
else: else:
setattr(concept.metadata, metadata_to_eval, resolved) concept.values[part_key] = resolved
# #
# TODO : Validate the POST condition # TODO : Validate the POST condition
@@ -789,7 +790,8 @@ class Sheerka(Concept):
unknown_concept = Concept() unknown_concept = Concept()
template = self.concepts_cache[str(BuiltinConcepts.UNKNOWN_CONCEPT)] template = self.concepts_cache[str(BuiltinConcepts.UNKNOWN_CONCEPT)]
unknown_concept.update_from(template) unknown_concept.update_from(template)
unknown_concept.metadata.body = concept_key unknown_concept.set_metadata_value(ConceptParts.BODY, concept_key)
unknown_concept.metadata.is_evaluated = True
return unknown_concept return unknown_concept
def new(self, concept_key, **kwargs): def new(self, concept_key, **kwargs):
@@ -812,13 +814,13 @@ class Sheerka(Concept):
concept_key != BuiltinConcepts.UNKNOWN_CONCEPT: concept_key != BuiltinConcepts.UNKNOWN_CONCEPT:
return template return template
if not isinstance(template, list): if isinstance(template, list):
# if template is a list, it means that there a multiple concepts under the same key
concepts = [self.new_from_template(t, concept_key, **kwargs) for t in template]
return concepts
else:
return self.new_from_template(template, concept_key, **kwargs) return self.new_from_template(template, concept_key, **kwargs)
# if template is a list, it means that there a multiple concepts under the same key
concepts = [self.new_from_template(t, concept_key, **kwargs) for t in template]
return concepts
def new_from_template(self, template, key, **kwargs): def new_from_template(self, template, key, **kwargs):
# manage singleton # manage singleton
if template.metadata.is_unique: if template.metadata.is_unique:
@@ -828,18 +830,23 @@ class Sheerka(Concept):
concept = self.builtin_cache[key]() if key in self.builtin_cache else Concept() concept = self.builtin_cache[key]() if key in self.builtin_cache else Concept()
concept.update_from(template) concept.update_from(template)
# update the properties if len(kwargs) == 0:
return concept
# update the properties, values, attributes
# Not quite sure that this is the correct process order
for k, v in kwargs.items(): for k, v in kwargs.items():
if k in concept.props: if k in concept.props:
concept.set_prop(k, v) concept.set_prop(k, v)
elif k in PROPERTIES_FOR_NEW: elif k in PROPERTIES_FOR_NEW:
setattr(concept.metadata, k, v) concept.values[ConceptParts(k)] = v
elif hasattr(concept, k): elif hasattr(concept, k):
setattr(concept, k, v) setattr(concept, k, v)
else: else:
return self.new(BuiltinConcepts.UNKNOWN_PROPERTY, body=k, concept=concept) return self.new(BuiltinConcepts.UNKNOWN_PROPERTY, body=k, concept=concept)
# TODO : add the concept to the list of known concepts (self.instances) # TODO : add the concept to the list of known concepts (self.instances)
concept.metadata.is_evaluated = True
return concept return concept
def ret(self, who: str, status: bool, value, message=None, parents=None): def ret(self, who: str, status: bool, value, message=None, parents=None):
@@ -880,7 +887,7 @@ class Sheerka(Concept):
return self.value(body_to_use) return self.value(body_to_use)
def values(self, objs): def get_values(self, objs):
if not (isinstance(objs, list) or if not (isinstance(objs, list) or
self.isinstance(objs, BuiltinConcepts.LIST) or self.isinstance(objs, BuiltinConcepts.LIST) or
self.isinstance(objs, BuiltinConcepts.ENUMERATION)): self.isinstance(objs, BuiltinConcepts.ENUMERATION)):
+13 -4
View File
@@ -26,6 +26,9 @@ class SheerkaTransformType(Enum):
Node = 5 Node = 5
Exception = 6 Exception = 6
def __repr__(self):
return self.__class__.__name__ + "." + self.name
class SheerkaTransform: class SheerkaTransform:
@@ -117,18 +120,24 @@ class SheerkaTransform:
# transform metadata # transform metadata
for prop in PROPERTIES_TO_SERIALIZE: for prop in PROPERTIES_TO_SERIALIZE:
value = self.to_dict(getattr(obj.metadata, prop)) value = getattr(obj.metadata, prop)
ref_value = getattr(ref.metadata, prop) ref_value = getattr(ref.metadata, prop)
if value != ref_value: if value != ref_value:
to_dict[prop] = value to_dict["meta." + prop] = self.to_dict(value)
# transform value
for metadata, value in obj.values.items():
ref_value = ref.values[metadata] if metadata in ref.values else None
if value != ref_value:
to_dict[metadata.value] = self.to_dict(value)
# transform properties # transform properties
for prop in obj.props: for prop in obj.props:
value = self.to_dict(obj.props[prop].value) value = obj.props[prop].value
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 to_dict: if "props" not in to_dict:
to_dict["props"] = [] to_dict["props"] = []
to_dict["props"].append((prop, value)) to_dict["props"].append((prop, self.to_dict(value)))
return to_dict return to_dict
+2 -3
View File
@@ -73,16 +73,15 @@ class AddConceptEvaluator(OneReturnValueEvaluator):
# add props order by appearance when possible # add props order by appearance when possible
for token in def_concept_node.name.tokens: for token in def_concept_node.name.tokens:
if token.value in props_found: if token.value in props_found:
concept.set_prop(token.value, None) concept.def_prop(token.value, None)
# add the remaining properties # add the remaining properties
for p in props_found: for p in props_found:
if p not in concept.props: if p not in concept.props:
concept.set_prop(p, None) concept.def_prop(p, None)
# finish initialisation # finish initialisation
concept.init_key(def_concept_node.name.tokens) concept.init_key(def_concept_node.name.tokens)
#concept.add_codes(def_concept_node.get_asts())
if not isinstance(def_concept_node.definition, NotInitializedNode) and \ if not isinstance(def_concept_node.definition, NotInitializedNode) and \
sheerka.is_success(def_concept_node.definition): sheerka.is_success(def_concept_node.definition):
concept.bnf = def_concept_node.definition.value.value concept.bnf = def_concept_node.definition.value.value
+1 -1
View File
@@ -47,7 +47,7 @@ class ConceptEvaluator(OneReturnValueEvaluator):
evaluated, evaluated,
parents=[return_value]) parents=[return_value])
if not self.return_body or ConceptParts.BODY not in evaluated.cached_asts: if not self.return_body or ConceptParts.BODY not in evaluated.compiled:
return sheerka.ret(self.name, True, evaluated, parents=[return_value]) return sheerka.ret(self.name, True, evaluated, parents=[return_value])
else: else:
return sheerka.ret(self.name, True, evaluated.body, parents=[return_value]) return sheerka.ret(self.name, True, evaluated.body, parents=[return_value])
+6 -6
View File
@@ -864,17 +864,17 @@ class ConceptLexerParser(BaseParser):
Adds a new entry, Adds a new entry,
makes a list if the property already exists makes a list if the property already exists
""" """
if prop_name not in _concept.cached_asts or _concept.cached_asts[prop_name] is None: if prop_name not in _concept.compiled or _concept.compiled[prop_name] is None:
# new entry # new entry
_concept.cached_asts[prop_name] = value _concept.compiled[prop_name] = value
else: else:
# make a list if there was a value # make a list if there was a value
previous_value = _concept.cached_asts[prop_name] previous_value = _concept.compiled[prop_name]
if isinstance(previous_value, list): if isinstance(previous_value, list):
previous_value.append(value) previous_value.append(value)
else: else:
new_value = [previous_value, value] new_value = [previous_value, value]
_concept.cached_asts[prop_name] = new_value _concept.compiled[prop_name] = new_value
def _look_for_concept_match(_underlying): def _look_for_concept_match(_underlying):
if isinstance(_underlying.parsing_expression, ConceptExpression): if isinstance(_underlying.parsing_expression, ConceptExpression):
@@ -913,9 +913,9 @@ class ConceptLexerParser(BaseParser):
key = (template.key, template.id) if template.id else template.key key = (template.key, template.id) if template.id else template.key
concept = sheerka.new(key) concept = sheerka.new(key)
if init_empty_body and concept.body is None: if init_empty_body and concept.metadata.body is None:
value = _get_underlying_value(underlying) value = _get_underlying_value(underlying)
concept.cached_asts[ConceptParts.BODY] = value concept.compiled[ConceptParts.BODY] = value
if underlying.parsing_expression.rule_name: if underlying.parsing_expression.rule_name:
_add_prop(concept, underlying.parsing_expression.rule_name, value) _add_prop(concept, underlying.parsing_expression.rule_name, value)
+2 -2
View File
@@ -54,7 +54,7 @@ class ConceptsWithConceptsParser(BaseParser):
if isinstance(node, ConceptNode): if isinstance(node, ConceptNode):
prop_name = list(concept.props.keys())[index] prop_name = list(concept.props.keys())[index]
concept.cached_asts[prop_name] = node.concept concept.compiled[prop_name] = node.concept
context.log( context.log(
self.verbose_log, self.verbose_log,
f"Setting property '{prop_name}='{node.concept}'.", f"Setting property '{prop_name}='{node.concept}'.",
@@ -64,7 +64,7 @@ class ConceptsWithConceptsParser(BaseParser):
prop_name = list(concept.props.keys())[index] prop_name = list(concept.props.keys())[index]
sheerka = context.sheerka sheerka = context.sheerka
value = sheerka.new(BuiltinConcepts.PARSER_RESULT, parser=self, source=node.source, body=node.node) value = sheerka.new(BuiltinConcepts.PARSER_RESULT, parser=self, source=node.source, body=node.node)
concept.cached_asts[prop_name] = [context.sheerka.ret(self.name, True, value)] concept.compiled[prop_name] = [context.sheerka.ret(self.name, True, value)]
context.log( context.log(
self.verbose_log, self.verbose_log,
f"Setting property '{prop_name}'='Python({node.source})'.", f"Setting property '{prop_name}'='Python({node.source})'.",
+1 -1
View File
@@ -55,7 +55,7 @@ class ExactConceptParser(BaseParser):
for i, token in enumerate(combination): for i, token in enumerate(combination):
if token.startswith(VARIABLE_PREFIX): if token.startswith(VARIABLE_PREFIX):
index = int(token[len(VARIABLE_PREFIX):]) index = int(token[len(VARIABLE_PREFIX):])
concept.set_prop_by_index(index, words[i]) concept.def_prop_by_index(index, words[i])
if self.verbose_log.isEnabledFor(logging.DEBUG): if self.verbose_log.isEnabledFor(logging.DEBUG):
prop_name = list(concept.props.keys())[index] prop_name = list(concept.props.keys())[index]
context.log( context.log(
+13 -11
View File
@@ -21,7 +21,7 @@ def get_context():
return ExecutionContext("test", Event(), sheerka) return ExecutionContext("test", Event(), sheerka)
def get_concept(name, where=None, pre=None, post=None, body=None, definition=None): def get_def_concept(name, where=None, pre=None, post=None, body=None, definition=None):
concept = DefConceptNode([], name=NameNode(list(Tokenizer(name)))) concept = DefConceptNode([], name=NameNode(list(Tokenizer(name))))
if body: if body:
@@ -87,7 +87,7 @@ def test_i_can_match(ret_val, expected):
def test_that_the_source_is_correctly_set(): def test_that_the_source_is_correctly_set():
context = get_context() context = get_context()
def_concept_return_value = get_concept( def_concept_return_value = get_def_concept(
name="hello a", name="hello a",
definition=get_concept_definition("hello a", Sequence(StrMatch("hello"), StrMatch("a"))), definition=get_concept_definition("hello a", Sequence(StrMatch("hello"), StrMatch("a"))),
where="isinstance(a, str )", where="isinstance(a, str )",
@@ -132,21 +132,22 @@ def test_that_the_source_is_correctly_set():
# #
# created_concept = evaluated.body.body # created_concept = evaluated.body.body
# #
# assert ConceptParts.WHERE in created_concept.cached_asts # assert ConceptParts.WHERE in created_concept.compiled
# assert ConceptParts.PRE in created_concept.cached_asts # assert ConceptParts.PRE in created_concept.compiled
# assert ConceptParts.BODY in created_concept.cached_asts # assert ConceptParts.BODY in created_concept.compiled
# assert ConceptParts.POST not in created_concept.cached_asts # assert ConceptParts.POST not in created_concept.compiled
def test_that_the_new_concept_is_correctly_saved(): def test_that_the_new_concept_is_correctly_saved_in_db():
context = get_context() context = get_context()
def_concept_return_value = get_concept( def_concept_return_value = get_def_concept(
name="hello a", name="hello a",
definition=get_concept_definition("hello a", Sequence(StrMatch("hello"), StrMatch("a"))), definition=get_concept_definition("hello a", Sequence(StrMatch("hello"), StrMatch("a"))),
where="isinstance(a, str )", where="isinstance(a, str )",
pre="a is not None", pre="a is not None",
body="print('hello' + a)") body="print('hello' + a)")
# sanity. Make sure that the concept does not already exist
from_db = context.sheerka.get("hello " + VARIABLE_PREFIX + "0") from_db = context.sheerka.get("hello " + VARIABLE_PREFIX + "0")
assert context.sheerka.isinstance(from_db, BuiltinConcepts.UNKNOWN_CONCEPT) assert context.sheerka.isinstance(from_db, BuiltinConcepts.UNKNOWN_CONCEPT)
@@ -161,10 +162,11 @@ def test_that_the_new_concept_is_correctly_saved():
assert from_db.metadata.post is None assert from_db.metadata.post is None
assert from_db.metadata.body == "print('hello' + a)" assert from_db.metadata.body == "print('hello' + a)"
assert from_db.metadata.definition == "hello a" assert from_db.metadata.definition == "hello a"
assert len(from_db.props) == 1 assert len(from_db.metadata.props) == 1
assert from_db.metadata.props[0] == ("a", None)
assert "a" in from_db.props assert "a" in from_db.props
assert from_db.cached_asts == {} # ast is not saved in db assert from_db.compiled == {} # ast is not saved in db
def test_i_can_get_props_from_python_node(): def test_i_can_get_props_from_python_node():
@@ -175,7 +177,7 @@ def test_i_can_get_props_from_python_node():
def test_i_can_get_props_from_another_concept(): def test_i_can_get_props_from_another_concept():
concept = Concept("hello").set_prop("a").set_prop("b") concept = Concept("hello").def_prop("a").def_prop("b")
ret_val = ReturnValueConcept(who="some_parser", ret_val = ReturnValueConcept(who="some_parser",
status=True, status=True,
value=ParserResultConcept(value=concept)) value=ParserResultConcept(value=concept))
+11 -9
View File
@@ -1,10 +1,9 @@
import pytest import pytest
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
from core.concept import Concept from core.concept import Concept, ConceptParts
from core.sheerka import Sheerka, ExecutionContext from core.sheerka import Sheerka, ExecutionContext
from evaluators.ConceptEvaluator import ConceptEvaluator from evaluators.ConceptEvaluator import ConceptEvaluator
from parsers.BaseParser import BaseParser
from parsers.ExactConceptParser import ExactConceptParser from parsers.ExactConceptParser import ExactConceptParser
from sdp.sheerkaDataProvider import Event from sdp.sheerkaDataProvider import Event
@@ -41,7 +40,7 @@ def test_i_can_evaluate_concept():
concept = Concept(name="foo", concept = Concept(name="foo",
where="1", where="1",
pre="2", pre="2",
post="3").set_prop("a", "4").set_prop("b", "5") post="3").def_prop("a", "4").def_prop("b", "5")
evaluator = ConceptEvaluator() evaluator = ConceptEvaluator()
item = get_return_value(concept) item = get_return_value(concept)
@@ -49,10 +48,13 @@ def test_i_can_evaluate_concept():
assert result.who == evaluator.name assert result.who == evaluator.name
assert result.status assert result.status
assert result.value == Concept(name="foo", assert result.value.name == "foo"
where=1, assert result.value.get_metadata_value(ConceptParts.WHERE) == 1
pre=2, assert result.value.get_metadata_value(ConceptParts.PRE) == 2
post=3).set_prop("a", 4).set_prop("b", 5).init_key() assert result.value.get_metadata_value(ConceptParts.POST) == 3
assert result.value.get_prop("a") == 4
assert result.value.get_prop("b") == 5
assert result.value.key == "foo"
assert result.parents == [item] assert result.parents == [item]
@@ -111,8 +113,8 @@ def test_i_cannot_recognize_a_concept_if_one_of_the_prop_is_unknown():
context = get_context() context = get_context()
context.sheerka.add_in_cache(Concept(name="one").init_key()) context.sheerka.add_in_cache(Concept(name="one").init_key())
concept_plus = context.sheerka.add_in_cache(Concept(name="a plus b") concept_plus = context.sheerka.add_in_cache(Concept(name="a plus b")
.set_prop("a", "one") .def_prop("a", "one")
.set_prop("b", "two").init_key()) .def_prop("b", "two").init_key())
evaluator = ConceptEvaluator() evaluator = ConceptEvaluator()
item = get_return_value(concept_plus) item = get_return_value(concept_plus)
+10 -7
View File
@@ -59,19 +59,21 @@ def get_context():
def get_expected(concept, text=None): def get_expected(concept, text=None):
c = Concept(name=concept.name) c = Concept(name=concept.name)
c.cached_asts[ConceptParts.BODY] = DoNotResolve(text or concept.name) c.compiled[ConceptParts.BODY] = DoNotResolve(text or concept.name)
c.init_key() c.init_key()
return c return c
def cbody(concept): def cbody(concept):
"""cbody stands for compiled body""" """cbody stands for compiled body"""
return concept.cached_asts[ConceptParts.BODY] if not ConceptParts.BODY in concept.compiled:
return None
return concept.compiled[ConceptParts.BODY]
def cprop(concept, prop_name): def cprop(concept, prop_name):
"""cbody stands for compiled property""" """cbody stands for compiled property"""
return concept.cached_asts[prop_name] return concept.compiled[prop_name]
def init(concepts, grammar): def init(concepts, grammar):
@@ -402,14 +404,15 @@ def test_i_can_use_a_reference_with_a_body():
assert context.sheerka.isinstance(res[0].value, BuiltinConcepts.PARSER_RESULT) assert context.sheerka.isinstance(res[0].value, BuiltinConcepts.PARSER_RESULT)
assert res[0].value.body == [cnode("foo", 0, 2, "one two")] assert res[0].value.body == [cnode("foo", 0, 2, "one two")]
concept_found_1 = res[0].value.body[0].concept concept_found_1 = res[0].value.body[0].concept
assert concept_found_1.body == "'foo'" assert concept_found_1.metadata.body == "'foo'"
assert cbody(concept_found_1) is None
assert res[1].status assert res[1].status
assert context.sheerka.isinstance(res[1].value, BuiltinConcepts.PARSER_RESULT) assert context.sheerka.isinstance(res[1].value, BuiltinConcepts.PARSER_RESULT)
assert res[1].value.body == [cnode("bar", 0, 2, "one two")] assert res[1].value.body == [cnode("bar", 0, 2, "one two")]
concept_found_2 = res[1].value.body[0].concept concept_found_2 = res[1].value.body[0].concept
# the body and the prop['foo'] are the same concept 'foo'
assert cbody(concept_found_2) == foo assert cbody(concept_found_2) == foo
# the body and the prop['foo'] are the same concept 'foo'
assert id(cprop(concept_found_2, "foo")) == id(cbody(concept_found_2)) assert id(cprop(concept_found_2, "foo")) == id(cbody(concept_found_2))
@@ -513,7 +516,7 @@ def test_i_can_parse_when_reference_has_a_body():
assert res.status assert res.status
assert res.value.body == [cnode("foo", 0, 0, "twenty")] assert res.value.body == [cnode("foo", 0, 0, "twenty")]
concept_found = res.value.body[0].concept concept_found = res.value.body[0].concept
assert concept_found.body == "'one'" assert concept_found.metadata.body == "'one'"
def test_i_can_parse_multiple_results(): def test_i_can_parse_multiple_results():
@@ -1089,7 +1092,7 @@ def test_i_get_multiple_props_when_zero_or_more():
assert return_value == [cnode("foo", 0, 4, "one one one")] assert return_value == [cnode("foo", 0, 4, "one one one")]
concept_found = return_value[0].concept concept_found = return_value[0].concept
assert cbody(concept_found) == DoNotResolve("one one one") assert cbody(concept_found) == DoNotResolve("one one one")
assert len(concept_found.cached_asts["one"]) == 3 assert len(concept_found.compiled["one"]) == 3
assert cprop(concept_found, "one")[0] == get_expected(one) assert cprop(concept_found, "one")[0] == get_expected(one)
assert cprop(concept_found, "one")[1] == get_expected(one) assert cprop(concept_found, "one")[1] == get_expected(one)
assert cprop(concept_found, "one")[2] == get_expected(one) assert cprop(concept_found, "one")[2] == get_expected(one)
+15 -15
View File
@@ -86,7 +86,7 @@ def test_not_interested(text, interested):
def test_i_can_parse_composition_of_concepts(): def test_i_can_parse_composition_of_concepts():
foo = Concept("foo") foo = Concept("foo")
bar = Concept("bar") bar = Concept("bar")
plus = Concept("a plus b").set_prop("a").set_prop("b") plus = Concept("a plus b").def_prop("a").def_prop("b")
context, parser, result, wrapper, return_value = execute([foo, bar, plus], [foo, " plus ", bar]) context, parser, result, wrapper, return_value = execute([foo, bar, plus], [foo, " plus ", bar])
@@ -96,8 +96,8 @@ def test_i_can_parse_composition_of_concepts():
assert wrapper.source == "foo plus bar" assert wrapper.source == "foo plus bar"
assert context.sheerka.isinstance(return_value, plus) assert context.sheerka.isinstance(return_value, plus)
assert return_value.cached_asts["a"] == foo assert return_value.compiled["a"] == foo
assert return_value.cached_asts["b"] == bar assert return_value.compiled["b"] == bar
# sanity check, I can evaluate the result # sanity check, I can evaluate the result
evaluated = context.sheerka.evaluate_concept(context, return_value) evaluated = context.sheerka.evaluate_concept(context, return_value)
@@ -107,7 +107,7 @@ def test_i_can_parse_composition_of_concepts():
def test_i_can_parse_when_composition_of_source_code(): def test_i_can_parse_when_composition_of_source_code():
plus = Concept("a plus b", body="a + b").set_prop("a").set_prop("b") plus = Concept("a plus b", body="a + b").def_prop("a").def_prop("b")
left = PythonNode("1+1", ast.parse("1+1", mode="eval")) left = PythonNode("1+1", ast.parse("1+1", mode="eval"))
right = PythonNode("2+2", ast.parse("2+2", mode="eval")) right = PythonNode("2+2", ast.parse("2+2", mode="eval"))
context, parser, result, wrapper, return_value = execute([plus], [left, " plus ", right]) context, parser, result, wrapper, return_value = execute([plus], [left, " plus ", right])
@@ -120,8 +120,8 @@ def test_i_can_parse_when_composition_of_source_code():
left_parser_result = ParserResultConcept(parser=parser, source="1+1", value=left) left_parser_result = ParserResultConcept(parser=parser, source="1+1", value=left)
right_parser_result = ParserResultConcept(parser=parser, source="2+2", value=right) right_parser_result = ParserResultConcept(parser=parser, source="2+2", value=right)
assert return_value.cached_asts["a"] == [ReturnValueConcept(parser.name, True, left_parser_result)] assert return_value.compiled["a"] == [ReturnValueConcept(parser.name, True, left_parser_result)]
assert return_value.cached_asts["b"] == [ReturnValueConcept(parser.name, True, right_parser_result)] assert return_value.compiled["b"] == [ReturnValueConcept(parser.name, True, right_parser_result)]
# sanity check, I can evaluate the result # sanity check, I can evaluate the result
evaluated = context.sheerka.evaluate_concept(context, return_value) evaluated = context.sheerka.evaluate_concept(context, return_value)
@@ -132,7 +132,7 @@ def test_i_can_parse_when_composition_of_source_code():
def test_i_can_parse_when_mix_of_concept_and_code(): def test_i_can_parse_when_mix_of_concept_and_code():
plus = Concept("a plus b").set_prop("a").set_prop("b") plus = Concept("a plus b").def_prop("a").def_prop("b")
code = PythonNode("1+1", ast.parse("1+1", mode="eval")) code = PythonNode("1+1", ast.parse("1+1", mode="eval"))
foo = Concept("foo") foo = Concept("foo")
context, parser, result, wrapper, return_value = execute([plus, foo], [foo, " plus ", code]) context, parser, result, wrapper, return_value = execute([plus, foo], [foo, " plus ", code])
@@ -144,8 +144,8 @@ def test_i_can_parse_when_mix_of_concept_and_code():
assert context.sheerka.isinstance(return_value, plus) assert context.sheerka.isinstance(return_value, plus)
code_parser_result = ParserResultConcept(parser=parser, source="1+1", value=code) code_parser_result = ParserResultConcept(parser=parser, source="1+1", value=code)
assert return_value.cached_asts["a"] == foo assert return_value.compiled["a"] == foo
assert return_value.cached_asts["b"] == [ReturnValueConcept(parser.name, True, code_parser_result)] assert return_value.compiled["b"] == [ReturnValueConcept(parser.name, True, code_parser_result)]
# sanity check, I can evaluate the result # sanity check, I can evaluate the result
evaluated = context.sheerka.evaluate_concept(context, return_value) evaluated = context.sheerka.evaluate_concept(context, return_value)
@@ -157,8 +157,8 @@ def test_i_can_parse_when_mix_of_concept_and_code():
def test_i_can_parse_when_multiple_concepts_are_recognized(): def test_i_can_parse_when_multiple_concepts_are_recognized():
foo = Concept("foo") foo = Concept("foo")
bar = Concept("bar") bar = Concept("bar")
plus_1 = Concept("a plus b", body="body1").set_prop("a").set_prop("b") plus_1 = Concept("a plus b", body="body1").def_prop("a").def_prop("b")
plus_2 = Concept("a plus b", body="body2").set_prop("a").set_prop("b") plus_2 = Concept("a plus b", body="body2").def_prop("a").def_prop("b")
context, input_return_values = init([foo, bar, plus_1, plus_2], [foo, " plus ", bar]) context, input_return_values = init([foo, bar, plus_1, plus_2], [foo, " plus ", bar])
parser = ConceptsWithConceptsParser() parser = ConceptsWithConceptsParser()
@@ -174,8 +174,8 @@ def test_i_can_parse_when_multiple_concepts_are_recognized():
assert res.who == wrapper.parser.name assert res.who == wrapper.parser.name
assert wrapper.source == "foo plus bar" assert wrapper.source == "foo plus bar"
assert context.sheerka.isinstance(return_value, plus_1) assert context.sheerka.isinstance(return_value, plus_1)
assert return_value.cached_asts["a"] == foo assert return_value.compiled["a"] == foo
assert return_value.cached_asts["b"] == bar assert return_value.compiled["b"] == bar
res = result[1] res = result[1]
wrapper = res.value wrapper = res.value
@@ -184,8 +184,8 @@ def test_i_can_parse_when_multiple_concepts_are_recognized():
assert res.who == wrapper.parser.name assert res.who == wrapper.parser.name
assert wrapper.source == "foo plus bar" assert wrapper.source == "foo plus bar"
assert context.sheerka.isinstance(return_value, plus_2) assert context.sheerka.isinstance(return_value, plus_2)
assert return_value.cached_asts["a"] == foo assert return_value.compiled["a"] == foo
assert return_value.cached_asts["b"] == bar assert return_value.compiled["b"] == bar
def test_i_cannot_parse_when_unknown_concept(): def test_i_cannot_parse_when_unknown_concept():
+3 -3
View File
@@ -23,13 +23,13 @@ eval_requested = ReturnValueConcept("some_name", True, Concept(key=BuiltinConcep
def test_i_can_match_and_eval(): def test_i_can_match_and_eval():
context = get_context() context = get_context()
to_eval1 = ReturnValueConcept("some_name", True, Concept(name="2", body="to eval")) to_eval1 = ReturnValueConcept("some_name", True, Concept(name="2", body="to eval").auto_init())
to_eval2 = ReturnValueConcept("some_name", True, Concept(name="3", body="also to eval")) to_eval2 = ReturnValueConcept("some_name", True, Concept(name="3", body="also to eval").auto_init())
return_values = [ return_values = [
ReturnValueConcept("some_name", True, "not to eval"), ReturnValueConcept("some_name", True, "not to eval"),
ReturnValueConcept("some_name", True, Concept(name="not to eval")), ReturnValueConcept("some_name", True, Concept(name="not to eval")),
ReturnValueConcept("some_name", False, Concept(name="1", body="not to eval")), ReturnValueConcept("some_name", False, Concept(name="1", body="'not to eval'")),
to_eval1, to_eval1,
to_eval2, to_eval2,
eval_requested eval_requested
+14 -6
View File
@@ -6,6 +6,14 @@ from parsers.ExactConceptParser import ExactConceptParser
from sdp.sheerkaDataProvider import Event from sdp.sheerkaDataProvider import Event
def metadata_prop(concept, prop_name):
for name, value in concept.metadata.props:
if name == prop_name:
return value
return None
def test_i_can_compute_combinations(): def test_i_can_compute_combinations():
parser = ExactConceptParser() parser = ExactConceptParser()
res = parser.combinations(["foo", "bar", "baz"]) res = parser.combinations(["foo", "bar", "baz"])
@@ -58,7 +66,7 @@ def test_i_can_recognize_concepts_defined_several_times():
assert results[0].status assert results[0].status
assert results[0].value.value.name == "hello a" assert results[0].value.value.name == "hello a"
assert results[0].value.value.props["a"].value == "world" assert metadata_prop(results[0].value.value, "a") == "world"
assert results[1].status assert results[1].status
assert results[1].value.value.name == "hello world" assert results[1].value.value.name == "hello world"
@@ -75,8 +83,8 @@ def test_i_can_recognize_a_concept_with_variables():
assert results[0].status assert results[0].status
concept_found = results[0].value.value concept_found = results[0].value.value
assert concept_found.key == concept.key assert concept_found.key == concept.key
assert concept_found.props["a"].value == "10" assert metadata_prop(concept_found, "a") == "10"
assert concept_found.props["b"].value == "5" assert metadata_prop(concept_found, "b") == "5"
def test_i_can_recognize_a_concept_with_duplicate_variables(): def test_i_can_recognize_a_concept_with_duplicate_variables():
@@ -90,8 +98,8 @@ def test_i_can_recognize_a_concept_with_duplicate_variables():
assert results[0].status assert results[0].status
concept_found = results[0].value.value concept_found = results[0].value.value
assert concept_found.key == concept.key assert concept_found.key == concept.key
assert concept_found.props["a"].value == "10" assert metadata_prop(concept_found, "a") == "10"
assert concept_found.props["b"].value == "5" assert metadata_prop(concept_found, "b") == "5"
def test_i_can_manage_unknown_concept(): def test_i_can_manage_unknown_concept():
@@ -138,6 +146,6 @@ def get_concept(name, variables):
c = Concept(name=name) c = Concept(name=name)
if variables: if variables:
for v in variables: for v in variables:
c.props[v] = Property(v, None) c.def_prop(v)
c.init_key() c.init_key()
return c return c
+1 -1
View File
@@ -90,7 +90,7 @@ def test_concept_is_returned_when_only_one_in_the_list():
assert wrapper.parser == evaluator assert wrapper.parser == evaluator
assert wrapper.source == "foo" assert wrapper.source == "foo"
assert return_value == Concept("foo").init_key() assert return_value == Concept("foo").init_key()
assert return_value.cached_asts[ConceptParts.BODY] == DoNotResolve("foo") assert return_value.compiled[ConceptParts.BODY] == DoNotResolve("foo")
assert result.parents == [ret_val] assert result.parents == [ret_val]
+2 -2
View File
@@ -136,12 +136,12 @@ def test_i_can_parse_when_multiple_concepts_are_matching():
assert ret_val[0].status assert ret_val[0].status
assert ret_val[0].value.value == [cnode("foo", 0, 0, "foo"), cnode("bar", 2, 2, "bar")] assert ret_val[0].value.value == [cnode("foo", 0, 0, "foo"), cnode("bar", 2, 2, "bar")]
assert ret_val[0].value.source == "foo bar" assert ret_val[0].value.source == "foo bar"
assert ret_val[0].value.value[1].concept.body == "bar1" assert ret_val[0].value.value[1].concept.metadata.body == "bar1"
assert ret_val[1].status assert ret_val[1].status
assert ret_val[1].value.value == [cnode("foo", 0, 0, "foo"), cnode("bar", 2, 2, "bar")] assert ret_val[1].value.value == [cnode("foo", 0, 0, "foo"), cnode("bar", 2, 2, "bar")]
assert ret_val[1].value.source == "foo bar" assert ret_val[1].value.source == "foo bar"
assert ret_val[1].value.value[1].concept.body == "bar2" assert ret_val[1].value.value[1].concept.metadata.body == "bar2"
def test_i_can_parse_when_source_code(): def test_i_can_parse_when_source_code():
+25 -25
View File
@@ -20,8 +20,8 @@ def test_i_can_match_and_eval():
return_values = [ return_values = [
ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"),
ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value").auto_init()),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value").auto_init()),
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED)) ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
] ]
@@ -30,7 +30,7 @@ def test_i_can_match_and_eval():
evaluated = evaluator.eval(context, return_values) evaluated = evaluator.eval(context, return_values)
assert evaluated.status assert evaluated.status
assert evaluated.value == Concept(name="1", body="value") # the first concept is returned assert evaluated.value == Concept(name="1", body="value").auto_init() # the first concept is returned
def test_i_can_match_and_eval_when_no_body(): def test_i_can_match_and_eval_when_no_body():
@@ -40,8 +40,8 @@ def test_i_can_match_and_eval_when_no_body():
return_values = [ return_values = [
ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"),
ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1").auto_init()),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1").auto_init()),
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED)) ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
] ]
@@ -50,7 +50,7 @@ def test_i_can_match_and_eval_when_no_body():
evaluated = evaluator.eval(context, return_values) evaluated = evaluator.eval(context, return_values)
assert evaluated.status assert evaluated.status
assert evaluated.value == Concept(name="1") assert evaluated.value == Concept(name="1").auto_init()
def test_i_can_match_and_eval_when_value_is_not_a_concept(): def test_i_can_match_and_eval_when_value_is_not_a_concept():
@@ -82,9 +82,9 @@ def test_i_can_match_and_eval_when_at_least_one_value_is_a_concept_concept_evalu
ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"),
ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, "value"), ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, "value"),
ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, "value"), ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, "value"),
ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, Concept(name="2", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, Concept(name="2", body="value").auto_init()),
ReturnValueConcept(BaseEvaluator.PREFIX + "Concept", True, Concept(name="1", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "Concept", True, Concept(name="1", body="value").auto_init()),
ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, Concept(name="3", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, Concept(name="3", body="value").auto_init()),
ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, "value"), ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, "value"),
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED)) ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
] ]
@@ -94,7 +94,7 @@ def test_i_can_match_and_eval_when_at_least_one_value_is_a_concept_concept_evalu
evaluated = evaluator.eval(context, return_values) evaluated = evaluator.eval(context, return_values)
assert evaluated.status assert evaluated.status
assert evaluated.value == Concept(name="1", body="value") # the concept is returned, not the value assert evaluated.value == Concept(name="1", body="value").auto_init() # the concept is returned, not the value
def test_i_can_match_and_eval_when_at_least_one_value_is_a_concept_python_evaluator_first(): def test_i_can_match_and_eval_when_at_least_one_value_is_a_concept_python_evaluator_first():
@@ -106,9 +106,9 @@ def test_i_can_match_and_eval_when_at_least_one_value_is_a_concept_python_evalua
ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"),
ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, "value"), ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, "value"),
ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, "value"), ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, "value"),
ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, Concept(name="2", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, Concept(name="2", body="value").auto_init()),
ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, Concept(name="1", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, Concept(name="1", body="value").auto_init()),
ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, Concept(name="3", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, Concept(name="3", body="value").auto_init()),
ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, "value"), ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, "value"),
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED)) ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
] ]
@@ -118,7 +118,7 @@ def test_i_can_match_and_eval_when_at_least_one_value_is_a_concept_python_evalua
evaluated = evaluator.eval(context, return_values) evaluated = evaluator.eval(context, return_values)
assert evaluated.status assert evaluated.status
assert evaluated.value == Concept(name="1", body="value") # the concept is returned, not the value assert evaluated.value == Concept(name="1", body="value").auto_init() # the concept is returned, not the value
def test_i_can_match_even_if_the_value_are_not_the_same_but_eval_will_fail(): def test_i_can_match_even_if_the_value_are_not_the_same_but_eval_will_fail():
@@ -128,8 +128,8 @@ def test_i_can_match_even_if_the_value_are_not_the_same_but_eval_will_fail():
return_values = [ return_values = [
ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"),
ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value").auto_init()),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value2")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value2").auto_init()),
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED)) ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
] ]
@@ -145,8 +145,8 @@ def test_i_can_match_even_if_the_value_are_not_the_same_but_eval_will_fail_when_
return_values = [ return_values = [
ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"),
ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1").auto_init()),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2").auto_init()),
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED)) ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
] ]
@@ -160,8 +160,8 @@ def test_i_can_match_if_no_parser():
sheerka = context.sheerka sheerka = context.sheerka
return_values = [ return_values = [
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value").auto_init()),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value").auto_init()),
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED)) ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
] ]
@@ -175,8 +175,8 @@ def test_i_cannot_match_if_not_reduced_requested():
return_values = [ return_values = [
ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"),
ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value").auto_init()),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value").auto_init()),
ReturnValueConcept("some_name", True, Concept(name="2", body="value")), ReturnValueConcept("some_name", True, Concept(name="2", body="value")),
# ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED)) # ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
] ]
@@ -192,7 +192,7 @@ def test_i_cannot_match_if_only_one_successful_evaluator():
ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"),
ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"),
# ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value")), # ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value")),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value").auto_init()),
ReturnValueConcept("some_name", True, Concept(name="2", body="value")), ReturnValueConcept("some_name", True, Concept(name="2", body="value")),
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED)) ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
] ]
@@ -207,8 +207,8 @@ def test_i_cannot_match_if_at_least_one_parser_is_successful():
return_values = [ return_values = [
ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"),
ReturnValueConcept(BaseParser.PREFIX + "some_name2", True, "Not relevant"), ReturnValueConcept(BaseParser.PREFIX + "some_name2", True, "Not relevant"),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value").auto_init()),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value")), ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value").auto_init()),
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED)) ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
] ]
+17 -14
View File
@@ -1,6 +1,6 @@
import pytest import pytest
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept
from core.concept import Concept from core.concept import Concept
from core.sheerka import Sheerka, ExecutionContext from core.sheerka import Sheerka, ExecutionContext
from evaluators.PrepareEvalEvaluator import PrepareEvalEvaluator from evaluators.PrepareEvalEvaluator import PrepareEvalEvaluator
@@ -13,18 +13,21 @@ def get_context():
return ExecutionContext("test", Event(), sheerka) return ExecutionContext("test", Event(), sheerka)
r = ReturnValueConcept
@pytest.mark.parametrize("ret_val, expected", [ @pytest.mark.parametrize("ret_val, expected", [
(ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body="eval 1 + 1")), True), (r("name", True, UserInputConcept("eval 1 + 1")), True),
(ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body=" eval 1 + 1")), True), (r("name", True, UserInputConcept(" eval 1 + 1")), True),
(ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body="eval")), False), (r("name", True, UserInputConcept("eval")), False),
(ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body="1+1")), False), (r("name", True, UserInputConcept("1+1")), False),
(ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body="")), False), (r("name", True, UserInputConcept("")), False),
(ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body="eval ")), False), (r("name", True, UserInputConcept("eval ")), False),
(ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body=[])), False), (r("name", True, UserInputConcept([])), False),
(ReturnValueConcept("some_name", True, Concept("foo")), False), (r("name", True, Concept("foo")), False),
(ReturnValueConcept("some_name", True, "not a concept"), False), (r("name", True, "not a concept"), False),
(ReturnValueConcept("some_name", False, Concept(key=BuiltinConcepts.USER_INPUT, body="eval 1 + 1")), False), (r("name", False, UserInputConcept("eval 1 + 1")), False),
(ReturnValueConcept("some_name", False, Concept(key=BuiltinConcepts.USER_INPUT, body=" eval 1 + 1")), False), (r("name", False, UserInputConcept(" eval 1 + 1")), False),
]) ])
def test_i_can_match(ret_val, expected): def test_i_can_match(ret_val, expected):
context = get_context() context = get_context()
@@ -32,8 +35,8 @@ def test_i_can_match(ret_val, expected):
@pytest.mark.parametrize("ret_val, expected", [ @pytest.mark.parametrize("ret_val, expected", [
(ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body="eval 1 + 1")), "1 + 1"), (r("name", True, UserInputConcept("eval 1 + 1")), "1 + 1"),
(ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body=" eval 1 + 1")), "1 + 1"), (r("name", True, UserInputConcept(" eval 1 + 1")), "1 + 1"),
]) ])
def test_i_can_eval(ret_val, expected): def test_i_can_eval(ret_val, expected):
context = get_context() context = get_context()
+4 -4
View File
@@ -73,8 +73,8 @@ def test_i_can_eval_when_same_success():
context = get_context() context = get_context()
return_values = [ return_values = [
r("evaluators.a", value=Concept("c1", body="1")), r("evaluators.a", value=Concept("c1", body="1").auto_init()),
r("evaluators.a", value=Concept("c2", body="1")), r("evaluators.a", value=Concept("c2", body="1").auto_init()),
r("other", False), r("other", False),
reduce_requested reduce_requested
] ]
@@ -90,8 +90,8 @@ def test_i_can_eval_when_same_success():
def test_other_success_are_not_reduced(): def test_other_success_are_not_reduced():
context = get_context() context = get_context()
value1 = r("evaluators.a", value=Concept("c1", body="1")) value1 = r("evaluators.a", value=Concept("c1", body="1").auto_init())
value2 = r("evaluators.a", value=Concept("c2", body="2")) value2 = r("evaluators.a", value=Concept("c2", body="2").auto_init())
other_success = r("other") other_success = r("other")
return_values = [ return_values = [
value1, value1,
+92 -12
View File
@@ -1,9 +1,18 @@
import pytest import pytest
from core.concept import Concept from core.concept import Concept, ConceptParts
@pytest.mark.parametrize("name, variables, expected", [ @pytest.mark.parametrize("name, properties, expected", [
("foo", [], "foo"),
("foo(bar)", [], "foo ( bar )"),
("foo a", ["a"], "foo __var__0"),
("a foo b", ["a", "b"], "__var__0 foo __var__1"),
("a foo b", ["b", "a"], "__var__1 foo __var__0"),
("foo", ["foo"], "foo"),
("foo a", ["foo"], "__var__0 a"),
("foo a b", ["a"], "foo __var__0 b"),
("'foo'", [], "foo"),
("my name is a", ["a"], "my name is __var__0"), ("my name is a", ["a"], "my name is __var__0"),
("a b c d", ["b", "c"], "a __var__0 __var__1 d"), ("a b c d", ["b", "c"], "a __var__0 __var__1 d"),
("a 'b c' d", ["b", "c"], "a b c d"), ("a 'b c' d", ["b", "c"], "a b c d"),
@@ -11,17 +20,17 @@ from core.concept import Concept
("a b a c", ["a", "b"], "__var__0 __var__1 __var__0 c"), ("a b a c", ["a", "b"], "__var__0 __var__1 __var__0 c"),
("a b a c", ["b", "a"], "__var__1 __var__0 __var__1 c"), ("a b a c", ["b", "a"], "__var__1 __var__0 __var__1 c"),
]) ])
def test_i_can_get_concept_key(name, variables, expected): def test_i_can_compute_the_key(name, properties, expected):
concept = Concept(name) concept = Concept(name)
for v in variables: for prop in properties:
concept.set_prop(v, None) concept.metadata.props.append((prop, None))
concept.init_key() concept.init_key()
assert concept.metadata.key == expected
assert concept.key == expected
def test_key_does_not_use_variable_when_definition_is_set(): def test_key_does_not_use_variable_when_definition_is_set():
concept = Concept("plus").set_prop('plus') concept = Concept("plus").def_prop('plus')
concept.init_key() concept.init_key()
assert concept.metadata.key == "plus" assert concept.metadata.key == "plus"
@@ -45,7 +54,7 @@ def test_i_can_serialize():
definition_type="def type", definition_type="def type",
desc="this this the desc", desc="this this the desc",
id="123456" id="123456"
).set_prop("a", 10).set_prop("b", None) ).def_prop("a", "10").def_prop("b", None)
to_dict = concept.to_dict() to_dict = concept.to_dict()
assert to_dict == { assert to_dict == {
@@ -60,7 +69,7 @@ def test_i_can_serialize():
'name': 'concept_name', 'name': 'concept_name',
'post': 'definition of the post', 'post': 'definition of the post',
'pre': 'definition of the pre', 'pre': 'definition of the pre',
'props': [('a', 10), ('b', None)], 'props': [('a', "10"), ('b', None)],
'where': 'definition of the where' 'where': 'definition of the where'
} }
@@ -83,7 +92,7 @@ def test_i_can_deserialize():
'name': 'concept_name', 'name': 'concept_name',
'post': 'definition of the post', 'post': 'definition of the post',
'pre': 'definition of the pre', 'pre': 'definition of the pre',
'props': [('a', 10), ('b', None)], 'props': [('a', "10"), ('b', None)],
'where': 'definition of the where' 'where': 'definition of the where'
} }
@@ -102,7 +111,50 @@ def test_i_can_deserialize():
definition_type="def type", definition_type="def type",
desc="this this the desc", desc="this this the desc",
id="123456" id="123456"
).set_prop("a", 10).set_prop("b", None) ).def_prop("a", "10").def_prop("b", None)
def test_i_can_deserialize_props_coming_from_sdp():
from_dict = {
'props': [['a', "10"], ['b', None]], # JSON transform set into list
}
concept = Concept().from_dict(from_dict)
assert concept == Concept().def_prop("a", "10").def_prop("b", None)
def test_i_can_compare_concepts():
concept_a = Concept(
name="concept_name",
is_builtin=True,
is_unique=True,
key="concept_key",
body="definition of the body",
where="definition of the where",
pre="definition of the pre",
post="definition of the post",
definition="bnf definition",
definition_type="def type",
desc="this this the desc",
id="123456"
).def_prop("a", "10").def_prop("b", None)
concept_b = Concept(
name="concept_name",
is_builtin=True,
is_unique=True,
key="concept_key",
body="definition of the body",
where="definition of the where",
pre="definition of the pre",
post="definition of the post",
definition="bnf definition",
definition_type="def type",
desc="this this the desc",
id="123456"
).def_prop("a", "10").def_prop("b", None)
assert concept_a == concept_b
def test_i_can_compare_concept_with_circular_reference(): def test_i_can_compare_concept_with_circular_reference():
@@ -128,3 +180,31 @@ def test_i_can_compare_concept_with_sophisticated_circular_reference_in_other_me
foo.metadata.pre = baz foo.metadata.pre = baz
assert foo != bar assert foo != bar
def test_i_can_update_from():
template = Concept(
name="concept_name",
is_builtin=True,
is_unique=True,
key="concept_key",
body="definition of the body",
where="definition of the where",
pre="definition of the pre",
post="definition of the post",
definition="bnf definition",
definition_type="def type",
desc="this this the desc",
id="123456"
).def_prop("a", "10").def_prop("b", None)
template.values[ConceptParts.BODY] = "value in body"
template.values[ConceptParts.WHERE] = "value in where"
template.values[ConceptParts.PRE] = "value in pre"
template.values[ConceptParts.POST] = "value in post"
template.set_prop("a", 10)
template.set_prop("b", 20)
concept = Concept().update_from(template)
assert concept == template
+63 -62
View File
@@ -5,7 +5,7 @@ import shutil
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept, ConceptAlreadyInSet, \ from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept, ConceptAlreadyInSet, \
ParserResultConcept ParserResultConcept
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, Property, ConceptParts, DoNotResolve from core.concept import Concept, PROPERTIES_TO_SERIALIZE, Property, ConceptParts, DoNotResolve, simplec
from core.sheerka import Sheerka, ExecutionContext from core.sheerka import Sheerka, ExecutionContext
from parsers.PythonParser import PythonNode from parsers.PythonParser import PythonNode
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event from sdp.sheerkaDataProvider import SheerkaDataProvider, Event
@@ -49,8 +49,8 @@ def get_default_concept():
post="isinstance(res, int)", post="isinstance(res, int)",
body="def func(x,y):\n return x+y\nfunc(a,b)", body="def func(x,y):\n return x+y\nfunc(a,b)",
desc="specific description") desc="specific description")
concept.set_prop("a", "value1") concept.def_prop("a", "value1")
concept.set_prop("b", "value2") concept.def_prop("b", "value2")
return concept return concept
@@ -238,7 +238,7 @@ def test_i_can_get_the_correct_concept_using_the_id_when_same_key_when_no_cache(
result = sheerka.get(concept1.key, res2.body.body.id) result = sheerka.get(concept1.key, res2.body.body.id)
assert result.name == "a + b" assert result.name == "a + b"
assert result.body == "a+b" assert result.metadata.body == "a+b"
def test_i_can_get_the_correct_concept_using_the_id__when_same_key_when_cache(): def test_i_can_get_the_correct_concept_using_the_id__when_same_key_when_cache():
@@ -254,7 +254,7 @@ def test_i_can_get_the_correct_concept_using_the_id__when_same_key_when_cache():
result = sheerka.get(concept1.key, res2.body.body.id) result = sheerka.get(concept1.key, res2.body.body.id)
assert result.name == "a + b" assert result.name == "a + b"
assert result.body == "a+b" assert result.metadata.body == "a+b"
def test_i_cannot_get_the_correct_concept_id_the_id_is_wrong(): def test_i_cannot_get_the_correct_concept_id_the_id_is_wrong():
@@ -283,11 +283,12 @@ def test_i_cannot_get_when_key_is_none():
def test_unknown_concept_is_return_when_the_concept_is_not_found(): def test_unknown_concept_is_return_when_the_concept_is_not_found():
sheerka = get_sheerka() sheerka = get_sheerka()
loaded = sheerka.get("fake_key") loaded = sheerka.get("concept_that_does_not_exist")
assert loaded is not None assert loaded is not None
assert sheerka.isinstance(loaded, BuiltinConcepts.UNKNOWN_CONCEPT) assert sheerka.isinstance(loaded, BuiltinConcepts.UNKNOWN_CONCEPT)
assert loaded.body == "fake_key" assert loaded.body == "concept_that_does_not_exist"
assert loaded.metadata.is_evaluated
def test_i_can_instantiate_a_builtin_concept_when_it_has_its_own_class(): def test_i_can_instantiate_a_builtin_concept_when_it_has_its_own_class():
@@ -335,10 +336,10 @@ def test_i_can_instantiate_with_the_name_and_the_id():
assert len(concepts) == 2 assert len(concepts) == 2
foo1 = sheerka.new(("foo", "1001")) foo1 = sheerka.new(("foo", "1001"))
assert foo1.body == "foo1" assert foo1.metadata.body == "foo1"
foo2 = sheerka.new(("foo", "1002")) foo2 = sheerka.new(("foo", "1002"))
assert foo2.body == "foo2" assert foo2.metadata.body == "foo2"
def test_instances_are_different_when_asking_for_new(): def test_instances_are_different_when_asking_for_new():
@@ -403,7 +404,7 @@ def test_concept_id_is_irrelevant_when_only_one_concept():
new = sheerka.new(("foo", "invalid_id")) new = sheerka.new(("foo", "invalid_id"))
assert sheerka.isinstance(new, "foo") assert sheerka.isinstance(new, "foo")
assert new.body == "foo1" assert new.metadata.body == "foo1"
def test_i_cannot_instantiate_when_properties_are_not_recognized(): def test_i_cannot_instantiate_when_properties_are_not_recognized():
@@ -439,6 +440,12 @@ def test_i_cannot_instantiate_when_properties_are_not_recognized():
def test_i_can_get_value(concept, reduce_simple_list, expected): def test_i_can_get_value(concept, reduce_simple_list, expected):
sheerka = get_sheerka() sheerka = get_sheerka()
# I use auto_init() instead of evaluate_concept() to be quicker
c = concept
while isinstance(c, Concept):
c.auto_init()
c = c.body
assert sheerka.value(concept, reduce_simple_list) == expected assert sheerka.value(concept, reduce_simple_list) == expected
@@ -462,16 +469,18 @@ def test_list_of_concept_is_sorted_by_id():
def test_i_can_evaluate_a_concept_with_simple_body(body, expected): def test_i_can_evaluate_a_concept_with_simple_body(body, expected):
sheerka = get_sheerka() sheerka = get_sheerka()
concept = Concept("foo", body=body).init_key() concept = Concept("foo", body=body)
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == expected assert evaluated.body == expected
assert evaluated.metadata.body == body
assert evaluated.metadata.pre is None assert evaluated.metadata.pre is None
assert evaluated.metadata.post is None assert evaluated.metadata.post is None
assert evaluated.metadata.where is None assert evaluated.metadata.where is None
assert evaluated.props == {} assert evaluated.props == {}
assert evaluated.metadata.is_evaluated assert evaluated.metadata.is_evaluated
assert len(evaluated.values) == 0 if body is None else 1
@pytest.mark.parametrize("expr, expected", [ @pytest.mark.parametrize("expr, expected", [
@@ -493,20 +502,22 @@ def test_i_can_evaluate_the_other_metadata(expr, expected):
sheerka = get_sheerka() sheerka = get_sheerka()
concept = Concept("foo", where=expr).init_key() concept = Concept("foo", where=expr)
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body is None assert evaluated.metadata.body is None
assert evaluated.metadata.pre is None assert evaluated.metadata.pre is None
assert evaluated.metadata.post is None assert evaluated.metadata.post is None
assert evaluated.metadata.where == expected assert evaluated.metadata.where == expr
assert evaluated.get_metadata_value(ConceptParts.WHERE) == expected
assert evaluated.props == {} assert evaluated.props == {}
assert evaluated.metadata.is_evaluated assert evaluated.metadata.is_evaluated
assert len(evaluated.values) == 0 if expr is None else 1
@pytest.mark.parametrize("expr, expected", [ @pytest.mark.parametrize("expr, expected", [
# (None, None), (None, None),
("", ""), ("", ""),
("1", 1), ("1", 1),
("1+1", 2), ("1+1", 2),
@@ -518,11 +529,11 @@ def test_i_can_evaluate_the_other_metadata(expr, expected):
def test_i_can_evaluate_a_concept_with_prop(expr, expected): def test_i_can_evaluate_a_concept_with_prop(expr, expected):
sheerka = get_sheerka() sheerka = get_sheerka()
concept = Concept("foo").set_prop("a", expr).init_key() concept = Concept("foo").def_prop("a", expr)
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body is None assert evaluated.metadata.pre is None
assert evaluated.metadata.pre is None assert evaluated.metadata.pre is None
assert evaluated.metadata.post is None assert evaluated.metadata.post is None
assert evaluated.metadata.where is None assert evaluated.metadata.where is None
@@ -533,7 +544,7 @@ def test_i_can_evaluate_a_concept_with_prop(expr, expected):
def test_i_can_evaluate_metadata_using_do_not_resolve(): def test_i_can_evaluate_metadata_using_do_not_resolve():
sheerka = get_sheerka() sheerka = get_sheerka()
concept = Concept("foo") concept = Concept("foo")
concept.cached_asts[ConceptParts.BODY] = DoNotResolve("do not resolve") concept.compiled[ConceptParts.BODY] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
@@ -543,8 +554,8 @@ def test_i_can_evaluate_metadata_using_do_not_resolve():
def test_i_can_evaluate_property_using_do_not_resolve(): def test_i_can_evaluate_property_using_do_not_resolve():
sheerka = get_sheerka() sheerka = get_sheerka()
concept = Concept("foo").set_prop("a") concept = Concept("foo").def_prop("a")
concept.cached_asts["a"] = DoNotResolve("do not resolve") concept.compiled["a"] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
@@ -555,8 +566,8 @@ def test_i_can_evaluate_property_using_do_not_resolve():
def test_original_value_is_overridden_when_using_do_no_resolve(): def test_original_value_is_overridden_when_using_do_no_resolve():
sheerka = get_sheerka() sheerka = get_sheerka()
concept = Concept("foo", body="original value").set_prop("a", "original value") concept = Concept("foo", body="original value").set_prop("a", "original value")
concept.cached_asts["a"] = DoNotResolve("do not resolve") concept.compiled["a"] = DoNotResolve("do not resolve")
concept.cached_asts[ConceptParts.BODY] = DoNotResolve("do not resolve") concept.compiled[ConceptParts.BODY] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
@@ -568,7 +579,7 @@ def test_original_value_is_overridden_when_using_do_no_resolve():
def test_props_are_evaluated_before_body(): def test_props_are_evaluated_before_body():
sheerka = get_sheerka() sheerka = get_sheerka()
concept = Concept("foo", body="a+1").set_prop("a", "10").init_key() concept = Concept("foo", body="a+1").def_prop("a", "10").init_key()
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated.key == concept.key
@@ -583,8 +594,7 @@ def test_i_can_evaluate_when_another_concept_is_referenced():
concept = Concept("foo", body="a").init_key() concept = Concept("foo", body="a").init_key()
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated == simplec("foo", simplec("a", None))
assert sheerka.isinstance(evaluated.body, concept_a)
assert id(evaluated.body) != id(concept_a) assert id(evaluated.body) != id(concept_a)
assert evaluated.metadata.is_evaluated assert evaluated.metadata.is_evaluated
assert evaluated.body.metadata.is_evaluated assert evaluated.body.metadata.is_evaluated
@@ -595,11 +605,11 @@ def test_i_can_evaluate_when_the_referenced_concept_has_a_body():
concept_a = Concept("a", body="1") concept_a = Concept("a", body="1")
sheerka.add_in_cache(concept_a) sheerka.add_in_cache(concept_a)
concept = Concept("foo", body="a").init_key() concept = Concept("foo", body="a")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == Concept("a", body=1).init_key() assert evaluated.body == simplec("a", 1)
assert not concept_a.metadata.is_evaluated assert not concept_a.metadata.is_evaluated
assert evaluated.metadata.is_evaluated assert evaluated.metadata.is_evaluated
@@ -614,13 +624,8 @@ def test_i_can_evaluate_concept_of_concept_when_the_leaf_has_a_body():
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept_d) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept_d)
assert evaluated.key == concept_d.key assert evaluated.key == concept_d.key
assert evaluated.body == Concept( expected = simplec("c", simplec("b", simplec("a", "a")))
name="c", assert evaluated.body == expected
body=Concept(
name="b",
body=Concept(
name="a",
body="a").init_key()).init_key()).init_key()
assert sheerka.value(evaluated) == 'a' assert sheerka.value(evaluated) == 'a'
assert evaluated.metadata.is_evaluated assert evaluated.metadata.is_evaluated
@@ -635,12 +640,8 @@ def test_i_can_evaluate_concept_of_concept_does_not_have_a_body():
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept_d) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept_d)
assert evaluated.key == concept_d.key assert evaluated.key == concept_d.key
assert evaluated.body == Concept( expected = simplec("c", simplec("b", simplec("a", None)))
name="c", assert evaluated.body == expected
body=Concept(
name="b",
body=Concept(
name="a").init_key()).init_key()).init_key()
assert sheerka.value(evaluated) == Concept(name="a").init_key() assert sheerka.value(evaluated) == Concept(name="a").init_key()
assert evaluated.metadata.is_evaluated assert evaluated.metadata.is_evaluated
@@ -649,7 +650,7 @@ def test_i_can_evaluate_concept_when_properties_reference_others_concepts():
sheerka = get_sheerka() sheerka = get_sheerka()
concept_a = sheerka.add_in_cache(Concept(name="a").init_key()) concept_a = sheerka.add_in_cache(Concept(name="a").init_key())
concept = Concept("foo", body="a").set_prop("a", "a").init_key() concept = Concept("foo", body="a").def_prop("a", "a").init_key()
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
# first prop a is evaluated to concept_a # first prop a is evaluated to concept_a
@@ -667,7 +668,7 @@ def test_i_can_evaluate_concept_when_properties_reference_others_concepts_2():
sheerka = get_sheerka() sheerka = get_sheerka()
concept_a = sheerka.add_in_cache(Concept(name="a")) concept_a = sheerka.add_in_cache(Concept(name="a"))
concept = Concept("foo", body="concept_a").set_prop("concept_a", "a") concept = Concept("foo", body="concept_a").def_prop("concept_a", "a")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated.key == concept.key
@@ -679,7 +680,7 @@ def test_i_can_evaluate_concept_when_properties_reference_others_concepts_with_b
sheerka.add_in_cache(Concept(name="a", body="1")) sheerka.add_in_cache(Concept(name="a", body="1"))
sheerka.add_in_cache(Concept(name="b", body="2")) sheerka.add_in_cache(Concept(name="b", body="2"))
concept = Concept("foo", body="propA + propB").set_prop("propA", "a").set_prop("propB", "b") concept = Concept("foo", body="propA + propB").def_prop("propA", "a").def_prop("propB", "b")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated.key == concept.key
@@ -690,24 +691,25 @@ def test_i_can_evaluate_concept_when_properties_is_a_concept():
sheerka = get_sheerka() sheerka = get_sheerka()
concept_a = sheerka.add_in_cache(Concept(name="a", body="'a'").init_key()) concept_a = sheerka.add_in_cache(Concept(name="a", body="'a'").init_key())
concept = Concept("foo").set_prop("a", concept_a) concept = Concept("foo").def_prop("a")
concept.compiled["a"] = concept_a
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.get_prop("a") == Concept(name="a", body="a").init_key() assert evaluated.get_prop("a") == simplec("a", "a")
def test_i_can_evaluate_when_property_asts_is_a_list(): def test_i_can_evaluate_when_property_asts_is_a_list():
sheerka = get_sheerka() sheerka = get_sheerka()
foo = Concept("foo", body="1") foo = Concept("foo", body="1")
concept = Concept("to_eval").set_prop("prop") concept = Concept("to_eval").def_prop("prop")
concept.cached_asts["prop"] = [foo, DoNotResolve("1")] concept.compiled["prop"] = [foo, DoNotResolve("1")]
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
props = evaluated.get_prop("prop") props = evaluated.get_prop("prop")
assert len(props) == 2 assert len(props) == 2
assert props[0] == Concept("foo", body=1).init_key() assert props[0] == simplec("foo", 1)
assert props[1] == "1" assert props[1] == "1"
@@ -717,14 +719,14 @@ def test_i_can_evaluate_when_compiled_is_set_up_with_return_value():
python_node = PythonNode("1 +1 ") python_node = PythonNode("1 +1 ")
parser_result = ParserResultConcept(parser="who", value=python_node) parser_result = ParserResultConcept(parser="who", value=python_node)
concept = Concept("to_eval").set_prop("prop") concept = Concept("to_eval").def_prop("prop")
concept.cached_asts["prop"] = [ReturnValueConcept("who", True, parser_result)] concept.compiled["prop"] = [ReturnValueConcept("who", True, parser_result)]
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.get_prop("prop") == 2 assert evaluated.get_prop("prop") == 2
# also works when only one return value # also works when only one return value
concept = Concept("to_eval").set_prop("prop") concept = Concept("to_eval").def_prop("prop")
concept.cached_asts["prop"] = ReturnValueConcept("who", True, parser_result) concept.compiled["prop"] = ReturnValueConcept("who", True, parser_result)
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.get_prop("prop") == 2 assert evaluated.get_prop("prop") == 2
@@ -747,19 +749,19 @@ def test_properties_values_takes_precedence_over_the_outside_world():
concept = Concept("foo", body="a") concept = Concept("foo", body="a")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == Concept(name="a", body="concept_a").init_key() # this test was already done assert evaluated.body == simplec("a", "concept_a") # this test was already done
# so check this one. # so check this one.
concept = Concept("foo", body="a").set_prop("a", "'property_a'") concept = Concept("foo", body="a").def_prop("a", "'property_a'")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == 'property_a' assert evaluated.body == 'property_a'
# or this one. # or this one.
concept = Concept("foo", body="a").set_prop("a", "b") concept = Concept("foo", body="a").def_prop("a", "b")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == Concept(name="b", body="concept_b").init_key() assert evaluated.body == simplec(name="b", body="concept_b")
def test_properties_values_takes_precedence(): def test_properties_values_takes_precedence():
@@ -767,7 +769,7 @@ def test_properties_values_takes_precedence():
sheerka.add_in_cache(Concept(name="a", body="'concept_a'")) sheerka.add_in_cache(Concept(name="a", body="'concept_a'"))
sheerka.add_in_cache(Concept(name="b", body="'concept_b'")) sheerka.add_in_cache(Concept(name="b", body="'concept_b'"))
concept = Concept("foo", body="a + b").set_prop("a", "'prop_a'") concept = Concept("foo", body="a + b").def_prop("a", "'prop_a'")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated.key == concept.key
assert evaluated.body == 'prop_aconcept_b' assert evaluated.body == 'prop_aconcept_b'
@@ -775,18 +777,17 @@ def test_properties_values_takes_precedence():
def test_i_can_reference_sub_property_of_a_property(): def test_i_can_reference_sub_property_of_a_property():
sheerka = get_sheerka() sheerka = get_sheerka()
sheerka.add_in_cache(Concept(name="concept_a").set_prop("subProp", "'sub_a'")) sheerka.add_in_cache(Concept(name="concept_a").def_prop("subProp", "'sub_a'"))
concept = Concept("foo", body="a.props['subProp'].value").set_prop("a", "concept_a") concept = Concept("foo", body="a.props['subProp'].value").def_prop("a", "concept_a")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key assert evaluated == simplec(concept.key, "sub_a")
assert evaluated.body == 'sub_a'
def test_i_cannot_evaluate_concept_if_property_is_in_error(): def test_i_cannot_evaluate_concept_if_property_is_in_error():
sheerka = get_sheerka() sheerka = get_sheerka()
concept = Concept(name="concept_a").set_prop("subProp", "undef_concept") concept = Concept(name="concept_a").def_prop("subProp", "undef_concept")
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR) assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
+32 -31
View File
@@ -5,7 +5,7 @@ from os import path
import pytest import pytest
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, Property from core.concept import Concept, PROPERTIES_TO_SERIALIZE, Property, simplec
from core.sheerka import Sheerka, ExecutionContext from core.sheerka import Sheerka, ExecutionContext
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
from parsers.ConceptLexerParser import Sequence, StrMatch, OrderedChoice, Optional, ConceptExpression from parsers.ConceptLexerParser import Sequence, StrMatch, OrderedChoice, Optional, ConceptExpression
@@ -50,8 +50,8 @@ def get_default_concept():
post="isinstance(res, int)", post="isinstance(res, int)",
body="def func(x,y):\n return x+y\nfunc(a,b)", body="def func(x,y):\n return x+y\nfunc(a,b)",
desc="specific description") desc="specific description")
concept.set_prop("a", "value1") concept.def_prop("a", "value1")
concept.set_prop("b", "value2") concept.def_prop("b", "value2")
return concept return concept
@@ -79,7 +79,7 @@ def test_i_can_eval_concept_with_python_body():
res = sheerka.evaluate_user_input(text) res = sheerka.evaluate_user_input(text)
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].value == Concept(name="one", body=1).init_key() # by default, the concept is returned assert res[0].value == simplec("one", 1) # by default, the concept is returned
def test_i_can_eval_concept_with_concept_body(): def test_i_can_eval_concept_with_concept_body():
@@ -93,7 +93,7 @@ def test_i_can_eval_concept_with_concept_body():
return_value = res[0].value return_value = res[0].value
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert return_value == Concept(name="un", body=Concept(name="one").init_key()).init_key() assert return_value == simplec("un", simplec("one", None))
def test_i_can_eval_concept_with_no_body(): def test_i_can_eval_concept_with_no_body():
@@ -137,6 +137,7 @@ as:
expected = get_default_concept() expected = get_default_concept()
expected.metadata.id = "1001" expected.metadata.id = "1001"
expected.metadata.desc = None expected.metadata.desc = None
expected.metadata.props = [("a", None), ("b", None)]
expected.init_key() expected.init_key()
sheerka = get_sheerka() sheerka = get_sheerka()
@@ -165,11 +166,11 @@ def test_i_can_eval_def_concept_part_when_one_part_is_a_ref_of_another_concept()
sheerka = get_sheerka() sheerka = get_sheerka()
# concept 'a plus b' is known # concept 'a plus b' is known
concept_a_plus_b = Concept(name="a plus b").set_prop("a").set_prop("b") concept_a_plus_b = Concept(name="a plus b").def_prop("a").def_prop("b")
sheerka.add_in_cache(concept_a_plus_b) sheerka.add_in_cache(concept_a_plus_b)
res = sheerka.evaluate_user_input("def concept a xx b as a plus b") res = sheerka.evaluate_user_input("def concept a xx b as a plus b")
expected = Concept(name="a xx b", body="a plus b").set_prop("a").set_prop("b").init_key() expected = Concept(name="a xx b", body="a plus b").def_prop("a").def_prop("b").init_key()
expected.metadata.id = "1001" expected.metadata.id = "1001"
assert len(res) == 1 assert len(res) == 1
@@ -224,7 +225,7 @@ def test_i_can_eval_a_empty_input(text):
def test_i_can_eval_concept_with_variable(): def test_i_can_eval_concept_with_variable():
sheerka = get_sheerka() sheerka = get_sheerka()
concept_hello = Concept(name="hello a").set_prop("a") concept_hello = Concept(name="hello a").def_prop("a")
concept_foo = Concept(name="foo") concept_foo = Concept(name="foo")
sheerka.add_in_cache(concept_hello) sheerka.add_in_cache(concept_hello)
sheerka.add_in_cache(concept_foo) sheerka.add_in_cache(concept_foo)
@@ -239,7 +240,7 @@ def test_i_can_eval_concept_with_variable():
def test_i_can_eval_concept_with_variable_and_python_as_body(): def test_i_can_eval_concept_with_variable_and_python_as_body():
sheerka = get_sheerka() sheerka = get_sheerka()
hello_a = sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").set_prop("a")) hello_a = sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").def_prop("a"))
sheerka.add_in_cache(Concept(name="foo", body="'foo'")) sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
res = sheerka.evaluate_user_input("hello foo") res = sheerka.evaluate_user_input("hello foo")
@@ -248,14 +249,14 @@ def test_i_can_eval_concept_with_variable_and_python_as_body():
assert sheerka.isinstance(res[0].value, hello_a) assert sheerka.isinstance(res[0].value, hello_a)
assert res[0].value.body == "hello foo" assert res[0].value.body == "hello foo"
assert res[0].value.metadata.is_evaluated assert res[0].value.metadata.is_evaluated
assert res[0].value.props["a"].value == Concept(name="foo", body="foo").init_key() assert res[0].value.props["a"].value == simplec("foo", "foo")
assert res[0].value.props["a"].value.metadata.is_evaluated assert res[0].value.props["a"].value.metadata.is_evaluated
def test_i_can_eval_duplicate_concepts_with_same_value(): def test_i_can_eval_duplicate_concepts_with_same_value():
sheerka = get_sheerka() sheerka = get_sheerka()
sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").set_prop("a")) sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").def_prop("a"))
sheerka.add_in_cache(Concept(name="hello foo", body="'hello foo'")) sheerka.add_in_cache(Concept(name="hello foo", body="'hello foo'"))
sheerka.add_in_cache(Concept(name="foo", body="'foo'")) sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
@@ -269,7 +270,7 @@ def test_i_can_eval_duplicate_concepts_with_same_value():
def test_i_cannot_manage_duplicate_concepts_when_the_values_are_different(): def test_i_cannot_manage_duplicate_concepts_when_the_values_are_different():
sheerka = get_sheerka() sheerka = get_sheerka()
sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").set_prop("a")) sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").def_prop("a"))
sheerka.add_in_cache(Concept(name="hello foo", body="'hello foo'")) sheerka.add_in_cache(Concept(name="hello foo", body="'hello foo'"))
sheerka.add_in_cache(Concept(name="foo", body="'another value'")) sheerka.add_in_cache(Concept(name="foo", body="'another value'"))
@@ -289,8 +290,8 @@ def test_i_can_manage_concepts_with_the_same_key_when_values_are_the_same():
sheerka = get_sheerka() sheerka = get_sheerka()
context = get_context(sheerka) context = get_context(sheerka)
sheerka.create_new_concept(context, Concept(name="hello a", body="'hello ' + a").set_prop("a")) sheerka.create_new_concept(context, Concept(name="hello a", body="'hello ' + a").def_prop("a"))
sheerka.create_new_concept(context, Concept(name="hello b", body="'hello ' + b").set_prop("b")) sheerka.create_new_concept(context, Concept(name="hello b", body="'hello ' + b").def_prop("b"))
res = sheerka.evaluate_user_input("hello 'foo'") res = sheerka.evaluate_user_input("hello 'foo'")
assert len(res) == 1 assert len(res) == 1
@@ -453,10 +454,10 @@ def test_i_can_mix_concept_with_python_to_define_numbers(desc, definitions):
assert res[0].status assert res[0].status
assert res[0].body == 22 assert res[0].body == 22
# res = sheerka.evaluate_user_input("1 + 1 + twenty one") res = sheerka.evaluate_user_input("1 + 1 + twenty one")
# assert len(res) == 1 assert len(res) == 1
# assert res[0].status assert res[0].status
# assert res[0].body == 23 assert res[0].body == 23
def test_i_can_mix_concept_of_concept(): def test_i_can_mix_concept_of_concept():
@@ -472,20 +473,20 @@ def test_i_can_mix_concept_of_concept():
for definition in definitions: for definition in definitions:
sheerka.evaluate_user_input(definition) sheerka.evaluate_user_input(definition)
# res = sheerka.evaluate_user_input("1 plus 2") res = sheerka.evaluate_user_input("1 plus 2")
# assert len(res) == 1 assert len(res) == 1
# assert res[0].status assert res[0].status
# assert res[0].body.body == 3 assert res[0].body.body == 3
#
# res = sheerka.evaluate_user_input("1 plus one")
# assert len(res) == 1
# assert res[0].status
# assert res[0].body.body == 2
# res = sheerka.evaluate_user_input("1 + 1 plus 1") res = sheerka.evaluate_user_input("1 plus one")
# assert len(res) == 1 assert len(res) == 1
# assert res[0].status assert res[0].status
# assert res[0].body.body == 3 assert res[0].body.body == 2
res = sheerka.evaluate_user_input("1 + 1 plus 1")
assert len(res) == 1
assert res[0].status
assert res[0].body.body == 3
res = sheerka.evaluate_user_input("1 plus twenty one") res = sheerka.evaluate_user_input("1 plus twenty one")
assert len(res) == 1 assert len(res) == 1
+75 -43
View File
@@ -1,5 +1,5 @@
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept from core.concept import Concept, ConceptParts
from core.sheerka import Sheerka, ExecutionContext, ExecutionContextIdManager from core.sheerka import Sheerka, ExecutionContext, ExecutionContextIdManager
from core.sheerka_transform import SheerkaTransform, OBJ_TYPE_KEY, SheerkaTransformType, OBJ_ID_KEY from core.sheerka_transform import SheerkaTransform, OBJ_TYPE_KEY, SheerkaTransformType, OBJ_ID_KEY
from sdp.sheerkaDataProvider import Event from sdp.sheerkaDataProvider import Event
@@ -33,7 +33,14 @@ def test_i_can_transform_an_unknown_concept():
definition="it is a definition", definition="it is a definition",
definition_type="def type", definition_type="def type",
desc="this this the desc" desc="this this the desc"
).set_prop("a", 10).set_prop("b", foo).set_prop("c", concept_with_sub) ).def_prop("a", "10").def_prop("b", "foo").def_prop("c", "concept_with_sub")
# add values and props
concept.values[ConceptParts.BODY] = Concept().update_from(concept_with_sub).auto_init()
concept.values[ConceptParts.WHERE] = [foo, 1, "1", True, 1.0]
concept.values[ConceptParts.PRE] = Concept().update_from(foo).auto_init()
concept.values[ConceptParts.POST] = "a value for POST"
concept.set_prop("a", 10).set_prop("b", foo).set_prop("c", concept_with_sub)
st = SheerkaTransform(sheerka) st = SheerkaTransform(sheerka)
to_dict = st.to_dict(concept) to_dict = st.to_dict(concept)
@@ -41,28 +48,41 @@ def test_i_can_transform_an_unknown_concept():
assert to_dict == { assert to_dict == {
OBJ_TYPE_KEY: SheerkaTransformType.Concept, OBJ_TYPE_KEY: SheerkaTransformType.Concept,
OBJ_ID_KEY: 0, OBJ_ID_KEY: 0,
'name': 'concept_name', 'meta.name': 'concept_name',
'key': 'concept_key', 'meta.key': 'concept_key',
'is_builtin': True, 'meta.is_builtin': True,
'is_unique': True, 'meta.is_unique': True,
'definition': 'it is a definition', 'meta.definition': 'it is a definition',
'definition_type': 'def type', 'meta.definition_type': 'def type',
'desc': 'this this the desc', 'meta.desc': 'this this the desc',
'where': [{OBJ_TYPE_KEY: SheerkaTransformType.Concept, 'meta.where': [{OBJ_TYPE_KEY: SheerkaTransformType.Concept,
OBJ_ID_KEY: 1, OBJ_ID_KEY: 1,
'body': 'body', 'meta.body': 'body',
'name': 'foo'}, 1, '1', True, 1.0], 'meta.name': 'foo'}, 1, '1', True, 1.0],
'pre': {OBJ_TYPE_KEY: SheerkaTransformType.Reference, OBJ_ID_KEY: 1}, 'meta.pre': {OBJ_TYPE_KEY: SheerkaTransformType.Reference, OBJ_ID_KEY: 1},
'body': { 'meta.body': {
OBJ_TYPE_KEY: SheerkaTransformType.Concept, '__type__': SheerkaTransformType.Concept,
OBJ_ID_KEY: 2, '__id__': 2,
'name': 'concept_with_sub', 'meta.name': 'concept_with_sub',
'body': {OBJ_TYPE_KEY: SheerkaTransformType.Reference, OBJ_ID_KEY: 1}}, 'meta.body': {
'props': [ '__type__': SheerkaTransformType.Reference,
('a', 10), '__id__': 1}},
('b', {OBJ_TYPE_KEY: SheerkaTransformType.Reference, OBJ_ID_KEY: 1}), 'meta.props': [['a', '10'], ['b', 'foo'], ['c', 'concept_with_sub']],
('c', {OBJ_TYPE_KEY: SheerkaTransformType.Reference, OBJ_ID_KEY: 2}) 'pre': {'__type__': SheerkaTransformType.Concept,
] '__id__': 4,
'meta.body': 'body',
'meta.name': 'foo',
'body': 'body'},
'post': "a value for POST",
'body': {'__type__': SheerkaTransformType.Concept,
'__id__': 3,
'meta.body': {'__id__': 1, '__type__': SheerkaTransformType.Reference},
'meta.name': 'concept_with_sub',
'body': {'__id__': 1, '__type__': SheerkaTransformType.Reference}},
'where': [{OBJ_TYPE_KEY: SheerkaTransformType.Reference, OBJ_ID_KEY: 1}, 1, '1', True, 1.0],
'props': [('a', 10),
('b', {OBJ_TYPE_KEY: SheerkaTransformType.Reference, OBJ_ID_KEY: 1}),
('c', {OBJ_TYPE_KEY: SheerkaTransformType.Reference, OBJ_ID_KEY: 2})],
} }
@@ -73,10 +93,16 @@ def test_i_can_transform_unknown_concept_with_almost_same_value():
st = SheerkaTransform(sheerka) st = SheerkaTransform(sheerka)
to_dict = st.to_dict(concept) to_dict = st.to_dict(concept)
assert to_dict == {OBJ_TYPE_KEY: SheerkaTransformType.Concept, OBJ_ID_KEY: 0, 'name': 'foo'} assert to_dict == {OBJ_TYPE_KEY: SheerkaTransformType.Concept, OBJ_ID_KEY: 0, 'meta.name': 'foo'}
def test_i_can_transform_known_concept_when_the_values_are_the_same(): def test_i_can_transform_known_concept_when_the_values_are_the_same():
"""
Values are the same means that we are serializing a concept which has kept all its default values
There is not diff between the concept to serialize and the one which was registered with create_new_concept()
We serialize only the id of the concept
:return:
"""
sheerka = get_sheerka() sheerka = get_sheerka()
concept = Concept( concept = Concept(
@@ -91,7 +117,7 @@ def test_i_can_transform_known_concept_when_the_values_are_the_same():
definition="it is a definition", definition="it is a definition",
definition_type="def type", definition_type="def type",
desc="this this the desc" desc="this this the desc"
).set_prop("a").set_prop("b") ).def_prop("a").def_prop("b")
sheerka.create_new_concept(get_context(sheerka), concept) sheerka.create_new_concept(get_context(sheerka), concept)
new_concept = sheerka.new(concept.key) new_concept = sheerka.new(concept.key)
@@ -102,6 +128,12 @@ def test_i_can_transform_known_concept_when_the_values_are_the_same():
def test_i_can_transform_known_concept_when_the_values_are_different(): def test_i_can_transform_known_concept_when_the_values_are_different():
"""
Values are the different means the concept was modified.
It's different from the one which was registered with create_new_concept()
We serialize only the differences
:return:
"""
sheerka = get_sheerka() sheerka = get_sheerka()
concept = Concept( concept = Concept(
@@ -116,7 +148,7 @@ def test_i_can_transform_known_concept_when_the_values_are_different():
definition="it is a definition", definition="it is a definition",
definition_type="def type", definition_type="def type",
desc="this this the desc" desc="this this the desc"
).set_prop("a").set_prop("b") ).def_prop("a").def_prop("b")
sheerka.create_new_concept(get_context(sheerka), concept) sheerka.create_new_concept(get_context(sheerka), concept)
new_concept = sheerka.new(concept.key, body="another", a=10, pre="another pre") new_concept = sheerka.new(concept.key, body="another", a=10, pre="another pre")
@@ -135,7 +167,7 @@ def test_i_can_transform_known_concept_when_the_values_are_different():
def test_i_can_transform_concept_with_circular_reference(): def test_i_can_transform_concept_with_circular_reference():
sheerka = get_sheerka() sheerka = get_sheerka()
foo = Concept("foo", ) foo = Concept("foo")
bar = Concept("bar", body=foo) bar = Concept("bar", body=foo)
foo.metadata.body = bar foo.metadata.body = bar
@@ -145,19 +177,19 @@ def test_i_can_transform_concept_with_circular_reference():
assert to_dict == { assert to_dict == {
OBJ_TYPE_KEY: SheerkaTransformType.Concept, OBJ_TYPE_KEY: SheerkaTransformType.Concept,
OBJ_ID_KEY: 0, OBJ_ID_KEY: 0,
'name': 'foo', 'meta.name': 'foo',
'body': {OBJ_TYPE_KEY: SheerkaTransformType.Concept, 'meta.body': {OBJ_TYPE_KEY: SheerkaTransformType.Concept,
OBJ_ID_KEY: 1, OBJ_ID_KEY: 1,
'name': 'bar', 'meta.name': 'bar',
'body': {OBJ_TYPE_KEY: SheerkaTransformType.Reference, 'meta.body': {OBJ_TYPE_KEY: SheerkaTransformType.Reference,
OBJ_ID_KEY: 0}, OBJ_ID_KEY: 0},
}, },
} }
def test_i_can_transform_concept_with_circular_reference_2(): def test_i_can_transform_concept_with_circular_reference_2():
sheerka = get_sheerka() sheerka = get_sheerka()
foo = Concept("foo", ) foo = Concept("foo")
bar = Concept("foo", body=foo) bar = Concept("foo", body=foo)
foo.metadata.body = bar foo.metadata.body = bar
@@ -167,13 +199,13 @@ def test_i_can_transform_concept_with_circular_reference_2():
assert to_dict == { assert to_dict == {
OBJ_TYPE_KEY: SheerkaTransformType.Concept, OBJ_TYPE_KEY: SheerkaTransformType.Concept,
OBJ_ID_KEY: 0, OBJ_ID_KEY: 0,
'name': 'foo', 'meta.name': 'foo',
'body': {OBJ_TYPE_KEY: SheerkaTransformType.Concept, 'meta.body': {OBJ_TYPE_KEY: SheerkaTransformType.Concept,
OBJ_ID_KEY: 1, OBJ_ID_KEY: 1,
'name': 'foo', 'meta.name': 'foo',
'body': {OBJ_TYPE_KEY: SheerkaTransformType.Reference, 'meta.body': {OBJ_TYPE_KEY: SheerkaTransformType.Reference,
OBJ_ID_KEY: 0}, OBJ_ID_KEY: 0},
}, },
} }