From a7b239c16703530fac4923ce387b9c94214edfff Mon Sep 17 00:00:00 2001 From: Kodjo Sossouvi Date: Fri, 17 Jan 2020 17:27:54 +0100 Subject: [PATCH] Refactored Concept class for better separation of metadata, compiled and values --- core/ast/nodes.py | 5 +- core/ast/visitors.py | 2 +- core/builtin_concepts.py | 47 +++++-- core/builtin_helpers.py | 7 +- core/concept.py | 155 +++++++++++++++++---- core/sheerka.py | 81 ++++++----- core/sheerka_transform.py | 17 ++- evaluators/AddConceptEvaluator.py | 5 +- evaluators/ConceptEvaluator.py | 2 +- parsers/ConceptLexerParser.py | 12 +- parsers/ConceptsWithConceptsParser.py | 4 +- parsers/ExactConceptParser.py | 2 +- tests/test_AddConceptEvaluator.py | 24 ++-- tests/test_ConceptEvaluator.py | 20 +-- tests/test_ConceptLexerParser.py | 17 ++- tests/test_ConceptsWithConceptsParser.py | 30 ++-- tests/test_EvalEvaluator.py | 6 +- tests/test_ExactConceptParser.py | 20 ++- tests/test_LexerNodeEvaluator.py | 2 +- tests/test_MultipleConceptsParser.py | 4 +- tests/test_MultipleSameSuccessEvaluator.py | 50 +++---- tests/test_PrepareEvalEvaluator.py | 31 +++-- tests/test_TooManySucessEvaluator.py | 8 +- tests/test_concept.py | 104 ++++++++++++-- tests/test_sheerka.py | 125 ++++++++--------- tests/test_sheerka_non_reg.py | 65 ++++----- tests/test_sheerka_transform.py | 118 ++++++++++------ 27 files changed, 614 insertions(+), 349 deletions(-) diff --git a/core/ast/nodes.py b/core/ast/nodes.py index 715afd8..7b9b9dc 100644 --- a/core/ast/nodes.py +++ b/core/ast/nodes.py @@ -86,7 +86,7 @@ class CallNodeConcept(NodeConcept): super().__init__(BuiltinConcepts.IDENTIFIER_NODE, "Call", parent) 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): @@ -105,6 +105,7 @@ def python_to_concept(python_node): continue value = getattr(node, field) + concept.def_prop(field) if isinstance(value, list): lst = ListConcept().init_key() for i in value: @@ -114,6 +115,8 @@ def python_to_concept(python_node): concept.set_prop(field, _transform(value, NodeParent(concept, field))) else: concept.set_prop(field, value) + + concept.metadata.is_evaluated = True return concept return _transform(python_node, None) diff --git a/core/ast/visitors.py b/core/ast/visitors.py index 6d1cb4b..93572ca 100644 --- a/core/ast/visitors.py +++ b/core/ast/visitors.py @@ -84,7 +84,7 @@ class UnreferencedNamesVisitor(ConceptNodeVisitor): if node.get_node_type() == "FunctionDef": # variable defined as a function parameter 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: return True diff --git a/core/builtin_concepts.py b/core/builtin_concepts.py index ace71e9..eff9f67 100644 --- a/core/builtin_concepts.py +++ b/core/builtin_concepts.py @@ -1,6 +1,6 @@ from enum import Enum -from core.concept import Concept +from core.concept import Concept, ConceptParts class BuiltinConcepts(Enum): @@ -97,8 +97,10 @@ It's mainly to ease the usage class UserInputConcept(Concept): 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.metadata.is_evaluated = True @property def text(self): @@ -114,7 +116,9 @@ class UserInputConcept(Concept): class ErrorConcept(Concept): 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): 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): - 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("status", status) self.set_prop("message", message) self.set_prop("parents", parents) + self.metadata.is_evaluated = True @property def who(self): @@ -155,7 +161,7 @@ class ReturnValueConcept(Concept): @value.setter def value(self, value): - self.metadata.body = value + self.set_metadata_value(ConceptParts.BODY, value) @property def message(self): @@ -200,8 +206,10 @@ class UnknownPropertyConcept(Concept): """ 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.metadata.is_evaluated = True def __repr__(self): 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): - 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("source", source) 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): text = f"ParserResult(parser={self.props['parser'].value}" @@ -273,9 +283,10 @@ class InvalidReturnValueConcept(Concept): BuiltinConcepts.INVALID_RETURN_VALUE, True, False, - BuiltinConcepts.INVALID_RETURN_VALUE, - return_value) + BuiltinConcepts.INVALID_RETURN_VALUE) + self.set_metadata_value(ConceptParts.BODY, return_value) self.set_prop("evaluator", evaluator) + self.metadata.is_evaluated = True class ConceptEvalError(Concept): @@ -283,10 +294,11 @@ class ConceptEvalError(Concept): super().__init__(BuiltinConcepts.CONCEPT_EVAL_ERROR, True, False, - BuiltinConcepts.CONCEPT_EVAL_ERROR, - error) + BuiltinConcepts.CONCEPT_EVAL_ERROR) + self.set_metadata_value(ConceptParts.BODY, error) self.set_prop("concept", concept) self.set_prop("property_name", property_name) + self.metadata.is_evaluated = True def __repr__(self): return f"ConceptEvalError(error={self.error}, concept={self.concept}, property={self.property_name})" @@ -306,7 +318,9 @@ class ConceptEvalError(Concept): class EnumerationConcept(Concept): 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): return iter(self.body) @@ -314,7 +328,9 @@ class EnumerationConcept(Concept): class ListConcept(Concept): 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): self.body.append(obj) @@ -340,9 +356,10 @@ class ConceptAlreadyInSet(Concept): super().__init__(BuiltinConcepts.CONCEPT_ALREADY_IN_SET, True, False, - BuiltinConcepts.CONCEPT_ALREADY_IN_SET, - concept) + BuiltinConcepts.CONCEPT_ALREADY_IN_SET) + self.set_metadata_value(ConceptParts.BODY, concept) self.set_prop("concept_set", concept_set) + self.metadata.is_evaluated = True def __repr__(self): return f"ConceptAlreadyInSet(concept={self.concept}, concept_set={self.concept_set})" diff --git a/core/builtin_helpers.py b/core/builtin_helpers.py index 55c4b16..0144ae9 100644 --- a/core/builtin_helpers.py +++ b/core/builtin_helpers.py @@ -121,10 +121,11 @@ def get_names(sheerka, concept_node): 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 - exp : isinstance(a, int) and isinstance(b, str) - will return 'isinstance(a, int)' if variable_name == 'a' + exp : isinstance(a, int) and isinstance(b, str) + will return 'isinstance(a, int)' if variable_name == 'a' :param sheerka: :param expression: :param variables_to_include: diff --git a/core/concept.py b/core/concept.py index 8ee0ae0..920e79e 100644 --- a/core/concept.py +++ b/core/concept.py @@ -1,5 +1,6 @@ import hashlib -from dataclasses import dataclass +from collections import namedtuple +from dataclasses import dataclass, field from enum import Enum from core.sheerka_logger import get_logger @@ -10,7 +11,7 @@ PROPERTIES_FOR_DIGEST = ("name", "key", "definition", "definition_type", "is_builtin", "is_unique", "where", "pre", "post", "body", - "desc") + "desc", "props") PROPERTIES_TO_SERIALIZE = PROPERTIES_FOR_DIGEST + tuple(["id"]) PROPERTIES_FOR_NEW = ("where", "pre", "post", "body", "desc") VARIABLE_PREFIX = "__var__" @@ -44,9 +45,13 @@ class ConceptMetadata: definition_type: str # definition can be done with something else than regex desc: str # possible description for the concept 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() +simplec = namedtuple("concept", "name body") # for simple concept (tests purposes only) + + class Concept: """ Default concept object @@ -65,7 +70,8 @@ class Concept: definition=None, definition_type=None, desc=None, - id=None): + id=None, + props=None): metadata = ConceptMetadata( str(name) if name else None, @@ -79,12 +85,14 @@ class Concept: definition, definition_type, desc, - id + id, + props or [] ) self.metadata = metadata - self.props = {} # list of Property for this concept - self.cached_asts = {} # cached ast for the where, pre, post and body parts + self.compiled = {} # 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.log = get_logger("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}" 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): return False - # check the attributes + # check the metadata for prop in PROPERTIES_TO_SERIALIZE: # print(prop) # use full to know which id does not match my_value = getattr(self.metadata, prop) @@ -119,9 +134,19 @@ class Concept: if my_value != other_value: return False - # check the props (Concept variables) - for var_name, p in self.props.items(): - if p != other.props[var_name]: + # checks the values + if len(self.values) != len(other.values): + 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 True @@ -138,6 +163,33 @@ class Concept: name = self.name if 'metadata' in vars(self) else 'Concept' raise AttributeError(f"'{name}' concept has no attribute '{item}'") + def def_prop(self, prop_name: str, default_value=None): + """ + 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 def name(self): return self.metadata.name @@ -165,7 +217,7 @@ class Concept: if tokens is None: 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 = "" first = True @@ -175,8 +227,8 @@ class Concept: if token.type == TokenKind.WHITESPACE: continue if not first: - key += " " # spaces are normalized - if variables is not None and token.value in variables: + key += " " # spaces are normalized + if token.value in variables: key += VARIABLE_PREFIX + str(variables.index(token.value)) else: key += token.value[1:-1] if token.type == TokenKind.STRING else token.value @@ -187,7 +239,7 @@ class Concept: @property 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): """ @@ -204,7 +256,7 @@ class Concept: return for key in codes: - self.cached_asts[key] = codes[key] + self.compiled[key] = codes[key] return self @@ -224,7 +276,6 @@ class Concept: 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["props"] = [(p, self.props[p].value) for p in self.props] return props_as_dict def from_dict(self, as_dict): @@ -235,10 +286,11 @@ class Concept: """ for prop in PROPERTIES_TO_SERIALIZE: if prop in as_dict: - setattr(self.metadata, prop, as_dict[prop]) - if "props" in as_dict: - for n, v in as_dict["props"]: - self.set_prop(n, v) + if prop == "props": + for name, value in as_dict[prop]: + self.def_prop(name, value) + else: + setattr(self.metadata, prop, as_dict[prop]) return self def update_from(self, other): @@ -252,24 +304,69 @@ class Concept: if other is None: return self + if id(other) == id(self): + return self + + # update metadata 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 - def set_prop(self, prop_name: str, prop_value=None): - self.props[prop_name] = Property(prop_name, prop_value) # Python 3.x order is kept in dictionaries - return self - - def set_prop_by_index(self, index: int, prop_value): - prop_name = list(self.props.keys())[index] + def set_prop(self, prop_name: str, prop_value): + """Directly sets a value to a property""" self.props[prop_name] = Property(prop_name, prop_value) return self def get_prop(self, prop_name: str): 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: """ @@ -303,6 +400,6 @@ class DoNotResolve: For example, if you want to set a value to the BODY that will not change when when the concept will be evaluated, - set concept.cached_asts[BODY] to DoNotResolve(value) + set concept.compiled[BODY] to DoNotResolve(value) """ value: object diff --git a/core/sheerka.py b/core/sheerka.py index 7595566..cc1b1e2 100644 --- a/core/sheerka.py +++ b/core/sheerka.py @@ -571,40 +571,41 @@ class Sheerka(Concept): """ steps = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING] for part_key in ConceptParts: - if part_key in concept.cached_asts: + if part_key in concept.compiled: continue source = getattr(concept.metadata, part_key.value) - if source is None or not isinstance(source, str) or source == "": - # 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 + if source is None or not isinstance(source, str): continue + + if source.strip() == "": + concept.compiled[part_key] = DoNotResolve(source) 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.add_inputs(source=source) to_parse = self.ret(context.who, True, self.new(BuiltinConcepts.USER_INPUT, body=source)) 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) - for prop in concept.props: - if prop in concept.cached_asts: + for prop, default_value in concept.metadata.props: + if prop in concept.compiled: continue - value = concept.props[prop].value - if value: - if isinstance(value, Concept): - concept.cached_asts[prop] = value - else: - to_parse = self.ret( - context.who, - True, - self.new(BuiltinConcepts.USER_INPUT, body=value)) - with context.push(desc=f"Initializing AST for property {prop}") as sub_context: - sub_context.log_new(logger) - res = self.execute(context, to_parse, steps) - concept.cached_asts[prop] = res - sub_context.add_values(return_values=res) + if default_value is None or not isinstance(default_value, str): + continue + + if default_value.strip() == "": + concept.compiled[prop] = DoNotResolve(default_value) + else: + with context.push(desc=f"Initializing AST for property {prop}") as sub_context: + sub_context.log_new(logger) + sub_context.add_inputs(source=default_value) + to_parse = self.ret(context.who, True, self.new(BuiltinConcepts.USER_INPUT, body=default_value)) + res = self.execute(context, to_parse, steps) + concept.compiled[prop] = res + sub_context.add_values(return_values=res) # Updates the cache of concepts when possible if concept.key in self.concepts_cache: @@ -613,7 +614,7 @@ class Sheerka(Concept): # TODO : manage when there are multiple entries pass 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): """ @@ -706,8 +707,8 @@ class Sheerka(Concept): for metadata_to_eval in all_metadata_to_eval: if metadata_to_eval == "props": - for prop_name in (p for p in concept.props if p in concept.cached_asts): - prop_ast = concept.cached_asts[prop_name] + for prop_name in (p for p in concept.props if p in concept.compiled): + prop_ast = concept.compiled[prop_name] if isinstance(prop_ast, list): resolved = _resolve_list(context.sheerka, prop_ast, prop_name, None) @@ -719,13 +720,13 @@ class Sheerka(Concept): concept.set_prop(prop_name, resolved) else: part_key = ConceptParts(metadata_to_eval) - if part_key in concept.cached_asts and concept.cached_asts[part_key] is not None: - metadata_ast = concept.cached_asts[part_key] + if part_key in concept.compiled and concept.compiled[part_key] is not None: + metadata_ast = concept.compiled[part_key] resolved = _resolve(metadata_ast, part_key, concept) if context.sheerka.isinstance(resolved, BuiltinConcepts.CONCEPT_EVAL_ERROR): return resolved else: - setattr(concept.metadata, metadata_to_eval, resolved) + concept.values[part_key] = resolved # # TODO : Validate the POST condition @@ -789,7 +790,8 @@ class Sheerka(Concept): unknown_concept = Concept() template = self.concepts_cache[str(BuiltinConcepts.UNKNOWN_CONCEPT)] 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 def new(self, concept_key, **kwargs): @@ -812,13 +814,13 @@ class Sheerka(Concept): concept_key != BuiltinConcepts.UNKNOWN_CONCEPT: 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) - # 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): # manage singleton 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.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(): if k in concept.props: concept.set_prop(k, v) elif k in PROPERTIES_FOR_NEW: - setattr(concept.metadata, k, v) + concept.values[ConceptParts(k)] = v elif hasattr(concept, k): setattr(concept, k, v) else: return self.new(BuiltinConcepts.UNKNOWN_PROPERTY, body=k, concept=concept) # TODO : add the concept to the list of known concepts (self.instances) + concept.metadata.is_evaluated = True return concept 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) - def values(self, objs): + def get_values(self, objs): if not (isinstance(objs, list) or self.isinstance(objs, BuiltinConcepts.LIST) or self.isinstance(objs, BuiltinConcepts.ENUMERATION)): diff --git a/core/sheerka_transform.py b/core/sheerka_transform.py index adbfc51..85415ae 100644 --- a/core/sheerka_transform.py +++ b/core/sheerka_transform.py @@ -26,6 +26,9 @@ class SheerkaTransformType(Enum): Node = 5 Exception = 6 + def __repr__(self): + return self.__class__.__name__ + "." + self.name + class SheerkaTransform: @@ -117,18 +120,24 @@ class SheerkaTransform: # transform metadata 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) 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 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 "props" not in to_dict: to_dict["props"] = [] - to_dict["props"].append((prop, value)) + to_dict["props"].append((prop, self.to_dict(value))) return to_dict diff --git a/evaluators/AddConceptEvaluator.py b/evaluators/AddConceptEvaluator.py index 0caeaae..bfbd262 100644 --- a/evaluators/AddConceptEvaluator.py +++ b/evaluators/AddConceptEvaluator.py @@ -73,16 +73,15 @@ class AddConceptEvaluator(OneReturnValueEvaluator): # add props order by appearance when possible for token in def_concept_node.name.tokens: if token.value in props_found: - concept.set_prop(token.value, None) + concept.def_prop(token.value, None) # add the remaining properties for p in props_found: if p not in concept.props: - concept.set_prop(p, None) + concept.def_prop(p, None) # finish initialisation 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 \ sheerka.is_success(def_concept_node.definition): concept.bnf = def_concept_node.definition.value.value diff --git a/evaluators/ConceptEvaluator.py b/evaluators/ConceptEvaluator.py index a9ec47e..ed5158c 100644 --- a/evaluators/ConceptEvaluator.py +++ b/evaluators/ConceptEvaluator.py @@ -47,7 +47,7 @@ class ConceptEvaluator(OneReturnValueEvaluator): evaluated, 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]) else: return sheerka.ret(self.name, True, evaluated.body, parents=[return_value]) diff --git a/parsers/ConceptLexerParser.py b/parsers/ConceptLexerParser.py index 629dab7..e00cb52 100644 --- a/parsers/ConceptLexerParser.py +++ b/parsers/ConceptLexerParser.py @@ -864,17 +864,17 @@ class ConceptLexerParser(BaseParser): Adds a new entry, 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 - _concept.cached_asts[prop_name] = value + _concept.compiled[prop_name] = value else: # 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): previous_value.append(value) else: new_value = [previous_value, value] - _concept.cached_asts[prop_name] = new_value + _concept.compiled[prop_name] = new_value def _look_for_concept_match(_underlying): if isinstance(_underlying.parsing_expression, ConceptExpression): @@ -913,9 +913,9 @@ class ConceptLexerParser(BaseParser): key = (template.key, template.id) if template.id else template.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) - concept.cached_asts[ConceptParts.BODY] = value + concept.compiled[ConceptParts.BODY] = value if underlying.parsing_expression.rule_name: _add_prop(concept, underlying.parsing_expression.rule_name, value) diff --git a/parsers/ConceptsWithConceptsParser.py b/parsers/ConceptsWithConceptsParser.py index 9f35f47..38a8a5a 100644 --- a/parsers/ConceptsWithConceptsParser.py +++ b/parsers/ConceptsWithConceptsParser.py @@ -54,7 +54,7 @@ class ConceptsWithConceptsParser(BaseParser): if isinstance(node, ConceptNode): prop_name = list(concept.props.keys())[index] - concept.cached_asts[prop_name] = node.concept + concept.compiled[prop_name] = node.concept context.log( self.verbose_log, f"Setting property '{prop_name}='{node.concept}'.", @@ -64,7 +64,7 @@ class ConceptsWithConceptsParser(BaseParser): prop_name = list(concept.props.keys())[index] sheerka = context.sheerka 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( self.verbose_log, f"Setting property '{prop_name}'='Python({node.source})'.", diff --git a/parsers/ExactConceptParser.py b/parsers/ExactConceptParser.py index 472407f..e1e4f53 100644 --- a/parsers/ExactConceptParser.py +++ b/parsers/ExactConceptParser.py @@ -55,7 +55,7 @@ class ExactConceptParser(BaseParser): for i, token in enumerate(combination): if token.startswith(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): prop_name = list(concept.props.keys())[index] context.log( diff --git a/tests/test_AddConceptEvaluator.py b/tests/test_AddConceptEvaluator.py index 4298a7d..77ff197 100644 --- a/tests/test_AddConceptEvaluator.py +++ b/tests/test_AddConceptEvaluator.py @@ -21,7 +21,7 @@ def get_context(): 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)))) if body: @@ -87,7 +87,7 @@ def test_i_can_match(ret_val, expected): def test_that_the_source_is_correctly_set(): context = get_context() - def_concept_return_value = get_concept( + def_concept_return_value = get_def_concept( name="hello a", definition=get_concept_definition("hello a", Sequence(StrMatch("hello"), StrMatch("a"))), where="isinstance(a, str )", @@ -132,21 +132,22 @@ def test_that_the_source_is_correctly_set(): # # created_concept = evaluated.body.body # -# assert ConceptParts.WHERE in created_concept.cached_asts -# assert ConceptParts.PRE in created_concept.cached_asts -# assert ConceptParts.BODY in created_concept.cached_asts -# assert ConceptParts.POST not in created_concept.cached_asts +# assert ConceptParts.WHERE in created_concept.compiled +# assert ConceptParts.PRE in created_concept.compiled +# assert ConceptParts.BODY in created_concept.compiled +# 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() - def_concept_return_value = get_concept( + def_concept_return_value = get_def_concept( name="hello a", definition=get_concept_definition("hello a", Sequence(StrMatch("hello"), StrMatch("a"))), where="isinstance(a, str )", pre="a is not None", body="print('hello' + a)") + # sanity. Make sure that the concept does not already exist from_db = context.sheerka.get("hello " + VARIABLE_PREFIX + "0") 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.body == "print('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 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(): @@ -175,7 +177,7 @@ def test_i_can_get_props_from_python_node(): 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", status=True, value=ParserResultConcept(value=concept)) diff --git a/tests/test_ConceptEvaluator.py b/tests/test_ConceptEvaluator.py index 5c935ec..bf609c8 100644 --- a/tests/test_ConceptEvaluator.py +++ b/tests/test_ConceptEvaluator.py @@ -1,10 +1,9 @@ import pytest 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 evaluators.ConceptEvaluator import ConceptEvaluator -from parsers.BaseParser import BaseParser from parsers.ExactConceptParser import ExactConceptParser from sdp.sheerkaDataProvider import Event @@ -41,7 +40,7 @@ def test_i_can_evaluate_concept(): concept = Concept(name="foo", where="1", pre="2", - post="3").set_prop("a", "4").set_prop("b", "5") + post="3").def_prop("a", "4").def_prop("b", "5") evaluator = ConceptEvaluator() item = get_return_value(concept) @@ -49,10 +48,13 @@ def test_i_can_evaluate_concept(): assert result.who == evaluator.name assert result.status - assert result.value == Concept(name="foo", - where=1, - pre=2, - post=3).set_prop("a", 4).set_prop("b", 5).init_key() + assert result.value.name == "foo" + assert result.value.get_metadata_value(ConceptParts.WHERE) == 1 + assert result.value.get_metadata_value(ConceptParts.PRE) == 2 + 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] @@ -111,8 +113,8 @@ def test_i_cannot_recognize_a_concept_if_one_of_the_prop_is_unknown(): context = get_context() context.sheerka.add_in_cache(Concept(name="one").init_key()) concept_plus = context.sheerka.add_in_cache(Concept(name="a plus b") - .set_prop("a", "one") - .set_prop("b", "two").init_key()) + .def_prop("a", "one") + .def_prop("b", "two").init_key()) evaluator = ConceptEvaluator() item = get_return_value(concept_plus) diff --git a/tests/test_ConceptLexerParser.py b/tests/test_ConceptLexerParser.py index d211c05..c648707 100644 --- a/tests/test_ConceptLexerParser.py +++ b/tests/test_ConceptLexerParser.py @@ -59,19 +59,21 @@ def get_context(): def get_expected(concept, text=None): 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() return c def cbody(concept): """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): """cbody stands for compiled property""" - return concept.cached_asts[prop_name] + return concept.compiled[prop_name] 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 res[0].value.body == [cnode("foo", 0, 2, "one two")] 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 context.sheerka.isinstance(res[1].value, BuiltinConcepts.PARSER_RESULT) assert res[1].value.body == [cnode("bar", 0, 2, "one two")] 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 + # the body and the prop['foo'] are the same concept 'foo' 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.value.body == [cnode("foo", 0, 0, "twenty")] 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(): @@ -1089,7 +1092,7 @@ def test_i_get_multiple_props_when_zero_or_more(): assert return_value == [cnode("foo", 0, 4, "one one one")] concept_found = return_value[0].concept 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")[1] == get_expected(one) assert cprop(concept_found, "one")[2] == get_expected(one) diff --git a/tests/test_ConceptsWithConceptsParser.py b/tests/test_ConceptsWithConceptsParser.py index a362844..b04f913 100644 --- a/tests/test_ConceptsWithConceptsParser.py +++ b/tests/test_ConceptsWithConceptsParser.py @@ -86,7 +86,7 @@ def test_not_interested(text, interested): def test_i_can_parse_composition_of_concepts(): foo = Concept("foo") 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]) @@ -96,8 +96,8 @@ def test_i_can_parse_composition_of_concepts(): assert wrapper.source == "foo plus bar" assert context.sheerka.isinstance(return_value, plus) - assert return_value.cached_asts["a"] == foo - assert return_value.cached_asts["b"] == bar + assert return_value.compiled["a"] == foo + assert return_value.compiled["b"] == bar # sanity check, I can evaluate the result 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(): - 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")) right = PythonNode("2+2", ast.parse("2+2", mode="eval")) 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) 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.cached_asts["b"] == [ReturnValueConcept(parser.name, True, right_parser_result)] + assert return_value.compiled["a"] == [ReturnValueConcept(parser.name, True, left_parser_result)] + assert return_value.compiled["b"] == [ReturnValueConcept(parser.name, True, right_parser_result)] # sanity check, I can evaluate the result 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(): - 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")) foo = Concept("foo") 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) code_parser_result = ParserResultConcept(parser=parser, source="1+1", value=code) - assert return_value.cached_asts["a"] == foo - assert return_value.cached_asts["b"] == [ReturnValueConcept(parser.name, True, code_parser_result)] + assert return_value.compiled["a"] == foo + assert return_value.compiled["b"] == [ReturnValueConcept(parser.name, True, code_parser_result)] # sanity check, I can evaluate the result 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(): foo = Concept("foo") bar = Concept("bar") - plus_1 = Concept("a plus b", body="body1").set_prop("a").set_prop("b") - plus_2 = Concept("a plus b", body="body2").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").def_prop("a").def_prop("b") context, input_return_values = init([foo, bar, plus_1, plus_2], [foo, " plus ", bar]) parser = ConceptsWithConceptsParser() @@ -174,8 +174,8 @@ def test_i_can_parse_when_multiple_concepts_are_recognized(): assert res.who == wrapper.parser.name assert wrapper.source == "foo plus bar" assert context.sheerka.isinstance(return_value, plus_1) - assert return_value.cached_asts["a"] == foo - assert return_value.cached_asts["b"] == bar + assert return_value.compiled["a"] == foo + assert return_value.compiled["b"] == bar res = result[1] wrapper = res.value @@ -184,8 +184,8 @@ def test_i_can_parse_when_multiple_concepts_are_recognized(): assert res.who == wrapper.parser.name assert wrapper.source == "foo plus bar" assert context.sheerka.isinstance(return_value, plus_2) - assert return_value.cached_asts["a"] == foo - assert return_value.cached_asts["b"] == bar + assert return_value.compiled["a"] == foo + assert return_value.compiled["b"] == bar def test_i_cannot_parse_when_unknown_concept(): diff --git a/tests/test_EvalEvaluator.py b/tests/test_EvalEvaluator.py index be633e2..d21276e 100644 --- a/tests/test_EvalEvaluator.py +++ b/tests/test_EvalEvaluator.py @@ -23,13 +23,13 @@ eval_requested = ReturnValueConcept("some_name", True, Concept(key=BuiltinConcep def test_i_can_match_and_eval(): context = get_context() - to_eval1 = ReturnValueConcept("some_name", True, Concept(name="2", body="to eval")) - to_eval2 = ReturnValueConcept("some_name", True, Concept(name="3", body="also 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").auto_init()) return_values = [ ReturnValueConcept("some_name", True, "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_eval2, eval_requested diff --git a/tests/test_ExactConceptParser.py b/tests/test_ExactConceptParser.py index 1c07eb3..9da895d 100644 --- a/tests/test_ExactConceptParser.py +++ b/tests/test_ExactConceptParser.py @@ -6,6 +6,14 @@ from parsers.ExactConceptParser import ExactConceptParser 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(): parser = ExactConceptParser() 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].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].value.value.name == "hello world" @@ -75,8 +83,8 @@ def test_i_can_recognize_a_concept_with_variables(): assert results[0].status concept_found = results[0].value.value assert concept_found.key == concept.key - assert concept_found.props["a"].value == "10" - assert concept_found.props["b"].value == "5" + assert metadata_prop(concept_found, "a") == "10" + assert metadata_prop(concept_found, "b") == "5" 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 concept_found = results[0].value.value assert concept_found.key == concept.key - assert concept_found.props["a"].value == "10" - assert concept_found.props["b"].value == "5" + assert metadata_prop(concept_found, "a") == "10" + assert metadata_prop(concept_found, "b") == "5" def test_i_can_manage_unknown_concept(): @@ -138,6 +146,6 @@ def get_concept(name, variables): c = Concept(name=name) if variables: for v in variables: - c.props[v] = Property(v, None) + c.def_prop(v) c.init_key() return c diff --git a/tests/test_LexerNodeEvaluator.py b/tests/test_LexerNodeEvaluator.py index 98b6b70..eceda82 100644 --- a/tests/test_LexerNodeEvaluator.py +++ b/tests/test_LexerNodeEvaluator.py @@ -90,7 +90,7 @@ def test_concept_is_returned_when_only_one_in_the_list(): assert wrapper.parser == evaluator assert wrapper.source == "foo" 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] diff --git a/tests/test_MultipleConceptsParser.py b/tests/test_MultipleConceptsParser.py index e288f3d..36ecd87 100644 --- a/tests/test_MultipleConceptsParser.py +++ b/tests/test_MultipleConceptsParser.py @@ -136,12 +136,12 @@ def test_i_can_parse_when_multiple_concepts_are_matching(): 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.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].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.value[1].concept.body == "bar2" + assert ret_val[1].value.value[1].concept.metadata.body == "bar2" def test_i_can_parse_when_source_code(): diff --git a/tests/test_MultipleSameSuccessEvaluator.py b/tests/test_MultipleSameSuccessEvaluator.py index 7c106af..69348e6 100644 --- a/tests/test_MultipleSameSuccessEvaluator.py +++ b/tests/test_MultipleSameSuccessEvaluator.py @@ -20,8 +20,8 @@ def test_i_can_match_and_eval(): return_values = [ ReturnValueConcept(BaseParser.PREFIX + "some_name", 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="2", 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").auto_init()), 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) 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(): @@ -40,8 +40,8 @@ def test_i_can_match_and_eval_when_no_body(): return_values = [ ReturnValueConcept(BaseParser.PREFIX + "some_name", 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")), + ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1").auto_init()), + ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1").auto_init()), 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) 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(): @@ -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(BaseEvaluator.PREFIX + "Python", True, "value"), ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, "value"), - ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, Concept(name="2", body="value")), - ReturnValueConcept(BaseEvaluator.PREFIX + "Concept", True, Concept(name="1", body="value")), - ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, Concept(name="3", body="value")), + ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, Concept(name="2", body="value").auto_init()), + ReturnValueConcept(BaseEvaluator.PREFIX + "Concept", True, Concept(name="1", body="value").auto_init()), + ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, Concept(name="3", body="value").auto_init()), ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, "value"), 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) 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(): @@ -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(BaseEvaluator.PREFIX + "Python", True, "value"), ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, "value"), - ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, Concept(name="2", body="value")), - ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, Concept(name="1", body="value")), - ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, Concept(name="3", body="value")), + ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, Concept(name="2", body="value").auto_init()), + ReturnValueConcept(BaseEvaluator.PREFIX + "Python", True, Concept(name="1", body="value").auto_init()), + ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, Concept(name="3", body="value").auto_init()), ReturnValueConcept(BaseEvaluator.PREFIX + "other", True, "value"), 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) 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(): @@ -128,8 +128,8 @@ def test_i_can_match_even_if_the_value_are_not_the_same_but_eval_will_fail(): return_values = [ ReturnValueConcept(BaseParser.PREFIX + "some_name", 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="2", body="value2")), + ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value").auto_init()), + ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value2").auto_init()), 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 = [ ReturnValueConcept(BaseParser.PREFIX + "some_name", 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="2")), + ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1").auto_init()), + ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2").auto_init()), ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED)) ] @@ -160,8 +160,8 @@ def test_i_can_match_if_no_parser(): sheerka = context.sheerka return_values = [ - 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="1", body="value").auto_init()), + ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value").auto_init()), ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED)) ] @@ -175,8 +175,8 @@ def test_i_cannot_match_if_not_reduced_requested(): return_values = [ ReturnValueConcept(BaseParser.PREFIX + "some_name", 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="2", 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").auto_init()), ReturnValueConcept("some_name", True, Concept(name="2", body="value")), # 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_name2", False, "Not relevant"), # 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, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED)) ] @@ -207,8 +207,8 @@ def test_i_cannot_match_if_at_least_one_parser_is_successful(): return_values = [ ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "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="2", 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").auto_init()), ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED)) ] diff --git a/tests/test_PrepareEvalEvaluator.py b/tests/test_PrepareEvalEvaluator.py index a5984b9..fbffbd3 100644 --- a/tests/test_PrepareEvalEvaluator.py +++ b/tests/test_PrepareEvalEvaluator.py @@ -1,6 +1,6 @@ import pytest -from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept +from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept from core.concept import Concept from core.sheerka import Sheerka, ExecutionContext from evaluators.PrepareEvalEvaluator import PrepareEvalEvaluator @@ -13,18 +13,21 @@ def get_context(): return ExecutionContext("test", Event(), sheerka) +r = ReturnValueConcept + + @pytest.mark.parametrize("ret_val, expected", [ - (ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body="eval 1 + 1")), True), - (ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body=" eval 1 + 1")), True), - (ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body="eval")), False), - (ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body="1+1")), False), - (ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body="")), False), - (ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body="eval ")), False), - (ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body=[])), False), - (ReturnValueConcept("some_name", True, Concept("foo")), False), - (ReturnValueConcept("some_name", True, "not a concept"), False), - (ReturnValueConcept("some_name", False, Concept(key=BuiltinConcepts.USER_INPUT, body="eval 1 + 1")), False), - (ReturnValueConcept("some_name", False, Concept(key=BuiltinConcepts.USER_INPUT, body=" eval 1 + 1")), False), + (r("name", True, UserInputConcept("eval 1 + 1")), True), + (r("name", True, UserInputConcept(" eval 1 + 1")), True), + (r("name", True, UserInputConcept("eval")), False), + (r("name", True, UserInputConcept("1+1")), False), + (r("name", True, UserInputConcept("")), False), + (r("name", True, UserInputConcept("eval ")), False), + (r("name", True, UserInputConcept([])), False), + (r("name", True, Concept("foo")), False), + (r("name", True, "not a concept"), False), + (r("name", False, UserInputConcept("eval 1 + 1")), False), + (r("name", False, UserInputConcept(" eval 1 + 1")), False), ]) def test_i_can_match(ret_val, expected): context = get_context() @@ -32,8 +35,8 @@ def test_i_can_match(ret_val, expected): @pytest.mark.parametrize("ret_val, expected", [ - (ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.USER_INPUT, body="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"), + (r("name", True, UserInputConcept(" eval 1 + 1")), "1 + 1"), ]) def test_i_can_eval(ret_val, expected): context = get_context() diff --git a/tests/test_TooManySucessEvaluator.py b/tests/test_TooManySucessEvaluator.py index cce3a32..8e2879f 100644 --- a/tests/test_TooManySucessEvaluator.py +++ b/tests/test_TooManySucessEvaluator.py @@ -73,8 +73,8 @@ def test_i_can_eval_when_same_success(): context = get_context() return_values = [ - r("evaluators.a", value=Concept("c1", body="1")), - r("evaluators.a", value=Concept("c2", body="1")), + r("evaluators.a", value=Concept("c1", body="1").auto_init()), + r("evaluators.a", value=Concept("c2", body="1").auto_init()), r("other", False), reduce_requested ] @@ -90,8 +90,8 @@ def test_i_can_eval_when_same_success(): def test_other_success_are_not_reduced(): context = get_context() - value1 = r("evaluators.a", value=Concept("c1", body="1")) - value2 = r("evaluators.a", value=Concept("c2", body="2")) + value1 = r("evaluators.a", value=Concept("c1", body="1").auto_init()) + value2 = r("evaluators.a", value=Concept("c2", body="2").auto_init()) other_success = r("other") return_values = [ value1, diff --git a/tests/test_concept.py b/tests/test_concept.py index 6016c76..a4428e2 100644 --- a/tests/test_concept.py +++ b/tests/test_concept.py @@ -1,9 +1,18 @@ 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"), ("a b c d", ["b", "c"], "a __var__0 __var__1 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", ["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) - for v in variables: - concept.set_prop(v, None) - + for prop in properties: + concept.metadata.props.append((prop, None)) concept.init_key() - assert concept.metadata.key == expected + + assert concept.key == expected 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() assert concept.metadata.key == "plus" @@ -45,7 +54,7 @@ def test_i_can_serialize(): definition_type="def type", desc="this this the desc", id="123456" - ).set_prop("a", 10).set_prop("b", None) + ).def_prop("a", "10").def_prop("b", None) to_dict = concept.to_dict() assert to_dict == { @@ -60,7 +69,7 @@ def test_i_can_serialize(): 'name': 'concept_name', 'post': 'definition of the post', 'pre': 'definition of the pre', - 'props': [('a', 10), ('b', None)], + 'props': [('a', "10"), ('b', None)], 'where': 'definition of the where' } @@ -83,7 +92,7 @@ def test_i_can_deserialize(): 'name': 'concept_name', 'post': 'definition of the post', 'pre': 'definition of the pre', - 'props': [('a', 10), ('b', None)], + 'props': [('a', "10"), ('b', None)], 'where': 'definition of the where' } @@ -102,7 +111,50 @@ def test_i_can_deserialize(): definition_type="def type", desc="this this the desc", 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(): @@ -128,3 +180,31 @@ def test_i_can_compare_concept_with_sophisticated_circular_reference_in_other_me foo.metadata.pre = baz 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 diff --git a/tests/test_sheerka.py b/tests/test_sheerka.py index dd35ed7..20573f9 100644 --- a/tests/test_sheerka.py +++ b/tests/test_sheerka.py @@ -5,7 +5,7 @@ import shutil from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept, ConceptAlreadyInSet, \ 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 parsers.PythonParser import PythonNode from sdp.sheerkaDataProvider import SheerkaDataProvider, Event @@ -49,8 +49,8 @@ def get_default_concept(): post="isinstance(res, int)", body="def func(x,y):\n return x+y\nfunc(a,b)", desc="specific description") - concept.set_prop("a", "value1") - concept.set_prop("b", "value2") + concept.def_prop("a", "value1") + concept.def_prop("b", "value2") 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) 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(): @@ -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) 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(): @@ -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(): sheerka = get_sheerka() - loaded = sheerka.get("fake_key") + loaded = sheerka.get("concept_that_does_not_exist") assert loaded is not None 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(): @@ -335,10 +336,10 @@ def test_i_can_instantiate_with_the_name_and_the_id(): assert len(concepts) == 2 foo1 = sheerka.new(("foo", "1001")) - assert foo1.body == "foo1" + assert foo1.metadata.body == "foo1" foo2 = sheerka.new(("foo", "1002")) - assert foo2.body == "foo2" + assert foo2.metadata.body == "foo2" 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")) assert sheerka.isinstance(new, "foo") - assert new.body == "foo1" + assert new.metadata.body == "foo1" 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): 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 @@ -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): sheerka = get_sheerka() - concept = Concept("foo", body=body).init_key() + concept = Concept("foo", body=body) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) assert evaluated.key == concept.key assert evaluated.body == expected + assert evaluated.metadata.body == body assert evaluated.metadata.pre is None assert evaluated.metadata.post is None assert evaluated.metadata.where is None assert evaluated.props == {} assert evaluated.metadata.is_evaluated + assert len(evaluated.values) == 0 if body is None else 1 @pytest.mark.parametrize("expr, expected", [ @@ -493,20 +502,22 @@ def test_i_can_evaluate_the_other_metadata(expr, expected): sheerka = get_sheerka() - concept = Concept("foo", where=expr).init_key() + concept = Concept("foo", where=expr) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) 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.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.metadata.is_evaluated + assert len(evaluated.values) == 0 if expr is None else 1 @pytest.mark.parametrize("expr, expected", [ - # (None, None), + (None, None), ("", ""), ("1", 1), ("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): 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) 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.post 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(): sheerka = get_sheerka() 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) @@ -543,8 +554,8 @@ def test_i_can_evaluate_metadata_using_do_not_resolve(): def test_i_can_evaluate_property_using_do_not_resolve(): sheerka = get_sheerka() - concept = Concept("foo").set_prop("a") - concept.cached_asts["a"] = DoNotResolve("do not resolve") + concept = Concept("foo").def_prop("a") + concept.compiled["a"] = DoNotResolve("do not resolve") 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(): sheerka = get_sheerka() concept = Concept("foo", body="original value").set_prop("a", "original value") - concept.cached_asts["a"] = DoNotResolve("do not resolve") - concept.cached_asts[ConceptParts.BODY] = DoNotResolve("do not resolve") + concept.compiled["a"] = DoNotResolve("do not resolve") + concept.compiled[ConceptParts.BODY] = DoNotResolve("do not resolve") 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(): 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) 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() evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) - assert evaluated.key == concept.key - assert sheerka.isinstance(evaluated.body, concept_a) + assert evaluated == simplec("foo", simplec("a", None)) assert id(evaluated.body) != id(concept_a) assert evaluated.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") 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) 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 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) assert evaluated.key == concept_d.key - assert evaluated.body == Concept( - name="c", - body=Concept( - name="b", - body=Concept( - name="a", - body="a").init_key()).init_key()).init_key() + expected = simplec("c", simplec("b", simplec("a", "a"))) + assert evaluated.body == expected assert sheerka.value(evaluated) == 'a' 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) assert evaluated.key == concept_d.key - assert evaluated.body == Concept( - name="c", - body=Concept( - name="b", - body=Concept( - name="a").init_key()).init_key()).init_key() + expected = simplec("c", simplec("b", simplec("a", None))) + assert evaluated.body == expected assert sheerka.value(evaluated) == Concept(name="a").init_key() assert evaluated.metadata.is_evaluated @@ -649,7 +650,7 @@ def test_i_can_evaluate_concept_when_properties_reference_others_concepts(): sheerka = get_sheerka() 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) # 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() 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) 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="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) assert evaluated.key == concept.key @@ -690,24 +691,25 @@ def test_i_can_evaluate_concept_when_properties_is_a_concept(): sheerka = get_sheerka() 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) 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(): sheerka = get_sheerka() foo = Concept("foo", body="1") - concept = Concept("to_eval").set_prop("prop") - concept.cached_asts["prop"] = [foo, DoNotResolve("1")] + concept = Concept("to_eval").def_prop("prop") + concept.compiled["prop"] = [foo, DoNotResolve("1")] evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) props = evaluated.get_prop("prop") assert len(props) == 2 - assert props[0] == Concept("foo", body=1).init_key() + assert props[0] == simplec("foo", 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 ") parser_result = ParserResultConcept(parser="who", value=python_node) - concept = Concept("to_eval").set_prop("prop") - concept.cached_asts["prop"] = [ReturnValueConcept("who", True, parser_result)] + concept = Concept("to_eval").def_prop("prop") + concept.compiled["prop"] = [ReturnValueConcept("who", True, parser_result)] evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) assert evaluated.get_prop("prop") == 2 # also works when only one return value - concept = Concept("to_eval").set_prop("prop") - concept.cached_asts["prop"] = ReturnValueConcept("who", True, parser_result) + concept = Concept("to_eval").def_prop("prop") + concept.compiled["prop"] = ReturnValueConcept("who", True, parser_result) evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) 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") evaluated = sheerka.evaluate_concept(get_context(sheerka), concept) 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. - 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) assert evaluated.key == concept.key assert evaluated.body == 'property_a' # 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) 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(): @@ -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="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) assert evaluated.key == concept.key 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(): 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) - assert evaluated.key == concept.key - assert evaluated.body == 'sub_a' + assert evaluated == simplec(concept.key, "sub_a") def test_i_cannot_evaluate_concept_if_property_is_in_error(): 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) assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR) diff --git a/tests/test_sheerka_non_reg.py b/tests/test_sheerka_non_reg.py index b4d6a5e..14864e7 100644 --- a/tests/test_sheerka_non_reg.py +++ b/tests/test_sheerka_non_reg.py @@ -5,7 +5,7 @@ from os import path import pytest 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 evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator from parsers.ConceptLexerParser import Sequence, StrMatch, OrderedChoice, Optional, ConceptExpression @@ -50,8 +50,8 @@ def get_default_concept(): post="isinstance(res, int)", body="def func(x,y):\n return x+y\nfunc(a,b)", desc="specific description") - concept.set_prop("a", "value1") - concept.set_prop("b", "value2") + concept.def_prop("a", "value1") + concept.def_prop("b", "value2") return concept @@ -79,7 +79,7 @@ def test_i_can_eval_concept_with_python_body(): res = sheerka.evaluate_user_input(text) assert len(res) == 1 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(): @@ -93,7 +93,7 @@ def test_i_can_eval_concept_with_concept_body(): return_value = res[0].value assert len(res) == 1 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(): @@ -137,6 +137,7 @@ as: expected = get_default_concept() expected.metadata.id = "1001" expected.metadata.desc = None + expected.metadata.props = [("a", None), ("b", None)] expected.init_key() 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() # 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) 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" 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(): 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") sheerka.add_in_cache(concept_hello) 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(): 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'")) 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 res[0].value.body == "hello foo" 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 def test_i_can_eval_duplicate_concepts_with_same_value(): 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="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(): 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="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() 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 b", body="'hello ' + b").set_prop("b")) + 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").def_prop("b")) res = sheerka.evaluate_user_input("hello 'foo'") 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].body == 22 - # res = sheerka.evaluate_user_input("1 + 1 + twenty one") - # assert len(res) == 1 - # assert res[0].status - # assert res[0].body == 23 + res = sheerka.evaluate_user_input("1 + 1 + twenty one") + assert len(res) == 1 + assert res[0].status + assert res[0].body == 23 def test_i_can_mix_concept_of_concept(): @@ -472,20 +473,20 @@ def test_i_can_mix_concept_of_concept(): for definition in definitions: sheerka.evaluate_user_input(definition) - # res = sheerka.evaluate_user_input("1 plus 2") - # assert len(res) == 1 - # assert res[0].status - # 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") - # assert len(res) == 1 - # assert res[0].status - # assert res[0].body.body == 3 + res = sheerka.evaluate_user_input("1 plus 2") + assert len(res) == 1 + assert res[0].status + 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") + assert len(res) == 1 + assert res[0].status + assert res[0].body.body == 3 res = sheerka.evaluate_user_input("1 plus twenty one") assert len(res) == 1 diff --git a/tests/test_sheerka_transform.py b/tests/test_sheerka_transform.py index 1aa6e74..1837aab 100644 --- a/tests/test_sheerka_transform.py +++ b/tests/test_sheerka_transform.py @@ -1,5 +1,5 @@ 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_transform import SheerkaTransform, OBJ_TYPE_KEY, SheerkaTransformType, OBJ_ID_KEY from sdp.sheerkaDataProvider import Event @@ -33,7 +33,14 @@ def test_i_can_transform_an_unknown_concept(): definition="it is a definition", definition_type="def type", 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) to_dict = st.to_dict(concept) @@ -41,28 +48,41 @@ def test_i_can_transform_an_unknown_concept(): assert to_dict == { OBJ_TYPE_KEY: SheerkaTransformType.Concept, OBJ_ID_KEY: 0, - 'name': 'concept_name', - 'key': 'concept_key', - 'is_builtin': True, - 'is_unique': True, - 'definition': 'it is a definition', - 'definition_type': 'def type', - 'desc': 'this this the desc', - 'where': [{OBJ_TYPE_KEY: SheerkaTransformType.Concept, - OBJ_ID_KEY: 1, - 'body': 'body', - 'name': 'foo'}, 1, '1', True, 1.0], - 'pre': {OBJ_TYPE_KEY: SheerkaTransformType.Reference, OBJ_ID_KEY: 1}, - 'body': { - OBJ_TYPE_KEY: SheerkaTransformType.Concept, - OBJ_ID_KEY: 2, - 'name': 'concept_with_sub', - 'body': {OBJ_TYPE_KEY: SheerkaTransformType.Reference, OBJ_ID_KEY: 1}}, - 'props': [ - ('a', 10), - ('b', {OBJ_TYPE_KEY: SheerkaTransformType.Reference, OBJ_ID_KEY: 1}), - ('c', {OBJ_TYPE_KEY: SheerkaTransformType.Reference, OBJ_ID_KEY: 2}) - ] + 'meta.name': 'concept_name', + 'meta.key': 'concept_key', + 'meta.is_builtin': True, + 'meta.is_unique': True, + 'meta.definition': 'it is a definition', + 'meta.definition_type': 'def type', + 'meta.desc': 'this this the desc', + 'meta.where': [{OBJ_TYPE_KEY: SheerkaTransformType.Concept, + OBJ_ID_KEY: 1, + 'meta.body': 'body', + 'meta.name': 'foo'}, 1, '1', True, 1.0], + 'meta.pre': {OBJ_TYPE_KEY: SheerkaTransformType.Reference, OBJ_ID_KEY: 1}, + 'meta.body': { + '__type__': SheerkaTransformType.Concept, + '__id__': 2, + 'meta.name': 'concept_with_sub', + 'meta.body': { + '__type__': SheerkaTransformType.Reference, + '__id__': 1}}, + 'meta.props': [['a', '10'], ['b', 'foo'], ['c', 'concept_with_sub']], + '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) 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(): + """ + 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() 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_type="def type", 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) 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(): + """ + 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() concept = Concept( @@ -116,7 +148,7 @@ def test_i_can_transform_known_concept_when_the_values_are_different(): definition="it is a definition", definition_type="def type", 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) 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(): sheerka = get_sheerka() - foo = Concept("foo", ) + foo = Concept("foo") bar = Concept("bar", body=foo) foo.metadata.body = bar @@ -145,19 +177,19 @@ def test_i_can_transform_concept_with_circular_reference(): assert to_dict == { OBJ_TYPE_KEY: SheerkaTransformType.Concept, OBJ_ID_KEY: 0, - 'name': 'foo', - 'body': {OBJ_TYPE_KEY: SheerkaTransformType.Concept, - OBJ_ID_KEY: 1, - 'name': 'bar', - 'body': {OBJ_TYPE_KEY: SheerkaTransformType.Reference, - OBJ_ID_KEY: 0}, - }, + 'meta.name': 'foo', + 'meta.body': {OBJ_TYPE_KEY: SheerkaTransformType.Concept, + OBJ_ID_KEY: 1, + 'meta.name': 'bar', + 'meta.body': {OBJ_TYPE_KEY: SheerkaTransformType.Reference, + OBJ_ID_KEY: 0}, + }, } def test_i_can_transform_concept_with_circular_reference_2(): sheerka = get_sheerka() - foo = Concept("foo", ) + foo = Concept("foo") bar = Concept("foo", body=foo) foo.metadata.body = bar @@ -167,13 +199,13 @@ def test_i_can_transform_concept_with_circular_reference_2(): assert to_dict == { OBJ_TYPE_KEY: SheerkaTransformType.Concept, OBJ_ID_KEY: 0, - 'name': 'foo', - 'body': {OBJ_TYPE_KEY: SheerkaTransformType.Concept, - OBJ_ID_KEY: 1, - 'name': 'foo', - 'body': {OBJ_TYPE_KEY: SheerkaTransformType.Reference, - OBJ_ID_KEY: 0}, - }, + 'meta.name': 'foo', + 'meta.body': {OBJ_TYPE_KEY: SheerkaTransformType.Concept, + OBJ_ID_KEY: 1, + 'meta.name': 'foo', + 'meta.body': {OBJ_TYPE_KEY: SheerkaTransformType.Reference, + OBJ_ID_KEY: 0}, + }, }