Added concepts with the same key handling
This commit is contained in:
@@ -24,12 +24,13 @@ class BuiltinConcepts(Enum):
|
|||||||
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 # after parsing
|
AFTER_PARSING = 17 # after parsing
|
||||||
BEFORE_EVALUATION = 18 # before evalution
|
BEFORE_EVALUATION = 18 # before evaluation
|
||||||
EVALUATION = 19 # activated when the parsing process seems to be finished
|
EVALUATION = 19 # activated when the parsing process seems to be finished
|
||||||
AFTER_EVALUATION = 20 # 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
|
CONCEPT_ALREADY_DEFINED = 21 # when you try to add the same concept twice
|
||||||
NOP = 22 # no operation concept. Does nothing
|
NOP = 22 # no operation concept. Does nothing
|
||||||
PROPERTY_EVAL_ERROR = 23
|
PROPERTY_EVAL_ERROR = 23 # cannot evaluate a property of a concept
|
||||||
|
ENUMERATION = 24 # represents a list or a set
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|||||||
+2
-2
@@ -24,8 +24,8 @@ class Concept:
|
|||||||
A concept is a the base object of our universe
|
A concept is a the base object of our universe
|
||||||
Everything is a concept
|
Everything is a concept
|
||||||
"""
|
"""
|
||||||
props_to_serialize = ("id", "is_builtin", "key", "name", "where", "pre", "post", "body", "desc", "obj")
|
props_for_digest = ("is_builtin", "is_unique", "key", "name", "where", "pre", "post", "body", "desc")
|
||||||
props_for_digest = ("is_builtin", "key", "name", "where", "pre", "post", "body", "desc")
|
props_to_serialize = ("id", "is_builtin", "is_unique", "key", "name", "where", "pre", "post", "body", "desc")
|
||||||
concept_parts = set(item.value for item in ConceptParts)
|
concept_parts = set(item.value for item in ConceptParts)
|
||||||
|
|
||||||
PROPERTY_PREFIX = "__var__"
|
PROPERTY_PREFIX = "__var__"
|
||||||
|
|||||||
+60
-24
@@ -46,6 +46,9 @@ class Sheerka(Concept):
|
|||||||
self.parsers = []
|
self.parsers = []
|
||||||
self.evaluators = []
|
self.evaluators = []
|
||||||
|
|
||||||
|
self.evaluators_prefix = None
|
||||||
|
self.parsers_prefix = None
|
||||||
|
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
|
|
||||||
def initialize(self, root_folder=None):
|
def initialize(self, root_folder=None):
|
||||||
@@ -327,7 +330,7 @@ class Sheerka(Concept):
|
|||||||
return self.ret(self.create_new_concept.__name__, False, ErrorConcept(error), error.args[0])
|
return self.ret(self.create_new_concept.__name__, False, ErrorConcept(error), error.args[0])
|
||||||
|
|
||||||
# add in cache for quick further reference
|
# add in cache for quick further reference
|
||||||
self.concepts_cache[concept.key] = concept
|
self.concepts_cache[concept.key] = self.sdp.get_safe(self.CONCEPTS_ENTRY, concept.key)
|
||||||
|
|
||||||
# process the return in needed
|
# process the return in needed
|
||||||
ret = self.ret(self.create_new_concept.__name__, True, self.new(BuiltinConcepts.NEW_CONCEPT, body=concept))
|
ret = self.ret(self.create_new_concept.__name__, True, self.new(BuiltinConcepts.NEW_CONCEPT, body=concept))
|
||||||
@@ -415,25 +418,12 @@ class Sheerka(Concept):
|
|||||||
concept_key != BuiltinConcepts.UNKNOWN_CONCEPT:
|
concept_key != BuiltinConcepts.UNKNOWN_CONCEPT:
|
||||||
return template
|
return template
|
||||||
|
|
||||||
# manage singleton
|
if not isinstance(template, list):
|
||||||
if template.is_unique:
|
return self._new_from_template(template, concept_key, **kwargs)
|
||||||
return template
|
|
||||||
|
|
||||||
# otherwise, create another instance
|
# if template is a list, it means that there a multiple concepts under the same key
|
||||||
concept = self.builtin_cache[concept_key]() if concept_key in self.builtin_cache else Concept()
|
concepts = [self._new_from_template(t, concept_key, **kwargs) for t in template]
|
||||||
concept.update_from(template)
|
return self.new(BuiltinConcepts.ENUMERATION, body=concepts)
|
||||||
|
|
||||||
# update the properties
|
|
||||||
for k, v in kwargs.items():
|
|
||||||
if k in concept.props:
|
|
||||||
concept.set_prop(k, v)
|
|
||||||
elif hasattr(concept, k):
|
|
||||||
setattr(concept, k, v)
|
|
||||||
else:
|
|
||||||
return self.new(BuiltinConcepts.UNKNOWN_PROPERTY, body=k, concept=concept)
|
|
||||||
|
|
||||||
# TODO : add the concept to the list of known concepts (self.instances)
|
|
||||||
return concept
|
|
||||||
|
|
||||||
def ret(self, who, status, value, message=None, parents=None):
|
def ret(self, who, status, value, message=None, parents=None):
|
||||||
"""
|
"""
|
||||||
@@ -473,6 +463,52 @@ class Sheerka(Concept):
|
|||||||
# for example, if a is a color, it will be found the entry 'All_Colors'
|
# for example, if a is a color, it will be found the entry 'All_Colors'
|
||||||
return a.key == b_key
|
return a.key == b_key
|
||||||
|
|
||||||
|
def get_evaluator_name(self, name):
|
||||||
|
if self.evaluators_prefix is None:
|
||||||
|
base_evaluator_class = core.utils.get_class("evaluators.BaseEvaluator.BaseEvaluator")
|
||||||
|
self.evaluators_prefix = base_evaluator_class.PREFIX
|
||||||
|
|
||||||
|
return self.evaluators_prefix + name
|
||||||
|
|
||||||
|
def get_parser_name(self, name):
|
||||||
|
if self.parsers_prefix is None:
|
||||||
|
base_parser_class = core.utils.get_class("parsers.BaseParser.BaseParser")
|
||||||
|
self.parsers_prefix = base_parser_class.PREFIX
|
||||||
|
|
||||||
|
return self.parsers_prefix + name
|
||||||
|
|
||||||
|
def concepts(self):
|
||||||
|
res = []
|
||||||
|
lst = self.sdp.list(self.CONCEPTS_ENTRY)
|
||||||
|
for item in lst:
|
||||||
|
if isinstance(item, list):
|
||||||
|
res.extend(item)
|
||||||
|
else:
|
||||||
|
res.append(item)
|
||||||
|
|
||||||
|
return sorted(res, key=lambda i: i.key)
|
||||||
|
|
||||||
|
def _new_from_template(self, template, concept_key, **kwargs):
|
||||||
|
# manage singleton
|
||||||
|
if template.is_unique:
|
||||||
|
return template
|
||||||
|
|
||||||
|
# otherwise, create another instance
|
||||||
|
concept = self.builtin_cache[concept_key]() if concept_key in self.builtin_cache else Concept()
|
||||||
|
concept.update_from(template)
|
||||||
|
|
||||||
|
# update the properties
|
||||||
|
for k, v in kwargs.items():
|
||||||
|
if k in concept.props:
|
||||||
|
concept.set_prop(k, v)
|
||||||
|
elif hasattr(concept, k):
|
||||||
|
setattr(concept, k, v)
|
||||||
|
else:
|
||||||
|
return self.new(BuiltinConcepts.UNKNOWN_PROPERTY, body=k, concept=concept)
|
||||||
|
|
||||||
|
# TODO : add the concept to the list of known concepts (self.instances)
|
||||||
|
return concept
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_builtins_classes_as_dict():
|
def get_builtins_classes_as_dict():
|
||||||
res = {}
|
res = {}
|
||||||
@@ -505,11 +541,11 @@ class ExecutionContext:
|
|||||||
"""
|
"""
|
||||||
To keep track of the execution of a request
|
To keep track of the execution of a request
|
||||||
"""
|
"""
|
||||||
who: object # who is asking
|
who: object # who is asking
|
||||||
event_digest: str # what was the (original) trigger
|
event_digest: str # what was the (original) trigger
|
||||||
sheerka: Sheerka # sheerka
|
sheerka: Sheerka # sheerka
|
||||||
desc: str = None # human description of what is going on
|
desc: str = None # human description of what is going on
|
||||||
obj: Concept = None # what is the subject of the execution context (if known)
|
obj: Concept = None # what is the subject of the execution context (if known)
|
||||||
|
|
||||||
def push(self, who, desc=None, obj=None):
|
def push(self, who, desc=None, obj=None):
|
||||||
return ExecutionContext(who, self.event_digest, self.sheerka, desc=desc, obj=obj)
|
return ExecutionContext(who, self.event_digest, self.sheerka, desc=desc, obj=obj)
|
||||||
|
|||||||
@@ -132,3 +132,5 @@ def remove_from_list(lst, to_remove):
|
|||||||
lst.remove(item)
|
lst.remove(item)
|
||||||
|
|
||||||
return lst
|
return lst
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,10 @@ class AddConceptEvaluator(OneReturnValueEvaluator):
|
|||||||
"""
|
"""
|
||||||
Used to add a new concept
|
Used to add a new concept
|
||||||
"""
|
"""
|
||||||
|
NAME = "AddNewConcept"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__("Add new Concept", 50)
|
super().__init__(self.NAME, 50)
|
||||||
|
|
||||||
def matches(self, context, return_value):
|
def matches(self, context, return_value):
|
||||||
return return_value.status and \
|
return return_value.status and \
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class ConceptEvaluator(OneReturnValueEvaluator):
|
class ConceptEvaluator(OneReturnValueEvaluator):
|
||||||
|
NAME = "Concept"
|
||||||
evaluation_steps = [BuiltinConcepts.EVALUATION, BuiltinConcepts.AFTER_EVALUATION]
|
evaluation_steps = [BuiltinConcepts.EVALUATION, BuiltinConcepts.AFTER_EVALUATION]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__("Concept Evaluator", 50)
|
super().__init__(self.NAME, 50)
|
||||||
|
|
||||||
def matches(self, context, return_value):
|
def matches(self, context, return_value):
|
||||||
return return_value.status and \
|
return return_value.status and \
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from core.builtin_concepts import BuiltinConcepts
|
from core.builtin_concepts import BuiltinConcepts
|
||||||
|
from evaluators.AddConceptEvaluator import AddConceptEvaluator
|
||||||
from evaluators.BaseEvaluator import AllReturnValuesEvaluator
|
from evaluators.BaseEvaluator import AllReturnValuesEvaluator
|
||||||
from parsers.BaseParser import BaseParser
|
from parsers.BaseParser import BaseParser
|
||||||
|
|
||||||
@@ -8,8 +9,10 @@ class DuplicateConceptEvaluator(AllReturnValuesEvaluator):
|
|||||||
Use to recognize when we tried to add the same concept twice
|
Use to recognize when we tried to add the same concept twice
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
NAME = "DuplicateConcept"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__("Duplicate Concept Evaluator", 10)
|
super().__init__(self.NAME, 10)
|
||||||
self.already_defined = None
|
self.already_defined = None
|
||||||
|
|
||||||
def matches(self, context, return_values):
|
def matches(self, context, return_values):
|
||||||
@@ -22,7 +25,7 @@ class DuplicateConceptEvaluator(AllReturnValuesEvaluator):
|
|||||||
if sheerka.isinstance(ret.value, BuiltinConcepts.AFTER_EVALUATION):
|
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 == sheerka.get_evaluator_name(AddConceptEvaluator.NAME):
|
||||||
if not ret.status and ret.value.body.args[0] == "Duplicate object.":
|
if not ret.status and ret.value.body.args[0] == "Duplicate object.":
|
||||||
add_concept_in_error = True
|
add_concept_in_error = True
|
||||||
self.already_defined = ret.value.body.obj
|
self.already_defined = ret.value.body.obj
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ class MultipleSameSuccessEvaluator(AllReturnValuesEvaluator):
|
|||||||
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
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
NAME = "MultipleSameSuccess"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__("Parsers Evaluator", 10)
|
super().__init__(self.NAME, 10)
|
||||||
self.success = []
|
self.success = []
|
||||||
|
|
||||||
def matches(self, context, return_values):
|
def matches(self, context, return_values):
|
||||||
|
|||||||
@@ -13,8 +13,10 @@ class OneSuccessEvaluator(AllReturnValuesEvaluator):
|
|||||||
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
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
NAME = "OneSuccess"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__("Parsers Evaluator", 10)
|
super().__init__(self.NAME, 10)
|
||||||
self.successful_return_value = None
|
self.successful_return_value = None
|
||||||
|
|
||||||
def matches(self, context, return_values):
|
def matches(self, context, return_values):
|
||||||
|
|||||||
@@ -8,8 +8,11 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class PythonEvaluator(OneReturnValueEvaluator):
|
class PythonEvaluator(OneReturnValueEvaluator):
|
||||||
|
|
||||||
|
NAME = "Python"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__("Python Evaluator", 50)
|
super().__init__(self.NAME, 50)
|
||||||
|
|
||||||
def matches(self, context, return_value):
|
def matches(self, context, return_value):
|
||||||
return return_value.status and \
|
return return_value.status and \
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
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 TooManySuccessEvaluator(AllReturnValuesEvaluator):
|
||||||
|
"""
|
||||||
|
Used to filter the responses
|
||||||
|
It has a low priority to let other evaluators try to resolve the errors
|
||||||
|
"""
|
||||||
|
|
||||||
|
NAME = "TooManySuccess"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(self.NAME, 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)
|
||||||
|
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].value)
|
||||||
|
|
||||||
|
for return_value in self.success[1:]:
|
||||||
|
actual = self.get_value(return_value.value)
|
||||||
|
if actual != reference:
|
||||||
|
sheerka = context.sheerka
|
||||||
|
too_many_success = sheerka.new(BuiltinConcepts.TOO_MANY_SUCCESS, obj=self.success)
|
||||||
|
return sheerka.ret(self.name, False, too_many_success, parents=return_values)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_value(obj):
|
||||||
|
if not isinstance(obj, Concept):
|
||||||
|
return obj
|
||||||
|
|
||||||
|
return obj if obj.body is None else obj.body
|
||||||
@@ -32,14 +32,16 @@ class ExactConceptParser(BaseParser):
|
|||||||
|
|
||||||
recognized = False
|
recognized = False
|
||||||
for combination in self.combinations(words):
|
for combination in self.combinations(words):
|
||||||
concept_key = " ".join(combination)
|
|
||||||
|
|
||||||
# Very important question to think about later
|
concept_key = " ".join(combination)
|
||||||
# Must we return a new instance or the existing one
|
result = sheerka.new(concept_key)
|
||||||
# That will depend on the context
|
|
||||||
# Let's return a new one for now and see if it works
|
if sheerka.isinstance(result, BuiltinConcepts.UNKNOWN_CONCEPT):
|
||||||
concept = sheerka.new(concept_key)
|
continue
|
||||||
if not sheerka.isinstance(concept, BuiltinConcepts.UNKNOWN_CONCEPT):
|
|
||||||
|
concepts = result.body if sheerka.isinstance(result, BuiltinConcepts.ENUMERATION) else [result]
|
||||||
|
|
||||||
|
for concept in concepts:
|
||||||
# update the properties if needed
|
# update the properties if needed
|
||||||
for i, token in enumerate(combination):
|
for i, token in enumerate(combination):
|
||||||
if token.startswith(Concept.PROPERTY_PREFIX):
|
if token.startswith(Concept.PROPERTY_PREFIX):
|
||||||
|
|||||||
@@ -576,7 +576,11 @@ class SheerkaDataProvider:
|
|||||||
if key is not None and key not in state.data[entry]:
|
if key is not None and key not in state.data[entry]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return self.load_ref_if_needed(state.data[entry] if key is None else state.data[entry][key])[0]
|
item = state.data[entry] if key is None else state.data[entry][key]
|
||||||
|
if isinstance(item, list):
|
||||||
|
return [self.load_ref_if_needed(i)[0] for i in item]
|
||||||
|
|
||||||
|
return self.load_ref_if_needed(item)[0]
|
||||||
|
|
||||||
def exists(self, entry, key=None, digest=None):
|
def exists(self, entry, key=None, digest=None):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from core import utils
|
|||||||
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept
|
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept
|
||||||
from core.concept import Concept, ConceptParts
|
from core.concept import Concept, ConceptParts
|
||||||
from core.sheerka import Sheerka, ExecutionContext
|
from core.sheerka import Sheerka, ExecutionContext
|
||||||
|
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
|
||||||
from parsers.DefaultParser import DefaultParser
|
from parsers.DefaultParser import DefaultParser
|
||||||
from parsers.PythonParser import PythonParser
|
from parsers.PythonParser import PythonParser
|
||||||
from sdp.sheerkaDataProvider import SheerkaDataProvider, SheerkaDataProviderDuplicateKeyError
|
from sdp.sheerkaDataProvider import SheerkaDataProvider, SheerkaDataProviderDuplicateKeyError
|
||||||
@@ -158,6 +159,44 @@ def test_i_can_get_a_known_concept_when_not_in_cache():
|
|||||||
assert loaded == concept
|
assert loaded == concept
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_get_list_of_concept_when_same_key_when_no_cache():
|
||||||
|
sheerka = get_sheerka()
|
||||||
|
concept1 = get_default_concept()
|
||||||
|
concept2 = get_default_concept()
|
||||||
|
concept2.body = "a+b"
|
||||||
|
|
||||||
|
res1 = sheerka.create_new_concept(get_context(sheerka), concept1)
|
||||||
|
res2 = sheerka.create_new_concept(get_context(sheerka), concept2)
|
||||||
|
|
||||||
|
assert res1.value.body.key == res2.value.body.key # same key
|
||||||
|
|
||||||
|
sheerka.concepts_cache = {} # reset the cache
|
||||||
|
|
||||||
|
from_cache = sheerka.get(concept1.key)
|
||||||
|
assert len(from_cache) == 2
|
||||||
|
assert from_cache[0] == concept1
|
||||||
|
assert from_cache[1] == concept2
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_get_list_of_concept_when_same_key_when_cache():
|
||||||
|
sheerka = get_sheerka()
|
||||||
|
concept1 = get_default_concept()
|
||||||
|
concept2 = get_default_concept()
|
||||||
|
concept2.body = "a+b"
|
||||||
|
|
||||||
|
res1 = sheerka.create_new_concept(get_context(sheerka), concept1)
|
||||||
|
res2 = sheerka.create_new_concept(get_context(sheerka), concept2)
|
||||||
|
|
||||||
|
assert res1.value.body.key == res2.value.body.key # same key
|
||||||
|
|
||||||
|
# sheerka.concepts_cache = {} # Do not reset the cache
|
||||||
|
|
||||||
|
from_cache = sheerka.get(concept1.key)
|
||||||
|
assert len(from_cache) == 2
|
||||||
|
assert from_cache[0] == concept1
|
||||||
|
assert from_cache[1] == concept2
|
||||||
|
|
||||||
|
|
||||||
def test_unknown_concept_is_return_when_the_concept_is_not_found():
|
def test_unknown_concept_is_return_when_the_concept_is_not_found():
|
||||||
sheerka = get_sheerka()
|
sheerka = get_sheerka()
|
||||||
|
|
||||||
@@ -538,6 +577,40 @@ def test_i_can_eval_duplicate_concepts_with_same_value():
|
|||||||
assert len(res) == 1
|
assert len(res) == 1
|
||||||
assert res[0].status
|
assert res[0].status
|
||||||
assert res[0].value, "hello foo"
|
assert res[0].value, "hello foo"
|
||||||
|
assert res[0].who == sheerka.get_evaluator_name(MultipleSameSuccessEvaluator.NAME)
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_cannot_manage_duplicate_concepts_when_the_values_are_different():
|
||||||
|
sheerka = get_sheerka()
|
||||||
|
|
||||||
|
sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").set_prop("a"))
|
||||||
|
sheerka.add_in_cache(Concept(name="hello foo", body="'hello foo'"))
|
||||||
|
sheerka.add_in_cache(Concept(name="foo", body="'another value'"))
|
||||||
|
|
||||||
|
res = sheerka.eval("hello foo")
|
||||||
|
assert len(res) == 1
|
||||||
|
assert not res[0].status
|
||||||
|
assert sheerka.isinstance(res[0].value, BuiltinConcepts.TOO_MANY_SUCCESS)
|
||||||
|
|
||||||
|
concepts = res[0].value.obj
|
||||||
|
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"
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_manage_concepts_with_the_same_key_when_values_are_the_same():
|
||||||
|
sheerka = get_sheerka()
|
||||||
|
context = get_context(sheerka)
|
||||||
|
|
||||||
|
sheerka.create_new_concept(context, Concept(name="hello a", body="'hello ' + a").set_prop("a"))
|
||||||
|
sheerka.create_new_concept(context, Concept(name="hello b", body="'hello ' + b").set_prop("b"))
|
||||||
|
|
||||||
|
res = sheerka.eval("hello 'foo'")
|
||||||
|
assert len(res) == 1
|
||||||
|
assert res[0].status
|
||||||
|
assert res[0].value, "hello foo"
|
||||||
|
assert res[0].who == sheerka.get_evaluator_name(MultipleSameSuccessEvaluator.NAME)
|
||||||
|
|
||||||
|
|
||||||
def get_sheerka():
|
def get_sheerka():
|
||||||
|
|||||||
@@ -1316,3 +1316,20 @@ def test_i_can_save_and_load_object_ref_with_history():
|
|||||||
state = sdp.load_state(sdp.get_snapshot())
|
state = sdp.load_state(sdp.get_snapshot())
|
||||||
assert state.data == {"entry": {
|
assert state.data == {"entry": {
|
||||||
"my_key": '##REF##:e6bf5b56428cfce0f08c94f2c3625dc3b3a8180d7229eaa9f8aa967fb16e5256'}}
|
"my_key": '##REF##:e6bf5b56428cfce0f08c94f2c3625dc3b3a8180d7229eaa9f8aa967fb16e5256'}}
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_add_obj_with_same_key_and_get_them_back():
|
||||||
|
sdp = SheerkaDataProvider(".sheerka")
|
||||||
|
obj1 = ObjDumpJson("key", "value1")
|
||||||
|
obj2 = ObjDumpJson("key", "value2")
|
||||||
|
sdp.serializer.register(ObjectSerializer(core.utils.get_full_qualified_name(obj1)))
|
||||||
|
|
||||||
|
entry1, key1 = sdp.add(evt_digest, "entry", obj1, use_ref=True)
|
||||||
|
entry2, key2 = sdp.add(evt_digest, "entry", obj2, use_ref=True)
|
||||||
|
|
||||||
|
loaded = sdp.get_safe(entry1, key1)
|
||||||
|
|
||||||
|
assert len(loaded) == 2
|
||||||
|
assert loaded[0] == obj1
|
||||||
|
assert loaded[1] == obj2
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user