You must now use 'eval' to get the body of a concept

This commit is contained in:
2019-12-24 16:58:09 +01:00
parent 5c90b07e1a
commit 44e4b75cf8
37 changed files with 1003 additions and 383 deletions
+3
View File
@@ -9,6 +9,9 @@ indent_size=4
indent_style=space
indent_size=2
[*.py]
insert_final_newline=true
# Tab indentation (no size specified)
[Makefile]
indent_style = tab
+12 -2
View File
@@ -44,8 +44,10 @@ class BuiltinConcepts(Enum):
CONCEPT_EVAL_ERROR = "concept evaluation error" # cannot evaluate a property or metadata of a concept
ENUMERATION = "enum" # represents a list or a set
LIST = "list" # represents a list
CANNOT_RESOLVE_VALUE_ERROR = "value cannot be resolved" # don't know how to find concept value
CONCEPT_ALREADY_IN_SET = "concept already in set"
EVALUATOR_PRE_PROCESS = "evaluator pre process" # used modify / tweak behaviour of evaluators
CONCEPT_EVAL_REQUESTED = "concept eval requested"
REDUCE_REQUESTED = "reduce requested" # remove meaningless error when possible
NODE = "node"
GENERIC_NODE = "generic node"
@@ -68,7 +70,6 @@ BuiltinErrors = [str(e) for e in {
BuiltinConcepts.INVALID_RETURN_VALUE,
BuiltinConcepts.CONCEPT_ALREADY_DEFINED,
BuiltinConcepts.CONCEPT_EVAL_ERROR,
BuiltinConcepts.CANNOT_RESOLVE_VALUE_ERROR,
BuiltinConcepts.CONCEPT_ALREADY_IN_SET,
}]
@@ -267,6 +268,15 @@ class AfterEvaluationConcept(Concept):
super().__init__(BuiltinConcepts.AFTER_EVALUATION, True, True, BuiltinConcepts.AFTER_EVALUATION)
class ConceptEvalRequested(Concept):
def __init__(self):
super().__init__(BuiltinConcepts.CONCEPT_EVAL_REQUESTED, True, True, BuiltinConcepts.CONCEPT_EVAL_REQUESTED)
class ReduceRequested(Concept):
def __init__(self):
super().__init__(BuiltinConcepts.REDUCE_REQUESTED, True, True, BuiltinConcepts.REDUCE_REQUESTED)
class ConceptEvalError(Concept):
def __init__(self, error=None, concept=None, property_name=None):
super().__init__(BuiltinConcepts.CONCEPT_EVAL_ERROR,
+1
View File
@@ -12,6 +12,7 @@ PROPERTIES_FOR_DIGEST = ("name", "key",
"where", "pre", "post", "body",
"desc")
PROPERTIES_TO_SERIALIZE = PROPERTIES_FOR_DIGEST + tuple(["id"])
PROPERTIES_FOR_NEW = ("where", "pre", "post", "body", "desc")
VARIABLE_PREFIX = "__var__"
+110 -40
View File
@@ -1,13 +1,13 @@
from dataclasses import dataclass, field
from core.builtin_concepts import BuiltinConcepts, ErrorConcept, ReturnValueConcept, BuiltinErrors
from core.concept import Concept, ConceptParts, PROPERTIES_FOR_DIGEST
from core.concept import Concept, ConceptParts, PROPERTIES_FOR_NEW
from parsers.BaseParser import BaseParser
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event, SheerkaDataProviderDuplicateKeyError
import core.utils
import core.builtin_helpers
from core.sheerka_logger import console_handler, get_logger
from core.sheerka_logger import console_handler
import logging
@@ -85,8 +85,9 @@ class Sheerka(Concept):
if self.sdp.first_time:
self.sdp.set_key(self.USER_CONCEPTS_KEYS, 1000)
evt_digest = self.sdp.save_event(Event("Initializing Sheerka."))
exec_context = ExecutionContext(self.key, evt_digest, self)
event = Event("Initializing Sheerka.")
self.sdp.save_event(event)
exec_context = ExecutionContext(self.key, event, self)
self.initialize_builtin_concepts()
self.initialize_builtin_parsers()
@@ -181,19 +182,24 @@ class Sheerka(Concept):
:return:
"""
self.log.debug(f"Processing user input '{text}', {user_name=}.")
evt_digest = self.sdp.save_event(Event(text, user_name))
event = Event(text, user_name)
evt_digest = self.sdp.save_event(event)
self.log.debug(f"{evt_digest=}")
execution_context = ExecutionContext(self.key, evt_digest, self)
execution_context = ExecutionContext(self.key, event, self)
user_input = self.ret(self.name, True, self.new(BuiltinConcepts.USER_INPUT, body=text, user_name=user_name))
reduce_requested = self.ret(self.name, True, self.new(BuiltinConcepts.REDUCE_REQUESTED))
steps = [
BuiltinConcepts.BEFORE_PARSING,
BuiltinConcepts.PARSING,
BuiltinConcepts.AFTER_PARSING,
BuiltinConcepts.BEFORE_EVALUATION,
BuiltinConcepts.EVALUATION,
BuiltinConcepts.AFTER_EVALUATION
]
return self.execute(execution_context, user_input, steps)
return self.execute(execution_context, [user_input, reduce_requested], steps)
def _call_parsers(self, execution_context, return_values, logger=None):
@@ -205,6 +211,7 @@ class Sheerka(Concept):
for return_value in return_values:
# make sure we only parse user input
if not return_value.status or not self.isinstance(return_value.body, BuiltinConcepts.USER_INPUT):
result.append(return_value)
continue
to_parse = self.value(return_value)
@@ -232,6 +239,26 @@ class Sheerka(Concept):
def _call_evaluators(self, execution_context, return_values, process_step, evaluation_context=None, logger=None):
def _preprocess_evaluators(context, evaluators):
if not context.preprocess:
return evaluators
if not hasattr(evaluators, "__iter__"):
single_one = True
evaluators = [evaluators]
else:
single_one = False
for preprocess in context.preprocess:
for e in evaluators:
if preprocess.props["name"].value == e.name:
for prop, value in preprocess.props.items():
if prop == "name":
continue
if hasattr(e, prop):
setattr(e, prop, value.value)
return evaluators[0] if single_one else evaluators
# return_values must be a list
if not isinstance(return_values, list):
return_values = [return_values]
@@ -255,6 +282,10 @@ class Sheerka(Concept):
# The first one to be applied will be the one with the highest priority
grouped_evaluators = {}
instantiated_evaluators = [e_class() for e_class in self.evaluators]
# pre-process evaluators if needed
instantiated_evaluators = _preprocess_evaluators(execution_context, instantiated_evaluators)
for evaluator in [e for e in instantiated_evaluators if e.enabled and process_step in e.steps]:
if logger:
evaluator.log = logger
@@ -273,6 +304,7 @@ class Sheerka(Concept):
evaluated_items = []
to_delete = []
for evaluator in grouped_evaluators[priority]:
evaluator = _preprocess_evaluators(execution_context, evaluator.__class__()) # fresh copy
# process evaluators that work on return value
from evaluators.BaseEvaluator import OneReturnValueEvaluator
@@ -334,12 +366,16 @@ class Sheerka(Concept):
for step in execution_steps:
sub_context = execution_context.push(step=step)
sub_context.log(logger or self.log, f"{step=}, context='{sub_context}'")
copy = return_values[:] if hasattr(return_values, "__iter__") else return_values
if step == BuiltinConcepts.PARSING:
return_values = self._call_parsers(sub_context, return_values, logger)
else:
return_values = self._call_evaluators(sub_context, return_values, step, None, logger)
sub_context.log_result(logger or self.log, return_values)
if copy != return_values:
sub_context.log_result(logger or self.log, return_values)
return return_values
@@ -374,7 +410,11 @@ class Sheerka(Concept):
# TODO checks if it exists in cache first
if self.sdp.exists(self.CONCEPTS_ENTRY, concept.key, concept.get_digest()):
error = SheerkaDataProviderDuplicateKeyError(self.CONCEPTS_ENTRY + "." + concept.key, concept)
return self.ret(self.create_new_concept.__name__, False, ErrorConcept(error), error.args[0])
return self.ret(
self.create_new_concept.__name__,
False,
self.new(BuiltinConcepts.CONCEPT_ALREADY_DEFINED, body=concept),
error.args[0])
# set id before saving in db
self.set_id_if_needed(concept, False)
@@ -394,12 +434,18 @@ class Sheerka(Concept):
# save the new context in sdp
try:
self.sdp.add(context.event_digest, self.CONCEPTS_ENTRY, concept, use_ref=True)
self.sdp.add(context.event.get_digest(), self.CONCEPTS_ENTRY, concept, use_ref=True)
if concepts_definitions is not None:
self.sdp.set(context.event_digest, self.CONCEPTS_DEFINITIONS_ENTRY, concepts_definitions, use_ref=True)
self.sdp.set(context.event.get_digest(),
self.CONCEPTS_DEFINITIONS_ENTRY,
concepts_definitions, use_ref=True)
except SheerkaDataProviderDuplicateKeyError as error:
context.log_error(logger, "Failed to create a new concept.", who=self.create_new_concept.__name__)
return self.ret(self.create_new_concept.__name__, False, ErrorConcept(error), error.args[0])
return self.ret(
self.create_new_concept.__name__,
False,
self.new(BuiltinConcepts.CONCEPT_ALREADY_DEFINED, body=concept),
error.args[0])
# Updates the caches
self.concepts_cache[concept.key] = self.sdp.get_safe(self.CONCEPTS_ENTRY, concept.key)
@@ -427,8 +473,8 @@ class Sheerka(Concept):
assert concept_set.id
try:
ret = self.sdp.add_unique(context.event_digest, "All_" + str(concept_set.id), concept.id)
if ret == (None, None): # concept already in set
ret = self.sdp.add_unique(context.event.get_digest(), "All_" + str(concept_set.id), concept.id)
if ret == (None, None): # concept already in set
return self.ret(
self.add_concept_to_set.__name__,
False,
@@ -506,12 +552,13 @@ class Sheerka(Concept):
# to make sure of the order, it don't use ConceptParts.get_parts()
# props must be evaluated first
properties_to_eval = ["props", "where", "pre", "post", "body"]
all_metadata_to_eval = ["props", "where", "pre", "post", "body"]
for prop_to_eval in properties_to_eval:
if prop_to_eval == "props":
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):
sub_context = context.push(desc=f"Evaluating property '{prop_name}'")
sub_context.add_preprocess(self.get_evaluator_name("Concept"), return_body=True)
res = _resolve(sub_context, concept.cached_asts[prop_name])
if res.status:
concept.set_prop(prop_name, res.value)
@@ -521,12 +568,14 @@ class Sheerka(Concept):
concept=concept,
property_name=prop_name)
else:
part_key = ConceptParts(prop_to_eval)
part_key = ConceptParts(metadata_to_eval)
if part_key in concept.cached_asts and concept.cached_asts[part_key] is not None:
sub_context = context.push(desc=f"Evaluating '{part_key}'", obj=concept)
sub_context.add_preprocess(self.get_evaluator_name("Concept"), return_body=True)
res = _resolve(sub_context, concept.cached_asts[part_key])
if res.status:
setattr(concept.metadata, prop_to_eval, res.value)
setattr(concept.metadata, metadata_to_eval, res.value)
else:
return self.new(BuiltinConcepts.CONCEPT_EVAL_ERROR,
body=res.value,
@@ -611,7 +660,7 @@ class Sheerka(Concept):
for k, v in kwargs_.items():
if k in concept.props:
concept.set_prop(k, v)
elif k in PROPERTIES_FOR_DIGEST:
elif k in PROPERTIES_FOR_NEW:
setattr(concept.metadata, k, v)
elif hasattr(concept, k):
setattr(concept, k, v)
@@ -651,28 +700,25 @@ class Sheerka(Concept):
message=message,
parents=parents)
def value(self, obj, allow_none_body=False):
def value(self, obj, reduce_simple_list=False):
if obj is None:
return None
if self.isinstance(obj, BuiltinConcepts.RETURN_VALUE) and \
obj.status and \
self.isinstance(obj.value, BuiltinConcepts.USER_INPUT):
return obj.value.body
if not isinstance(obj, Concept):
return obj
if hasattr(obj, "get_value"):
return obj.get_value()
if obj.body is not None:
if (isinstance(obj.body, list) or isinstance(obj.body, set)) and len(obj.body) == 1:
return obj.body[0]
else:
return obj.body
if not isinstance(obj, Concept):
return obj
return obj if allow_none_body else self.new(BuiltinConcepts.CANNOT_RESOLVE_VALUE_ERROR, body=obj)
if obj.body is None:
return obj
if reduce_simple_list and (isinstance(obj.body, list) or isinstance(obj.body, set)) and len(obj.body) == 1:
body_to_use = obj.body[0]
else:
body_to_use = obj.body
return self.value(body_to_use)
def values(self, objs):
if not (isinstance(objs, list) or
@@ -786,6 +832,17 @@ class Sheerka(Concept):
defs = self.sdp.get(self.CONCEPTS_DEFINITIONS_ENTRY)
self.log.info(defs)
def dump_desc(self, concept_name):
c = self.get(concept_name)
if self.isinstance(c, BuiltinConcepts.UNKNOWN_CONCEPT):
self.log.error("Concept unknown")
return False
self.log.info(f"name : {c.name}")
self.log.info(f"bnf : {c.metadata.definition}")
self.log.info(f"key : {c.key}")
self.log.info(f"body : {c.body}")
@staticmethod
def get_builtins_classes_as_dict():
res = {}
@@ -817,7 +874,7 @@ class ExecutionContext:
def __init__(self,
who,
event_digest: str,
event: Event,
sheerka: Sheerka,
/,
desc: str = None,
@@ -827,20 +884,32 @@ class ExecutionContext:
concepts: dict = None):
self.who = who # who is asking
self.event_digest = event_digest # what was the (original) trigger
self.event = event # what was the (original) trigger
self.sheerka = sheerka # sheerka
self.step = step
self.iteration = iteration
self.preprocess = None
self.desc = desc # human description of what is going on
self.obj = obj # what is the subject of the execution context (if known)
self.concepts = concepts or {}
self.concepts = concepts or {} # cache for concepts that are specific to this execution
self._id = ExecutionContextIdManager.get_id(event_digest)
self._id = ExecutionContextIdManager.get_id(event.get_digest())
self._tab = ""
def add_preprocess(self, name, **kwargs):
preprocess = self.sheerka.new(BuiltinConcepts.EVALUATOR_PRE_PROCESS)
preprocess.set_prop("name", name)
for k, v in kwargs.items():
preprocess.set_prop(k, v)
if not self.preprocess:
self.preprocess = set()
self.preprocess.add(preprocess)
return self
@property
def id(self):
return self._id
@@ -854,7 +923,7 @@ class ExecutionContext:
iteration = kwargs.get("iteration", self.iteration)
new = ExecutionContext(
who,
self.event_digest,
self.event,
self.sheerka,
desc=desc,
obj=obj,
@@ -863,6 +932,7 @@ class ExecutionContext:
iteration=iteration,
)
new._tab = self._tab + " " * DEBUG_TAB_SIZE
new.preprocess = self.preprocess
return new
def log_new(self, logger):
+8
View File
@@ -19,6 +19,9 @@ class BaseEvaluator:
self.priority = priority
self.enabled = enabled
def __repr__(self):
return f"{self.name} ({self.priority})"
class OneReturnValueEvaluator(BaseEvaluator):
"""
@@ -37,8 +40,13 @@ class AllReturnValuesEvaluator(BaseEvaluator):
Evaluates the groups of ReturnValues
"""
def __init__(self, name, steps, priority: int, enabled=True):
super().__init__(name, steps, priority, enabled)
self.eaten = []
def matches(self, context: ExecutionContext, return_values):
pass
def eval(self, context: ExecutionContext, return_values):
pass
+4 -3
View File
@@ -17,8 +17,9 @@ class ConceptEvaluator(OneReturnValueEvaluator):
BuiltinConcepts.AFTER_EVALUATION
]
def __init__(self):
def __init__(self, return_body=False):
super().__init__(self.NAME, [BuiltinConcepts.EVALUATION], 50)
self.return_body = return_body
def matches(self, context, return_value):
return return_value.status and \
@@ -35,7 +36,7 @@ class ConceptEvaluator(OneReturnValueEvaluator):
# If we evaluate Concept("foo", body="a").set_prop("a", "'property_a'")
# The body should be 'property_a', and not a concept called a in our universe
if context.obj and concept.name in context.obj.props:
return sheerka.ret(self.name, False, sheerka.new(BuiltinConcepts.NOT_FOR_ME), parents=[return_value])
return sheerka.ret(self.name, True, context.obj.props[concept.name].value, parents=[return_value])
evaluated = sheerka.evaluate_concept(context, concept, self.verbose_log)
@@ -48,7 +49,7 @@ class ConceptEvaluator(OneReturnValueEvaluator):
evaluated,
parents=[return_value])
if ConceptParts.BODY not in evaluated.cached_asts:
if not self.return_body or ConceptParts.BODY not in evaluated.cached_asts:
return sheerka.ret(self.name, True, evaluated, parents=[return_value])
else:
return sheerka.ret(self.name, True, evaluated.body, parents=[return_value])
-45
View File
@@ -1,45 +0,0 @@
from core.builtin_concepts import BuiltinConcepts
from evaluators.AddConceptEvaluator import AddConceptEvaluator
from evaluators.BaseEvaluator import AllReturnValuesEvaluator
from parsers.BaseParser import BaseParser
from sdp.sheerkaDataProvider import SheerkaDataProviderDuplicateKeyError
class DuplicateConceptEvaluator(AllReturnValuesEvaluator):
"""
Use to recognize when we tried to add the same concept twice
"""
NAME = "DuplicateConcept"
def __init__(self):
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 10)
self.already_defined = None
def matches(self, context, return_values):
sheerka = context.sheerka
parsing = False
add_concept_in_error = False
only_parsers = True
for ret in return_values:
if sheerka.isinstance(ret.value, BuiltinConcepts.AFTER_EVALUATION):
if ret.status:
parsing = True
elif ret.who == sheerka.get_evaluator_name(AddConceptEvaluator.NAME):
if not ret.status and isinstance(ret.value.body, SheerkaDataProviderDuplicateKeyError):
add_concept_in_error = True
self.already_defined = ret.value.body.obj
else:
if not ret.who.startswith(BaseParser.PREFIX):
only_parsers = False
return parsing and add_concept_in_error and only_parsers
def eval(self, context, return_values):
sheerka = context.sheerka
return sheerka.ret(
self.name,
False,
sheerka.new(BuiltinConcepts.CONCEPT_ALREADY_DEFINED, body=self.already_defined),
parents=return_values)
+38
View File
@@ -0,0 +1,38 @@
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from evaluators.BaseEvaluator import AllReturnValuesEvaluator
class EvalEvaluator(AllReturnValuesEvaluator):
"""
Returns the body of all successful concepts
"""
NAME = "Eval"
def __init__(self):
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 80)
self.successful_return_value = None
self.to_eval = []
self.eval_requested = None
def matches(self, context, return_values):
sheerka = context.sheerka
for ret in return_values:
if ret.status and sheerka.isinstance(ret.body, BuiltinConcepts.CONCEPT_EVAL_REQUESTED):
self.eval_requested = ret
elif ret.status and isinstance(ret.body, Concept) and ret.body.body:
self.to_eval.append(ret)
return self.eval_requested is not None and len(self.to_eval) > 0
def eval(self, context, return_value):
sheerka = context.sheerka
result = []
context.log(self.verbose_log, f"{len(self.to_eval)} return value(s) to eval", who=self)
for ret_val in self.to_eval:
context.log(self.verbose_log, f"{ret_val}", who=self)
result.append(sheerka.ret(self.name, True, ret_val.body.body, parents=[ret_val, self.eval_requested]))
return result
+46 -15
View File
@@ -1,6 +1,9 @@
from core.builtin_concepts import BuiltinConcepts
import core.builtin_helpers
from core.concept import Concept
from evaluators.BaseEvaluator import AllReturnValuesEvaluator, BaseEvaluator
from evaluators.ConceptEvaluator import ConceptEvaluator
from evaluators.PythonEvaluator import PythonEvaluator
from parsers.BaseParser import BaseParser
@@ -15,38 +18,66 @@ class MultipleSameSuccessEvaluator(AllReturnValuesEvaluator):
NAME = "MultipleSameSuccess"
def __init__(self):
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 10)
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 50)
self.success = []
def matches(self, context, return_values):
sheerka = context.sheerka
after_evaluation = False
nb_successful_evaluators = 0
only_parsers_in_error = True
unlisted = False
to_process = False
for ret in return_values:
if sheerka.isinstance(ret.value, BuiltinConcepts.AFTER_EVALUATION):
if ret.status:
after_evaluation = True
if ret.status and context.sheerka.isinstance(ret.body, BuiltinConcepts.REDUCE_REQUESTED):
to_process = True
self.eaten.append(ret)
elif ret.who.startswith(BaseEvaluator.PREFIX):
if ret.status:
nb_successful_evaluators += 1
self.success.append(ret)
self.eaten.append(ret)
elif ret.who.startswith(BaseParser.PREFIX):
self.eaten.append(ret)
if ret.status:
only_parsers_in_error = False
else:
unlisted = True
return after_evaluation and nb_successful_evaluators > 1 and only_parsers_in_error and not unlisted
return to_process and nb_successful_evaluators > 1 and only_parsers_in_error
def eval(self, context, return_values):
sheerka = context.sheerka
if core.builtin_helpers.is_same_success(sheerka, self.success):
reference = sheerka.value(self.success[0].value, allow_none_body=True)
return sheerka.ret(self.name, True, reference, parents=return_values)
context.log(self.verbose_log, f"{len(self.success)} successful return value(s)", who=self)
for s in self.success:
context.log(self.verbose_log, f"{s}", who=self)
if not core.builtin_helpers.is_same_success(sheerka, self.success):
return None
# ######################################
# !!!!! W A R N I N G !!!!!!!!
# I have a massive issue with how I implement this feature
# I have forced an arbitrary order between Concept evaluator and Python evaluator
# I gave a random order to the other
#
# I guess that we need a proper algorithm to elect which return value to use if they have the same result
# I guts feeling is that, it will depend on the intent of the user
# So it depends on the context
# try to return a concept if possible
# give the priority to the ConceptEvaluator
for s in self.success:
if isinstance(s.value, Concept) and s.who == ConceptEvaluator().name:
return sheerka.ret(self.name, True, s.value, parents=self.eaten)
# Then the PythonEvaluator
for s in self.success:
if isinstance(s.value, Concept) and s.who == PythonEvaluator().name:
return sheerka.ret(self.name, True, s.value, parents=self.eaten)
# Then the first concept.
# It's not predictable, so I guess that it's not a good implementation choice
for s in self.success:
if isinstance(s.value, Concept):
return sheerka.ret(self.name, True, s.value, parents=self.eaten)
return sheerka.ret(self.name, True, self.success[0].value, parents=self.eaten)
return None
+42
View File
@@ -0,0 +1,42 @@
from core.builtin_concepts import BuiltinConcepts
from evaluators.BaseEvaluator import AllReturnValuesEvaluator
from parsers.BaseParser import BaseParser
class OneErrorEvaluator(AllReturnValuesEvaluator):
"""
Use to reduce when there is only one evaluator in error
The rest of the return values must be parsers in error
"""
NAME = "OneError"
def __init__(self):
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 40)
self.return_value_in_error = None
def matches(self, context, return_values):
nb_evaluators_in_error = 0
to_process = False
for ret in return_values:
if ret.status and (ret.who.startswith(self.PREFIX) or ret.who.startswith(BaseParser.PREFIX)):
return False
elif ret.status and context.sheerka.isinstance(ret.body, BuiltinConcepts.REDUCE_REQUESTED):
to_process = True
self.eaten.append(ret)
elif not ret.status and ret.who.startswith(self.PREFIX):
nb_evaluators_in_error += 1
self.return_value_in_error = ret
self.eaten.append(ret)
elif not ret.status and ret.who.startswith(BaseParser.PREFIX):
self.eaten.append(ret)
return to_process and nb_evaluators_in_error == 1
def eval(self, context, return_values):
context.log(self.verbose_log, f"1 return value in error, {len(self.eaten)} item(s) eaten", who=self)
context.log(self.verbose_log, f"{self.return_value_in_error}", who=self)
sheerka = context.sheerka
return sheerka.ret(self.name, False, self.return_value_in_error.value, parents=self.eaten)
+20 -17
View File
@@ -14,28 +14,31 @@ class OneSuccessEvaluator(AllReturnValuesEvaluator):
NAME = "OneSuccess"
def __init__(self):
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 10)
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 60) # before MultipleSameSuccess
self.successful_return_value = None
def matches(self, context, return_values):
sheerka = context.sheerka
after_evaluation = False
nb_successful_evaluators = 0
only_parsers = True
for ret in return_values:
if sheerka.isinstance(ret.value, BuiltinConcepts.AFTER_EVALUATION):
if ret.status:
after_evaluation = True
elif ret.who.startswith(self.PREFIX):
if ret.status:
nb_successful_evaluators += 1
self.successful_return_value = ret
else:
if not ret.who.startswith(BaseParser.PREFIX):
only_parsers = False
to_process = False
return after_evaluation and nb_successful_evaluators == 1 and only_parsers
for ret in return_values:
if ret.status and ret.who.startswith(BaseParser.PREFIX):
return False
elif ret.status and context.sheerka.isinstance(ret.body, BuiltinConcepts.REDUCE_REQUESTED):
to_process = True
self.eaten.append(ret)
elif ret.status and ret.who.startswith(self.PREFIX):
nb_successful_evaluators += 1
self.successful_return_value = ret
self.eaten.append(ret)
elif not ret.status:
self.eaten.append(ret)
return to_process and nb_successful_evaluators == 1
def eval(self, context, return_values):
context.log(self.verbose_log, f"1 successful return value, {len(self.eaten)} item(s) eaten", who=self)
context.log(self.verbose_log, f"{self.successful_return_value}", who=self)
sheerka = context.sheerka
return sheerka.ret(self.name, True, self.successful_return_value.value, parents=return_values)
return sheerka.ret(self.name, True, self.successful_return_value.value, parents=self.eaten)
+40
View File
@@ -0,0 +1,40 @@
from core.builtin_concepts import BuiltinConcepts
from evaluators.BaseEvaluator import OneReturnValueEvaluator
class PrepareEvalEvaluator(OneReturnValueEvaluator):
"""
To parse evaluation requests
"""
NAME = "PrepareEval"
def __init__(self, **kwargs):
super().__init__(self.NAME, [BuiltinConcepts.BEFORE_PARSING], 90)
self.text = None
def matches(self, context, return_value):
if not (return_value.status and
context.sheerka.isinstance(return_value.body, BuiltinConcepts.USER_INPUT) and
isinstance(return_value.body.body, str)):
return False
text = return_value.body.body.strip()
if not text.startswith("eval "):
return False
self.text = text
return True
def eval(self, context, return_value):
sheerka = context.sheerka
new_text_to_parse = sheerka.ret(
self.name,
True, sheerka.new(BuiltinConcepts.USER_INPUT, body=self.text[5:], user_name=context.event.user))
evaluation_requested = sheerka.ret(
self.name,
True, sheerka.new(BuiltinConcepts.CONCEPT_EVAL_REQUESTED))
return [new_text_to_parse, evaluation_requested]
+10 -1
View File
@@ -2,6 +2,7 @@ import copy
from core.ast.visitors import UnreferencedNamesVisitor
from core.builtin_concepts import BuiltinConcepts, ParserResultConcept
from core.concept import ConceptParts
from evaluators.BaseEvaluator import OneReturnValueEvaluator
from parsers.PythonParser import PythonNode
import ast
@@ -29,6 +30,14 @@ class PythonEvaluator(OneReturnValueEvaluator):
try:
context.log(self.verbose_log, f"Evaluating python node {node}.", self.name)
# Do not evaluate if the ast refers to a concept (leave it to ConceptEvaluator)
if isinstance(node.ast_, ast.Expression) and isinstance(node.ast_.body, ast.Name):
c = context.sheerka.get(node.ast_.body.id)
if not context.sheerka.isinstance(c, BuiltinConcepts.UNKNOWN_CONCEPT):
context.log(self.verbose_log, "It's a simple concept. Not for me.", self.name)
not_for_me = context.sheerka.new(BuiltinConcepts.NOT_FOR_ME, body=node)
return sheerka.ret(self.name, False, not_for_me, parents=[return_value])
my_locals = self.get_locals(context, node.ast_)
context.log(self.verbose_log, f"locals={my_locals}", self.name)
@@ -78,7 +87,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
evaluated = context.sheerka.evaluate_concept(sub_context, concept, self.verbose_log)
if evaluated.key == concept.key:
my_locals[name] = evaluated.body or evaluated
my_locals[name] = evaluated.body or evaluated # if ConceptParts.BODY not in evaluated.cached_asts else evaluated
return my_locals
+15 -24
View File
@@ -17,33 +17,25 @@ class TooManySuccessEvaluator(AllReturnValuesEvaluator):
NAME = "TooManySuccess"
def __init__(self):
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 10)
super().__init__(self.NAME, [BuiltinConcepts.AFTER_EVALUATION], 60)
self.success = []
def matches(self, context, return_values):
sheerka = context.sheerka
after_evaluation = False
nb_successful_evaluators = 0
only_parsers_in_error = True
unlisted = False
to_process = False
for ret in return_values:
if ret.status and ret.who.startswith(BaseParser.PREFIX):
return False
elif ret.status and context.sheerka.isinstance(ret.body, BuiltinConcepts.REDUCE_REQUESTED):
to_process = True
self.eaten.append(ret)
elif ret.status and ret.who.startswith(self.PREFIX):
self.success.append(ret)
self.eaten.append(ret)
elif not ret.status:
self.eaten.append(ret)
if sheerka.isinstance(ret.value, BuiltinConcepts.AFTER_EVALUATION):
if ret.status:
after_evaluation = True
elif ret.who.startswith(BaseEvaluator.PREFIX):
if ret.status:
nb_successful_evaluators += 1
self.success.append(ret)
elif ret.who.startswith(BaseParser.PREFIX):
if ret.status:
only_parsers_in_error = False
else:
unlisted = True
return after_evaluation and nb_successful_evaluators > 1 and only_parsers_in_error and not unlisted
return to_process and len(self.success) > 1
def eval(self, context, return_values):
sheerka = context.sheerka
@@ -56,8 +48,7 @@ class TooManySuccessEvaluator(AllReturnValuesEvaluator):
context.log(self.verbose_log,
f"Values are different. Raising {BuiltinConcepts.TOO_MANY_SUCCESS}.", self.name)
too_many_success = sheerka.new(BuiltinConcepts.TOO_MANY_SUCCESS, body=self.success)
return sheerka.ret(self.name, False, too_many_success, parents=return_values)
return sheerka.ret(self.name, False, too_many_success, parents=self.eaten)
context.log(self.verbose_log,
f"Values are the same. Nothing to do.", self.name)
context.log(self.verbose_log, f"Values are the same. Nothing to do.", self.name)
return None
-3
View File
@@ -1,8 +1,5 @@
from core.builtin_concepts import BuiltinConcepts
from parsers.BaseParser import BaseParser
import logging
log = logging.getLogger(__name__)
class EmptyStringParser(BaseParser):
+12 -2
View File
@@ -25,21 +25,31 @@ class Event(object):
Class that represents something that modifies the state of the system
"""
def __init__(self, message="", user="kodjo", date=datetime.now()):
def __init__(self, message="", user="", date=datetime.now()):
self.version = 1
self.user = user
self.date = date
self.message = message
self._digest = None
def get_digest(self):
"""
Returns the digest of the event
:return: hexa form of the sha256
"""
if self._digest:
return self._digest
if self.message == "" and self.user == "":
self._digest = "xxx" # to speed unit tests
return self._digest
if not isinstance(self.message, str):
raise NotImplementedError
return hashlib.sha256(f"Event:{self.user}{self.date}{self.message}".encode("utf-8")).hexdigest()
self._digest = hashlib.sha256(f"Event:{self.user}{self.date}{self.message}".encode("utf-8")).hexdigest()
return self._digest
def to_dict(self):
return self.__dict__
+2 -1
View File
@@ -12,12 +12,13 @@ from parsers.ConceptLexerParser import Sequence, StrMatch, ZeroOrMore, ConceptMa
from parsers.BnfParser import BnfParser
from parsers.DefaultParser import DefConceptNode, NameNode
from parsers.PythonParser import PythonNode, PythonParser
from sdp.sheerkaDataProvider import Event
def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("test", "xxx", sheerka)
return ExecutionContext("test", Event(), sheerka)
def get_concept(name, where=None, pre=None, post=None, body=None, definition=None):
+19 -1
View File
@@ -6,12 +6,13 @@ from core.sheerka import Sheerka, ExecutionContext
from core.tokenizer import Tokenizer
from evaluators.AddConceptInSetEvaluator import AddConceptInSetEvaluator
from parsers.DefaultParser import IsaConceptNode, NameNode
from sdp.sheerkaDataProvider import Event
def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("test", "xxx", sheerka)
return ExecutionContext("test", Event(), sheerka)
def get_ret_val(concept_name, concept_set_name):
@@ -74,6 +75,23 @@ def test_i_can_add_concept_to_a_set_of_concept():
assert context.sheerka.isinstance(res.value, BuiltinConcepts.SUCCESS)
def test_i_can_add_concept_with_a_body_to_a_set_of_concept():
context = get_context()
foo = Concept("foo", body="1")
context.sheerka.set_id_if_needed(foo, False)
context.sheerka.add_in_cache(foo)
bar = Concept("bar")
context.sheerka.set_id_if_needed(bar, False)
context.sheerka.add_in_cache(bar)
ret_val = get_ret_val("foo", "bar")
res = AddConceptInSetEvaluator().eval(context, ret_val)
assert res.status
assert context.sheerka.isinstance(res.value, BuiltinConcepts.SUCCESS)
def test_i_cannot_add_the_same_concept_twice():
context = get_context()
foo = Concept("foo")
+2 -1
View File
@@ -7,13 +7,14 @@ from parsers.BaseParser import UnexpectedTokenErrorNode
from parsers.BnfParser import BnfParser, UnexpectedEndOfFileError
from parsers.ConceptLexerParser import StrMatch, Optional, ZeroOrMore, OrderedChoice, Sequence, OneOrMore, \
ConceptLexerParser, ConceptNode, ConceptMatch
from sdp.sheerkaDataProvider import Event
def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("sheerka", "xxxx", sheerka)
return ExecutionContext("sheerka", Event(), sheerka)
@pytest.mark.parametrize("expression, expected", [
+25 -6
View File
@@ -6,12 +6,13 @@ 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
def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("test", "xxx", sheerka)
return ExecutionContext("test", Event(), sheerka)
def get_return_value(concept, source=None):
@@ -55,7 +56,7 @@ def test_i_can_evaluate_concept():
assert result.parents == [item]
def test_body_is_returned_when_defined():
def test_body_is_returned_when_defined_and_requested():
context = get_context()
concept = Concept(name="foo",
body="'I have a value'",
@@ -63,7 +64,7 @@ def test_body_is_returned_when_defined():
pre="2",
post="3").set_prop("a", "4").set_prop("b", "5")
evaluator = ConceptEvaluator()
evaluator = ConceptEvaluator(return_body=True)
item = get_return_value(concept)
result = evaluator.eval(context, item)
@@ -73,7 +74,25 @@ def test_body_is_returned_when_defined():
assert result.parents == [item]
def test_i_cannot_eval_if_with_the_same_name_is_defined_in_the_context():
def test_body_is_not_returned_if_not_requested():
context = get_context()
concept = Concept(name="foo",
body="'I have a value'",
where="1",
pre="2",
post="3").set_prop("a", "4").set_prop("b", "5")
evaluator = ConceptEvaluator(return_body=False) # which is the default behaviour
item = get_return_value(concept)
result = evaluator.eval(context, item)
assert result.who == evaluator.name
assert result.status
assert result.value == concept
assert result.parents == [item]
def test_i_can_eval_if_with_the_same_name_is_defined_in_the_context():
# If we evaluate Concept("foo", body="a").set_prop("a", "'property_a'")
# ConceptEvaluator will be called to resolve 'a' while we know that 'a' refers to the string 'property_a'
@@ -84,8 +103,8 @@ def test_i_cannot_eval_if_with_the_same_name_is_defined_in_the_context():
item = get_return_value(concept)
result = ConceptEvaluator().eval(context, item)
assert not result.status
assert context.sheerka.isinstance(result.value, BuiltinConcepts.NOT_FOR_ME)
assert result.status
assert result.value == "'some_other_value'"
def test_i_cannot_recognize_a_concept_if_one_of_the_prop_is_unknown():
+2 -1
View File
@@ -4,6 +4,7 @@ from core.concept import Concept
from core.sheerka import Sheerka, ExecutionContext
from parsers.ConceptLexerParser import ConceptLexerParser, ConceptNode, Sequence, StrMatch, OrderedChoice, Optional, \
ParsingExpressionVisitor, TerminalNode, NonTerminalNode, LexerNode, ConceptMatch, ZeroOrMore, OneOrMore
from sdp.sheerkaDataProvider import Event
class ConceptVisitor(ParsingExpressionVisitor):
@@ -849,4 +850,4 @@ def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("sheerka", "xxxx", sheerka)
return ExecutionContext("sheerka", Event(), sheerka)
+3 -2
View File
@@ -4,14 +4,15 @@ from core.builtin_concepts import ReturnValueConcept, ParserResultConcept
from core.concept import Concept
from core.sheerka import Sheerka, ExecutionContext
from evaluators.ConceptNodeEvaluator import ConceptNodeEvaluator
from parsers.ConceptLexerParser import ConceptNode, ConceptLexerParser, NonTerminalNode, Sequence, TerminalNode, \
from parsers.ConceptLexerParser import ConceptNode, ConceptLexerParser, Sequence, TerminalNode, \
StrMatch, Optional, OrderedChoice, ZeroOrMore
from sdp.sheerkaDataProvider import Event
def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("test", "xxx", sheerka)
return ExecutionContext("test", Event(), sheerka)
def get_return_value(nodes, source):
+2 -82
View File
@@ -11,49 +11,8 @@ from parsers.DefaultParser import UnexpectedTokenErrorNode, DefConceptNode
from parsers.BnfParser import BnfParser
# def nop():
# return NopNode()
#
#
# def n(number):
# return NumberNode([], number)
#
#
# def s(string, quote="'"):
# return StringNode([], string, quote)
#
#
# def v(name):
# return VariableNode([], name)
#
#
# def t():
# return TrueNode([])
#
#
# def f():
# return FalseNode([])
#
#
# def null():
# return NullNode([])
#
#
# def b(operator, left, right):
# return BinaryNode([], operator, left, right)
from sdp.sheerkaDataProvider import Event
#
# def compare_ast(left, right):
# left_as_string = ast.dump(left)
# left_as_string = left_as_string.replace(", ctx=Load()", "")
# left_as_string = left_as_string.replace(", kind=None", "")
#
# right_as_string = right if isinstance(right, str) else ast.dump(right)
# right_as_string = right_as_string.replace(", ctx=Load()", "")
# right_as_string = right_as_string.replace(", kind=None", "")
#
# return left_as_string == right_as_string
#
def get_def_concept(name, where=None, pre=None, post=None, body=None, definition=None):
def_concept = DefConceptNode([], name=NameNode(list(Tokenizer(name))))
@@ -78,7 +37,7 @@ def get_def_concept(name, where=None, pre=None, post=None, body=None, definition
def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("test", "xxx", sheerka)
return ExecutionContext("test", Event(), sheerka)
def get_concept_part(part):
@@ -104,45 +63,6 @@ def get_concept_part(part):
if isinstance(part, ReturnValueConcept):
return part
# @pytest.mark.parametrize("text, expected", [
# ("1", n(1)),
# ("+1", n(1)),
# ("-1", n(-1)),
# ("'foo'", s("foo")),
# ("identifier", v("identifier")),
# ("true", t()),
# ("false", f()),
# ("null", null()),
# ("1 * 2", b(TokenKind.STAR, n(1), n(2))),
# ("1 * 2/3", b(TokenKind.STAR, n(1), b(TokenKind.SLASH, n(2), n(3)))),
# ("1 + 2", b(TokenKind.PLUS, n(1), n(2))),
# ("1 + 2 - 3", b(TokenKind.PLUS, n(1), b(TokenKind.MINUS, n(2), n(3)))),
# ("1 + 2-3", b(TokenKind.PLUS, n(1), b(TokenKind.PLUS, n(2), n(-3)))),
# ("1 + 2 +-3", b(TokenKind.PLUS, n(1), b(TokenKind.PLUS, n(2), n(-3)))),
# ("1 + 2 * 3", b(TokenKind.PLUS, n(1), b(TokenKind.STAR, n(2), n(3)))),
# ("1 * 2 + 3", b(TokenKind.PLUS, b(TokenKind.STAR, n(1), n(2)), n(3))),
# ("(1 + 2) * 3", b(TokenKind.STAR, b(TokenKind.PLUS, n(1), n(2)), n(3))),
# ("1 * (2 + 3)", b(TokenKind.STAR, n(1), b(TokenKind.PLUS, n(2), n(3)))),
# ])
# def test_i_can_parse_simple_expression(text, expected):
# parser = DefaultParser(text, None)
# ast = parser.parse()
# assert ast.is_same(expected)
#
#
# @pytest.mark.parametrize("text, token_found, expected_tokens", [
# ("1+", TokenKind.EOF,
# [TokenKind.NUMBER, TokenKind.STRING, TokenKind.IDENTIFIER, 'true', 'false', 'null', TokenKind.LPAR]),
# ("(1+1", TokenKind.EOF, [TokenKind.RPAR])
# ])
# def test_i_can_detect_unexpected_end_of_code(text, token_found, expected_tokens):
# parser = DefaultParser(text, None)
# parser.parse()
#
# assert parser.has_error
# assert parser.error_sink[0].tokens[0].type == token_found
# assert parser.error_sink[0].expected_tokens == expected_tokens
@pytest.mark.parametrize("text, expected", [
("def concept hello", get_def_concept(name="hello")),
+59
View File
@@ -0,0 +1,59 @@
import pytest
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
from core.concept import Concept
from core.sheerka import Sheerka, ExecutionContext
from evaluators.EvalEvaluator import EvalEvaluator
from sdp.sheerkaDataProvider import Event
def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("test", Event(), sheerka)
def r(value, status=True):
return ReturnValueConcept("some_name", status, value)
eval_requested = ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.CONCEPT_EVAL_REQUESTED))
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"))
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")),
to_eval1,
to_eval2,
eval_requested
]
evaluator = EvalEvaluator()
assert evaluator.matches(context, return_values)
evaluated = evaluator.eval(context, return_values)
assert len(evaluated) == 2
assert evaluated[0].value == to_eval1.body.body
assert evaluated[0].parents == [to_eval1, eval_requested]
assert evaluated[1].value == to_eval2.body.body
assert evaluated[1].parents == [to_eval2, eval_requested]
@pytest.mark.parametrize("return_values, expected", [
([r(Concept("foo", body="bar")), eval_requested], True),
([r(Concept("status is false", body="bar"), False), eval_requested], False),
([r("string_value"), eval_requested], False),
([r(Concept("no body")), eval_requested], False),
([r(Concept("eval requested missing", body="bar"))], False),
])
def test_i_cannot_match_if_eval_request_is_not_present(return_values, expected):
context = get_context()
assert EvalEvaluator().matches(context, return_values) == expected
+2 -1
View File
@@ -3,6 +3,7 @@ from core.concept import Concept, Property
from core.sheerka import Sheerka, ExecutionContext
from core.tokenizer import Tokenizer
from parsers.ExactConceptParser import ExactConceptParser
from sdp.sheerkaDataProvider import Event
def test_i_can_compute_combinations():
@@ -130,7 +131,7 @@ def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("sheerka", "xxxx", sheerka)
return ExecutionContext("sheerka", Event(), sheerka)
def get_concept(name, variables):
+9 -5
View File
@@ -1,12 +1,13 @@
from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept
from core.sheerka import ExecutionContext
from sdp.sheerkaDataProvider import Event
def test_id_is_incremented_by_event_digest():
a = ExecutionContext("foo", "event_1", None)
b = ExecutionContext("foo", "event_1", None)
c = ExecutionContext("foo", "event_2", None)
a = ExecutionContext("foo", Event("event_1"), None)
b = ExecutionContext("foo", Event("event_1"), None)
c = ExecutionContext("foo", Event("event_2"), None)
d = b.push()
e = c.push()
@@ -18,17 +19,19 @@ def test_id_is_incremented_by_event_digest():
def test_some_properties_are_given_to_the_child():
a = ExecutionContext("foo", "event_1", "fake_sheerka",
a = ExecutionContext("foo", Event("event_1"), "fake_sheerka",
desc="some description",
obj=Concept("foo"),
step=BuiltinConcepts.EVALUATION,
iteration=15,
concepts={"bar": Concept("bar")})
a.preprocess = set()
a.preprocess.add("preprocess")
b = a.push()
assert b.who == a.who
assert b.event_digest == a.event_digest
assert b.event == a.event
assert b.sheerka == a.sheerka
assert b.desc == ""
assert b.obj == a.obj
@@ -37,3 +40,4 @@ def test_some_properties_are_given_to_the_child():
assert b.concepts == a.concepts
assert b.id == a.id + 1
assert b._tab == a._tab + " "
assert b.preprocess == a.preprocess
+61 -45
View File
@@ -4,12 +4,13 @@ from core.sheerka import Sheerka, ExecutionContext
from evaluators.BaseEvaluator import BaseEvaluator
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
from parsers.BaseParser import BaseParser
from sdp.sheerkaDataProvider import Event
def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("test", "xxx", sheerka)
return ExecutionContext("test", Event(), sheerka)
def test_i_can_match_and_eval():
@@ -21,7 +22,7 @@ def test_i_can_match_and_eval():
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("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
]
evaluator = MultipleSameSuccessEvaluator()
@@ -29,7 +30,7 @@ def test_i_can_match_and_eval():
evaluated = evaluator.eval(context, return_values)
assert evaluated.status
assert evaluated.value == "value"
assert evaluated.value == Concept(name="1", body="value") # the first concept is returned
def test_i_can_match_and_eval_when_no_body():
@@ -41,7 +42,7 @@ def test_i_can_match_and_eval_when_no_body():
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("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
]
evaluator = MultipleSameSuccessEvaluator()
@@ -61,7 +62,7 @@ def test_i_can_match_and_eval_when_value_is_not_a_concept():
ReturnValueConcept(BaseParser.PREFIX + "some_name2", False, "Not relevant"),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, "value"),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, "value"),
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
]
evaluator = MultipleSameSuccessEvaluator()
@@ -72,6 +73,54 @@ def test_i_can_match_and_eval_when_value_is_not_a_concept():
assert evaluated.value == "value"
def test_i_can_match_and_eval_when_at_least_one_value_is_a_concept_concept_evaluator_first():
context = get_context()
sheerka = context.sheerka
return_values = [
ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"),
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 + "other", True, "value"),
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
]
evaluator = MultipleSameSuccessEvaluator()
assert evaluator.matches(context, return_values)
evaluated = evaluator.eval(context, return_values)
assert evaluated.status
assert evaluated.value == Concept(name="1", body="value") # 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():
context = get_context()
sheerka = context.sheerka
return_values = [
ReturnValueConcept(BaseParser.PREFIX + "some_name", False, "Not relevant"),
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, "value"),
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
]
evaluator = MultipleSameSuccessEvaluator()
assert evaluator.matches(context, return_values)
evaluated = evaluator.eval(context, return_values)
assert evaluated.status
assert evaluated.value == Concept(name="1", body="value") # the concept is returned, not the value
def test_i_can_match_even_if_the_value_are_not_the_same_but_eval_will_fail():
context = get_context()
sheerka = context.sheerka
@@ -81,7 +130,7 @@ def test_i_can_match_even_if_the_value_are_not_the_same_but_eval_will_fail():
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("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
]
evaluator = MultipleSameSuccessEvaluator()
@@ -98,7 +147,7 @@ def test_i_can_match_even_if_the_value_are_not_the_same_but_eval_will_fail_when_
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("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
]
evaluator = MultipleSameSuccessEvaluator()
@@ -113,13 +162,13 @@ def test_i_can_match_if_no_parser():
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("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
]
assert MultipleSameSuccessEvaluator().matches(context, return_values)
def test_i_cannot_match_if_not_after_evaluation():
def test_i_cannot_match_if_not_reduced_requested():
context = get_context()
sheerka = context.sheerka
@@ -129,7 +178,7 @@ def test_i_cannot_match_if_not_after_evaluation():
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value")),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value")),
ReturnValueConcept("some_name", True, Concept(name="2", body="value")),
# ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
# ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
]
assert not MultipleSameSuccessEvaluator().matches(context, return_values)
@@ -145,7 +194,7 @@ def test_i_cannot_match_if_only_one_successful_evaluator():
# ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1", body="value")),
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2", body="value")),
ReturnValueConcept("some_name", True, Concept(name="2", body="value")),
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
]
assert not MultipleSameSuccessEvaluator().matches(context, return_values)
@@ -160,41 +209,8 @@ def test_i_cannot_match_if_at_least_one_parser_is_successful():
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("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.REDUCE_REQUESTED))
]
assert not MultipleSameSuccessEvaluator().matches(context, return_values)
def test_i_cannot_match_if_i_have_unlisted_return_value_in_success():
context = get_context()
sheerka = context.sheerka
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("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION)),
ReturnValueConcept("some_name", True, "not relevant"),
]
assert not MultipleSameSuccessEvaluator().matches(context, return_values)
def test_i_cannot_match_if_i_have_unlisted_return_value_in_error():
context = get_context()
sheerka = context.sheerka
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("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION)),
ReturnValueConcept("some_name", False, "not relevant"),
]
assert not MultipleSameSuccessEvaluator().matches(context, return_values)
+80
View File
@@ -0,0 +1,80 @@
import pytest
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
from core.concept import Concept
from core.sheerka import Sheerka, ExecutionContext
from evaluators.OneErrorEvaluator import OneErrorEvaluator
from sdp.sheerkaDataProvider import Event
def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("test", Event(), sheerka)
def r(value, status=True):
return ReturnValueConcept(value, status, value)
reduce_requested = ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.REDUCE_REQUESTED))
@pytest.mark.parametrize("return_values, expected", [
([r("evaluators.one error", False), reduce_requested], True),
([r("evaluators.one error", False), r("failed", False), r("failed", False), reduce_requested], True),
([r("evaluators.error", False), r("not a parser in success"), reduce_requested], True),
([r("evaluators.no reduce required", False), r("failed", False), r("failed", False)], False),
([r("evaluators.no reduce required", False)], False),
([r("evaluators.error", False), r("evaluators.success"), reduce_requested], False),
([r("evaluators.error", False), r("parsers.success"), reduce_requested], False),
([r("evaluators.success"), r("not an evaluator in error", False), reduce_requested], False),
([r("evaluators.error", False), r("evaluators.another error", False), reduce_requested], False),
])
def test_i_can_match(return_values, expected):
context = get_context()
assert OneErrorEvaluator().matches(context, return_values) == expected
def test_i_can_eval():
context = get_context()
return_values = [
r("evaluators.one error", False),
r("parsers.failed", False),
r("parsers.failed", False),
reduce_requested
]
evaluator = OneErrorEvaluator()
evaluator.matches(context, return_values)
res = evaluator.eval(context, return_values)
assert not res.status
assert res.body == "evaluators.one error"
assert len(res.parents) == 4
def test_unwanted_return_values_are_not_eaten():
context = get_context()
a_successful_concept = r("successful concept")
a_concept_in_error = r("concept in error", False)
return_values = [
r("evaluators.one error", False),
r("parsers.failed", False),
r("parsers.failed", False),
a_successful_concept,
a_concept_in_error,
reduce_requested
]
evaluator = OneErrorEvaluator()
evaluator.matches(context, return_values)
res = evaluator.eval(context, return_values)
assert not res.status
assert res.body == "evaluators.one error"
assert len(res.parents) == 4
assert a_successful_concept not in res.parents
+79
View File
@@ -0,0 +1,79 @@
import pytest
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
from core.concept import Concept
from core.sheerka import Sheerka, ExecutionContext
from evaluators.OneSuccessEvaluator import OneSuccessEvaluator
from sdp.sheerkaDataProvider import Event
def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("test", Event(), sheerka)
def r(value, status=True):
return ReturnValueConcept(value, status, value)
reduce_requested = ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.REDUCE_REQUESTED))
@pytest.mark.parametrize("return_values, expected", [
([r("evaluators.one success"), reduce_requested], True),
([r("evaluators.one success"), r("failed", False), r("failed", False), reduce_requested], True),
([r("evaluators.no reduce required"), r("failed", False), r("failed", False)], False),
([r("evaluators.no reduce required")], False),
([r("evaluators.failed", False), r("failed", False), r("failed", False), reduce_requested], False),
([r("evaluators.failed", False), r("not evaluator success"), reduce_requested], False),
([r("evaluators.success"), r("evaluators.another success"), reduce_requested], False),
([r("evaluators.one success"), r("other success"), r("failed", False), reduce_requested], True),
([r("evaluators.one success"), r("parsers.success"), reduce_requested], False),
])
def test_i_can_match(return_values, expected):
context = get_context()
assert OneSuccessEvaluator().matches(context, return_values) == expected
def test_i_can_eval():
context = get_context()
return_values = [
r("evaluators.one success"),
r("failed", False),
r("failed", False),
reduce_requested
]
evaluator = OneSuccessEvaluator()
matches = evaluator.matches(context, return_values)
res = evaluator.eval(context, return_values)
assert matches
assert res.status
assert res.body == "evaluators.one success"
assert len(res.parents) == 4
def test_i_do_not_eat_the_other_success():
context = get_context()
not_a_parser_success = r("other success")
return_values = [
r("evaluators.one success"),
not_a_parser_success,
r("failed", False),
reduce_requested
]
evaluator = OneSuccessEvaluator()
matches = evaluator.matches(context, return_values)
res = evaluator.eval(context, return_values)
assert matches
assert res.status
assert res.body == "evaluators.one success"
assert len(res.parents) == 3
assert not_a_parser_success not in res.parents
+52
View File
@@ -0,0 +1,52 @@
import pytest
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept
from core.concept import Concept
from core.sheerka import Sheerka, ExecutionContext
from evaluators.PrepareEvalEvaluator import PrepareEvalEvaluator
from sdp.sheerkaDataProvider import Event
def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("test", Event(), sheerka)
@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),
])
def test_i_can_match(ret_val, expected):
context = get_context()
assert PrepareEvalEvaluator().matches(context, 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"),
])
def test_i_can_eval(ret_val, expected):
context = get_context()
sheerka = context.sheerka
prepare_evaluator = PrepareEvalEvaluator()
prepare_evaluator.matches(context, ret_val)
res = prepare_evaluator.eval(context, ret_val)
assert len(res) == 2
assert res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.USER_INPUT)
assert res[0].body.body == expected
assert res[1].status
assert sheerka.isinstance(res[1].body, BuiltinConcepts.CONCEPT_EVAL_REQUESTED)
+63 -30
View File
@@ -5,12 +5,13 @@ from core.sheerka import Sheerka, ExecutionContext
from core.concept import Concept
from evaluators.PythonEvaluator import PythonEvaluator
from parsers.PythonParser import PythonNode, PythonParser
from sdp.sheerkaDataProvider import Event
def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("test", "xxx", sheerka)
return ExecutionContext("test", Event(), sheerka)
@pytest.mark.parametrize("ret_val, expected", [
@@ -39,30 +40,62 @@ def test_i_can_eval(text, expected):
assert evaluated.value == expected
def test_i_can_eval_expression_that_references_concepts():
@pytest.mark.parametrize("concept", [
Concept("foo"),
Concept("foo", body="2"),
Concept("foo").set_prop("prop", "'a'"),
Concept("foo", body="bar")
])
def test_i_cannot_eval_simple_concept(concept):
context = get_context()
context.sheerka.add_in_cache(Concept("foo"))
parsed = PythonParser().parse(context, "foo")
evaluated = PythonEvaluator().eval(context, parsed)
assert evaluated.status
assert evaluated.value == Concept("foo").init_key()
assert not evaluated.status
assert context.sheerka.isinstance(evaluated.value, BuiltinConcepts.NOT_FOR_ME)
def test_i_can_eval_expression_that_references_concepts_with_body():
#
# def test_i_can_eval_expression_that_references_concepts():
# context = get_context()
# context.sheerka.add_in_cache(Concept("foo"))
#
# parsed = PythonParser().parse(context, "foo")
# evaluated = PythonEvaluator().eval(context, parsed)
#
# assert evaluated.status
# assert evaluated.value == Concept("foo").init_key()
#
#
# def test_i_can_eval_expression_that_references_concepts_with_body():
# """
# I can test expression with variables
# :return:
# """
# context = get_context()
# context.sheerka.add_in_cache(Concept("foo", body="2"))
#
# parsed = PythonParser().parse(context, "foo")
# evaluated = PythonEvaluator().eval(context, parsed)
#
# assert evaluated.status
# assert evaluated.value == 2
def test_i_can_eval_expression_with_that_references_concepts():
"""
I can test expression with variables
I can test modules with variables
:return:
"""
context = get_context()
context.sheerka.add_in_cache(Concept("foo", body="2"))
context.sheerka.add_in_cache(Concept("foo", body=1))
parsed = PythonParser().parse(context, "foo")
parsed = PythonParser().parse(context, "foo + 2")
evaluated = PythonEvaluator().eval(context, parsed)
assert evaluated.status
assert evaluated.value == 2
assert evaluated.value == 3
def test_i_can_eval_module_with_that_references_concepts():
@@ -94,24 +127,24 @@ def test_i_can_eval_module_with_that_references_concepts_with_body():
assert evaluated.status
assert evaluated.value == 2
def test_i_can_eval_concept_with_props():
context = get_context()
context.sheerka.add_in_cache(Concept("foo").set_prop("prop", "'a'"))
parsed = PythonParser().parse(context, "foo")
evaluated = PythonEvaluator().eval(context, parsed)
assert evaluated.status
assert evaluated.value == Concept("foo").set_prop("prop", "a").init_key() # evaluated version of foo
def test_i_cannot_eval_when_body_references_unknown_concept():
context = get_context()
context.sheerka.add_in_cache(Concept("foo", body="bar"))
parsed = PythonParser().parse(context, "foo")
evaluated = PythonEvaluator().eval(context, parsed)
assert not evaluated.status
assert context.sheerka.isinstance(evaluated.value, BuiltinConcepts.ERROR)
#
# def test_i_can_eval_concept_with_props():
# context = get_context()
# context.sheerka.add_in_cache(Concept("foo").set_prop("prop", "'a'"))
#
# parsed = PythonParser().parse(context, "foo")
# evaluated = PythonEvaluator().eval(context, parsed)
#
# assert evaluated.status
# assert evaluated.value == Concept("foo").set_prop("prop", "a").init_key() # evaluated version of foo
#
#
# def test_i_cannot_eval_when_body_references_unknown_concept():
# context = get_context()
# context.sheerka.add_in_cache(Concept("foo", body="bar"))
#
# parsed = PythonParser().parse(context, "foo")
# evaluated = PythonEvaluator().eval(context, parsed)
#
# assert not evaluated.status
# assert context.sheerka.isinstance(evaluated.value, BuiltinConcepts.ERROR)
+2 -1
View File
@@ -6,12 +6,13 @@ from core.builtin_concepts import ParserResultConcept
from core.sheerka import Sheerka, ExecutionContext
from core.tokenizer import Tokenizer
from parsers.PythonParser import PythonNode, PythonParser, PythonErrorNode
from sdp.sheerkaDataProvider import Event
def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("test", "xxx", sheerka)
return ExecutionContext("test", Event(), sheerka)
@pytest.mark.parametrize("text, expected", [
+112
View File
@@ -0,0 +1,112 @@
import pytest
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
from core.concept import Concept
from core.sheerka import Sheerka, ExecutionContext
from evaluators.TooManySuccessEvaluator import TooManySuccessEvaluator
from sdp.sheerkaDataProvider import Event
def get_context():
sheerka = Sheerka(skip_builtins_in_db=True)
sheerka.initialize("mem://")
return ExecutionContext("test", Event(), sheerka)
def r(name, status=True, value=None):
value = value or name
return ReturnValueConcept(name, status, value)
reduce_requested = ReturnValueConcept("some_name", True, Concept(key=BuiltinConcepts.REDUCE_REQUESTED))
@pytest.mark.parametrize("return_values, expected", [
([r("evaluators.success1"), r("evaluators.success2"), reduce_requested], True),
([r("evaluators.success1"), r("evaluators.success2"), r("other"), reduce_requested], True),
([r("evaluators.success1"), r("evaluators.success2"), r("other", False), reduce_requested], True),
([r("evaluators.a", value=Concept("c1", body="1")),
r("evaluators.a", value=Concept("c2", body="1")),
r("other"),
reduce_requested], True),
([r("evaluators.a", value=Concept("c1", body="1")),
r("evaluators.a", value=Concept("c2", body="1")),
r("parsers.other", False),
reduce_requested], True),
([r("evaluators.a", value=Concept("c1", body="1")),
r("evaluators.a", value=Concept("c2", body="1")),
r("parsers.other"),
reduce_requested], False),
([r("evaluators.success1"), reduce_requested], False),
([reduce_requested], False),
([r("evaluators.success1"), r("evaluators.success2")], False),
])
def test_i_can_match(return_values, expected):
context = get_context()
assert TooManySuccessEvaluator().matches(context, return_values) == expected
def test_i_can_eval():
context = get_context()
value1 = r("evaluators.a", value=Concept("c1", body="1"))
value2 = r("evaluators.a", value=Concept("c2", body="2"))
return_values = [
value1,
value2,
r("other", False),
reduce_requested
]
evaluator = TooManySuccessEvaluator()
matches = evaluator.matches(context, return_values)
res = evaluator.eval(context, return_values)
assert matches
assert not res.status
assert context.sheerka.isinstance(res.body, BuiltinConcepts.TOO_MANY_SUCCESS)
assert res.body.body == [value1, value2]
assert len(res.parents) == 4
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("other", False),
reduce_requested
]
evaluator = TooManySuccessEvaluator()
matches = evaluator.matches(context, return_values)
res = evaluator.eval(context, return_values)
assert matches
assert res is None
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"))
other_success = r("other")
return_values = [
value1,
value2,
other_success,
reduce_requested
]
evaluator = TooManySuccessEvaluator()
matches = evaluator.matches(context, return_values)
res = evaluator.eval(context, return_values)
assert matches
assert not res.status
assert context.sheerka.isinstance(res.body, BuiltinConcepts.TOO_MANY_SUCCESS)
assert res.body.body == [value1, value2]
assert len(res.parents) == 3
assert other_success not in res.parents
+2 -1
View File
@@ -5,6 +5,7 @@ import pytest
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
from core.sheerka import Sheerka, ExecutionContext
import core.builtin_helpers
from sdp.sheerkaDataProvider import Event
def test_i_can_use_expect_one_when_empty():
@@ -160,7 +161,7 @@ def get_sheerka():
def get_context(sheerka):
return ExecutionContext("test", "xxx", sheerka)
return ExecutionContext("test", Event(), sheerka)
def dump_ast(node):
+24 -21
View File
@@ -9,7 +9,7 @@ from core.sheerka import Sheerka, ExecutionContext
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
from parsers.ConceptLexerParser import Sequence, ZeroOrMore, StrMatch, OrderedChoice, Optional, ConceptMatch, \
ConceptLexerParser
from sdp.sheerkaDataProvider import SheerkaDataProvider
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event
tests_root = path.abspath("../build/tests")
root_folder = "init_folder"
@@ -39,7 +39,7 @@ def get_sheerka(use_dict=True, skip_builtins_in_db=True):
def get_context(sheerka):
return ExecutionContext("test", "xxx", sheerka)
return ExecutionContext("test", Event(), sheerka)
def get_default_concept():
@@ -131,8 +131,8 @@ def test_i_cannot_add_the_same_concept_twice():
res = sheerka.create_new_concept(get_context(sheerka), concept)
assert not res.status
assert sheerka.isinstance(res.value, BuiltinConcepts.ERROR)
assert res.value.body.args[0] == "Duplicate object."
assert sheerka.isinstance(res.value, BuiltinConcepts.CONCEPT_ALREADY_DEFINED)
assert res.value.body == concept
def test_i_can_get_a_builtin_concept_by_their_enum_or_the_string():
@@ -317,33 +317,27 @@ def test_i_cannot_instantiate_when_properties_are_not_recognized():
assert sheerka.isinstance(new.concept, concept)
@pytest.mark.parametrize("concept, allow_non_body, expected", [
@pytest.mark.parametrize("concept, reduce_simple_list, expected", [
(None, False, None),
(3.14, False, 3.14),
("foo", False, "foo"),
(True, False, True),
(Concept("name", body="foo"), False, "foo"),
(Concept("name"), True, Concept("name")),
(ConceptWithGetValue("name").set_prop("my_prop", "my_value"), True, "my_value"),
(Concept("name"), False, Concept("name")),
(ConceptWithGetValue("name").set_prop("my_prop", "my_value"), False, "my_value"),
(ReturnValueConcept(value="return_value"), False, "return_value"),
(ReturnValueConcept(value=Concept(key=BuiltinConcepts.USER_INPUT, body="text"), status=True), False, "text"),
(ReturnValueConcept(value=UserInputConcept("text"), status=True), False, "text"),
(Concept("name", body=["foo", "bar"]), False, ["foo", "bar"]),
(Concept("name", body=["foo"]), False, "foo"),
(Concept("name", body=["foo"]), True, "foo"),
(Concept("name", body=Concept("foo")), False, Concept("foo")),
(Concept("name", body=Concept("foo", body="value")), False, "value"),
(Concept("name", body=Concept("foo", body=ReturnValueConcept(value="return_value"))), False, "return_value"),
])
def test_i_can_get_value(concept, allow_non_body, expected):
def test_i_can_get_value(concept, reduce_simple_list, expected):
sheerka = get_sheerka()
assert sheerka.value(concept, allow_non_body) == expected
def test_i_cannot_get_value_when_no_body_and_allow_none_body_is_false():
sheerka = get_sheerka()
concept = Concept("name")
allow_none_body = False
assert sheerka.value(concept, allow_none_body) == sheerka.new(BuiltinConcepts.CANNOT_RESOLVE_VALUE_ERROR,
body=concept)
assert sheerka.value(concept, reduce_simple_list) == expected
def test_list_of_concept_is_sorted_by_id():
@@ -569,6 +563,17 @@ def test_properties_values_takes_precedence_over_the_outside_world():
assert evaluated.body == 'concept_b'
def test_properties_values_takes_precedence():
sheerka = get_sheerka()
sheerka.add_in_cache(Concept(name="a", body="'concept_a'").init_key())
sheerka.add_in_cache(Concept(name="b", body="'concept_b'").init_key())
concept = Concept("foo", body="a + b").set_prop("a", "'prop_a'").init_key()
evaluated = sheerka.evaluate_concept(get_context(sheerka), concept)
assert evaluated.key == concept.key
assert evaluated.body == 'prop_aconcept_b'
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'").init_key())
@@ -666,5 +671,3 @@ def test_i_cannot_add_the_same_concept_twice_in_a_set():
all_entries = sheerka.sdp.get("All_" + all_foos.id, None, False)
assert len(all_entries) == 1
assert foo.id in all_entries
+32 -6
View File
@@ -3,6 +3,7 @@ from core.builtin_concepts import BuiltinConcepts, SuccessConcept
from core.concept import Concept
from core.sheerka import Sheerka, ExecutionContext
from evaluators.BaseEvaluator import OneReturnValueEvaluator, BaseEvaluator, AllReturnValuesEvaluator
from sdp.sheerkaDataProvider import Event
def get_sheerka():
@@ -12,7 +13,7 @@ def get_sheerka():
def get_context(sheerka):
return ExecutionContext("test", "xxx", sheerka)
return ExecutionContext("test", Event(), sheerka)
def get_ret_val(sheerka, concept, who="who"):
@@ -142,7 +143,7 @@ class EvaluatorOnePreEvaluation(OneReturnValueEvaluatorForTestingPurpose):
class EvaluatorOneMultiSteps(OneReturnValueEvaluatorForTestingPurpose):
def __init__(self):
super().__init__("multiStep", [BuiltinConcepts.BEFORE_EVALUATION, BuiltinConcepts.EVALUATION], 10)
super().__init__("multiStep", [BuiltinConcepts.EVALUATION, BuiltinConcepts.BEFORE_EVALUATION], 10)
class EvaluatorAllReduceFooBar(EvaluatorAllWithPriority):
@@ -321,10 +322,10 @@ def test_evaluation_steps_are_respected():
sheerka.evaluators = [EvaluatorOneWithPriority10, EvaluatorOnePreEvaluation]
entries = [get_ret_val(sheerka, Concept("foo"))]
BaseEvaluator.debug_out = []
Out.debug_out = []
sheerka.execute(get_context(sheerka), entries, [BuiltinConcepts.BEFORE_EVALUATION])
assert BaseEvaluator.debug_out == [
assert Out.debug_out == [
'__BEFORE_EVALUATION [0] preEval - matches - target=foo',
'__BEFORE_EVALUATION [0] preEval - eval - target=foo',
'__BEFORE_EVALUATION [0] preEval - matches - target=__BEFORE_EVALUATION',
@@ -336,10 +337,10 @@ def test_evaluation_multi_steps_are_respected():
sheerka.evaluators = [EvaluatorOneMultiSteps]
entries = [get_ret_val(sheerka, Concept("foo"))]
BaseEvaluator.debug_out = []
Out.debug_out = []
sheerka.execute(get_context(sheerka), entries, [BuiltinConcepts.BEFORE_EVALUATION, BuiltinConcepts.EVALUATION])
assert BaseEvaluator.debug_out == [
assert Out.debug_out == [
'__BEFORE_EVALUATION [0] multiStep - matches - target=foo',
'__BEFORE_EVALUATION [0] multiStep - eval - target=foo',
'__BEFORE_EVALUATION [0] multiStep - matches - target=__BEFORE_EVALUATION',
@@ -349,3 +350,28 @@ def test_evaluation_multi_steps_are_respected():
'__EVALUATION [0] multiStep - matches - target=__EVALUATION',
'__EVALUATION [0] multiStep - eval - target=__EVALUATION'
]
def test_evaluators_can_be_pre_processed():
sheerka = get_sheerka()
sheerka.evaluators = [EvaluatorOneModifyFoo]
entries = [get_ret_val(sheerka, Concept("foo"))]
# disable evaluator
context = get_context(sheerka)
context.add_preprocess(EvaluatorOneModifyFoo().name, enabled=False) # disabled for this exec context
Out.debug_out = []
sheerka.execute(context, entries, [BuiltinConcepts.EVALUATION])
assert Out.debug_out == []
# other contextes are not impacted
Out.debug_out = []
sheerka.execute(get_context(sheerka), entries, [BuiltinConcepts.EVALUATION])
assert Out.debug_out == [
'__EVALUATION [0] modifyFoo - matches - target=foo',
'__EVALUATION [0] modifyFoo - eval - target=foo',
'__EVALUATION [0] modifyFoo - matches - target=__EVALUATION',
'__EVALUATION [1] modifyFoo - matches - target=bar',
'__EVALUATION [1] modifyFoo - matches - target=__EVALUATION'
]
+9 -26
View File
@@ -9,7 +9,7 @@ from core.sheerka import Sheerka, ExecutionContext
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
from parsers.ConceptLexerParser import Sequence, ZeroOrMore, StrMatch, OrderedChoice, Optional, ConceptMatch, \
ConceptLexerParser
from sdp.sheerkaDataProvider import SheerkaDataProvider
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event
tests_root = path.abspath("../build/tests")
root_folder = "init_folder"
@@ -39,7 +39,7 @@ def get_sheerka(use_dict=True, skip_builtins_in_db=True):
def get_context(sheerka):
return ExecutionContext("test", "xxx", sheerka)
return ExecutionContext("test", Event(), sheerka)
def get_default_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 == 1
assert res[0].value == Concept(name="one", body=1).init_key() # 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 sheerka.isinstance(return_value, concept_one)
assert return_value == Concept(name="un", body=Concept(name="one").init_key()).init_key()
def test_i_can_eval_concept_with_no_body():
@@ -207,23 +207,6 @@ as:
assert sheerka.isinstance(res[0].value, BuiltinConcepts.CONCEPT_ALREADY_DEFINED)
# def test_i_can_disable_an_evaluator():
# sheerka = get_sheerka()
# concept = Concept(name="one", body="1")
# sheerka.add_in_cache(concept)
#
# text = "one"
# p = next(e for e in sheerka.evaluators if e.__name__ == "PythonEvaluator")
# p.enabled = False # not that you disable the class, not the instance
#
# res = sheerka.evaluate_user_input(text)
# assert len(res) == 1
# assert res[0].status
# assert sheerka.isinstance(res[0].value, BuiltinConcepts.PARSER_RESULT)
#
# p.enabled = True # put back for the remaining unit tests
@pytest.mark.parametrize("text", [
"",
" ",
@@ -293,9 +276,9 @@ def test_i_cannot_manage_duplicate_concepts_when_the_values_are_different():
concepts = res[0].value.body
assert len(concepts) == 2
sorted_values = sorted(concepts, key=lambda x: x.value)
assert sorted_values[0].value == "hello another value"
assert sorted_values[1].value == "hello foo"
sorted_values = sorted(concepts, key=lambda x: x.value.body)
assert sorted_values[0].value.body == "hello another value"
assert sorted_values[1].value.body == "hello foo"
def test_i_can_manage_concepts_with_the_same_key_when_values_are_the_same():
@@ -308,7 +291,7 @@ def test_i_can_manage_concepts_with_the_same_key_when_values_are_the_same():
res = sheerka.evaluate_user_input("hello 'foo'")
assert len(res) == 1
assert res[0].status
assert res[0].value == "hello foo"
assert res[0].value.body == "hello foo" # I don't know yet the one to choose
assert res[0].who == sheerka.get_evaluator_name(MultipleSameSuccessEvaluator.NAME)
@@ -321,7 +304,7 @@ def test_i_can_create_concepts_with_python_code_as_body():
assert len(res) == 1
assert res[0].status
assert isinstance(res[0].value, list)
assert isinstance(res[0].value.body, list)
def test_i_can_create_concept_with_bnf_definition():