Refactored Concept class for better separation of metadata, compiled and values
This commit is contained in:
+4
-1
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+32
-15
@@ -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})"
|
||||
|
||||
@@ -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:
|
||||
|
||||
+126
-29
@@ -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
|
||||
|
||||
+44
-37
@@ -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)):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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})'.",
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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))
|
||||
]
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
+92
-12
@@ -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
|
||||
|
||||
+63
-62
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user