Managing concept properties in ConceptEvaluator
This commit is contained in:
@@ -23,9 +23,13 @@ class BuiltinConcepts(Enum):
|
|||||||
INVALID_RETURN_VALUE = 14 # the return value of an evaluator is not correct
|
INVALID_RETURN_VALUE = 14 # the return value of an evaluator is not correct
|
||||||
BEFORE_PARSING = 15 # activated before evaluation by the parsers
|
BEFORE_PARSING = 15 # activated before evaluation by the parsers
|
||||||
PARSING = 16 # activated during the parsing. It contains the text to parse
|
PARSING = 16 # activated during the parsing. It contains the text to parse
|
||||||
AFTER_PARSING = 17 # activated when the parsing process seems to be finished
|
AFTER_PARSING = 17 # after parsing
|
||||||
CONCEPT_ALREADY_DEFINED = 18 # when you try to add the same concept twice
|
BEFORE_EVALUATION = 18 # before evalution
|
||||||
NOP = 19 # no operation concept. Does nothing
|
EVALUATION = 19 # activated when the parsing process seems to be finished
|
||||||
|
AFTER_EVALUATION = 20 # activated when the parsing process seems to be finished
|
||||||
|
CONCEPT_ALREADY_DEFINED = 21 # when you try to add the same concept twice
|
||||||
|
NOP = 22 # no operation concept. Does nothing
|
||||||
|
PROPERTY_EVAL_ERROR = 23
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -198,11 +202,34 @@ class BeforeParsingConcept(Concept):
|
|||||||
super().__init__(BuiltinConcepts.BEFORE_PARSING, True, True, BuiltinConcepts.BEFORE_PARSING)
|
super().__init__(BuiltinConcepts.BEFORE_PARSING, True, True, BuiltinConcepts.BEFORE_PARSING)
|
||||||
|
|
||||||
|
|
||||||
class ParsingConcept(Concept):
|
class EvaluationConcept(Concept):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(BuiltinConcepts.PARSING, True, True, BuiltinConcepts.PARSING)
|
super().__init__(BuiltinConcepts.EVALUATION, True, True, BuiltinConcepts.EVALUATION)
|
||||||
|
|
||||||
|
|
||||||
class AfterParsingConcept(Concept):
|
class AfterEvaluationConcept(Concept):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(BuiltinConcepts.AFTER_PARSING, True, True, BuiltinConcepts.AFTER_PARSING)
|
super().__init__(BuiltinConcepts.AFTER_EVALUATION, True, True, BuiltinConcepts.AFTER_EVALUATION)
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyEvalError(Concept):
|
||||||
|
def __init__(self, property_name=None, concept=None, error=None):
|
||||||
|
super().__init__(BuiltinConcepts.PROPERTY_EVAL_ERROR, True, False, BuiltinConcepts.PROPERTY_EVAL_ERROR)
|
||||||
|
self.set_prop("concept", concept)
|
||||||
|
self.set_prop("error", error)
|
||||||
|
self.body = property_name
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"PropertyEvalError(property={self.property_name}, concept={self.concept}), error={self.error})"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def concept(self):
|
||||||
|
return self.props["concept"].value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def error(self):
|
||||||
|
return self.props["error"].value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def property_name(self):
|
||||||
|
return self.body
|
||||||
|
|||||||
+1
-1
@@ -69,7 +69,7 @@ class Concept:
|
|||||||
# check the attributes
|
# check the attributes
|
||||||
for prop in self.props_to_serialize:
|
for prop in self.props_to_serialize:
|
||||||
if getattr(self, prop) != getattr(other, prop):
|
if getattr(self, prop) != getattr(other, prop):
|
||||||
print(prop)
|
# print(prop) # use full to know which id does not match
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# check the props (Concept variables)
|
# check the props (Concept variables)
|
||||||
|
|||||||
+59
-22
@@ -150,19 +150,24 @@ class Sheerka(Concept):
|
|||||||
evt_digest = self.sdp.save_event(Event(text))
|
evt_digest = self.sdp.save_event(Event(text))
|
||||||
exec_context = ExecutionContext(self.key, evt_digest, self)
|
exec_context = ExecutionContext(self.key, evt_digest, self)
|
||||||
|
|
||||||
before_parsing = self.ret(self.eval.__name__, True, self.new(BuiltinConcepts.BEFORE_PARSING))
|
# Before parsing
|
||||||
|
before_parsing = self.new(BuiltinConcepts.BEFORE_PARSING)
|
||||||
return_values = self.process(exec_context, [], [before_parsing])
|
return_values = self.process(exec_context, [], [before_parsing])
|
||||||
return_values = core.utils.remove_from_list(return_values, [before_parsing])
|
return_values = core.utils.remove_from_list(return_values, lambda x: x.value == before_parsing)
|
||||||
|
|
||||||
|
# parse
|
||||||
parsing_results = self.parse(exec_context, text)
|
parsing_results = self.parse(exec_context, text)
|
||||||
return_values.extend(parsing_results)
|
return_values.extend(parsing_results)
|
||||||
processing_parsing = self.ret(self.eval.__name__, True, self.new(BuiltinConcepts.PARSING))
|
|
||||||
return_values = self.process(exec_context, return_values, [processing_parsing])
|
|
||||||
return_values = core.utils.remove_from_list(return_values, [processing_parsing])
|
|
||||||
|
|
||||||
after_parsing = self.ret(self.eval.__name__, True, self.new(BuiltinConcepts.AFTER_PARSING))
|
# evaluate
|
||||||
return_values = self.process(exec_context, return_values, [after_parsing])
|
evaluating = self.new(BuiltinConcepts.EVALUATION)
|
||||||
return_values = core.utils.remove_from_list(return_values, [after_parsing])
|
return_values = self.process(exec_context, return_values, [evaluating])
|
||||||
|
return_values = core.utils.remove_from_list(return_values, lambda x: x.value == evaluating)
|
||||||
|
|
||||||
|
# post evaluation
|
||||||
|
after_evaluation = self.new(BuiltinConcepts.AFTER_EVALUATION)
|
||||||
|
return_values = self.process(exec_context, return_values, [after_evaluation])
|
||||||
|
return_values = core.utils.remove_from_list(return_values, lambda x: x.value == after_evaluation)
|
||||||
|
|
||||||
return return_values
|
return return_values
|
||||||
|
|
||||||
@@ -207,17 +212,17 @@ class Sheerka(Concept):
|
|||||||
result.append(res)
|
result.append(res)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def process(self, context, return_values, contextual_concepts=None):
|
def process(self, context, return_values, initial_concepts=None):
|
||||||
contextual_concepts_values = [c.value for c in contextual_concepts] if contextual_concepts else []
|
log.debug(f"Processing parsing result. context concept={initial_concepts}")
|
||||||
log.debug(f"Processing parsing result. context concept={contextual_concepts_values}")
|
|
||||||
|
|
||||||
# return_values must be a list
|
# return_values must be a list
|
||||||
if not isinstance(return_values, list):
|
if not isinstance(return_values, list):
|
||||||
return_values = [return_values]
|
return_values = [return_values]
|
||||||
|
|
||||||
# adds contextual concepts
|
# adds contextual concepts
|
||||||
if contextual_concepts:
|
if initial_concepts:
|
||||||
return_values.extend(contextual_concepts)
|
for concept in initial_concepts:
|
||||||
|
return_values.append(self.ret(context.who, True, concept))
|
||||||
|
|
||||||
# group the evaluators by priority and sort them
|
# group the evaluators by priority and sort them
|
||||||
# The first one to be applied will be the one with the highest priority
|
# The first one to be applied will be the one with the highest priority
|
||||||
@@ -261,6 +266,8 @@ class Sheerka(Concept):
|
|||||||
else:
|
else:
|
||||||
if evaluator.matches(context, original_items):
|
if evaluator.matches(context, original_items):
|
||||||
results = evaluator.eval(context, original_items)
|
results = evaluator.eval(context, original_items)
|
||||||
|
if results is None:
|
||||||
|
continue
|
||||||
if not isinstance(results, list):
|
if not isinstance(results, list):
|
||||||
results = [results]
|
results = [results]
|
||||||
for result in results:
|
for result in results:
|
||||||
@@ -277,6 +284,24 @@ class Sheerka(Concept):
|
|||||||
|
|
||||||
return return_values
|
return return_values
|
||||||
|
|
||||||
|
def chain_process(self, context, return_values, initial_concepts):
|
||||||
|
"""
|
||||||
|
Executes process for all initial contexts
|
||||||
|
:param context:
|
||||||
|
:param return_values:
|
||||||
|
:param initial_concepts:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
for concept in initial_concepts:
|
||||||
|
if isinstance(concept, BuiltinConcepts):
|
||||||
|
concept = self.new(BuiltinConcepts)
|
||||||
|
|
||||||
|
init = [self.ret(context.who, True, concept)]
|
||||||
|
return_values = self.process(context, return_values, [init])
|
||||||
|
return_values = core.utils.remove_from_list(return_values, lambda x: x.value == init)
|
||||||
|
|
||||||
|
return return_values
|
||||||
|
|
||||||
def create_new_concept(self, context, concept):
|
def create_new_concept(self, context, concept):
|
||||||
"""
|
"""
|
||||||
Adds a new concept to the system
|
Adds a new concept to the system
|
||||||
@@ -319,13 +344,14 @@ class Sheerka(Concept):
|
|||||||
for part_key in ConceptParts:
|
for part_key in ConceptParts:
|
||||||
source = getattr(concept, part_key.value)
|
source = getattr(concept, part_key.value)
|
||||||
if source is None or not isinstance(source, str) or source == "":
|
if source is None or not isinstance(source, str) or source == "":
|
||||||
|
|
||||||
# the only sources that I am sure to parse are strings
|
# the only sources that I am sure to parse are strings
|
||||||
# I refuse empty strings for performance, I don't want to handle useless NOPConcepts
|
# I refuse empty strings for performance, I don't want to handle useless NOPConcepts
|
||||||
continue
|
continue
|
||||||
|
else:
|
||||||
|
concept.codes[part_key] = self.parse(context, source)
|
||||||
|
|
||||||
ret_val = self.expect_one(context, self.parse(context, source))
|
for prop in concept.props:
|
||||||
concept.codes[part_key] = ret_val
|
concept.codes[prop] = self.parse(context, concept.props[prop].value)
|
||||||
|
|
||||||
def add_in_cache(self, concept):
|
def add_in_cache(self, concept):
|
||||||
"""
|
"""
|
||||||
@@ -334,7 +360,16 @@ class Sheerka(Concept):
|
|||||||
:param concept:
|
:param concept:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# sanity check
|
||||||
|
if concept.key is None:
|
||||||
|
concept.init_key()
|
||||||
|
|
||||||
|
if concept.key is None:
|
||||||
|
raise KeyError()
|
||||||
|
|
||||||
self.concepts_cache[concept.key] = concept
|
self.concepts_cache[concept.key] = concept
|
||||||
|
return concept
|
||||||
|
|
||||||
def get(self, concept_key):
|
def get(self, concept_key):
|
||||||
"""
|
"""
|
||||||
@@ -455,7 +490,7 @@ class Sheerka(Concept):
|
|||||||
base_class = core.utils.get_class("parsers.BaseParser.BaseParser")
|
base_class = core.utils.get_class("parsers.BaseParser.BaseParser")
|
||||||
|
|
||||||
for c in core.utils.get_classes_recursive("parsers"):
|
for c in core.utils.get_classes_recursive("parsers"):
|
||||||
#if issubclass(c, base_class) and c != base_class:
|
# if issubclass(c, base_class) and c != base_class:
|
||||||
res.append(c)
|
res.append(c)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
@@ -470,9 +505,11 @@ class ExecutionContext:
|
|||||||
"""
|
"""
|
||||||
To keep track of the execution of a request
|
To keep track of the execution of a request
|
||||||
"""
|
"""
|
||||||
who: object
|
who: object # who is asking
|
||||||
event_digest: str
|
event_digest: str # what was the (original) trigger
|
||||||
sheerka: Sheerka
|
sheerka: Sheerka # sheerka
|
||||||
|
desc: str = None # human description of what is going on
|
||||||
|
obj: Concept = None # what is the subject of the execution context (if known)
|
||||||
|
|
||||||
def push(self, who):
|
def push(self, who, desc=None, obj=None):
|
||||||
return ExecutionContext(who, self.event_digest, self.sheerka)
|
return ExecutionContext(who, self.event_digest, self.sheerka, desc=desc, obj=obj)
|
||||||
|
|||||||
+7
-3
@@ -106,7 +106,6 @@ def get_classes_from_package(package_name):
|
|||||||
|
|
||||||
|
|
||||||
def get_sub_classes(package_name, base_class_name):
|
def get_sub_classes(package_name, base_class_name):
|
||||||
|
|
||||||
pkg = __import__(package_name)
|
pkg = __import__(package_name)
|
||||||
prefix = pkg.__name__ + "."
|
prefix = pkg.__name__ + "."
|
||||||
for (module_loader, name, ispkg) in pkgutil.iter_modules(pkg.__path__, prefix):
|
for (module_loader, name, ispkg) in pkgutil.iter_modules(pkg.__path__, prefix):
|
||||||
@@ -123,8 +122,13 @@ def remove_from_list(lst, to_remove):
|
|||||||
:param to_remove:
|
:param to_remove:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
for item in to_remove:
|
|
||||||
if item in lst:
|
flagged = []
|
||||||
|
for item in lst:
|
||||||
|
if to_remove(item):
|
||||||
|
flagged.append(item)
|
||||||
|
|
||||||
|
for item in flagged:
|
||||||
lst.remove(item)
|
lst.remove(item)
|
||||||
|
|
||||||
return lst
|
return lst
|
||||||
|
|||||||
@@ -397,3 +397,76 @@ I have plenty of ideas that I would like to express, sometimes just to put the i
|
|||||||
but I lack of time. It would be great if I can find a tool that will allow me to just to
|
but I lack of time. It would be great if I can find a tool that will allow me to just to
|
||||||
dictate my words. I know that there are plenty out there, I need to spend some time to test
|
dictate my words. I know that there are plenty out there, I need to spend some time to test
|
||||||
them and choose one.
|
them and choose one.
|
||||||
|
|
||||||
|
2019-11-15
|
||||||
|
**********
|
||||||
|
|
||||||
|
Managing concepts resolutions
|
||||||
|
"""""""""""""""""""""""""""""
|
||||||
|
I am a little stuck on the algorithm I must use to derive (resolve) concepts. This is
|
||||||
|
one of this day I strongly regret to have someone I can discuss with :-(
|
||||||
|
|
||||||
|
Let's write the problem down, sometimes, it helps figure out the best approach.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
def concept one as 1
|
||||||
|
one
|
||||||
|
|
||||||
|
The concept is first define (it returns the number 1), and then it's called.
|
||||||
|
During the call
|
||||||
|
|
||||||
|
1. During parsing,
|
||||||
|
Both Python parser and concept parser will recognize 'one'
|
||||||
|
2. During Evaluation,
|
||||||
|
* Python Evaluator will fail (one is not know by python)
|
||||||
|
* Concept Evaluator will success. My question is what should it return ?
|
||||||
|
|
||||||
|
The two option are:
|
||||||
|
1. Python node, to let the Python Evaluator work and return one, in the next row
|
||||||
|
2. Returns '1' directly
|
||||||
|
|
||||||
|
I as write it down, it is obvious that it must return 1, since the purpose of any
|
||||||
|
evaluation is to give a result, not the path to find the result.
|
||||||
|
|
||||||
|
Plus, if don"t resolve the body in the Concept Evaluator, I will loose where the
|
||||||
|
'1' comes from.
|
||||||
|
|
||||||
|
I don't know if I was clear. I don't even know if I will be able to re-read myself.
|
||||||
|
But I think that I have my solution.
|
||||||
|
|
||||||
|
|
||||||
|
2019-11-16
|
||||||
|
**********
|
||||||
|
|
||||||
|
ExactConceptParser limitation
|
||||||
|
"""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
From the beginning, my simplest example is to show that addition can be simply
|
||||||
|
explained to Sheerka
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
def concept a plus b as a + b
|
||||||
|
def concept one as 1
|
||||||
|
def concept two as 2
|
||||||
|
one plus two
|
||||||
|
|
||||||
|
The :code:`one plus two` is perfectly recognized, and the result is 3.
|
||||||
|
:code:`two plus one` also work (with the correct response).
|
||||||
|
|
||||||
|
But I was quite surprised to see that :code:`one plus one` was not recognized !!
|
||||||
|
|
||||||
|
Indeed, the **ExactConceptParser** looks for :code:`__var0__ plus __var1__`. So
|
||||||
|
the first operand and the second have to be different.
|
||||||
|
|
||||||
|
It's unexpected :-(
|
||||||
|
|
||||||
|
Do I need to enhance the parser to recognize it, or no I need to build another parser ?
|
||||||
|
|
||||||
|
If I tell the parser that :code:`a plus b`, how do I handle the cases where 'a 'and 'b'
|
||||||
|
MUST be different ? How I handle when the explicitly have to be the same ?
|
||||||
|
|
||||||
|
I seems that the purpose of the **ExactConceptParser** is to find exact match.
|
||||||
|
I need another way to express that 'a' and 'b' can be the same.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from core.builtin_concepts import ParserResultConcept
|
from core.builtin_concepts import ParserResultConcept, BuiltinConcepts
|
||||||
from core.concept import Concept, ConceptParts
|
from core.concept import Concept, ConceptParts
|
||||||
from evaluators.BaseEvaluator import OneReturnValueEvaluator
|
from evaluators.BaseEvaluator import OneReturnValueEvaluator
|
||||||
import logging
|
import logging
|
||||||
@@ -9,6 +9,8 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class ConceptEvaluator(OneReturnValueEvaluator):
|
class ConceptEvaluator(OneReturnValueEvaluator):
|
||||||
|
evaluation_steps = [BuiltinConcepts.EVALUATION, BuiltinConcepts.AFTER_EVALUATION]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__("Concept Evaluator", 50)
|
super().__init__("Concept Evaluator", 50)
|
||||||
|
|
||||||
@@ -31,12 +33,32 @@ class ConceptEvaluator(OneReturnValueEvaluator):
|
|||||||
# TODO; check pre
|
# TODO; check pre
|
||||||
# if pre is not true, return Concept with a false value
|
# if pre is not true, return Concept with a false value
|
||||||
|
|
||||||
if ConceptParts.BODY in concept.codes:
|
# Evaluate the properties
|
||||||
|
for prop in concept.props:
|
||||||
|
sub_context = context.push(self.name, f"Evaluating property '{prop}'", concept)
|
||||||
|
res = self.evaluate_parsing(sheerka, sub_context, concept.codes[prop])
|
||||||
|
if res.status:
|
||||||
|
concept.set_prop(prop, res.value)
|
||||||
|
else:
|
||||||
|
return sheerka.ret(
|
||||||
|
self.name,
|
||||||
|
False,
|
||||||
|
sheerka.new(BuiltinConcepts.PROPERTY_EVAL_ERROR, body=prop, concept=concept, error=res.value),
|
||||||
|
parents=[return_value])
|
||||||
|
|
||||||
|
# Evaluate body
|
||||||
|
if ConceptParts.BODY not in concept.codes:
|
||||||
|
return sheerka.ret(self.name, True, concept, parents=[return_value])
|
||||||
|
|
||||||
body = concept.codes[ConceptParts.BODY]
|
body = concept.codes[ConceptParts.BODY]
|
||||||
if body is None:
|
if body is None:
|
||||||
return None # nothing to do
|
return None # seems weird
|
||||||
|
|
||||||
return sheerka.ret(self.name, True, body.value, parents=[return_value])
|
sub_context = context.push(self.name, "Evaluating body", concept)
|
||||||
|
res = self.evaluate_parsing(sheerka, sub_context, body)
|
||||||
|
return sheerka.ret(self.name, res.status, res.value, parents=[return_value])
|
||||||
|
|
||||||
else:
|
def evaluate_parsing(self, sheerka, context, parsing_result):
|
||||||
return sheerka.ret(self.name, True, concept, parents=[return_value])
|
res = sheerka.chain_process(context, parsing_result, self.evaluation_steps)
|
||||||
|
res = sheerka.expect_one(context, res)
|
||||||
|
return res
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class DuplicateConceptEvaluator(AllReturnValuesEvaluator):
|
|||||||
only_parsers = True
|
only_parsers = True
|
||||||
|
|
||||||
for ret in return_values:
|
for ret in return_values:
|
||||||
if sheerka.isinstance(ret.value, BuiltinConcepts.PARSING):
|
if sheerka.isinstance(ret.value, BuiltinConcepts.AFTER_EVALUATION):
|
||||||
if ret.status:
|
if ret.status:
|
||||||
parsing = True
|
parsing = True
|
||||||
elif ret.who == "Evaluators:Add new Concept":
|
elif ret.who == "Evaluators:Add new Concept":
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
from core.builtin_concepts import BuiltinConcepts
|
||||||
|
from core.concept import Concept
|
||||||
|
from evaluators.BaseEvaluator import AllReturnValuesEvaluator, BaseEvaluator
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from parsers.BaseParser import BaseParser
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class MultipleSameSuccessEvaluator(AllReturnValuesEvaluator):
|
||||||
|
"""
|
||||||
|
Used to filter the responses
|
||||||
|
It has a low priority to let other evaluators try to resolve the errors
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("Parsers Evaluator", 10)
|
||||||
|
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
|
||||||
|
|
||||||
|
for ret in return_values:
|
||||||
|
|
||||||
|
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.value)
|
||||||
|
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
|
||||||
|
|
||||||
|
def eval(self, context, return_values):
|
||||||
|
reference = self.get_value(self.success[0])
|
||||||
|
|
||||||
|
for return_value in self.success[1:]:
|
||||||
|
actual = self.get_value(return_value)
|
||||||
|
if actual != reference:
|
||||||
|
return None
|
||||||
|
|
||||||
|
sheerka = context.sheerka
|
||||||
|
return sheerka.ret(self.name, True, reference, parents=return_values)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_value(obj):
|
||||||
|
if not isinstance(obj, Concept):
|
||||||
|
return obj
|
||||||
|
|
||||||
|
return obj if obj.body is None else obj.body
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
from core.builtin_concepts import BuiltinConcepts
|
from core.builtin_concepts import BuiltinConcepts
|
||||||
from core.concept import Concept
|
|
||||||
from evaluators.BaseEvaluator import AllReturnValuesEvaluator
|
from evaluators.BaseEvaluator import AllReturnValuesEvaluator
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@@ -8,7 +7,7 @@ from parsers.BaseParser import BaseParser
|
|||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ParsersEvaluator(AllReturnValuesEvaluator):
|
class OneSuccessEvaluator(AllReturnValuesEvaluator):
|
||||||
"""
|
"""
|
||||||
Used to filter the responses
|
Used to filter the responses
|
||||||
It has a low priority to let other evaluators try to resolve the errors
|
It has a low priority to let other evaluators try to resolve the errors
|
||||||
@@ -20,13 +19,13 @@ class ParsersEvaluator(AllReturnValuesEvaluator):
|
|||||||
|
|
||||||
def matches(self, context, return_values):
|
def matches(self, context, return_values):
|
||||||
sheerka = context.sheerka
|
sheerka = context.sheerka
|
||||||
after_parsing = False
|
after_evaluation = False
|
||||||
nb_successful_evaluators = 0
|
nb_successful_evaluators = 0
|
||||||
only_parsers = True
|
only_parsers = True
|
||||||
for ret in return_values:
|
for ret in return_values:
|
||||||
if sheerka.isinstance(ret.value, BuiltinConcepts.AFTER_PARSING):
|
if sheerka.isinstance(ret.value, BuiltinConcepts.AFTER_EVALUATION):
|
||||||
if ret.status:
|
if ret.status:
|
||||||
after_parsing = True
|
after_evaluation = True
|
||||||
elif ret.who.startswith(self.PREFIX):
|
elif ret.who.startswith(self.PREFIX):
|
||||||
if ret.status:
|
if ret.status:
|
||||||
nb_successful_evaluators += 1
|
nb_successful_evaluators += 1
|
||||||
@@ -35,7 +34,7 @@ class ParsersEvaluator(AllReturnValuesEvaluator):
|
|||||||
if not ret.who.startswith(BaseParser.PREFIX):
|
if not ret.who.startswith(BaseParser.PREFIX):
|
||||||
only_parsers = False
|
only_parsers = False
|
||||||
|
|
||||||
return after_parsing and nb_successful_evaluators == 1 and only_parsers
|
return after_evaluation and nb_successful_evaluators == 1 and only_parsers
|
||||||
|
|
||||||
def eval(self, context, return_values):
|
def eval(self, context, return_values):
|
||||||
sheerka = context.sheerka
|
sheerka = context.sheerka
|
||||||
@@ -23,10 +23,18 @@ class PythonEvaluator(OneReturnValueEvaluator):
|
|||||||
try:
|
try:
|
||||||
log.debug(f"Evaluating python node {node}")
|
log.debug(f"Evaluating python node {node}")
|
||||||
compiled = compile(node.ast_, "<string>", "eval")
|
compiled = compile(node.ast_, "<string>", "eval")
|
||||||
evaluated = eval(compiled, {}, {"sheerka": context.sheerka})
|
evaluated = eval(compiled, {}, self.get_locals(context))
|
||||||
return sheerka.ret(self.name, True, evaluated, parents=[return_value])
|
return sheerka.ret(self.name, True, evaluated, parents=[return_value])
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
error = sheerka.new(BuiltinConcepts.ERROR, body=error)
|
error = sheerka.new(BuiltinConcepts.ERROR, body=error)
|
||||||
return sheerka.ret(self.name, False, error, parents=[return_value])
|
return sheerka.ret(self.name, False, error, parents=[return_value])
|
||||||
else:
|
else:
|
||||||
return sheerka.ret(self.name, False, sheerka.new(BuiltinConcepts.ERROR), parents=[return_value])
|
return sheerka.ret(self.name, False, sheerka.new(BuiltinConcepts.ERROR), parents=[return_value])
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_locals(context):
|
||||||
|
my_locals = {"sheerka": context.sheerka}
|
||||||
|
if context.obj:
|
||||||
|
for prop_name, prop_value in context.obj.props.items():
|
||||||
|
my_locals[prop_name] = prop_value.value
|
||||||
|
return my_locals
|
||||||
|
|||||||
@@ -0,0 +1,217 @@
|
|||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
|
||||||
|
from core.concept import Concept
|
||||||
|
from core.sheerka import Sheerka, ExecutionContext
|
||||||
|
from evaluators.ConceptEvaluator import ConceptEvaluator
|
||||||
|
from parsers.BaseParser import BaseParser
|
||||||
|
|
||||||
|
tests_root = path.abspath("../build/tests")
|
||||||
|
root_folder = "init_folder"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def init_test():
|
||||||
|
if path.exists(tests_root):
|
||||||
|
shutil.rmtree(tests_root)
|
||||||
|
|
||||||
|
if not path.exists(tests_root):
|
||||||
|
os.makedirs(tests_root)
|
||||||
|
current_pwd = os.getcwd()
|
||||||
|
os.chdir(tests_root)
|
||||||
|
|
||||||
|
yield None
|
||||||
|
os.chdir(current_pwd)
|
||||||
|
|
||||||
|
|
||||||
|
def get_context():
|
||||||
|
sheerka = Sheerka()
|
||||||
|
sheerka.initialize(root_folder)
|
||||||
|
return ExecutionContext("test", "xxx", sheerka)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("ret_val, expected", [
|
||||||
|
(ReturnValueConcept(BaseParser.PREFIX + "some_name", True, Concept()), True),
|
||||||
|
(ReturnValueConcept(BaseParser.PREFIX + "some_name", False, Concept()), False),
|
||||||
|
(ReturnValueConcept("Not a parser", True, Concept()), False),
|
||||||
|
(ReturnValueConcept(BaseParser.PREFIX + "some_name", True, "not a concept"), False),
|
||||||
|
(ReturnValueConcept(BaseParser.PREFIX + "some_name", True, ParserResultConcept()), False),
|
||||||
|
])
|
||||||
|
def test_i_can_match(ret_val, expected):
|
||||||
|
context = get_context()
|
||||||
|
assert ConceptEvaluator().matches(context, ret_val) == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_concept_is_returned_when_no_body():
|
||||||
|
context = get_context()
|
||||||
|
concept = Concept(name="one").init_key()
|
||||||
|
|
||||||
|
evaluator = ConceptEvaluator()
|
||||||
|
item = ReturnValueConcept(BaseParser.PREFIX + "some_name", True, concept)
|
||||||
|
result = evaluator.eval(context, item)
|
||||||
|
|
||||||
|
assert result.who == evaluator.name
|
||||||
|
assert result.status
|
||||||
|
assert result.value == concept
|
||||||
|
assert result.parents == [item]
|
||||||
|
|
||||||
|
|
||||||
|
def test_body_is_evaluated_when_python_body():
|
||||||
|
context = get_context()
|
||||||
|
concept = Concept(name="one", body="1").init_key()
|
||||||
|
|
||||||
|
evaluator = ConceptEvaluator()
|
||||||
|
item = ReturnValueConcept(BaseParser.PREFIX + "some_name", True, concept)
|
||||||
|
result = evaluator.eval(context, item)
|
||||||
|
|
||||||
|
assert result.who == evaluator.name
|
||||||
|
assert result.status
|
||||||
|
assert result.value == 1
|
||||||
|
assert result.parents == [item]
|
||||||
|
|
||||||
|
|
||||||
|
def test_body_is_evaluated_when_concept_body():
|
||||||
|
context = get_context()
|
||||||
|
concept_one = Concept(name="one").init_key()
|
||||||
|
context.sheerka.add_in_cache(concept_one)
|
||||||
|
concept_un = Concept(name="un", body="one").init_key()
|
||||||
|
|
||||||
|
evaluator = ConceptEvaluator()
|
||||||
|
item = ReturnValueConcept(BaseParser.PREFIX + "some_name", True, concept_un)
|
||||||
|
result = evaluator.eval(context, item)
|
||||||
|
|
||||||
|
assert result.who == evaluator.name
|
||||||
|
assert result.status
|
||||||
|
assert result.value == concept_one
|
||||||
|
assert result.parents == [item]
|
||||||
|
|
||||||
|
|
||||||
|
def test_body_is_evaluated_when_concept_body_with_a_body():
|
||||||
|
context = get_context()
|
||||||
|
concept_one = Concept(name="one", body="1").init_key()
|
||||||
|
context.sheerka.add_in_cache(concept_one)
|
||||||
|
concept_un = Concept(name="un", body="one").init_key()
|
||||||
|
|
||||||
|
evaluator = ConceptEvaluator()
|
||||||
|
item = ReturnValueConcept(BaseParser.PREFIX + "some_name", True, concept_un)
|
||||||
|
result = evaluator.eval(context, item)
|
||||||
|
|
||||||
|
assert result.who == evaluator.name
|
||||||
|
assert result.status
|
||||||
|
assert result.value == 1
|
||||||
|
assert result.parents == [item]
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_evaluate_longer_chains():
|
||||||
|
context = get_context()
|
||||||
|
context.sheerka.add_in_cache(Concept(name="a", body="'a'").init_key())
|
||||||
|
context.sheerka.add_in_cache(Concept(name="b", body="a").init_key())
|
||||||
|
context.sheerka.add_in_cache(Concept(name="c", body="b").init_key())
|
||||||
|
concept_d = context.sheerka.add_in_cache(Concept(name="d", body="c").init_key())
|
||||||
|
|
||||||
|
evaluator = ConceptEvaluator()
|
||||||
|
item = ReturnValueConcept(BaseParser.PREFIX + "some_name", True, concept_d)
|
||||||
|
result = evaluator.eval(context, item)
|
||||||
|
|
||||||
|
assert result.status
|
||||||
|
assert result.value == 'a'
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_evaluate_longer_chains_2():
|
||||||
|
context = get_context()
|
||||||
|
concept_a = context.sheerka.add_in_cache(Concept(name="a").init_key())
|
||||||
|
context.sheerka.add_in_cache(Concept(name="b", body="a").init_key())
|
||||||
|
context.sheerka.add_in_cache(Concept(name="c", body="b").init_key())
|
||||||
|
concept_d = context.sheerka.add_in_cache(Concept(name="d", body="c").init_key())
|
||||||
|
|
||||||
|
evaluator = ConceptEvaluator()
|
||||||
|
item = ReturnValueConcept(BaseParser.PREFIX + "some_name", True, concept_d)
|
||||||
|
result = evaluator.eval(context, item)
|
||||||
|
|
||||||
|
assert result.status
|
||||||
|
assert result.value == concept_a
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_recognize_concept_properties():
|
||||||
|
"""
|
||||||
|
The concept 'plus' has some properties.
|
||||||
|
Let's check if they are recognized as concepts
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
context = get_context()
|
||||||
|
concept_one = context.sheerka.add_in_cache(Concept(name="one").init_key())
|
||||||
|
concept_two = context.sheerka.add_in_cache(Concept(name="two").init_key())
|
||||||
|
concept_plus = context.sheerka.add_in_cache(Concept(name="a plus b")
|
||||||
|
.set_prop("a", "one")
|
||||||
|
.set_prop("b", "two").init_key())
|
||||||
|
|
||||||
|
evaluator = ConceptEvaluator()
|
||||||
|
item = ReturnValueConcept(BaseParser.PREFIX + "some_name", True, concept_plus)
|
||||||
|
result = evaluator.eval(context, item)
|
||||||
|
|
||||||
|
assert result.status
|
||||||
|
assert context.sheerka.isinstance(result.value, concept_plus)
|
||||||
|
assert result.value.props["a"].value == concept_one
|
||||||
|
assert result.value.props["b"].value == concept_two
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_recognize_concept_properties_with_body():
|
||||||
|
"""
|
||||||
|
The concept 'plus' has some properties.
|
||||||
|
Let's check if they are recognized as concepts with Python code
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
context = get_context()
|
||||||
|
context.sheerka.add_in_cache(Concept(name="one", body="1").init_key())
|
||||||
|
context.sheerka.add_in_cache(Concept(name="two", body="2").init_key())
|
||||||
|
concept_plus = context.sheerka.add_in_cache(Concept(name="a plus b")
|
||||||
|
.set_prop("a", "one")
|
||||||
|
.set_prop("b", "two").init_key())
|
||||||
|
|
||||||
|
evaluator = ConceptEvaluator()
|
||||||
|
item = ReturnValueConcept(BaseParser.PREFIX + "some_name", True, concept_plus)
|
||||||
|
result = evaluator.eval(context, item)
|
||||||
|
|
||||||
|
assert result.status
|
||||||
|
assert context.sheerka.isinstance(result.value, concept_plus)
|
||||||
|
assert result.value.props["a"].value == 1
|
||||||
|
assert result.value.props["b"].value == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_recognize_concept_properties_with_body_when_concept_has_a_body():
|
||||||
|
context = get_context()
|
||||||
|
context.sheerka.add_in_cache(Concept(name="one", body="1").init_key())
|
||||||
|
context.sheerka.add_in_cache(Concept(name="two", body="2").init_key())
|
||||||
|
concept_plus = context.sheerka.add_in_cache(Concept(name="a plus b", body="a + b")
|
||||||
|
.set_prop("a", "one")
|
||||||
|
.set_prop("b", "two").init_key())
|
||||||
|
|
||||||
|
evaluator = ConceptEvaluator()
|
||||||
|
item = ReturnValueConcept(BaseParser.PREFIX + "some_name", True, concept_plus)
|
||||||
|
result = evaluator.eval(context, item)
|
||||||
|
|
||||||
|
assert result.status
|
||||||
|
assert result.value == 3
|
||||||
|
|
||||||
|
|
||||||
|
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())
|
||||||
|
|
||||||
|
evaluator = ConceptEvaluator()
|
||||||
|
item = ReturnValueConcept(BaseParser.PREFIX + "some_name", True, concept_plus)
|
||||||
|
result = evaluator.eval(context, item)
|
||||||
|
|
||||||
|
assert not result.status
|
||||||
|
assert context.sheerka.isinstance(result.value, BuiltinConcepts.PROPERTY_EVAL_ERROR)
|
||||||
|
assert result.value.property_name == "b"
|
||||||
|
assert context.sheerka.isinstance(result.value.error, BuiltinConcepts.TOO_MANY_ERRORS)
|
||||||
|
assert result.value.concept == concept_plus
|
||||||
|
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
|
||||||
|
from core.concept import Concept
|
||||||
|
from core.sheerka import Sheerka, ExecutionContext
|
||||||
|
from evaluators.BaseEvaluator import BaseEvaluator
|
||||||
|
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
|
||||||
|
from parsers.BaseParser import BaseParser
|
||||||
|
|
||||||
|
tests_root = path.abspath("../build/tests")
|
||||||
|
root_folder = "init_folder"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def init_test():
|
||||||
|
if path.exists(tests_root):
|
||||||
|
shutil.rmtree(tests_root)
|
||||||
|
|
||||||
|
if not path.exists(tests_root):
|
||||||
|
os.makedirs(tests_root)
|
||||||
|
current_pwd = os.getcwd()
|
||||||
|
os.chdir(tests_root)
|
||||||
|
|
||||||
|
yield None
|
||||||
|
os.chdir(current_pwd)
|
||||||
|
|
||||||
|
|
||||||
|
def get_context():
|
||||||
|
sheerka = Sheerka()
|
||||||
|
sheerka.initialize(root_folder)
|
||||||
|
return ExecutionContext("test", "xxx", sheerka)
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_match_and_eval():
|
||||||
|
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))
|
||||||
|
]
|
||||||
|
|
||||||
|
evaluator = MultipleSameSuccessEvaluator()
|
||||||
|
assert evaluator.matches(context, return_values)
|
||||||
|
|
||||||
|
evaluated = evaluator.eval(context, return_values)
|
||||||
|
assert evaluated.status
|
||||||
|
assert evaluated.value == "value"
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_match_and_eval_when_no_body():
|
||||||
|
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")),
|
||||||
|
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="1")),
|
||||||
|
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
|
||||||
|
]
|
||||||
|
|
||||||
|
evaluator = MultipleSameSuccessEvaluator()
|
||||||
|
assert evaluator.matches(context, return_values)
|
||||||
|
|
||||||
|
evaluated = evaluator.eval(context, return_values)
|
||||||
|
assert evaluated.status
|
||||||
|
assert evaluated.value == Concept(name="1")
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_match_and_eval_when_value_is_not_a_concept():
|
||||||
|
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, "value"),
|
||||||
|
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, "value"),
|
||||||
|
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
|
||||||
|
]
|
||||||
|
|
||||||
|
evaluator = MultipleSameSuccessEvaluator()
|
||||||
|
assert evaluator.matches(context, return_values)
|
||||||
|
|
||||||
|
evaluated = evaluator.eval(context, return_values)
|
||||||
|
assert evaluated.status
|
||||||
|
assert evaluated.value == "value"
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_match_even_if_the_value_are_not_the_same_but_eval_will_fail():
|
||||||
|
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="value2")),
|
||||||
|
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
|
||||||
|
]
|
||||||
|
|
||||||
|
evaluator = MultipleSameSuccessEvaluator()
|
||||||
|
assert evaluator.matches(context, return_values)
|
||||||
|
assert evaluator.eval(context, return_values) is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_match_even_if_the_value_are_not_the_same_but_eval_will_fail_when_no_body():
|
||||||
|
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")),
|
||||||
|
ReturnValueConcept(BaseEvaluator.PREFIX + "some_name", True, Concept(name="2")),
|
||||||
|
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
|
||||||
|
]
|
||||||
|
|
||||||
|
evaluator = MultipleSameSuccessEvaluator()
|
||||||
|
assert evaluator.matches(context, return_values)
|
||||||
|
assert evaluator.eval(context, return_values) is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_match_if_no_parser():
|
||||||
|
context = get_context()
|
||||||
|
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("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
|
||||||
|
]
|
||||||
|
|
||||||
|
assert MultipleSameSuccessEvaluator().matches(context, return_values)
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_cannot_match_if_not_after_evaluation():
|
||||||
|
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, Concept(name="2", body="value")),
|
||||||
|
# ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
|
||||||
|
]
|
||||||
|
|
||||||
|
assert not MultipleSameSuccessEvaluator().matches(context, return_values)
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_cannot_match_if_only_one_successful_evaluator():
|
||||||
|
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, Concept(name="2", body="value")),
|
||||||
|
ReturnValueConcept("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
|
||||||
|
]
|
||||||
|
|
||||||
|
assert not MultipleSameSuccessEvaluator().matches(context, return_values)
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_cannot_match_if_at_least_one_parser_is_successful():
|
||||||
|
context = get_context()
|
||||||
|
sheerka = context.sheerka
|
||||||
|
|
||||||
|
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("some_name", True, sheerka.new(BuiltinConcepts.AFTER_EVALUATION))
|
||||||
|
]
|
||||||
|
|
||||||
|
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)
|
||||||
+83
-4
@@ -341,7 +341,7 @@ def test_i_can_use_expect_one_when_not_a_list_false():
|
|||||||
("1 + 1", 2),
|
("1 + 1", 2),
|
||||||
("sheerka.test()", 'I have access to Sheerka !')
|
("sheerka.test()", 'I have access to Sheerka !')
|
||||||
])
|
])
|
||||||
def test_i_can_eval_simple_python_expressions(text, expected):
|
def test_i_can_eval_python_expressions_with_no_variable(text, expected):
|
||||||
sheerka = get_sheerka()
|
sheerka = get_sheerka()
|
||||||
|
|
||||||
res = sheerka.eval(text)
|
res = sheerka.eval(text)
|
||||||
@@ -351,9 +351,9 @@ def test_i_can_eval_simple_python_expressions(text, expected):
|
|||||||
assert res[0].value == expected
|
assert res[0].value == expected
|
||||||
|
|
||||||
|
|
||||||
def test_i_can_eval_simple_concept():
|
def test_i_can_eval_concept_with_python_body():
|
||||||
sheerka = get_sheerka()
|
sheerka = get_sheerka()
|
||||||
concept = Concept(name="one", body="1").init_key()
|
concept = Concept(name="one", body="1")
|
||||||
sheerka.add_in_cache(concept)
|
sheerka.add_in_cache(concept)
|
||||||
|
|
||||||
text = "one"
|
text = "one"
|
||||||
@@ -363,6 +363,46 @@ def test_i_can_eval_simple_concept():
|
|||||||
assert res[0].value == 1
|
assert res[0].value == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_eval_concept_with_concept_body():
|
||||||
|
sheerka = get_sheerka()
|
||||||
|
concept_one = Concept(name="one")
|
||||||
|
concept_un = Concept(name="un", body="one")
|
||||||
|
sheerka.add_in_cache(concept_one)
|
||||||
|
sheerka.add_in_cache(concept_un)
|
||||||
|
|
||||||
|
res = sheerka.eval("un")
|
||||||
|
return_value = res[0].value
|
||||||
|
assert len(res) == 1
|
||||||
|
assert res[0].status
|
||||||
|
assert sheerka.isinstance(return_value, concept_one)
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_eval_concept_with_no_body():
|
||||||
|
sheerka = get_sheerka()
|
||||||
|
concept = Concept(name="one")
|
||||||
|
sheerka.add_in_cache(concept)
|
||||||
|
|
||||||
|
text = "one"
|
||||||
|
res = sheerka.eval(text)
|
||||||
|
assert len(res) == 1
|
||||||
|
assert res[0].status
|
||||||
|
assert res[0].value == concept
|
||||||
|
assert id(res[0].value) != id(concept)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_unique_property_is_used_when_evaluating():
|
||||||
|
sheerka = get_sheerka()
|
||||||
|
concept = Concept(name="one", is_unique=True)
|
||||||
|
sheerka.add_in_cache(concept)
|
||||||
|
|
||||||
|
text = "one"
|
||||||
|
res = sheerka.eval(text)
|
||||||
|
assert len(res) == 1
|
||||||
|
assert res[0].status
|
||||||
|
assert res[0].value == concept
|
||||||
|
assert id(res[0].value) == id(concept)
|
||||||
|
|
||||||
|
|
||||||
def test_i_can_eval_def_concept_request():
|
def test_i_can_eval_def_concept_request():
|
||||||
text = """
|
text = """
|
||||||
def concept a + b
|
def concept a + b
|
||||||
@@ -405,7 +445,7 @@ def test_i_can_eval_def_concept_part_when_one_part_is_a_ref_of_another_concept()
|
|||||||
sheerka = get_sheerka()
|
sheerka = get_sheerka()
|
||||||
|
|
||||||
# concept 'a plus b' is known
|
# concept 'a plus b' is known
|
||||||
concept_a_plus_b = Concept(name="a plus b").set_prop("a").set_prop("b").init_key()
|
concept_a_plus_b = Concept(name="a plus b").set_prop("a").set_prop("b")
|
||||||
sheerka.add_in_cache(concept_a_plus_b)
|
sheerka.add_in_cache(concept_a_plus_b)
|
||||||
|
|
||||||
res = sheerka.eval("def concept a xx b as a plus b")
|
res = sheerka.eval("def concept a xx b as a plus b")
|
||||||
@@ -461,6 +501,45 @@ def test_i_can_eval_a_empty_input(text):
|
|||||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NOP)
|
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NOP)
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_eval_concept_with_variable():
|
||||||
|
sheerka = get_sheerka()
|
||||||
|
concept_hello = Concept(name="hello a").set_prop("a")
|
||||||
|
concept_foo = Concept(name="foo")
|
||||||
|
sheerka.add_in_cache(concept_hello)
|
||||||
|
sheerka.add_in_cache(concept_foo)
|
||||||
|
|
||||||
|
res = sheerka.eval("hello foo")
|
||||||
|
return_value = res[0].value
|
||||||
|
assert len(res) == 1
|
||||||
|
assert res[0].status
|
||||||
|
assert sheerka.isinstance(return_value, concept_hello)
|
||||||
|
assert return_value.props["a"].value == concept_foo
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_eval_concept_with_variable_and_python_as_body():
|
||||||
|
sheerka = get_sheerka()
|
||||||
|
sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").set_prop("a"))
|
||||||
|
sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
|
||||||
|
|
||||||
|
res = sheerka.eval("hello foo")
|
||||||
|
assert len(res) == 1
|
||||||
|
assert res[0].status
|
||||||
|
assert res[0].value, "hello foo"
|
||||||
|
|
||||||
|
|
||||||
|
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 foo", body="'hello foo'"))
|
||||||
|
sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
|
||||||
|
|
||||||
|
res = sheerka.eval("hello foo")
|
||||||
|
assert len(res) == 1
|
||||||
|
assert res[0].status
|
||||||
|
assert res[0].value, "hello foo"
|
||||||
|
|
||||||
|
|
||||||
def get_sheerka():
|
def get_sheerka():
|
||||||
sheerka = Sheerka()
|
sheerka = Sheerka()
|
||||||
sheerka.initialize(root_folder)
|
sheerka.initialize(root_folder)
|
||||||
|
|||||||
Reference in New Issue
Block a user