Fixed #100 : SheerkaAdmin: Add builtins() command
Fixed #99 : SheerkaQueryManager: I can manage contains predicate when filtering objects Fixed #97 : ERROR: list indices must be integers or slices, not Concept Fixed #96 : SequenceNodeParser: SequenceNodeParser must correctly handle concept definition Fixed #95 : ResolveAmbiguity must not remove concepts that do not require evaluation Fixed #94 : Concepts with the same key are lost when new ontology Fixed #93 : Introduce BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED Fixed #92 : ExpressionParser: Implement compile_disjunctions() Fixed #91 : Implement get_concepts_complexity(context, concepts, concept_parts) Fixed #90 : ResolveAmbiguity : where predicate is not used to resolve ambiguity Fixed #89 : ResolveAmbiguityEvaluator: Concepts embedded in ConceptNode are not resolved Fixed #88: SyaNodeParser: Parse multiple parameters when some of the are not recognized Fixed #87: SyaNodeParser : Parse the multiple parameters
This commit is contained in:
@@ -4,3 +4,5 @@ def concept x is a integer pre is_question() as isinstance(x, int)
|
||||
def concept x starts with y pre is_question() where x is a string as x.startswith(y)
|
||||
def concept sha256 from bnf r'[a-f0-9]{64}'
|
||||
def concept sha512 from bnf r'[a-f0-9]{128}'
|
||||
|
||||
def concept explain x where isinstance(x, sha256) as get_results_by_digest(x, id=0, depth=2) auto_eval True
|
||||
Vendored
+3
-2
@@ -83,18 +83,19 @@ class CacheManager:
|
||||
|
||||
self.caches[name] = CacheDefinition(cache, use_ref, None, persist)
|
||||
|
||||
def add_concept(self, concept):
|
||||
def add_concept(self, concept, alt_sdp=None):
|
||||
"""
|
||||
We need multiple indexes to retrieve a concept
|
||||
So the new concept is dispatched into multiple caches
|
||||
:param concept:
|
||||
:param alt_sdp: if not found in self.sdp, look in other repositories
|
||||
:return:
|
||||
"""
|
||||
with self._lock:
|
||||
for name in self.concept_caches:
|
||||
cache_def = self.caches[name]
|
||||
key = cache_def.get_key(concept)
|
||||
cache_def.cache.put(key, concept)
|
||||
cache_def.cache.put(key, concept, alt_sdp)
|
||||
|
||||
self.is_dirty = True
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ class BuiltinConcepts:
|
||||
REDUCE_REQUESTED = "__REDUCE_REQUESTED" # remove meaningless error when possible
|
||||
EVAL_UNTIL_SUCCESS_REQUESTED = "__EVAL_UNTIL_SUCCESS_REQUESTED" # PythonEvaluator tries combination until True is found
|
||||
EVAL_QUESTION_REQUESTED = "__EVAL_QUESTION_REQUESTED" # the user input must be treated as question
|
||||
EVAL_GLOBAL_TRUTH_REQUESTED = "__EVAL_GLOBAL_TRUTH_REQUESTED" # the user input is a global truth
|
||||
VALIDATION_ONLY_REQUESTED = "__VALIDATION_ONLY_REQUESTED" # Validation mode activated. Never evaluate the body
|
||||
|
||||
# possible actions during sheerka.execute() or sheerka.evaluate_rules()
|
||||
@@ -47,6 +48,7 @@ class BuiltinConcepts:
|
||||
EXEC_CODE = "__EXEC_CODE" # to use when executing Python or other language compiled code
|
||||
TESTING = "__TESTING"
|
||||
EVALUATOR_PRE_PROCESS = "__EVALUATOR_PRE_PROCESS" # used modify / tweak behaviour of evaluators
|
||||
EVALUATING_PRE_OR_WHERE_CLAUSE = "EVALUATING_PRE_OR_WHERE_CLAUSE" # use in is_question()
|
||||
|
||||
# builtin attributes
|
||||
ISA = "__ISA" # when a concept is an instance of another one
|
||||
|
||||
+73
-10
@@ -7,8 +7,10 @@ from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept, ConceptParts, DEFINITION_TYPE_BNF, concept_part_value
|
||||
from core.global_symbols import NotInit, NotFound, INIT_AST_PARSERS, DEFAULT_EVALUATORS
|
||||
from core.rule import Rule
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Tokenizer, TokenKind
|
||||
from core.utils import as_bag
|
||||
from parsers.BaseExpressionParser import compile_disjunctions, AndNode
|
||||
from parsers.BaseNodeParser import SourceCodeNode, ConceptNode, UnrecognizedTokensNode, SourceCodeWithConceptNode, \
|
||||
RuleNode, LexerNode
|
||||
from parsers.BaseParser import ParsingError
|
||||
@@ -205,7 +207,7 @@ def only_successful(context, return_values):
|
||||
def resolve_ambiguity(context, concepts):
|
||||
"""
|
||||
From the list of concepts, elect the one(s) that best suit(s) the context
|
||||
Use the PRE metadata to choose the correct concepts
|
||||
Use the PRE and WHERE metadata to choose the correct concepts
|
||||
:param context:
|
||||
:param concepts:
|
||||
:return:
|
||||
@@ -214,8 +216,9 @@ def resolve_ambiguity(context, concepts):
|
||||
# we first sort by condition complexity. The more complex is the PRE condition, the more likely
|
||||
# the concept matches the context
|
||||
by_complexity = {}
|
||||
parts = [concept_part_value(ConceptParts.PRE), concept_part_value(ConceptParts.WHERE)]
|
||||
for c in concepts:
|
||||
by_complexity.setdefault(get_condition_complexity(c, concept_part_value(ConceptParts.PRE)), []).append(c)
|
||||
by_complexity.setdefault(get_concept_complexity(context, c, parts), []).append(c)
|
||||
|
||||
remaining_concepts = []
|
||||
for complexity in sorted(by_complexity.keys(), reverse=True):
|
||||
@@ -226,14 +229,14 @@ def resolve_ambiguity(context, concepts):
|
||||
evaluated = context.sheerka.evaluate_concept(context, c,
|
||||
eval_body=False,
|
||||
validation_only=True,
|
||||
metadata=[ConceptParts.PRE])
|
||||
metadata=[ConceptParts.PRE, ConceptParts.WHERE])
|
||||
if context.sheerka.is_success(evaluated) or evaluated.key == c.key:
|
||||
remaining_concepts.append(c)
|
||||
|
||||
if len(remaining_concepts) > 0:
|
||||
break # no need to check concept with lower complexity
|
||||
|
||||
if len(remaining_concepts) in (0, 1):
|
||||
if len(remaining_concepts) < 2:
|
||||
return remaining_concepts # they all failed the pre conditions or one champ is found
|
||||
|
||||
# for concepts with the same condition complexity, we choose the one that has the less number of variables
|
||||
@@ -246,19 +249,58 @@ def resolve_ambiguity(context, concepts):
|
||||
return by_number_of_vars[min(by_number_of_vars.keys())]
|
||||
|
||||
|
||||
def get_condition_complexity(concept, concept_part_str):
|
||||
def get_condition_complexity(context, condition):
|
||||
if condition is None or condition.strip() == "":
|
||||
return 0
|
||||
|
||||
# # count the number of conjunctions
|
||||
from parsers.LogicalOperatorParser import LogicalOperatorParser
|
||||
parser = LogicalOperatorParser()
|
||||
res = parser.parse(context, ParserInput(condition))
|
||||
if not res.status:
|
||||
return 0
|
||||
|
||||
disjunctions = compile_disjunctions(res.body.body)
|
||||
complexity = 0
|
||||
for conjunction in disjunctions:
|
||||
node_complexity = len(conjunction.parts) if isinstance(conjunction, AndNode) else 1
|
||||
if node_complexity > complexity:
|
||||
complexity = node_complexity
|
||||
|
||||
return complexity
|
||||
|
||||
|
||||
def get_concept_complexity(context, concept, concepts_parts):
|
||||
"""
|
||||
Need to find a proper algorithm to compute the complexity of a concept metadata
|
||||
So far, the concept is considered as complex if it has concept_part_str (so far with concept_part_str='pre')
|
||||
:param context:
|
||||
:param concept:
|
||||
:param concept_part_str:
|
||||
:param concepts_parts:
|
||||
:return:
|
||||
"""
|
||||
value = getattr(concept.get_metadata(), concept_part_str)
|
||||
if value is None or value.strip() == 0:
|
||||
return 0
|
||||
complexity = 0
|
||||
for i, parts in enumerate(reversed(concepts_parts)):
|
||||
|
||||
return 1 # no real computing as of now
|
||||
for part in parts.split("|"):
|
||||
value = getattr(concept.get_metadata(), part)
|
||||
part_complexity = get_condition_complexity(context, value)
|
||||
|
||||
if part_complexity > 0:
|
||||
complexity += part_complexity + (i * 100)
|
||||
|
||||
return complexity
|
||||
|
||||
|
||||
def get_concepts_complexity(context, concepts, concepts_parts):
|
||||
"""
|
||||
compute the complexity of the concepts, relatively to each others
|
||||
:param context:
|
||||
:param concepts: concepts
|
||||
:param concepts_parts: metadata to use to compute the complexity
|
||||
:return:
|
||||
"""
|
||||
return {c.id or c.name: get_concept_complexity(context, c, concepts_parts) for c in concepts}
|
||||
|
||||
|
||||
def only_parsers_results(context, return_values):
|
||||
@@ -723,6 +765,27 @@ def set_is_evaluated(concepts, check_nb_variables=False):
|
||||
concepts.get_hints().is_evaluated = True
|
||||
|
||||
|
||||
def update_concepts_hints(concepts, is_evaluated=None, recognized_by=None, is_instance=None):
|
||||
if concepts is None:
|
||||
return
|
||||
|
||||
def update_concept_hints(c, _is_evaluated, _recognized_by, _is_instance):
|
||||
if _is_evaluated is not None:
|
||||
c.get_hints().is_evaluated = _is_evaluated
|
||||
|
||||
if _recognized_by is not None:
|
||||
c.get_hints().recognized_by = _recognized_by
|
||||
|
||||
if _is_instance is not None:
|
||||
c.get_hints().is_instance = _is_instance
|
||||
|
||||
if hasattr(concepts, "__iter__"):
|
||||
for concept in concepts:
|
||||
update_concept_hints(concept, is_evaluated, recognized_by, is_instance)
|
||||
else:
|
||||
update_concept_hints(concepts, is_evaluated, recognized_by, is_instance)
|
||||
|
||||
|
||||
def ensure_concept(*concepts):
|
||||
if hasattr(concepts, "__iter__"):
|
||||
for concept in concepts:
|
||||
|
||||
+10
-3
@@ -44,14 +44,16 @@ def concept_part_value(c):
|
||||
class ConceptHints:
|
||||
is_evaluated: bool = False # True is the concept is evaluated by sheerka.eval_concept()
|
||||
need_validation: bool = False # True if the properties of the concept need to be validated
|
||||
recognized_by: str = None
|
||||
use_copy: bool = False
|
||||
recognized_by: str = None # recognized by its name, by its id or its key
|
||||
use_copy: bool = False # Do not modify, make a copy first
|
||||
is_instance: bool = True # False if we think we recognize the definition of a concept, not its usage
|
||||
|
||||
def copy(self):
|
||||
return ConceptHints(self.is_evaluated,
|
||||
self.need_validation,
|
||||
self.recognized_by,
|
||||
self.use_copy)
|
||||
self.use_copy,
|
||||
self.is_instance)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -624,6 +626,11 @@ class Concept:
|
||||
return Concept().update_from(self, update_hint=True, update_compiled=True)
|
||||
|
||||
def get_concept(self):
|
||||
"""
|
||||
Used when there is a mix of Concept and ConceptNode
|
||||
To quickly get the inner concept
|
||||
:return:
|
||||
"""
|
||||
return self
|
||||
|
||||
|
||||
|
||||
@@ -96,4 +96,4 @@ INIT_AST_PARSERS = ["ExactConcept",
|
||||
|
||||
INIT_AST_QUESTION_PARSERS = ["Expression"]
|
||||
|
||||
DEFAULT_EVALUATORS = ["Python", "Concept", "LexerNode", "ValidateConcept", "ResolveAmbiguity"]
|
||||
DEFAULT_EVALUATORS = ["Python", "Concept", "LexerNode", "Expression", "ValidateConcept", "ResolveAmbiguity"]
|
||||
|
||||
@@ -79,7 +79,7 @@ class ExecutionContext:
|
||||
self.private_hints = set()
|
||||
self.protected_hints = set()
|
||||
self.global_hints = set() if global_hints is None else global_hints
|
||||
self.errors = [] if errors is None else errors # error are global
|
||||
self.errors = [] if errors is None else errors # errors are global
|
||||
|
||||
self.inputs = {} # what were the parameters of the execution context
|
||||
self.values = {} # what was produced by the execution context
|
||||
|
||||
+66
-15
@@ -46,6 +46,7 @@ RULES_EXECUTE_STEPS = [
|
||||
# It indicate which parameter was used to recognize the concept
|
||||
RECOGNIZED_BY_ID = "by_id"
|
||||
RECOGNIZED_BY_NAME = "by_name"
|
||||
RECOGNIZED_BY_KEY = "by_key"
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -53,9 +54,17 @@ class SheerkaMethod:
|
||||
"""
|
||||
Wrapper to sheerka method, to indicate if it's safe to call
|
||||
"""
|
||||
name: str
|
||||
service: str
|
||||
method: object
|
||||
has_side_effect: bool
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.name, self.service))
|
||||
|
||||
|
||||
class Sheerka(Concept):
|
||||
"""
|
||||
@@ -111,16 +120,18 @@ class Sheerka(Concept):
|
||||
self.methods_with_context = {"test_using_context"} # only the names, the method is defined in sheerka_methods
|
||||
self.pipe_functions = set()
|
||||
self.sheerka_methods = {
|
||||
"test": SheerkaMethod(self.test, False),
|
||||
"test_using_context": SheerkaMethod(self.test_using_context, False),
|
||||
"test_dict": SheerkaMethod(self.test_dict, False),
|
||||
"test_error": SheerkaMethod(self.test_error, False),
|
||||
"is_sheerka": SheerkaMethod(self.is_sheerka, False),
|
||||
"objvalue": SheerkaMethod(self.objvalue, False),
|
||||
"test": SheerkaMethod("test", self.name, self.test, False),
|
||||
"test_using_context": SheerkaMethod("test_using_context", self.name, self.test_using_context, False),
|
||||
"test_dict": SheerkaMethod("test_dict", self.name, self.test_dict, False),
|
||||
"test_error": SheerkaMethod("test_error", self.name, self.test_error, False),
|
||||
"is_sheerka": SheerkaMethod("is_sheerka", self.name, self.is_sheerka, False),
|
||||
"objvalue": SheerkaMethod("objvalue", self.name, self.objvalue, False),
|
||||
}
|
||||
|
||||
self.concepts_ids = None
|
||||
|
||||
self._global_context_hints = set() # hints to add to every execution contexts before every execution
|
||||
|
||||
def __copy__(self):
|
||||
return self
|
||||
|
||||
@@ -135,9 +146,10 @@ class Sheerka(Concept):
|
||||
def root_folder(self):
|
||||
return self.om.root_folder
|
||||
|
||||
def bind_service_method(self, bound_method, has_side_effect, as_name=None, visible=True):
|
||||
def bind_service_method(self, service_name, bound_method, has_side_effect, as_name=None, visible=True):
|
||||
"""
|
||||
Bind service method to sheerka instance for ease of use ?
|
||||
:param service_name:
|
||||
:param bound_method:
|
||||
:param has_side_effect: False if the method is safe
|
||||
:param as_name: give another name to the method
|
||||
@@ -157,7 +169,7 @@ class Sheerka(Concept):
|
||||
signature = inspect.signature(bound_method)
|
||||
if len(signature.parameters) > 0 and list(signature.parameters.keys())[0] == "context":
|
||||
self.methods_with_context.add(as_name)
|
||||
self.sheerka_methods[as_name] = SheerkaMethod(bound_method, has_side_effect)
|
||||
self.sheerka_methods[as_name] = SheerkaMethod(as_name, service_name, bound_method, has_side_effect)
|
||||
if is_pipe_function:
|
||||
self.pipe_functions.add(as_name)
|
||||
|
||||
@@ -368,6 +380,9 @@ class Sheerka(Concept):
|
||||
text,
|
||||
desc=f"Evaluating '{text}'") as execution_context:
|
||||
|
||||
# adds the global context hints if any
|
||||
execution_context.global_hints = self._global_context_hints.copy()
|
||||
|
||||
user_input = self.ret(self.name, True, self.new(BuiltinConcepts.USER_INPUT, body=text, user_name=user_name))
|
||||
execution_context.add_inputs(user_input=user_input)
|
||||
|
||||
@@ -465,17 +480,35 @@ class Sheerka(Concept):
|
||||
|
||||
return None
|
||||
|
||||
def fast_resolve(self, key, return_new=True):
|
||||
def add_recognized_by(c, _recognized_by):
|
||||
c.get_hints().recognized_by = _recognized_by
|
||||
def fast_resolve(self, key, return_new=True, force_instance=False):
|
||||
"""
|
||||
Resolve a concept, but do not use get_by_name() or get_by_id()
|
||||
:param key:
|
||||
:param return_new:
|
||||
:param force_instance: When set, return an concept instance, not a concept definition
|
||||
:return:
|
||||
"""
|
||||
|
||||
def update_hints(c, rec_by, is_inst, is_eval):
|
||||
c.get_hints().recognized_by = rec_by
|
||||
c.get_hints().is_instance = is_inst
|
||||
if is_eval is None:
|
||||
c.get_hints().is_evaluated = len(c.get_metadata().variables) > 0
|
||||
else:
|
||||
c.get_hints().is_evaluated = is_eval
|
||||
return c
|
||||
|
||||
def new_instances(concepts, _recognized_by):
|
||||
def new_instances(concepts, rec_by, is_inst, is_eval):
|
||||
if hasattr(concepts, "__iter__"):
|
||||
return [add_recognized_by(self.new_from_template(c, c.key), _recognized_by) for c in concepts]
|
||||
return [update_hints(self.new_from_template(c, c.key), rec_by, is_inst, is_eval) for c in
|
||||
concepts]
|
||||
|
||||
return add_recognized_by(self.new_from_template(concepts, concepts.key), _recognized_by)
|
||||
return update_hints(self.new_from_template(concepts, concepts.key), rec_by, is_inst, is_eval)
|
||||
|
||||
# ##############
|
||||
# PREPROCESS
|
||||
# ##############
|
||||
# if the entry is a concept token, use its values.
|
||||
if isinstance(key, Token):
|
||||
if key.type == TokenKind.RULE: # do not recognize rules !!!
|
||||
return None
|
||||
@@ -484,10 +517,15 @@ class Sheerka(Concept):
|
||||
elif isinstance(key, str) and key.startswith("c:"):
|
||||
key = core.utils.unstr_concept(key)
|
||||
|
||||
# ##############
|
||||
# Get the concept(s)
|
||||
# ##############
|
||||
if isinstance(key, tuple):
|
||||
if key == (None, None):
|
||||
return None
|
||||
|
||||
is_instance = force_instance
|
||||
is_evaluated = not force_instance
|
||||
if key[1]:
|
||||
concept = self.om.get(self.CONCEPTS_BY_ID_ENTRY, key[1])
|
||||
recognized_by = RECOGNIZED_BY_ID
|
||||
@@ -495,12 +533,15 @@ class Sheerka(Concept):
|
||||
concept = self.om.get(self.CONCEPTS_BY_NAME_ENTRY, key[0])
|
||||
recognized_by = RECOGNIZED_BY_NAME
|
||||
else:
|
||||
is_instance = True
|
||||
is_evaluated = None
|
||||
concept = self.om.get(self.CONCEPTS_BY_NAME_ENTRY, key)
|
||||
recognized_by = RECOGNIZED_BY_NAME
|
||||
|
||||
if concept is NotFound:
|
||||
return None
|
||||
return new_instances(concept, recognized_by) if return_new else concept
|
||||
|
||||
return new_instances(concept, recognized_by, is_instance, is_evaluated) if return_new else concept
|
||||
|
||||
def new(self, concept_key, **kwargs):
|
||||
"""
|
||||
@@ -632,6 +673,16 @@ class Sheerka(Concept):
|
||||
if hasattr(service, "reset_state"):
|
||||
service.reset_state()
|
||||
|
||||
def add_to_context(self, concept_key):
|
||||
concept_key = concept_key.name if isinstance(concept_key, Concept) else concept_key
|
||||
self._global_context_hints.add(concept_key)
|
||||
return self.ret(self.name, True, self.new(BuiltinConcepts.SUCCESS))
|
||||
|
||||
def remove_fom_context(self, concept_key):
|
||||
concept_key = concept_key.name if isinstance(concept_key, Concept) else concept_key
|
||||
self._global_context_hints.remove(concept_key)
|
||||
return self.ret(self.name, True, self.new(BuiltinConcepts.SUCCESS))
|
||||
|
||||
def ret(self, who: str, status: bool, value, parents=None):
|
||||
"""
|
||||
Creates and returns a ReturnValue concept
|
||||
|
||||
@@ -300,7 +300,7 @@ class SheerkaOntologyManager:
|
||||
:param concept:
|
||||
:return:
|
||||
"""
|
||||
return self.current_cache_manager().add_concept(concept)
|
||||
return self.current_cache_manager().add_concept(concept, self.ontologies[0].alt_sdp)
|
||||
|
||||
def update_concept(self, old, new):
|
||||
"""
|
||||
|
||||
@@ -11,7 +11,7 @@ from core.sheerka.services.SheerkaHistoryManager import SheerkaHistoryManager
|
||||
from core.sheerka.services.SheerkaMemory import SheerkaMemory
|
||||
from core.sheerka.services.sheerka_service import BaseService
|
||||
|
||||
CONCEPTS_FILE_FULL = "full.sb"
|
||||
CONCEPTS_FILE_FULL = "full.sb" # .sb for sheerka backup
|
||||
CONCEPTS_FILE_TO_USE = CONCEPTS_FILE_FULL
|
||||
|
||||
|
||||
@@ -22,24 +22,24 @@ class SheerkaAdmin(BaseService):
|
||||
super().__init__(sheerka)
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.caches_names, False)
|
||||
self.sheerka.bind_service_method(self.cache, False)
|
||||
self.sheerka.bind_service_method(self.restore, True)
|
||||
self.sheerka.bind_service_method(self.concepts, False)
|
||||
self.sheerka.bind_service_method(self.desc, False)
|
||||
self.sheerka.bind_service_method(self.desc_evaluators, False)
|
||||
self.sheerka.bind_service_method(self.desc_parsers, False)
|
||||
self.sheerka.bind_service_method(self.extended_isinstance, False)
|
||||
self.sheerka.bind_service_method(self.is_container, False)
|
||||
self.sheerka.bind_service_method(self.format_rules, False)
|
||||
self.sheerka.bind_service_method(self.exec_rules, False)
|
||||
self.sheerka.bind_service_method(self.admin_push_ontology, True, as_name="push_ontology")
|
||||
self.sheerka.bind_service_method(self.admin_pop_ontology, True, as_name="pop_ontology")
|
||||
self.sheerka.bind_service_method(self.ontologies, False)
|
||||
self.sheerka.bind_service_method(self.in_memory, False)
|
||||
self.sheerka.bind_service_method(self.admin_history, False, as_name="history")
|
||||
self.sheerka.bind_service_method(self.sdp, False)
|
||||
self.sheerka.bind_service_method(self.atomic_def, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.caches_names, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.cache, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.restore, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.concepts, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.builtins, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.desc, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.desc_evaluators, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.desc_parsers, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.extended_isinstance, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.is_container, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.format_rules, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.exec_rules, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.admin_push_ontology, True, as_name="push_ontology")
|
||||
self.sheerka.bind_service_method(self.NAME, self.admin_pop_ontology, True, as_name="pop_ontology")
|
||||
self.sheerka.bind_service_method(self.NAME, self.ontologies, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.in_memory, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.admin_history, False, as_name="history")
|
||||
self.sheerka.bind_service_method(self.NAME, self.sdp, False)
|
||||
|
||||
def caches_names(self):
|
||||
"""
|
||||
@@ -138,9 +138,11 @@ class SheerkaAdmin(BaseService):
|
||||
self.sheerka.save_execution_context = False
|
||||
enable_process_return_values_previous_value = self.sheerka.enable_process_return_values
|
||||
self.sheerka.enable_process_return_values = False
|
||||
self.sheerka.add_to_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
|
||||
|
||||
nb_lines, nb_instructions, nb_lines_in_error, min_time, max_time = restore_from_file(backup_file)
|
||||
|
||||
self.sheerka.remove_fom_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
|
||||
self.sheerka.enable_process_return_values = enable_process_return_values_previous_value
|
||||
self.sheerka.save_execution_context = True
|
||||
self.sheerka.during_restore = False
|
||||
@@ -167,6 +169,10 @@ class SheerkaAdmin(BaseService):
|
||||
concepts = sorted(self.sheerka.om.list(self.sheerka.CONCEPTS_BY_ID_ENTRY), key=lambda item: int(item.id))
|
||||
return self.sheerka.new(BuiltinConcepts.TO_LIST, body=concepts)
|
||||
|
||||
def builtins(self):
|
||||
builtins = sorted(self.sheerka.sheerka_methods.values(), key=lambda builtin_method: builtin_method.name)
|
||||
return self.sheerka.new(BuiltinConcepts.TO_LIST, body=builtins)
|
||||
|
||||
def desc_evaluators(self):
|
||||
evaluators = {k: sorted(v[0].items(), reverse=True)
|
||||
for k, v in self.sheerka.services[SheerkaExecute.NAME].grouped_evaluators_cache.items()}
|
||||
@@ -241,20 +247,6 @@ class SheerkaAdmin(BaseService):
|
||||
|
||||
return self.sheerka.isinstance(a, b)
|
||||
|
||||
@staticmethod
|
||||
def atomic_def(a):
|
||||
"""
|
||||
Return the 'atomic definition' of a concept
|
||||
a concept key stripped from its 'var' tokens
|
||||
>>> assert atomic_def(Concept('a plus b').def_var("a").def_var("b")) == "plus"
|
||||
>>> assert atomic_def(Concept('x is a y').def_var("x").def_var("y")) == "is a"
|
||||
:param a:
|
||||
:return:
|
||||
"""
|
||||
ensure_concept(a)
|
||||
|
||||
return a.get_atomic_def()
|
||||
|
||||
@staticmethod
|
||||
def is_container(obj):
|
||||
"""
|
||||
|
||||
@@ -47,12 +47,12 @@ class SheerkaComparisonManager(BaseService):
|
||||
cache = Cache().auto_configure(self.RESOLVED_COMPARISON_ENTRY)
|
||||
self.sheerka.om.register_cache(self.RESOLVED_COMPARISON_ENTRY, cache, persist=False)
|
||||
|
||||
self.sheerka.bind_service_method(self.set_is_greater_than, True)
|
||||
self.sheerka.bind_service_method(self.set_is_less_than, True)
|
||||
self.sheerka.bind_service_method(self.set_is_lesser, True)
|
||||
self.sheerka.bind_service_method(self.set_is_greatest, True)
|
||||
self.sheerka.bind_service_method(self.get_partition, False)
|
||||
self.sheerka.bind_service_method(self.get_weights, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_is_greater_than, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_is_less_than, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_is_lesser, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_is_greatest, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_partition, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_weights, False)
|
||||
|
||||
@staticmethod
|
||||
def _compute_key(prop_name, comparison_context):
|
||||
|
||||
@@ -113,26 +113,26 @@ class SheerkaConceptManager(BaseService):
|
||||
self.compiled_concepts_by_regex = []
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.create_new_concept, True)
|
||||
self.sheerka.bind_service_method(self.modify_concept, True)
|
||||
self.sheerka.bind_service_method(self.remove_concept, True)
|
||||
self.sheerka.bind_service_method(self.set_id_if_needed, True)
|
||||
self.sheerka.bind_service_method(self.set_attr, True)
|
||||
self.sheerka.bind_service_method(self.get_attr, False)
|
||||
self.sheerka.bind_service_method(self.smart_get_attr, False)
|
||||
self.sheerka.bind_service_method(self.set_property, True, as_name="set_prop")
|
||||
self.sheerka.bind_service_method(self.get_property, False, as_name="get_prop")
|
||||
self.sheerka.bind_service_method(self.get_by_key, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.get_by_name, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.get_by_hash, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.get_by_id, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.is_not_a_concept_name, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.is_a_concept_name, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.get_concepts_by_first_token, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.get_concepts_by_first_regex, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.get_concepts_bnf_definitions, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.clear_bnf_definition, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.set_precedence, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.create_new_concept, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.modify_concept, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.remove_concept, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_id_if_needed, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_attr, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_attr, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.smart_get_attr, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_property, True, as_name="set_prop")
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_property, False, as_name="get_prop")
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_by_key, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_by_name, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_by_hash, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_by_id, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.is_not_a_concept_name, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.is_a_concept_name, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_concepts_by_first_token, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_concepts_by_first_regex, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_concepts_bnf_definitions, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.clear_bnf_definition, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_precedence, True)
|
||||
|
||||
register_concept_cache = self.sheerka.om.register_concept_cache
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ from operator import attrgetter
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.builtin_helpers import ensure_concept
|
||||
from core.concept import Concept
|
||||
from core.sheerka.Sheerka import Sheerka
|
||||
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||
from core.sheerka.services.sheerka_service import BaseService
|
||||
|
||||
@@ -28,9 +27,9 @@ class SheerkaConceptsAlgebra(BaseService):
|
||||
super().__init__(sheerka)
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.cadd, False)
|
||||
self.sheerka.bind_service_method(self.csub, False)
|
||||
self.sheerka.bind_service_method(self.recognize, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.cadd, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.csub, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.recognize, False)
|
||||
|
||||
def cadd(self, context, *concepts):
|
||||
"""
|
||||
|
||||
@@ -320,22 +320,22 @@ class SheerkaDebugManager(BaseService):
|
||||
}
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.set_debug, True)
|
||||
self.sheerka.bind_service_method(self.inspect, False)
|
||||
self.sheerka.bind_service_method(self.get_value, False)
|
||||
self.sheerka.bind_service_method(self.get_debugger, False)
|
||||
self.sheerka.bind_service_method(self.reset_debug, False)
|
||||
self.sheerka.bind_service_method(self.set_debug_var, True)
|
||||
self.sheerka.bind_service_method(self.set_debug_rule, True)
|
||||
self.sheerka.bind_service_method(self.set_debug_concept, True)
|
||||
self.sheerka.bind_service_method(self.list_debug_vars, True)
|
||||
self.sheerka.bind_service_method(self.list_debug_rules, True)
|
||||
self.sheerka.bind_service_method(self.list_debug_concepts, True)
|
||||
self.sheerka.bind_service_method(self.register_debug_vars, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.register_debug_rules, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.register_debug_concepts, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_debug, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.inspect, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_value, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_debugger, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.reset_debug, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_debug_var, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_debug_rule, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_debug_concept, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.list_debug_vars, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.list_debug_rules, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.list_debug_concepts, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.register_debug_vars, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.register_debug_rules, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.register_debug_concepts, True, visible=False)
|
||||
|
||||
# self.sheerka.bind_service_method(self.get_debug_settings, False, as_name="debug_settings")
|
||||
# self.sheerka.bind_service_method(self.NAME,self.get_debug_settings, False, as_name="debug_settings")
|
||||
# register what can be registered
|
||||
from parsers.BnfNodeParser import BnfNodeParser
|
||||
from evaluators.DefConceptEvaluator import DefConceptEvaluator
|
||||
@@ -919,4 +919,3 @@ class SheerkaDebugManager(BaseService):
|
||||
del res["self"]
|
||||
|
||||
return res
|
||||
|
||||
|
||||
@@ -20,8 +20,11 @@ class SheerkaDump(BaseService):
|
||||
super().__init__(sheerka)
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.dump_desc, True, "old_desc") # has_side_effect 'cause concept is evaluated
|
||||
self.sheerka.bind_service_method(self.dump_sdp, False, "dump_sdp")
|
||||
self.sheerka.bind_service_method(self.NAME,
|
||||
self.dump_desc,
|
||||
True,
|
||||
"old_desc") # has_side_effect 'cause concept is evaluated
|
||||
self.sheerka.bind_service_method(self.NAME, self.dump_sdp, False, "dump_sdp")
|
||||
|
||||
def dump_desc(self, *concept_names, eval=False):
|
||||
first = True
|
||||
|
||||
@@ -46,10 +46,10 @@ class SheerkaEvaluateConcept(BaseService):
|
||||
self.rule_evaluator = None
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.evaluate_concept, True)
|
||||
self.sheerka.bind_service_method(self.call_concept, True)
|
||||
self.sheerka.bind_service_method(self.call_concept, False, as_name="evaluate_question")
|
||||
self.sheerka.bind_service_method(self.set_auto_eval, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.evaluate_concept, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.call_concept, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.call_concept, False, as_name="evaluate_question")
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_auto_eval, True)
|
||||
|
||||
def initialize_deferred(self, context, is_first_time):
|
||||
self.rule_evaluator = self.sheerka.services[SheerkaEvaluateRules.NAME]
|
||||
@@ -499,9 +499,7 @@ class SheerkaEvaluateConcept(BaseService):
|
||||
|
||||
if current_prop in (ConceptParts.WHERE, ConceptParts.PRE):
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_UNTIL_SUCCESS_REQUESTED)
|
||||
|
||||
if current_prop == ConceptParts.WHERE:
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVALUATING_PRE_OR_WHERE_CLAUSE)
|
||||
|
||||
# when it's a concept, evaluate it
|
||||
if isinstance(to_resolve, Concept) and \
|
||||
@@ -642,6 +640,9 @@ class SheerkaEvaluateConcept(BaseService):
|
||||
if context.sheerka.isa(concept, context.sheerka.new(BuiltinConcepts.AUTO_EVAL)):
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
|
||||
if context.in_context(BuiltinConcepts.EVALUATING_PRE_OR_WHERE_CLAUSE):
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
|
||||
sub_context.add_to_short_term_memory(CURRENT_OBJ, concept)
|
||||
|
||||
try:
|
||||
@@ -764,6 +765,13 @@ class SheerkaEvaluateConcept(BaseService):
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
if concept.get_hints().use_copy or not concept.get_hints().is_instance:
|
||||
concept = concept.copy()
|
||||
concept.get_hints().use_copy = False
|
||||
concept.get_hints().is_instance = True
|
||||
concept.get_hints().is_evaluated = False # force evaluation
|
||||
|
||||
# TODO : update the variables before calling the concept
|
||||
|
||||
evaluated = self.evaluate_concept(context, concept)
|
||||
if self.sheerka.has_error(context, evaluated):
|
||||
|
||||
@@ -18,8 +18,8 @@ class SheerkaEvaluateRules(BaseService):
|
||||
self.network = ReteNetwork()
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.evaluate_format_rules, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.evaluate_exec_rules, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.evaluate_format_rules, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.evaluate_exec_rules, False, visible=False)
|
||||
self.reset_evaluators()
|
||||
self.sheerka.subscribe(EVENT_RULE_CREATED, self.on_rule_created)
|
||||
self.sheerka.subscribe(EVENT_RULE_DELETED, self.on_rule_deleted)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from threading import RLock
|
||||
|
||||
from core.global_symbols import NotFound
|
||||
from core.sheerka.services.sheerka_service import BaseService
|
||||
|
||||
@@ -16,8 +17,8 @@ class SheerkaEventManager(BaseService):
|
||||
self.subscribers = {}
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.subscribe, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.publish, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.subscribe, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.publish, True, visible=False)
|
||||
|
||||
def save_state(self, context):
|
||||
with self._lock:
|
||||
|
||||
@@ -221,12 +221,12 @@ class SheerkaExecute(BaseService):
|
||||
self.rules_eval_service = None
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.execute, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.execute_rules, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.parse_unrecognized, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.parse_function, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.parse_python, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.parse_expression, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.execute, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.execute_rules, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.parse_unrecognized, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.parse_function, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.parse_python, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.parse_expression, False, visible=False)
|
||||
|
||||
self.reset_registered_evaluators()
|
||||
self.reset_registered_parsers()
|
||||
|
||||
@@ -11,8 +11,8 @@ class SheerkaHasAManager(BaseService):
|
||||
super().__init__(sheerka, order=22)
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.set_hasa, True)
|
||||
self.sheerka.bind_service_method(self.hasa, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_hasa, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.hasa, True)
|
||||
|
||||
def set_hasa(self, context, concept_a, concept_b):
|
||||
"""
|
||||
@@ -37,8 +37,13 @@ class SheerkaHasAManager(BaseService):
|
||||
concept=concept_a))
|
||||
|
||||
merged_concepts = merge_sets(concept_a.get_prop(BuiltinConcepts.HASA), {concept_b})
|
||||
|
||||
if context.in_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED):
|
||||
to_add = {"props": {BuiltinConcepts.HASA: merged_concepts}}
|
||||
return self.sheerka.modify_concept(context, concept_a, to_add, modify_source=True)
|
||||
else:
|
||||
concept_a.set_prop(BuiltinConcepts.HASA, merged_concepts)
|
||||
return self.sheerka.ret(self.NAME, True, concept_a)
|
||||
|
||||
def hasa(self, concept_a, concept_b):
|
||||
"""
|
||||
|
||||
@@ -19,12 +19,12 @@ class SheerkaIsAManager(BaseService):
|
||||
super().__init__(sheerka, order=21)
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.set_isa, True)
|
||||
self.sheerka.bind_service_method(self.get_set_elements, True) # concepts are evaluated
|
||||
self.sheerka.bind_service_method(self.add_concept_to_set, True)
|
||||
self.sheerka.bind_service_method(self.isinset, False)
|
||||
self.sheerka.bind_service_method(self.isa, False)
|
||||
self.sheerka.bind_service_method(self.isaset, True) # concept is evaluated, need to change the code
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_isa, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_set_elements, True) # concepts are evaluated
|
||||
self.sheerka.bind_service_method(self.NAME, self.add_concept_to_set, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.isinset, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.isa, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.isaset, True) # concept is evaluated, need to change the code
|
||||
|
||||
cache = SetCache().auto_configure(self.CONCEPTS_GROUPS_ENTRY)
|
||||
self.sheerka.om.register_cache(self.CONCEPTS_GROUPS_ENTRY, cache)
|
||||
@@ -53,6 +53,8 @@ class SheerkaIsAManager(BaseService):
|
||||
# KSI 20200709 add the concept, not its 'id' or 'key'
|
||||
# It will allow conditions handling if concept set has its WHERE or PRE set to something
|
||||
new_concept_set = merge_sets(concept.get_prop(BuiltinConcepts.ISA), {concept_set})
|
||||
|
||||
if context.in_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED):
|
||||
to_add = {"props": {BuiltinConcepts.ISA: new_concept_set}}
|
||||
res = self.sheerka.modify_concept(context, concept, to_add, modify_source=True)
|
||||
if not res.status:
|
||||
@@ -61,8 +63,10 @@ class SheerkaIsAManager(BaseService):
|
||||
concept = res.body.body
|
||||
|
||||
res = self.add_concept_to_set(context, concept, concept_set)
|
||||
|
||||
return res
|
||||
else:
|
||||
concept.set_prop(BuiltinConcepts.ISA, new_concept_set)
|
||||
return self.sheerka.ret(self.NAME, True, concept)
|
||||
|
||||
def add_concept_to_set(self, context, concept, concept_set):
|
||||
"""
|
||||
@@ -270,7 +274,7 @@ class SheerkaIsAManager(BaseService):
|
||||
sub_context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
errors = []
|
||||
for element_id in ids:
|
||||
concept = self.sheerka.fast_resolve((None, element_id))
|
||||
concept = self.sheerka.fast_resolve((None, element_id), force_instance=True)
|
||||
if concept:
|
||||
if len(concept.get_metadata().variables) == 0:
|
||||
evaluated = self.sheerka.evaluate_concept(sub_context, concept)
|
||||
|
||||
@@ -36,21 +36,23 @@ class SheerkaMemory(BaseService):
|
||||
super().__init__(sheerka, order=13)
|
||||
self.short_term_objects = FastCache()
|
||||
self.registration = {}
|
||||
self.enable_memory_registration = True
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.get_from_short_term_memory, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.get_all_short_term_memory, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.add_to_short_term_memory, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.remove_context, True, as_name="clear_short_term_memory", visible=False)
|
||||
self.sheerka.bind_service_method(self.add_to_memory, True)
|
||||
self.sheerka.bind_service_method(self.add_many_to_short_term_memory, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.get_from_memory, False)
|
||||
self.sheerka.bind_service_method(self.get_last_from_memory, False)
|
||||
self.sheerka.bind_service_method(self.register_object, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.unregister_object, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.commit_registered_objects, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.memory, False)
|
||||
self.sheerka.bind_service_method(self.mem, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_from_short_term_memory, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_all_short_term_memory, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.add_to_short_term_memory, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.remove_context, True, as_name="clear_short_term_memory",
|
||||
visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.add_to_memory, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.add_many_to_short_term_memory, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_from_memory, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_last_from_memory, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.register_object, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.unregister_object, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.commit_registered_objects, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.memory, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.mem, False)
|
||||
|
||||
cache = ListIfNeededCache().auto_configure(self.OBJECTS_ENTRY)
|
||||
self.sheerka.om.register_cache(self.OBJECTS_ENTRY, cache, persist=True, use_ref=True)
|
||||
@@ -187,7 +189,7 @@ class SheerkaMemory(BaseService):
|
||||
:param concept:
|
||||
:return:
|
||||
"""
|
||||
if self.sheerka.during_initialisation or self.sheerka.during_restore:
|
||||
if not self.enable_memory_registration or self.sheerka.during_initialisation or self.sheerka.during_restore:
|
||||
return
|
||||
self.registration[key] = concept
|
||||
|
||||
@@ -220,6 +222,8 @@ class SheerkaMemory(BaseService):
|
||||
:param name:
|
||||
:return:
|
||||
"""
|
||||
self.enable_memory_registration = False
|
||||
try:
|
||||
name_to_use = name.name if isinstance(name, Concept) else name
|
||||
self.unregister_object(context, name_to_use)
|
||||
|
||||
@@ -228,6 +232,11 @@ class SheerkaMemory(BaseService):
|
||||
if obj is not NotFound:
|
||||
return obj.obj
|
||||
|
||||
# only filter if it's a valid predicate
|
||||
from parsers.BaseExpressionParser import VariableNode, NameExprNode
|
||||
parsed_ret_val = self.sheerka.parse_expression(context, name_to_use, auto_compile=False)
|
||||
if parsed_ret_val.status and not isinstance(parsed_ret_val.body.body, (VariableNode, NameExprNode)):
|
||||
|
||||
all_objects = self.sheerka.om.list(SheerkaMemory.OBJECTS_ENTRY) # not always a list of list
|
||||
all_objects_copy = [] # to transform into list of list
|
||||
for obj in all_objects:
|
||||
@@ -253,6 +262,8 @@ class SheerkaMemory(BaseService):
|
||||
return res[0] # only the first, as it should have a better timestamp
|
||||
|
||||
return self.sheerka.new(BuiltinConcepts.NOT_FOUND, body={"#name": name_to_use})
|
||||
finally:
|
||||
self.enable_memory_registration = True
|
||||
|
||||
def mem(self):
|
||||
keys = sorted([k for k in self.sheerka.om.list(SheerkaMemory.OBJECTS_ENTRY)])
|
||||
|
||||
@@ -13,7 +13,7 @@ class SheerkaOut(BaseService):
|
||||
self.out_visitors = [ConsoleVisitor(expand_mode="all_but_first")]
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.process_return_values, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.process_return_values, False)
|
||||
self.sheerka.register_debug_vars("Visitor", "create_out_tree", "Exception")
|
||||
self.sheerka.register_debug_vars(SheerkaOut.NAME, "create_out_tree", "out_tree")
|
||||
|
||||
|
||||
@@ -26,13 +26,13 @@ class SheerkaQueryManager(BaseService):
|
||||
self.rule_evaluator = None
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.filter_objects, False)
|
||||
self.sheerka.bind_service_method(self.select_objects, False)
|
||||
self.sheerka.bind_service_method(self.collect_attributes, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.filter_objects, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.select_objects, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.collect_attributes, False)
|
||||
|
||||
self.sheerka.bind_service_method(self.filter_objects, False, as_name="pipe_where")
|
||||
self.sheerka.bind_service_method(self.select_objects, False, as_name="pipe_select")
|
||||
self.sheerka.bind_service_method(self.collect_attributes, False, as_name="pipe_props")
|
||||
self.sheerka.bind_service_method(self.NAME, self.filter_objects, False, as_name="pipe_where")
|
||||
self.sheerka.bind_service_method(self.NAME, self.select_objects, False, as_name="pipe_select")
|
||||
self.sheerka.bind_service_method(self.NAME, self.collect_attributes, False, as_name="pipe_props")
|
||||
|
||||
self.sheerka.register_debug_vars(SheerkaQueryManager.NAME, "filter_objects", "query")
|
||||
|
||||
@@ -59,12 +59,13 @@ class SheerkaQueryManager(BaseService):
|
||||
if k == "__type":
|
||||
conditions.append(f"get_type(self) == {current_variable_name}")
|
||||
|
||||
elif k == "atomic_def":
|
||||
conditions.append(f"atomic_def(self) == {current_variable_name}")
|
||||
|
||||
elif k in ("__self", "_"):
|
||||
conditions.append(f"self == {current_variable_name}")
|
||||
|
||||
elif k.endswith("_contains"):
|
||||
prop_name = k[:-9]
|
||||
conditions.append(f"{current_variable_name} in self.{prop_name}")
|
||||
|
||||
else:
|
||||
conditions.append(f"self.{k} == {current_variable_name}")
|
||||
|
||||
@@ -91,6 +92,7 @@ class SheerkaQueryManager(BaseService):
|
||||
objects = objects.body
|
||||
|
||||
debugger.debug_entering(nb_objects=len(objects), predicate=predicate, **kwargs)
|
||||
|
||||
local_namespace = {}
|
||||
query_by_kwargs = self.get_query_by_kwargs(local_namespace, **kwargs)
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.sheerka.services.sheerka_service import BaseService
|
||||
|
||||
|
||||
@@ -10,7 +9,7 @@ class SheerkaQuestion(BaseService):
|
||||
super().__init__(sheerka)
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.is_question, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.is_question, False)
|
||||
|
||||
@staticmethod
|
||||
def is_question(context):
|
||||
|
||||
@@ -31,14 +31,15 @@ class SheerkaResultManager(BaseService):
|
||||
self.state_vars = ["last_created_concept_id", "last_error_event_id"]
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.get_results_by_digest, True) # digest is recorded
|
||||
self.sheerka.bind_service_method(self.get_results_by_command, True) # digest is recorded
|
||||
self.sheerka.bind_service_method(self.get_last_results, True) # digest is recorded
|
||||
self.sheerka.bind_service_method(self.get_results, False)
|
||||
self.sheerka.bind_service_method(self.get_execution_item, False)
|
||||
self.sheerka.bind_service_method(self.get_last_return_value, False, as_name="last_ret")
|
||||
self.sheerka.bind_service_method(self.get_last_created_concept, False, as_name="last_created_concept")
|
||||
self.sheerka.bind_service_method(self.get_last_error, False, as_name="last_err")
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_results_by_digest, True) # digest is recorded
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_results_by_command, True) # digest is recorded
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_last_results, True) # digest is recorded
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_results, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_execution_item, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_last_return_value, False, as_name="last_ret")
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_last_created_concept, False,
|
||||
as_name="last_created_concept")
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_last_error, False, as_name="last_err")
|
||||
|
||||
self.sheerka.subscribe(EVENT_USER_INPUT_EVALUATED, self.user_input_evaluated)
|
||||
self.sheerka.subscribe(EVENT_CONCEPT_CREATED, self.new_concept_created)
|
||||
@@ -77,6 +78,7 @@ class SheerkaResultManager(BaseService):
|
||||
"""
|
||||
if len(kwargs) == 0:
|
||||
return None
|
||||
|
||||
res = []
|
||||
if "filter" in kwargs:
|
||||
res.append(kwargs["filter"])
|
||||
@@ -90,6 +92,10 @@ class SheerkaResultManager(BaseService):
|
||||
v = '"' + v.translate(str.maketrans({'"': r'\"'})) + '"'
|
||||
res.append(f"{k} == {v}")
|
||||
predicate = " and ".join(res)
|
||||
|
||||
if predicate.strip() == "":
|
||||
return None
|
||||
|
||||
return compile(ast.parse(predicate, mode="eval"), "<SheerkaResultManager.get_predicate>", mode="eval")
|
||||
|
||||
@staticmethod
|
||||
@@ -380,15 +386,16 @@ class SheerkaResultManager(BaseService):
|
||||
|
||||
folder = os.getenv(SHEERKA_BACKUP_FOLDER)
|
||||
if folder is None:
|
||||
print(f"{CCM['red']}Cannot backup command. Backup folder (env SHEERKA_BACKUP_FOLDER) is not defined.{CCM['reset']}")
|
||||
print(
|
||||
f"{CCM['red']}Cannot backup command. Backup folder (env SHEERKA_BACKUP_FOLDER) is not defined.{CCM['reset']}")
|
||||
return
|
||||
|
||||
file = os.getenv(SHEERKA_BACKUP_FILE)
|
||||
if file is None:
|
||||
print(f"{CCM['red']}Cannot backup command. Backup file (env SHEERKA_BACKUP_FILE) is not defined.{CCM['reset']}")
|
||||
print(
|
||||
f"{CCM['red']}Cannot backup command. Backup file (env SHEERKA_BACKUP_FILE) is not defined.{CCM['reset']}")
|
||||
return
|
||||
|
||||
full_path = os.path.join(folder, file)
|
||||
with open(full_path, "a") as f:
|
||||
f.write(f"{execution_context.event.message}\n")
|
||||
|
||||
|
||||
@@ -82,13 +82,13 @@ class SheerkaRuleManager(BaseService):
|
||||
self.expression_parser = LogicalOperatorParser()
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.create_new_rule, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.remove_rule, True)
|
||||
self.sheerka.bind_service_method(self.get_rule_by_id, False)
|
||||
self.sheerka.bind_service_method(self.get_rule_by_name, False)
|
||||
self.sheerka.bind_service_method(self.get_format_rules, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.get_exec_rules, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.resolve_rule, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.create_new_rule, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.remove_rule, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_rule_by_id, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_rule_by_name, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_format_rules, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_exec_rules, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.resolve_rule, False, visible=False)
|
||||
|
||||
cache = Cache().auto_configure(self.FORMAT_RULE_ENTRY)
|
||||
self.sheerka.om.register_cache(self.FORMAT_RULE_ENTRY, cache, True, True)
|
||||
|
||||
@@ -53,14 +53,14 @@ class SheerkaVariableManager(BaseService):
|
||||
}
|
||||
|
||||
def initialize(self):
|
||||
self.sheerka.bind_service_method(self.record_var, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.load_var, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.record_internal_var, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.load_internal_var, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.delete_var, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.set_var, True)
|
||||
self.sheerka.bind_service_method(self.get_var, False)
|
||||
self.sheerka.bind_service_method(self.list_vars, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.record_var, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.load_var, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.record_internal_var, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.load_internal_var, False, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.delete_var, True, visible=False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.set_var, True)
|
||||
self.sheerka.bind_service_method(self.NAME, self.get_var, False)
|
||||
self.sheerka.bind_service_method(self.NAME, self.list_vars, False)
|
||||
|
||||
cache = Cache().auto_configure(self.VARIABLES_ENTRY)
|
||||
self.sheerka.om.register_cache(self.VARIABLES_ENTRY, cache, True, True)
|
||||
|
||||
+46
-8
@@ -327,6 +327,12 @@ def merge_dictionaries(a, b):
|
||||
|
||||
|
||||
def merge_sets(a, b):
|
||||
"""
|
||||
Merge that can handle None
|
||||
:param a:
|
||||
:param b:
|
||||
:return:
|
||||
"""
|
||||
if a is None and b is None:
|
||||
return None
|
||||
|
||||
@@ -494,7 +500,7 @@ def unstr_concept(concept_repr, prefix='c:'):
|
||||
"""
|
||||
if concept_repr is like :c:key:id:
|
||||
return the key and the id
|
||||
>>> assert unstr_concept("c:key:") == "key"
|
||||
>>> assert unstr_concept("c:key:") == ("key", None)
|
||||
>>> assert unstr_concept("c:key|id:") == ("key", "id")
|
||||
>>> assert unstr_concept("c:|id:") == ("None", "id")
|
||||
>>> assert unstr_concept("c:key|:") == ("key", "None")
|
||||
@@ -515,28 +521,30 @@ def unstr_concept(concept_repr, prefix='c:'):
|
||||
key = ""
|
||||
while i < length:
|
||||
c = concept_repr[i]
|
||||
i += 1
|
||||
if c in (":", "|"):
|
||||
break
|
||||
key += c
|
||||
i += 1
|
||||
else:
|
||||
return None, None
|
||||
|
||||
if c == ":":
|
||||
return key if key != "" else None, None
|
||||
return key if key != "" and i == length else None, None
|
||||
|
||||
i += 1
|
||||
id = ""
|
||||
c_id = ""
|
||||
while i < length:
|
||||
c = concept_repr[i]
|
||||
i += 1
|
||||
if c == ":":
|
||||
break
|
||||
id += c
|
||||
i += 1
|
||||
c_id += c
|
||||
else:
|
||||
return None, None
|
||||
|
||||
return key if key != "" else None, id if id != "" else None
|
||||
if i != length:
|
||||
return None, None
|
||||
|
||||
return key if key != "" else None, c_id if c_id != "" else None
|
||||
|
||||
|
||||
def encode_concept(t, wrapper="C"):
|
||||
@@ -682,6 +690,36 @@ def flatten(list_of_lists):
|
||||
return functools.reduce(operator.iconcat, list_of_lists, [])
|
||||
|
||||
|
||||
def replace_after(lst: list, start_item, new_items: list):
|
||||
"""
|
||||
given a list 'lst', replace all items (starting with 'item') with the new_items
|
||||
>>> my_new_items =["alpha", "beta", "gamma"]
|
||||
>>>
|
||||
>>> my_list1 = ["a", "b", "c", "d"]
|
||||
>>> replace_after(my_list1, "c", new_items)
|
||||
>>> assert my_list1 == ["a", "b", "alpha", "beta", "gamma"]
|
||||
>>>
|
||||
>>> my_list2 = ["a", "b", "c", "d"]
|
||||
>>> replace_after(my_list2, "a", new_items)
|
||||
>>> assert my_list2 == ["alpha", "beta", "gamma"]
|
||||
>>> # replace_after(lst, "x", new_items) raises a KeyError
|
||||
|
||||
:param lst:
|
||||
:param start_item:
|
||||
:param new_items:
|
||||
:return:
|
||||
"""
|
||||
for i, current in enumerate(lst):
|
||||
if current == start_item:
|
||||
break
|
||||
else:
|
||||
raise KeyError(start_item)
|
||||
|
||||
del lst[i:]
|
||||
lst.extend(new_items)
|
||||
return lst
|
||||
|
||||
|
||||
def get_text_from_tokens(tokens, custom_switcher=None, tracker=None):
|
||||
"""
|
||||
Create the source code, from the list of token
|
||||
|
||||
@@ -30,7 +30,7 @@ class ExpressionEvaluator(OneReturnValueEvaluator):
|
||||
success = False
|
||||
|
||||
with context.push(BuiltinConcepts.EXEC_CODE, return_value.value.value.source) as sub_context:
|
||||
# sub condition is created only to add a namespace
|
||||
# sub_context is created only to add a namespace
|
||||
|
||||
requested_vars = set()
|
||||
for c in conditions:
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from evaluators.BaseEvaluator import OneReturnValueEvaluator
|
||||
|
||||
|
||||
class PrepareEvalGlobalTruthEvaluator(OneReturnValueEvaluator):
|
||||
"""
|
||||
To recognize when the user input is a global truth
|
||||
"""
|
||||
|
||||
NAME = "PrepareEvalGlobalTruth"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(self.NAME, [BuiltinConcepts.BEFORE_PARSING], 90)
|
||||
self.inner_text = None
|
||||
|
||||
def reset(self):
|
||||
self.inner_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("global_truth(") and text.endswith(")")):
|
||||
return False
|
||||
|
||||
self.inner_text = text[13:-1].strip()
|
||||
if self.inner_text == "":
|
||||
return False
|
||||
|
||||
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.inner_text, user_name=context.event.user_id))
|
||||
|
||||
root = context.get_parents(lambda ec: ec.action in (BuiltinConcepts.EVALUATING_CONCEPT,
|
||||
BuiltinConcepts.PROCESS_INPUT))
|
||||
root = root[0] if root else context
|
||||
root.add_to_protected_hints(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
|
||||
root.add_to_protected_hints(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
root.add_to_protected_hints(BuiltinConcepts.RETURN_BODY_REQUESTED)
|
||||
|
||||
return new_text_to_parse
|
||||
@@ -2,6 +2,7 @@ from core.builtin_concepts import BuiltinConcepts
|
||||
from core.builtin_helpers import resolve_ambiguity
|
||||
from core.concept import Concept
|
||||
from evaluators.BaseEvaluator import AllReturnValuesEvaluator
|
||||
from parsers.BaseNodeParser import ConceptNode
|
||||
|
||||
|
||||
class ResolveAmbiguityEvaluator(AllReturnValuesEvaluator):
|
||||
@@ -24,10 +25,12 @@ class ResolveAmbiguityEvaluator(AllReturnValuesEvaluator):
|
||||
# If they share the same source, that means that there are multiple results for one ParserInput
|
||||
self.sources = {}
|
||||
success = False
|
||||
for ret in [ret for ret in return_values if ret.status]:
|
||||
for ret in [ret for ret in return_values if
|
||||
ret.status and context.sheerka.isinstance(ret.body, BuiltinConcepts.PARSER_RESULT)]:
|
||||
source = self.get_source(context, ret)
|
||||
concept_is_instance = self.get_has_concept_instance(ret)
|
||||
|
||||
if source:
|
||||
if source and concept_is_instance:
|
||||
self.sources.setdefault(source, []).append(ret)
|
||||
|
||||
if len(self.sources[source]) > 1:
|
||||
@@ -39,17 +42,26 @@ class ResolveAmbiguityEvaluator(AllReturnValuesEvaluator):
|
||||
ret = []
|
||||
|
||||
for ret_vals in self.sources.values():
|
||||
parser_results = {id(r.body.body): r.body for r in ret_vals}
|
||||
resolved = resolve_ambiguity(context, [r.body.body for r in ret_vals])
|
||||
presults_concepts_map = {id(self.get_concept(r)): r.body for r in ret_vals}
|
||||
resolved = resolve_ambiguity(context, [self.get_concept(r) for r in ret_vals])
|
||||
if len(resolved) == 0:
|
||||
ret.append(context.sheerka.ret(self.name, True, BuiltinConcepts.NO_RESULT, parents=ret_vals))
|
||||
else:
|
||||
if len(resolved) < len(ret_vals):
|
||||
for c in resolved:
|
||||
ret.append(context.sheerka.ret(self.name, True, parser_results[id(c)], parents=ret_vals))
|
||||
ret.append(context.sheerka.ret(self.name, True, presults_concepts_map[id(c)], parents=ret_vals))
|
||||
|
||||
return None if len(ret) == 0 else ret
|
||||
|
||||
@staticmethod
|
||||
def get_concept(return_value):
|
||||
if isinstance(return_value.body.body, Concept):
|
||||
return return_value.body.body
|
||||
elif isinstance(return_value.body.body, list) and isinstance(return_value.body.body[0], ConceptNode):
|
||||
return return_value.body.body[0].concept
|
||||
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_source(context, return_value):
|
||||
"""
|
||||
@@ -60,6 +72,16 @@ class ResolveAmbiguityEvaluator(AllReturnValuesEvaluator):
|
||||
:return:
|
||||
"""
|
||||
if context.sheerka.isinstance(return_value.body, BuiltinConcepts.PARSER_RESULT) and \
|
||||
isinstance(return_value.body.body, Concept):
|
||||
(isinstance(return_value.body.body, Concept) or
|
||||
(isinstance(return_value.body.body, list) and
|
||||
len(return_value.body.body) == 1) and
|
||||
isinstance(return_value.body.body[0], ConceptNode)):
|
||||
return return_value.body.source
|
||||
return None
|
||||
|
||||
def get_has_concept_instance(self, return_value):
|
||||
concept = self.get_concept(return_value)
|
||||
if concept is None:
|
||||
return False
|
||||
|
||||
return concept.get_hints().is_instance
|
||||
|
||||
@@ -7,7 +7,7 @@ from parsers.BaseParser import BaseParser
|
||||
|
||||
class ValidateConceptEvaluator(OneReturnValueEvaluator):
|
||||
"""
|
||||
To recognize when the user input is a question
|
||||
Filter the concept that does not meet its pre and where conditions
|
||||
"""
|
||||
|
||||
NAME = "ValidateConcept"
|
||||
@@ -40,9 +40,12 @@ class ValidateConceptEvaluator(OneReturnValueEvaluator):
|
||||
|
||||
def eval(self, context, return_value):
|
||||
"""
|
||||
This evaluator returns None is the concept validates its PRE and POST constraint or if the constraint cannot
|
||||
be validated
|
||||
This evaluator returns None if
|
||||
* the constraint cannot be validated
|
||||
* the concept is already a copy and it validates its PRE and POST constraint
|
||||
If the constraint can be validated, but fails, an error is returned
|
||||
If concept was not a copy and the constraint is validated, an evaluated copy is returned
|
||||
|
||||
:param context:
|
||||
:param return_value:
|
||||
:return:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from dataclasses import dataclass
|
||||
from itertools import product
|
||||
from typing import List, Union
|
||||
|
||||
from core.builtin_concepts_ids import BuiltinConcepts
|
||||
@@ -453,7 +454,7 @@ class BaseExpressionParser(BaseParser):
|
||||
|
||||
return ret
|
||||
|
||||
def parse_input(self, context, parser_input, error_sink):
|
||||
def parse_input(self, context, parser_input: ParserInput, error_sink: list):
|
||||
raise NotImplementedError
|
||||
|
||||
def parse_tokens_stop_condition(self, token, parser_input):
|
||||
@@ -666,3 +667,71 @@ class IsAQuestionVisitor(ExpressionVisitor):
|
||||
def is_a_question(self, expr_node):
|
||||
res = self.visit(expr_node)
|
||||
return isinstance(res, bool) and res
|
||||
|
||||
|
||||
def compile_disjunctions(expr_node, nest: bool = True):
|
||||
def get_start_end(items):
|
||||
start, end = None, None
|
||||
for item in items:
|
||||
if start is None or item.start < start:
|
||||
start = item.start
|
||||
if end is None or item.end > end:
|
||||
end = item.end
|
||||
|
||||
return start, end
|
||||
|
||||
def _compile_disjunctions(node, _nest: bool = True):
|
||||
if isinstance(node, OrNode):
|
||||
inner = []
|
||||
for part in node.parts:
|
||||
result = _compile_disjunctions(part, _nest=False)
|
||||
if isinstance(result, tuple):
|
||||
inner.extend(result)
|
||||
else:
|
||||
inner.append(result)
|
||||
return tuple(inner)
|
||||
|
||||
elif isinstance(node, AndNode):
|
||||
inner = []
|
||||
for ele in node.parts:
|
||||
if isinstance(ele, NotNode):
|
||||
t = _compile_disjunctions(ele),
|
||||
inner.append(t)
|
||||
else:
|
||||
inner.append(_compile_disjunctions(ele))
|
||||
|
||||
temp_res = tuple(product(*inner))
|
||||
|
||||
all_conjunctions = []
|
||||
for conjunctions in temp_res:
|
||||
# first transform 'a and (b and c)' into 'a and b and c'
|
||||
conjunctions_to_use = []
|
||||
for item in conjunctions:
|
||||
if isinstance(item, tuple) and isinstance(item[0], AndNode):
|
||||
conjunctions_to_use.extend(item[0].parts)
|
||||
elif isinstance(item, AndNode):
|
||||
conjunctions_to_use.extend(item.parts)
|
||||
else:
|
||||
conjunctions_to_use.append(item)
|
||||
|
||||
start, end = get_start_end(conjunctions_to_use)
|
||||
all_conjunctions.append(AndNode(start, end, expr_node.tokens[start: end + 1], *conjunctions_to_use))
|
||||
return tuple(all_conjunctions)
|
||||
|
||||
elif isinstance(node, NotNode):
|
||||
inner = _compile_disjunctions(node.node)
|
||||
if len(inner) == 1:
|
||||
return node, # do not remove the comma, it's a tuple
|
||||
|
||||
temp_res = tuple(NotNode(branch.start, branch.end, [], branch) for branch in inner)
|
||||
start, end = get_start_end(temp_res)
|
||||
conjunction = AndNode(start, end, expr_node.tokens[start: end + 1], *temp_res)
|
||||
return conjunction, # do not remove the comma, it's a tuple
|
||||
|
||||
elif _nest:
|
||||
return node, # do not remove the comma, it's a tuple
|
||||
|
||||
else:
|
||||
return node
|
||||
|
||||
return list(_compile_disjunctions(expr_node, nest))
|
||||
|
||||
@@ -224,8 +224,14 @@ class ConceptNode(LexerNode):
|
||||
return f'CN({self.concept})'
|
||||
|
||||
def get_concept(self):
|
||||
"""
|
||||
Used when there is a mix of Concept and ConceptNode
|
||||
To quickly get the inner concept
|
||||
:return:
|
||||
"""
|
||||
return self.concept
|
||||
|
||||
|
||||
class SourceCodeNode(LexerNode):
|
||||
"""
|
||||
Returned when some source code (like Python source code is recognized)
|
||||
|
||||
@@ -250,23 +250,3 @@ class BaseParserInputParser(BaseParser):
|
||||
end -= 1
|
||||
|
||||
return start, end
|
||||
|
||||
@staticmethod
|
||||
def merge_concepts(list_a, b):
|
||||
if not b:
|
||||
return list_a
|
||||
|
||||
list_b = b if isinstance(b, list) else [b]
|
||||
|
||||
if not list_a:
|
||||
return list_b
|
||||
|
||||
by_ids = {c.id for c in list_b}
|
||||
for c in list_b:
|
||||
if c.id in by_ids: # and c.metadata.is_evaluated == by_ids[c.id].metadata.is_evaluated:
|
||||
continue
|
||||
|
||||
list_a.append(c)
|
||||
by_ids.add(c.id)
|
||||
|
||||
return list_a
|
||||
|
||||
@@ -52,7 +52,7 @@ class RegExDef:
|
||||
return flags
|
||||
|
||||
def serialize(self):
|
||||
return f"{self.to_match}__!##ZZSEPZZ##!__{self.ignore_case}|{self.multiline}|{self.explicit_flags}"
|
||||
return f"{self.to_match}__!##ZZSEPZZ##!__{self.ignore_case}|{self.multiline}|{int(self.explicit_flags)}"
|
||||
|
||||
def deserialize(self, txt):
|
||||
parts = txt.split("__!##ZZSEPZZ##!__")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import core.builtin_helpers
|
||||
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
|
||||
from core.concept import VARIABLE_PREFIX
|
||||
from core.sheerka.Sheerka import RECOGNIZED_BY_KEY
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import TokenKind
|
||||
from core.utils import str_concept
|
||||
@@ -43,6 +44,7 @@ class ExactConceptParser(BaseParserInputParser):
|
||||
body = sheerka.new(BuiltinConcepts.NOT_FOR_ME, body=parser_input.as_text(), reason=too_long)
|
||||
return sheerka.ret(self.name, False, body)
|
||||
|
||||
# First, get the concept using there keys
|
||||
already_recognized = [] # keep track of the concepts founds
|
||||
for combination in self.combinations(words):
|
||||
|
||||
@@ -75,11 +77,19 @@ class ExactConceptParser(BaseParserInputParser):
|
||||
value = words[i]
|
||||
concept.def_var_by_index(index, str_concept(value) if isinstance(value, tuple) else value)
|
||||
concept.get_hints().need_validation = True
|
||||
concept.get_hints().recognized_by = RECOGNIZED_BY_KEY
|
||||
|
||||
already_recognized.append(concept)
|
||||
|
||||
# Also try to recognize concepts by their names
|
||||
by_name = sheerka.fast_resolve(parser_input.as_text())
|
||||
core.builtin_helpers.set_is_evaluated(by_name)
|
||||
if by_name:
|
||||
core.builtin_helpers.update_concepts_hints(by_name,
|
||||
# recognized_by=RECOGNIZED_BY_NAME, # keep fast_resolve settings
|
||||
is_instance=False,
|
||||
is_evaluated=True)
|
||||
|
||||
# merge the two
|
||||
recognized = self.merge_concepts(already_recognized, by_name)
|
||||
for c in recognized:
|
||||
c.get_hints().use_copy = True
|
||||
@@ -169,6 +179,32 @@ class ExactConceptParser(BaseParserInputParser):
|
||||
res.append(vars[value] if value in vars else value)
|
||||
return tuple(res)
|
||||
|
||||
@staticmethod
|
||||
def merge_concepts(concepts_by_key, concepts_by_name):
|
||||
"""
|
||||
Merge concepts when the id is the same and there is no variable
|
||||
:param concepts_by_key:
|
||||
:param concepts_by_name:
|
||||
:return:
|
||||
"""
|
||||
if not concepts_by_name:
|
||||
return concepts_by_key
|
||||
|
||||
concepts_by_name = concepts_by_name if isinstance(concepts_by_name, list) else [concepts_by_name]
|
||||
|
||||
if not concepts_by_key:
|
||||
return concepts_by_name
|
||||
|
||||
by_ids = {c.id for c in concepts_by_key}
|
||||
for c in concepts_by_name:
|
||||
if c.id in by_ids:
|
||||
continue # keep the 'by_key' version to allow evaluation
|
||||
|
||||
concepts_by_key.append(c)
|
||||
by_ids.add(c.id)
|
||||
|
||||
return concepts_by_key
|
||||
|
||||
def as_return_value(self, context, parser_input, concept):
|
||||
return ReturnValueConcept(
|
||||
self.name,
|
||||
|
||||
@@ -2,6 +2,7 @@ from dataclasses import dataclass
|
||||
|
||||
from core import builtin_helpers
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.builtin_helpers import update_concepts_hints
|
||||
from core.concept import DEFINITION_TYPE_BNF, Concept
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Tokenizer, TokenKind
|
||||
@@ -230,7 +231,8 @@ class SequenceNodeParser(BaseNodeParser):
|
||||
:param concept:
|
||||
:return:
|
||||
"""
|
||||
return len(concept.get_metadata().variables) == 0 and concept.get_metadata().definition_type != DEFINITION_TYPE_BNF
|
||||
return len(concept.get_metadata().variables) == 0 \
|
||||
and concept.get_metadata().definition_type != DEFINITION_TYPE_BNF
|
||||
|
||||
def get_concepts(self, token, to_keep, custom=None, to_map=None, strip_quotes=False):
|
||||
|
||||
@@ -245,11 +247,11 @@ class SequenceNodeParser(BaseNodeParser):
|
||||
|
||||
def as_list(a):
|
||||
if a is None:
|
||||
return a
|
||||
return None
|
||||
|
||||
return a if isinstance(a, list) else [a]
|
||||
|
||||
concepts_by_name = as_list(self.sheerka.resolve(token))
|
||||
concepts_by_name = as_list(self.sheerka.fast_resolve(token))
|
||||
concepts_by_first_keyword = new_instances(self.sheerka.get_concepts_by_first_token(token, self._is_eligible))
|
||||
|
||||
if concepts_by_name is None:
|
||||
@@ -339,11 +341,17 @@ class SequenceNodeParser(BaseNodeParser):
|
||||
It will use the name of the concept, but also its compact form (c::)
|
||||
:return:
|
||||
"""
|
||||
|
||||
source = self.parser_input.as_text()
|
||||
concepts = self.sheerka.resolve(source.strip())
|
||||
concepts = self.sheerka.fast_resolve(source.strip())
|
||||
if concepts is None:
|
||||
return None
|
||||
|
||||
update_concepts_hints(concepts,
|
||||
# recognized_by=RECOGNIZED_BY_NAME, # keep fast_resolve settings
|
||||
is_instance=False,
|
||||
is_evaluated=True)
|
||||
|
||||
concepts = [concepts] if isinstance(concepts, Concept) else concepts
|
||||
res = []
|
||||
start, end = self.get_tokens_boundaries(self.parser_input.as_tokens())
|
||||
@@ -414,6 +422,8 @@ class SequenceNodeParser(BaseNodeParser):
|
||||
|
||||
sequences = self.get_concepts_sequences()
|
||||
if by_name := self.get_by_name():
|
||||
# note that concepts by names must be appended, not prepended
|
||||
# In case of conflict, we want to keep the one found by get_concepts_sequences()
|
||||
sequences.extend(by_name)
|
||||
|
||||
parser_helpers = self.get_valid(sequences)
|
||||
|
||||
@@ -11,7 +11,7 @@ from core.global_symbols import CONCEPT_COMPARISON_CONTEXT, SyaAssociativity
|
||||
from core.sheerka.services.SheerkaComparisonManager import SheerkaComparisonManager
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import Token, TokenKind, Tokenizer
|
||||
from core.utils import get_n_clones, get_text_from_tokens, NextIdManager
|
||||
from core.utils import get_n_clones, get_text_from_tokens, NextIdManager, replace_after
|
||||
from parsers.BaseNodeParser import UnrecognizedTokensNode, ConceptNode, SourceCodeNode, \
|
||||
SourceCodeWithConceptNode, BaseNodeParser, VariableNode
|
||||
from parsers.BaseParser import ParsingError
|
||||
@@ -185,6 +185,19 @@ class SyaConceptParserHelper:
|
||||
if token.type != TokenKind.WHITESPACE:
|
||||
self.expected_parameters_before_first_token += 1
|
||||
|
||||
# remove useless whitespaces (spaces that are between VAR_DEF)
|
||||
if len(self.expected) > 2:
|
||||
temp = [self.expected[0]]
|
||||
for i in range(1, len(self.expected) - 1):
|
||||
token = self.expected[i]
|
||||
if (token.type == TokenKind.WHITESPACE and
|
||||
self.expected[i - 1].type == TokenKind.VAR_DEF and
|
||||
self.expected[i + 1].type == TokenKind.VAR_DEF):
|
||||
continue # skip it
|
||||
temp.append(token)
|
||||
temp.append(self.expected[-1])
|
||||
self.expected = temp
|
||||
|
||||
self.eat_token(first_keyword_found) # remove the first token
|
||||
self.tokens.append(first_keyword_found)
|
||||
|
||||
@@ -496,10 +509,19 @@ class InFixToPostFix:
|
||||
:return:
|
||||
"""
|
||||
if len(self.parameters_list) < parser_helper.expected_parameters_before_first_token:
|
||||
# There is not enough parameters to fill the new concept
|
||||
# Try to develop the UnrecognizedTokesNode, to see if it can match
|
||||
developed_param_list = self.develop_parameter_list(self.parameters_list)
|
||||
if len(developed_param_list) < parser_helper.expected_parameters_before_first_token:
|
||||
# The new concept expect some prefix parameters, but there's not enough
|
||||
parser_helper.error = "Not enough prefix parameters"
|
||||
return
|
||||
|
||||
# the developed_param_list does the job. Let's replace the previous values
|
||||
pivot = self.parameters_list[0]
|
||||
replace_after(self.parameters_list, pivot, developed_param_list)
|
||||
replace_after(self.out, pivot, developed_param_list)
|
||||
|
||||
if len(self.parameters_list) > parser_helper.expected_parameters_before_first_token:
|
||||
# There are more parameters than needed by the new concept
|
||||
# These others parameters are either
|
||||
@@ -530,6 +552,20 @@ class InFixToPostFix:
|
||||
:return:
|
||||
"""
|
||||
|
||||
def nb_expected_parameters(expected):
|
||||
"""
|
||||
Count the number of successive variables that are expected
|
||||
:param expected:
|
||||
:return:
|
||||
"""
|
||||
i = 0
|
||||
for token in expected:
|
||||
if token.type == TokenKind.VAR_DEF:
|
||||
i += 1
|
||||
else:
|
||||
break
|
||||
return i
|
||||
|
||||
# manage parenthesis that didn't find any match
|
||||
if self._is_lpar(self.stack[-1]):
|
||||
self._add_error(ParenthesisMismatchError(self.stack[-1]))
|
||||
@@ -538,6 +574,16 @@ class InFixToPostFix:
|
||||
assert len(self._concepts()) != 0 # sanity check
|
||||
|
||||
current_concept = self._concepts()[-1]
|
||||
|
||||
if (nb_expected := nb_expected_parameters(current_concept.expected)) > len(self.parameters_list):
|
||||
# There is not enough parameters in the list to fill the concept
|
||||
# Try to develop the UnrecognizedTokensNode to see if it can match
|
||||
developed_param_list = self.develop_parameter_list(self.parameters_list)
|
||||
if nb_expected == len(developed_param_list):
|
||||
pivot = self.parameters_list[0]
|
||||
replace_after(self.parameters_list, pivot, developed_param_list)
|
||||
replace_after(self.out, pivot, developed_param_list)
|
||||
|
||||
while len(current_concept.expected) > 0 and current_concept.expected[0].type == TokenKind.VAR_DEF:
|
||||
# eat everything that was expected
|
||||
if len(self.parameters_list) == 0:
|
||||
@@ -640,13 +686,24 @@ class InFixToPostFix:
|
||||
Helper function that pops the stack and put the item to the output, if needed
|
||||
:return:
|
||||
"""
|
||||
|
||||
item = self.stack[-1]
|
||||
|
||||
# fix the concept is needed
|
||||
if isinstance(item, SyaConceptParserHelper):
|
||||
if len(item.expected) > 0:
|
||||
# make sure the expected parameters of this item are eaten
|
||||
if 0 < len(item.expected) <= len(self.parameters_list):
|
||||
if len(item.expected) <= len(self.parameters_list):
|
||||
self.manage_parameters()
|
||||
else:
|
||||
# second chance to match the parameter list when it contains unrecognized token
|
||||
developed_param_list = self.develop_parameter_list(self.parameters_list)
|
||||
if len(item.expected) <= len(developed_param_list):
|
||||
pivot = self.parameters_list[0]
|
||||
replace_after(self.parameters_list, pivot, developed_param_list)
|
||||
replace_after(self.out, pivot, developed_param_list)
|
||||
self.manage_parameters()
|
||||
|
||||
item.fix_concept()
|
||||
|
||||
self.stack.pop()
|
||||
@@ -1119,6 +1176,25 @@ class InFixToPostFix:
|
||||
# clone.forked = self.forked
|
||||
return clone
|
||||
|
||||
@staticmethod
|
||||
def develop_parameter_list(parameter_list):
|
||||
"""
|
||||
given a list of parameter (solely from self.parameter_list)
|
||||
develop UnrecognizedTokensNode parameter that contains whitespaces
|
||||
:param parameter_list:
|
||||
:return:
|
||||
"""
|
||||
temp = []
|
||||
for parameter in parameter_list:
|
||||
if isinstance(parameter, UnrecognizedTokensNode):
|
||||
for i, token in [(i, t) for i, t in enumerate(parameter.tokens) if t.type != TokenKind.WHITESPACE]:
|
||||
temp.append(UnrecognizedTokensNode(parameter.start + i,
|
||||
parameter.start + i,
|
||||
[token]))
|
||||
else:
|
||||
temp.append(parameter)
|
||||
return temp
|
||||
|
||||
|
||||
@dataclass()
|
||||
class PostFixToItem:
|
||||
@@ -1428,8 +1504,8 @@ class SyaNodeParser(BaseNodeParser):
|
||||
def _has_sya(items):
|
||||
for item in items:
|
||||
if isinstance(item, SourceCodeWithConceptNode):
|
||||
if _has_sya(item.nodes):
|
||||
return True
|
||||
return _has_sya(item.nodes)
|
||||
|
||||
if isinstance(item, SyaConceptParserHelper):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -41,6 +41,8 @@ class SheerkaPickler:
|
||||
self.to_reduce.append(ToReduce(lambda o: isinstance(o, (BaseParser, BaseEvaluator)), lambda o: o.name))
|
||||
self.to_reduce.append(ToReduce(lambda o: isinstance(o, ParserInput), lambda o: o.as_text()))
|
||||
self.to_reduce.append(ToReduce(lambda o: isinstance(o, Ontology), lambda o: o.name))
|
||||
from core.sheerka.Sheerka import SheerkaMethod
|
||||
self.to_reduce.append(ToReduce(lambda o: isinstance(o, SheerkaMethod), lambda o: o.name))
|
||||
|
||||
def flatten(self, obj):
|
||||
if utils.is_to_discard(obj):
|
||||
|
||||
@@ -155,7 +155,7 @@ def resolve_object(context, who, obj):
|
||||
raise Exception()
|
||||
|
||||
if (isinstance(obj, str) and obj.startswith("c:")) or isinstance(obj, Token):
|
||||
concept = context.sheerka.fast_resolve(obj)
|
||||
concept = context.sheerka.fast_resolve(obj, force_instance=True)
|
||||
if concept is None:
|
||||
return None
|
||||
|
||||
|
||||
+19
-5
@@ -104,7 +104,7 @@ class BaseTest:
|
||||
def get_sheerka(self, **kwargs) -> Sheerka:
|
||||
pass
|
||||
|
||||
def get_context(self, sheerka=None, eval_body=False, eval_where=False, message=""):
|
||||
def get_context(self, sheerka=None, eval_body=False, eval_where=False, global_truth=False, message=""):
|
||||
context = ExecutionContext("test",
|
||||
Event(message=message),
|
||||
sheerka or self.get_sheerka(),
|
||||
@@ -114,20 +114,29 @@ class BaseTest:
|
||||
context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||
if eval_where:
|
||||
context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
|
||||
if global_truth:
|
||||
context.protected_hints.add(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
|
||||
|
||||
return context
|
||||
|
||||
@staticmethod
|
||||
def get_init_test_args(**kwargs):
|
||||
return {k: v for k, v in kwargs.items() if k in ["cache_only", "ontology", "eval_body", "eval_where"]}
|
||||
return {k: v for k, v in kwargs.items() if k in ["cache_only",
|
||||
"ontology",
|
||||
"eval_body",
|
||||
"eval_where",
|
||||
"global_truth"]}
|
||||
|
||||
@staticmethod
|
||||
def get_with_concepts_args(**kwargs):
|
||||
return {k: v for k, v in kwargs.items() if k in ["create_new"]}
|
||||
|
||||
def init_test(self, cache_only=None, ontology=None, eval_body=False, eval_where=False):
|
||||
def init_test(self, cache_only=None, ontology=None, eval_body=False, eval_where=False, global_truth=False):
|
||||
sheerka = self.get_sheerka(cache_only=cache_only, ontology=ontology)
|
||||
context = self.get_context(sheerka=sheerka, eval_body=eval_body, eval_where=eval_where)
|
||||
context = self.get_context(sheerka=sheerka,
|
||||
eval_body=eval_body,
|
||||
eval_where=eval_where,
|
||||
global_truth=global_truth)
|
||||
|
||||
return InitTestHelper(sheerka, context)
|
||||
|
||||
@@ -255,14 +264,19 @@ class BaseTest:
|
||||
concept.get_metadata().variables[k] = v
|
||||
return concept
|
||||
|
||||
def init_scenario(self, init_expressions):
|
||||
def init_scenario(self, init_expressions, global_truth=False):
|
||||
sheerka = self.get_sheerka()
|
||||
if global_truth:
|
||||
sheerka.add_to_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
|
||||
|
||||
for expression in init_expressions:
|
||||
res = sheerka.evaluate_user_input(expression)
|
||||
assert len(res) == 1, f"Failed to execute '{expression}'"
|
||||
assert res[0].status, f"Error while executing '{expression}'"
|
||||
|
||||
if global_truth:
|
||||
sheerka.remove_fom_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
|
||||
|
||||
return sheerka
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -7,9 +7,9 @@ from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_add_concepts(self):
|
||||
sheerka, context, man, human, male, driver, licence, car = self.init_concepts(
|
||||
sheerka, context, man, human, male, driver, licence, car = self.init_test(global_truth=True).with_concepts(
|
||||
"man", "human", "male",
|
||||
"driver", "licence", "car")
|
||||
"driver", "licence", "car").unpack()
|
||||
|
||||
sheerka.set_isa(context, sheerka.new("man"), human)
|
||||
sheerka.set_isa(context, sheerka.new("man"), male)
|
||||
@@ -23,8 +23,8 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
|
||||
BuiltinConcepts.HASA: {car, licence}, }
|
||||
|
||||
def test_can_add_concepts_when_property_already_exist(self):
|
||||
sheerka, context, man, human, king, male = self.init_concepts(
|
||||
"man", "human", "king", "male")
|
||||
sheerka, context, man, human, king, male = self.init_test(global_truth=True).with_concepts(
|
||||
"man", "human", "king", "male").unpack()
|
||||
|
||||
sheerka.set_isa(context, sheerka.new("man"), human)
|
||||
sheerka.set_isa(context, sheerka.new("king"), male)
|
||||
@@ -35,9 +35,9 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
|
||||
assert res.get_metadata().props == {BuiltinConcepts.ISA: {male, human}}
|
||||
|
||||
def test_i_can_subtract_concepts(self):
|
||||
sheerka, context, foo, bar, isa1, isa2, hasa1, hasa2 = self.init_concepts(
|
||||
sheerka, context, foo, bar, isa1, isa2, hasa1, hasa2 = self.init_test(global_truth=True).with_concepts(
|
||||
"foo", "bar",
|
||||
"isa1", "isa2", "has1", "has2")
|
||||
"isa1", "isa2", "has1", "has2").unpack()
|
||||
|
||||
new_foo = sheerka.new("foo")
|
||||
sheerka.set_isa(context, new_foo, isa1)
|
||||
@@ -61,9 +61,10 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
|
||||
BuiltinConcepts.HASA: {hasa2}, }
|
||||
|
||||
def test_i_can_recognize_myself_when_using_sdp_repository(self):
|
||||
sheerka, context, foo, isa1, hasa1, = self.init_test(cache_only=False). \
|
||||
with_concepts("foo", "isa1", "has1", create_new=True). \
|
||||
unpack()
|
||||
sheerka, context, foo, isa1, hasa1, = self.init_test(cache_only=False, global_truth=True).with_concepts(
|
||||
"foo",
|
||||
"isa1",
|
||||
"has1", create_new=True).unpack()
|
||||
sheerka.om.commit(context)
|
||||
|
||||
new_foo = sheerka.new("foo")
|
||||
@@ -74,7 +75,10 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
|
||||
assert sheerka.recognize(new_foo, all_scores=True) == [ConceptScore(1, new_foo, new_foo)]
|
||||
|
||||
def test_i_can_recognize_myself_when_not_using_sdp_repository(self):
|
||||
sheerka, context, foo, isa1, hasa1, = self.init_concepts("foo", "isa1", "has1")
|
||||
sheerka, context, foo, isa1, hasa1, = self.init_test(global_truth=True).with_concepts(
|
||||
"foo",
|
||||
"isa1",
|
||||
"has1").unpack()
|
||||
|
||||
new_foo = sheerka.new("foo")
|
||||
sheerka.set_isa(context, new_foo, isa1)
|
||||
@@ -100,9 +104,9 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
|
||||
assert sheerka.recognize(Concept(), all_scores=True) == []
|
||||
|
||||
def test_i_can_recognize_multiple_concepts_with_the_proper_score(self):
|
||||
sheerka, context, foo, bar, isa1, isa2, hasa1, hasa2 = self.init_concepts(
|
||||
sheerka, context, foo, bar, isa1, isa2, hasa1, hasa2 = self.init_test(global_truth=True).with_concepts(
|
||||
"foo", "bar",
|
||||
"isa1", "isa2", "has1", "has2")
|
||||
"isa1", "isa2", "has1", "has2").unpack()
|
||||
|
||||
new_foo = sheerka.new("foo")
|
||||
sheerka.set_isa(context, new_foo, isa1)
|
||||
@@ -131,9 +135,9 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
|
||||
ConceptScore(0.5, sheerka.new("bar"), to_recognize)]
|
||||
|
||||
def test_i_can_recognize_if_all_scores_is_disabled(self):
|
||||
sheerka, context, foo, bar, isa1, isa2, hasa1, hasa2 = self.init_concepts(
|
||||
sheerka, context, foo, bar, isa1, isa2, hasa1, hasa2 = self.init_test(global_truth=True).with_concepts(
|
||||
"foo", "bar",
|
||||
"isa1", "isa2", "has1", "has2")
|
||||
"isa1", "isa2", "has1", "has2").unpack()
|
||||
|
||||
new_foo = sheerka.new("foo")
|
||||
sheerka.set_isa(context, new_foo, isa1)
|
||||
@@ -153,9 +157,9 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
|
||||
assert res == ConceptScore(1.0, sheerka.new("bar"), to_recognize)
|
||||
|
||||
def test_i_can_recognize_if_all_scores_is_disabled_but_multiple_high_scores(self):
|
||||
sheerka, context, foo, bar, isa1, hasa1 = self.init_concepts(
|
||||
sheerka, context, foo, bar, isa1, hasa1 = self.init_test(global_truth=True).with_concepts(
|
||||
"foo", "bar",
|
||||
"isa1", "has1")
|
||||
"isa1", "has1").unpack()
|
||||
|
||||
new_foo = sheerka.new("foo")
|
||||
sheerka.set_isa(context, new_foo, isa1)
|
||||
|
||||
@@ -1105,13 +1105,14 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
Concept("hundreds", definition="number hundred"),
|
||||
)
|
||||
|
||||
sheerka.set_isa(context, sheerka.new("one"), number)
|
||||
sheerka.set_isa(context, sheerka.new("two"), number)
|
||||
sheerka.set_isa(context, sheerka.new("twenty"), number)
|
||||
sheerka.set_isa(context, sheerka.new("thirty"), number)
|
||||
sheerka.set_isa(context, sheerka.new("hundred"), number)
|
||||
sheerka.set_isa(context, sheerka.new("twenties"), number)
|
||||
sheerka.set_isa(context, sheerka.new("hundreds"), number)
|
||||
global_truth_context = self.get_context(sheerka, global_truth=True)
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("one"), number)
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("two"), number)
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("twenty"), number)
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("thirty"), number)
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("hundred"), number)
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("twenties"), number)
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("hundreds"), number)
|
||||
|
||||
sheerka.clear_bnf_definition() # reset all the grammar to simulate Sheerka restart
|
||||
|
||||
@@ -1129,12 +1130,12 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
}
|
||||
|
||||
def test_i_can_resolve_when_concepts_have_multiple_levels_of_sets(self):
|
||||
sheerka, context, adjective, color, red, qualified_table = self.init_concepts(
|
||||
sheerka, context, adjective, color, red, qualified_table = self.init_test(global_truth=True).with_concepts(
|
||||
"adjective",
|
||||
"color",
|
||||
"red",
|
||||
Concept("qualified table", definition="adjective 'table'"),
|
||||
)
|
||||
).unpack()
|
||||
|
||||
sheerka.set_isa(context, color, adjective)
|
||||
sheerka.set_isa(context, red, color)
|
||||
@@ -1404,7 +1405,8 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||
def test_i_cannot_smart_get_attr_when_attribute_does_not_exist(self):
|
||||
sheerka, context, adjective, color, red, size, table = self.init_concepts("adjective",
|
||||
"color",
|
||||
Concept("red", body="red").auto_init(),
|
||||
Concept("red",
|
||||
body="red").auto_init(),
|
||||
"size",
|
||||
"table",
|
||||
create_new=True)
|
||||
|
||||
@@ -391,8 +391,8 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
:return:
|
||||
"""
|
||||
sheerka, context, predicate, foo = self.init_concepts(
|
||||
Concept("Sometimes True", body="in_context('a')"),
|
||||
Concept("foo", pre="c:Sometimes True:"))
|
||||
Concept("Sometimes True", body="in_context('a')", pre="is_question()"),
|
||||
Concept("foo", pre="Sometimes True"))
|
||||
|
||||
foo1 = sheerka.new("foo")
|
||||
foo1 = sheerka.evaluate_concept(context, foo1) # 'a' is not in context, so it fails
|
||||
@@ -400,7 +400,7 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
||||
context2 = self.get_context(sheerka)
|
||||
context2.add_to_protected_hints('a')
|
||||
foo2 = sheerka.new("foo")
|
||||
foo2 = sheerka.evaluate_concept(context2, foo2) # 'a' in context + new instance of 'Sometimes True'
|
||||
foo2 = sheerka.evaluate_concept(context2, foo2) # 'a' is now in context
|
||||
|
||||
assert sheerka.isinstance(foo1, BuiltinConcepts.CONDITION_FAILED)
|
||||
assert sheerka.isinstance(foo2, "foo")
|
||||
|
||||
@@ -7,6 +7,33 @@ class TestSheerkaHasAManager(TestUsingMemoryBasedSheerka):
|
||||
def test_i_can_set_hasa(self):
|
||||
sheerka, context, king, kingdom = self.init_concepts("king", "kingdom")
|
||||
|
||||
king_instance = sheerka.new("king")
|
||||
res = sheerka.set_hasa(context, king_instance, kingdom)
|
||||
assert res.status
|
||||
|
||||
# when global truth is not activated, only the current instance is modified
|
||||
another_king = sheerka.get_by_key("king")
|
||||
assert not another_king.get_prop(BuiltinConcepts.HASA) == {kingdom}
|
||||
assert not sheerka.hasa(another_king, kingdom)
|
||||
|
||||
def test_i_cannot_set_the_same_attribute_twice(self):
|
||||
sheerka, context, king, kingdom = self.init_concepts("king", "kingdom")
|
||||
|
||||
king_instance = sheerka.new("king")
|
||||
sheerka.set_hasa(context, king_instance, kingdom)
|
||||
res = sheerka.set_hasa(context, king_instance, kingdom)
|
||||
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.PROPERTY_ALREADY_DEFINED)
|
||||
assert res.body.property_name == BuiltinConcepts.HASA
|
||||
assert res.body.property_value == kingdom
|
||||
assert res.body.concept == king_instance
|
||||
|
||||
def test_i_can_set_hasa_when_global_truth_is_activated(self):
|
||||
sheerka, context, king, kingdom = self.init_test(global_truth=True).with_concepts(
|
||||
"king",
|
||||
"kingdom").unpack()
|
||||
|
||||
res = sheerka.set_hasa(context, sheerka.new("king"), kingdom)
|
||||
assert res.status
|
||||
|
||||
@@ -16,8 +43,10 @@ class TestSheerkaHasAManager(TestUsingMemoryBasedSheerka):
|
||||
# check that the definition of the concept has been updated
|
||||
assert sheerka.hasa(sheerka.new("king"), kingdom)
|
||||
|
||||
def test_i_cannot_set_the_same_attribute_twice(self):
|
||||
sheerka, context, king, kingdom = self.init_concepts("king", "kingdom")
|
||||
def test_i_cannot_set_the_same_attribute_twice_when_global_truth_is_activated(self):
|
||||
sheerka, context, king, kingdom = self.init_test(global_truth=True).with_concepts(
|
||||
"king",
|
||||
"kingdom").unpack()
|
||||
|
||||
sheerka.set_hasa(context, sheerka.new("king"), kingdom)
|
||||
res = sheerka.set_hasa(context, sheerka.new("king"), kingdom)
|
||||
|
||||
@@ -86,15 +86,46 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
def test_isa(self):
|
||||
sheerka, context, blue, color = self.init_concepts(Concept("blue"), Concept("color"))
|
||||
|
||||
assert not sheerka.isa(blue, color)
|
||||
|
||||
sheerka.set_isa(context, blue, color)
|
||||
assert sheerka.isa(blue, color)
|
||||
blue_instance = sheerka.new("blue")
|
||||
assert not sheerka.isa(blue_instance, color)
|
||||
|
||||
sheerka.set_isa(context, blue_instance, color)
|
||||
assert sheerka.isa(blue_instance, color)
|
||||
|
||||
# isa tests the id of a concept, not it's content
|
||||
another_color_instance_but_with_a_body = sheerka.new(color, body="a body")
|
||||
assert sheerka.isa(blue, another_color_instance_but_with_a_body)
|
||||
assert sheerka.isa(blue_instance, another_color_instance_but_with_a_body)
|
||||
|
||||
# isa, when EVAL_GLOBAL_TRUTH_REQUESTED is not activated, only affect the current concept
|
||||
another_blue_instance = sheerka.new("blue")
|
||||
assert not sheerka.isa(another_blue_instance, color)
|
||||
|
||||
# when EVAL_GLOBAL_TRUTH_REQUESTED is not activated, color is not a set
|
||||
assert not sheerka.isinset(blue_instance, color)
|
||||
assert not sheerka.isaset(context, color)
|
||||
|
||||
def test_isa_global_truth(self):
|
||||
sheerka, context, blue, color = self.init_concepts(Concept("blue"), Concept("color"))
|
||||
|
||||
blue_instance = sheerka.new("blue")
|
||||
assert not sheerka.isa(blue_instance, color)
|
||||
assert not sheerka.isaset(context, color)
|
||||
assert not sheerka.isinset(blue_instance, color)
|
||||
|
||||
context.add_to_private_hints(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
|
||||
|
||||
sheerka.set_isa(context, blue_instance, color)
|
||||
assert sheerka.isa(blue_instance, color)
|
||||
assert sheerka.isaset(context, color)
|
||||
assert sheerka.isinset(blue_instance, color)
|
||||
|
||||
# all blue instances are now a color
|
||||
another_blue_instance = sheerka.new("blue")
|
||||
assert sheerka.isa(another_blue_instance, color)
|
||||
assert sheerka.isaset(context, color)
|
||||
assert sheerka.isinset(another_blue_instance, color)
|
||||
|
||||
def test_isaset(self):
|
||||
sheerka, context, group, foo = self.init_concepts(Concept("group"), Concept("foo"))
|
||||
@@ -246,13 +277,28 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
|
||||
|
||||
foo = sheerka.new(foo.key) # new instance
|
||||
sheerka.set_isa(context, foo, all_foo)
|
||||
sheerka.set_isa(context, foo, all_bar)
|
||||
|
||||
assert foo.get_prop(BuiltinConcepts.ISA) == {all_foo, all_bar}
|
||||
assert sheerka.isa(foo, all_foo)
|
||||
assert sheerka.isa(foo, all_bar)
|
||||
|
||||
def test_a_concept_can_be_in_multiple_sets_when_global_truth_is_activated(self):
|
||||
sheerka, context, foo, all_foo, all_bar = self.init_test(global_truth=True).with_concepts(
|
||||
Concept("foo"),
|
||||
Concept("all_foo"),
|
||||
Concept("all_bar"),
|
||||
create_new=True).unpack()
|
||||
|
||||
foo = sheerka.new(foo.key) # new instance
|
||||
sheerka.set_isa(context, foo, all_foo)
|
||||
foo = sheerka.new(foo.key) # new instance
|
||||
sheerka.set_isa(context, foo, all_bar)
|
||||
|
||||
assert foo.get_prop(BuiltinConcepts.ISA) == {all_foo, all_bar}
|
||||
assert sheerka.isa(foo, all_foo)
|
||||
assert sheerka.isa(foo, all_bar)
|
||||
|
||||
assert sheerka.isinset(foo, all_foo)
|
||||
assert sheerka.isinset(foo, all_bar)
|
||||
assert sheerka.isaset(context, all_foo)
|
||||
@@ -270,6 +316,25 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
|
||||
Concept("baz"),
|
||||
)
|
||||
|
||||
sheerka.set_isa(context, foo, bar)
|
||||
sheerka.set_isa(context, bar, baz)
|
||||
|
||||
assert sheerka.isa(foo, bar)
|
||||
assert sheerka.isa(bar, baz)
|
||||
assert sheerka.isa(foo, baz)
|
||||
|
||||
def test_i_can_manage_isa_transitivity_when_global_truth_is_activated(self):
|
||||
"""
|
||||
if foo isa bar and bar isa baz, then foo isa baz
|
||||
:return:
|
||||
"""
|
||||
|
||||
sheerka, context, foo, bar, baz = self.init_test(global_truth=True).with_concepts(
|
||||
Concept("foo"),
|
||||
Concept("bar"),
|
||||
Concept("baz"),
|
||||
).unpack()
|
||||
|
||||
sheerka.set_isa(context, sheerka.new("foo"), bar)
|
||||
sheerka.set_isa(context, sheerka.new("bar"), baz)
|
||||
|
||||
@@ -278,11 +343,11 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
|
||||
assert sheerka.isa(sheerka.new("foo"), baz)
|
||||
|
||||
def test_i_cannot_manage_isa_transitivity_when_using_body(self):
|
||||
sheerka, context, one, another_one, number = self.init_concepts(
|
||||
sheerka, context, one, another_one, number = self.init_test(global_truth=True).with_concepts(
|
||||
"one",
|
||||
Concept("another one", body="one"),
|
||||
"number"
|
||||
)
|
||||
).unpack()
|
||||
|
||||
sheerka.set_isa(context, sheerka.new("one"), number)
|
||||
|
||||
@@ -290,7 +355,10 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
|
||||
assert not sheerka.isa(another_one, number) # Correct this misbehaviour when BuiltinConcepts.IS is implemented
|
||||
|
||||
def test_concepts_in_group_cache_is_updated(self):
|
||||
sheerka, context, one, two, number = self.init_concepts("one", "two", "number")
|
||||
sheerka, context, one, two, number = self.init_test(global_truth=True).with_concepts(
|
||||
"one",
|
||||
"two",
|
||||
"number").unpack()
|
||||
|
||||
sheerka.set_isa(context, sheerka.new("one"), number)
|
||||
|
||||
@@ -315,12 +383,12 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
|
||||
assert number.id not in sheerka.get_concepts_bnf_definitions()
|
||||
|
||||
def test_i_can_get_and_set_isa_when_multiple_ontology_layers(self):
|
||||
sheerka, context, foo, group1, group2 = self.init_concepts(
|
||||
sheerka, context, foo, group1, group2 = self.init_test(global_truth=True).with_concepts(
|
||||
Concept("foo"),
|
||||
Concept("group1"),
|
||||
Concept("group2"),
|
||||
cache_only=False
|
||||
)
|
||||
).unpack()
|
||||
|
||||
sheerka.set_isa(context, foo, group1)
|
||||
|
||||
@@ -401,7 +469,7 @@ class TestSheerkaSetsManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
|
||||
}
|
||||
|
||||
def test_i_can_set_isa(self):
|
||||
sheerka, context, foo, bar, group = self.init_test().with_concepts("foo",
|
||||
sheerka, context, foo, bar, group = self.init_test(global_truth=True).with_concepts("foo",
|
||||
"bar",
|
||||
"group",
|
||||
).unpack()
|
||||
|
||||
@@ -116,6 +116,15 @@ class TestSheerkaMemory(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert sheerka.memory(context, "self.name == 'foo'") == foo
|
||||
|
||||
def test_i_can_use_memory_when_the_entry_does_not_exist(self):
|
||||
sheerka, context, foo, bar = self.init_test().with_concepts("foo", "bar", create_new=True).unpack()
|
||||
|
||||
sheerka.add_to_memory(context, "foo", foo) # add at least one element
|
||||
|
||||
res = sheerka.memory(context, "bar")
|
||||
assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND)
|
||||
assert res.body == {'#name': 'bar'}
|
||||
|
||||
def test_i_retrieve_the_last_entry_when_requesting_memory_with_a_query(self):
|
||||
sheerka, context, foo, bar, foo2 = self.init_concepts("foo", "bar", Concept("foo", body="2"))
|
||||
|
||||
|
||||
@@ -52,22 +52,16 @@ class TestSheerkaQueryManager(TestUsingMemoryBasedSheerka):
|
||||
assert sheerka.filter_objects(context, lst, prop2={"key": "value"}) == [lst[3]]
|
||||
# assert sheerka.filter_objects(context, lst, prop1={1, "v"}) == [lst[2]] set are not supported
|
||||
|
||||
# complex properties
|
||||
assert sheerka.filter_objects(context, lst, prop1_contains="a") == [lst[0], lst[1]]
|
||||
assert sheerka.filter_objects(context, lst, prop1_contains=1) == [lst[2], lst[3]]
|
||||
|
||||
def test_i_can_filter_by_object_type(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
lst = [A("a11", "a12"), Concept("foo", body="a").auto_init(), Concept("foo", body="b").auto_init()]
|
||||
|
||||
assert sheerka.filter_objects(context, lst, __type="foo") == [lst[1], lst[2]]
|
||||
|
||||
def test_i_can_filter_on_atomic_def(self):
|
||||
sheerka, context, isa, plus, isa2 = self.init_concepts(
|
||||
Concept('x is a y').def_var("x").def_var("y"),
|
||||
Concept('a plus b').def_var("a").def_var("b"),
|
||||
Concept('u is a v').def_var("u").def_var("v"),
|
||||
)
|
||||
|
||||
lst = [isa, plus, isa2]
|
||||
assert sheerka.filter_objects(context, lst, atomic_def="is a") == [lst[0], lst[2]]
|
||||
|
||||
def test_i_can_filter_on_as_bag_property(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
lst = [B("a11", "a12"), B("a21", "a22"), B("a31", "a32")]
|
||||
|
||||
@@ -253,6 +253,28 @@ class TestBuiltinHelpers(TestUsingMemoryBasedSheerka):
|
||||
# a second time, now that bar is already evaluated
|
||||
assert core.builtin_helpers.ensure_evaluated(context, bar) == foo
|
||||
|
||||
@pytest.mark.parametrize("concept, concepts_parts, expected", [
|
||||
(Concept("foo"), ["where"], 0),
|
||||
(Concept("foo", where="x"), ["where"], 1),
|
||||
(Concept("foo", where="x and y"), ["where"], 2),
|
||||
(Concept("foo", where="x or y"), ["where"], 1),
|
||||
(Concept("foo", where="x or y and z"), ["where"], 2),
|
||||
(Concept("foo", where="not w"), ["where"], 1),
|
||||
(Concept("foo", where=""), ["where"], 0),
|
||||
|
||||
(Concept("foo", pre="x"), ["pre", "where"], 101),
|
||||
(Concept("foo", where="x"), ["pre", "where"], 1),
|
||||
(Concept("foo", where="x and y", pre="z"), ["pre", "where"], 103),
|
||||
|
||||
(Concept("foo", pre="x"), ["pre|where"], 1),
|
||||
(Concept("foo", where="x"), ["pre|where"], 1),
|
||||
(Concept("foo", where="x and y", pre="z"), ["pre|where"], 3),
|
||||
|
||||
])
|
||||
def test_i_can_get_concept_complexity(self, concept, concepts_parts, expected):
|
||||
context = self.get_context()
|
||||
assert core.builtin_helpers.get_concept_complexity(context, concept, concepts_parts) == expected
|
||||
|
||||
# @pytest.mark.parametrize("return_values", [
|
||||
# None,
|
||||
# []
|
||||
|
||||
@@ -559,6 +559,37 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
||||
ret_val = ReturnValueConcept("Test", True, sheerka.err("an error"))
|
||||
assert sheerka.get_errors(context, ret_val) == []
|
||||
|
||||
def test_i_can_add_and_remove_global_context_hints(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
sheerka.add_to_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
assert sheerka._global_context_hints == {BuiltinConcepts.EVAL_QUESTION_REQUESTED}
|
||||
|
||||
sheerka.remove_fom_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
|
||||
assert sheerka._global_context_hints == set()
|
||||
|
||||
sheerka.add_to_context(sheerka.new(BuiltinConcepts.EVAL_QUESTION_REQUESTED))
|
||||
assert sheerka._global_context_hints == {BuiltinConcepts.EVAL_QUESTION_REQUESTED}
|
||||
|
||||
sheerka.remove_fom_context(sheerka.new(BuiltinConcepts.EVAL_QUESTION_REQUESTED))
|
||||
assert sheerka._global_context_hints == set()
|
||||
|
||||
def test_global_context_hints_are_added_to_every_user_input_execution(self):
|
||||
sheerka, context, foo = self.init_test().with_concepts(
|
||||
Concept("foo", pre="in_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)")
|
||||
).unpack()
|
||||
|
||||
res = sheerka.evaluate_user_input("eval foo", "testing_user")
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.CONDITION_FAILED) # sanity check
|
||||
|
||||
sheerka.add_to_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
|
||||
res = sheerka.evaluate_user_input("eval foo", "testing_user")
|
||||
assert sheerka.isinstance(res[0].value, "foo")
|
||||
|
||||
sheerka.remove_fom_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
|
||||
res = sheerka.evaluate_user_input("eval foo", "testing_user")
|
||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.CONDITION_FAILED)
|
||||
|
||||
|
||||
class TestSheerkaUsingFileBasedSheerka(TestUsingFileBasedSheerka):
|
||||
|
||||
|
||||
@@ -842,11 +842,9 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
|
||||
sheerka, context, foo = self.init_concepts("foo", cache_only=False)
|
||||
|
||||
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
|
||||
cache = Cache(default=lambda sdp, key: sdp.get("by_id", key),
|
||||
extend_exists=lambda sdp, key: sdp.get("by_id", key))
|
||||
cache = Cache().auto_configure("by_id")
|
||||
manager.register_concept_cache("by_id", cache, lambda obj: obj.id, use_ref=True)
|
||||
cache = ListIfNeededCache(default=lambda sdp, key: sdp.get("by_key", key),
|
||||
extend_exists=lambda sdp, key: sdp.get("by_key", key))
|
||||
cache = ListIfNeededCache().auto_configure("by_key")
|
||||
manager.register_concept_cache("by_key", cache, lambda obj: obj.key, use_ref=True)
|
||||
manager.freeze()
|
||||
|
||||
@@ -863,11 +861,9 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
|
||||
sheerka, context, foo = self.init_concepts("foo", cache_only=False)
|
||||
|
||||
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
|
||||
cache = Cache(default=lambda sdp, key: sdp.get("by_id", key),
|
||||
extend_exists=lambda sdp, key: sdp.get("by_id", key))
|
||||
cache = Cache().auto_configure("by_id")
|
||||
manager.register_concept_cache("by_id", cache, lambda obj: obj.id, use_ref=True)
|
||||
cache = ListIfNeededCache(default=lambda sdp, key: sdp.get("by_key", key),
|
||||
extend_exists=lambda sdp, key: sdp.get("by_key", key))
|
||||
cache = ListIfNeededCache().auto_configure("by_key")
|
||||
manager.register_concept_cache("by_key", cache, lambda obj: obj.key, use_ref=True)
|
||||
manager.freeze()
|
||||
|
||||
@@ -887,15 +883,33 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
|
||||
assert list(manager.ontologies[0].cache_manager.sdp.state.data.keys()) == ['by_id', 'by_key']
|
||||
assert manager.ontologies[1].cache_manager.sdp.state.data == {}
|
||||
|
||||
def test_i_can_add_the_concepts_with_the_same_key_from_different_layers(self):
|
||||
sheerka, context, foo_1, foo_2 = self.init_concepts(
|
||||
Concept("foo x", body="x + 1").def_var("x"),
|
||||
Concept("foo x", body="x + 2").def_var("x"),
|
||||
cache_only=False)
|
||||
|
||||
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
|
||||
cache = ListIfNeededCache().auto_configure("by_key")
|
||||
manager.register_concept_cache("by_key", cache, lambda obj: obj.key, use_ref=True)
|
||||
manager.freeze()
|
||||
|
||||
manager.add_concept(foo_1)
|
||||
manager.commit(context)
|
||||
|
||||
manager.push_ontology("new ontology")
|
||||
manager.add_concept(foo_2)
|
||||
manager.commit(context)
|
||||
|
||||
assert manager.current_sdp().get("by_key", foo_1.key) == [foo_1, foo_2]
|
||||
|
||||
def test_i_can_update_concept_in_default_layer(self):
|
||||
sheerka, context, foo = self.init_concepts("foo", cache_only=False)
|
||||
|
||||
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
|
||||
cache = Cache(default=lambda sdp, key: sdp.get("by_id", key),
|
||||
extend_exists=lambda sdp, key: sdp.get("by_id", key))
|
||||
cache = Cache().auto_configure("by_id")
|
||||
manager.register_concept_cache("by_id", cache, lambda obj: obj.id, use_ref=True)
|
||||
cache = ListIfNeededCache(default=lambda sdp, key: sdp.get("by_key", key),
|
||||
extend_exists=lambda sdp, key: sdp.get("by_key", key))
|
||||
cache = ListIfNeededCache().auto_configure("by_key")
|
||||
manager.register_concept_cache("by_key", cache, lambda obj: obj.key, use_ref=True)
|
||||
manager.freeze()
|
||||
|
||||
@@ -953,11 +967,9 @@ class TestSheerkaOntology(TestUsingMemoryBasedSheerka):
|
||||
sheerka, context, foo = self.init_concepts("foo", cache_only=False)
|
||||
|
||||
manager = SheerkaOntologyManager(sheerka, sheerka.root_folder, sheerka.cache_only)
|
||||
cache = Cache(default=lambda sdp, key: sdp.get("by_id", key),
|
||||
extend_exists=lambda sdp, key: sdp.get("by_id", key))
|
||||
cache = Cache().auto_configure("by_id")
|
||||
manager.register_concept_cache("by_id", cache, lambda obj: obj.id, use_ref=True)
|
||||
cache = ListIfNeededCache(default=lambda sdp, key: sdp.get("by_key", key),
|
||||
extend_exists=lambda sdp, key: sdp.get("by_key", key))
|
||||
cache = ListIfNeededCache().auto_configure("by_key")
|
||||
manager.register_concept_cache("by_key", cache, lambda obj: obj.key, use_ref=True)
|
||||
manager.freeze()
|
||||
|
||||
|
||||
@@ -193,6 +193,8 @@ def test_i_can_escape():
|
||||
("c:|id:", None, "id"),
|
||||
("c:key|:", "key", None),
|
||||
("c:key|id:x", None, None),
|
||||
("c:one: plus c:two:", None, None),
|
||||
("c:one|id: plus c:two:", None, None),
|
||||
])
|
||||
def test_i_can_unstr_concept(text, expected_key, expected_id):
|
||||
k, i = core.utils.unstr_concept(text)
|
||||
@@ -494,3 +496,19 @@ def test_sheerka_hasattr_get_attr():
|
||||
assert not core.utils.sheerka_hasattr(concept, "b")
|
||||
with pytest.raises(AttributeError):
|
||||
core.utils.sheerka_getattr(concept, "b")
|
||||
|
||||
|
||||
def test_i_can_replace_after():
|
||||
my_new_items = ["alpha", "beta", "gamma"]
|
||||
|
||||
my_list1 = ["a", "b", "c", "d"]
|
||||
core.utils.replace_after(my_list1, "c", my_new_items)
|
||||
assert my_list1 == ["a", "b", "alpha", "beta", "gamma"]
|
||||
|
||||
my_list2 = ["a", "b", "c", "d"]
|
||||
core.utils.replace_after(my_list2, "a", my_new_items)
|
||||
assert my_list2 == ["alpha", "beta", "gamma"]
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
my_list3 = ["a", "b", "c", "d"]
|
||||
core.utils.replace_after(my_list3, "x", my_new_items)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.tokenizer import Tokenizer
|
||||
from evaluators.AddConceptInSetEvaluator import AddConceptInSetEvaluator
|
||||
from parsers.DefConceptParser import IsaConceptNode, NameNode
|
||||
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
@@ -51,7 +51,20 @@ class TestAddConceptInSetEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert res.value.body == "bar"
|
||||
|
||||
def test_i_can_add_concept_to_a_set_of_concept(self):
|
||||
sheerka, context, foo, bar = self.init_test().with_concepts("foo", "bar", create_new=True).unpack()
|
||||
sheerka, context, foo, bar = self.init_test().with_concepts("foo", "bar").unpack()
|
||||
ret_val = get_isa_ret_val("foo", "bar")
|
||||
|
||||
res = AddConceptInSetEvaluator().eval(context, ret_val)
|
||||
foo = res.body # get the created instance
|
||||
|
||||
assert res.status
|
||||
assert context.sheerka.isinstance(res.value, foo.key)
|
||||
assert context.sheerka.isa(foo, bar)
|
||||
|
||||
assert foo.get_prop(BuiltinConcepts.ISA) == {bar}
|
||||
|
||||
def test_i_can_add_concept_to_a_set_of_concept_when_global_truth_is_activated(self):
|
||||
sheerka, context, foo, bar = self.init_test(global_truth=True).with_concepts("foo", "bar").unpack()
|
||||
ret_val = get_isa_ret_val("foo", "bar")
|
||||
|
||||
res = AddConceptInSetEvaluator().eval(context, ret_val)
|
||||
@@ -65,19 +78,18 @@ class TestAddConceptInSetEvaluator(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert foo.get_prop(BuiltinConcepts.ISA) == {bar}
|
||||
|
||||
def test_i_can_add_bnf_concept_to_a_set_of_concept(self):
|
||||
def test_i_can_add_bnf_concept_to_a_set_of_concept_when_global_truth_is_activated(self):
|
||||
"""
|
||||
This test is the reason why I have started the whole eval on demand stuff
|
||||
Sheerka tries to evaluate the body but it can't (as a and b are not defined)
|
||||
So 'foo' cannot be put is set
|
||||
:return:
|
||||
"""
|
||||
sheerka, context, one, two, foo, bar = self.init_test().with_concepts(
|
||||
sheerka, context, one, two, foo, bar = self.init_test(global_truth=True).with_concepts(
|
||||
"one",
|
||||
"two",
|
||||
Concept("foo", definition="(one|two)=a 'plus' (one|two)=b", body="a + b").def_var("a").def_var("b"),
|
||||
"bar",
|
||||
create_new=True).unpack()
|
||||
"bar").unpack()
|
||||
|
||||
ret_val = get_isa_ret_val("foo", "bar")
|
||||
res = AddConceptInSetEvaluator().eval(context, ret_val)
|
||||
@@ -103,11 +115,25 @@ class TestAddConceptInSetEvaluator(TestUsingMemoryBasedSheerka):
|
||||
ret_val = get_isa_ret_val("foo", "bar")
|
||||
res = AddConceptInSetEvaluator().eval(context, ret_val)
|
||||
|
||||
assert res.status
|
||||
assert context.sheerka.isinstance(res.value, foo.key)
|
||||
|
||||
def test_i_can_add_concept_with_a_body_to_a_set_of_concept_when_global_truth_is_activated(self):
|
||||
context = self.get_context(global_truth=True)
|
||||
foo = Concept("foo", body="1")
|
||||
context.sheerka.create_new_concept(context, foo)
|
||||
|
||||
bar = Concept("bar")
|
||||
context.sheerka.create_new_concept(context, bar)
|
||||
|
||||
ret_val = get_isa_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(self):
|
||||
sheerka, context, foo, bar = self.init_test().with_concepts("foo", "bar", create_new=True).unpack()
|
||||
sheerka, context, foo, bar = self.init_test(global_truth=True).with_concepts("foo", "bar").unpack()
|
||||
|
||||
ret_val = get_isa_ret_val("foo", "bar")
|
||||
AddConceptInSetEvaluator().eval(context, ret_val)
|
||||
|
||||
@@ -43,7 +43,8 @@ class TestExpressionEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert not res.body
|
||||
|
||||
# second time
|
||||
sheerka.set_isa(context, one, number)
|
||||
global_truth_context = self.get_context(sheerka, global_truth=True)
|
||||
sheerka.set_isa(global_truth_context, one, number)
|
||||
parsed_return_value = ExpressionParser().parse(context, ParserInput("one is a number"))
|
||||
res = evaluator.eval(context, parsed_return_value)
|
||||
assert res.status
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept
|
||||
from core.concept import Concept
|
||||
from evaluators.PrepareEvalGlobalTruthEvaluator import PrepareEvalGlobalTruthEvaluator
|
||||
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
r = ReturnValueConcept
|
||||
|
||||
|
||||
class TestPrepareEvalGlobalTruthEvaluator(TestUsingMemoryBasedSheerka):
|
||||
|
||||
@pytest.mark.parametrize("ret_val, expected", [
|
||||
(r("name", True, UserInputConcept("global_truth(1 + 1)")), True),
|
||||
(r("name", True, UserInputConcept(" global_truth(1 + 1) ")), True),
|
||||
(r("name", True, UserInputConcept("global_truth()")), False),
|
||||
(r("name", True, UserInputConcept("1+1")), False),
|
||||
(r("name", True, UserInputConcept("")), False),
|
||||
(r("name", True, UserInputConcept("global_truth(")), False),
|
||||
(r("name", True, UserInputConcept(")")), False),
|
||||
(r("name", True, UserInputConcept([])), False),
|
||||
(r("name", True, Concept("foo")), False),
|
||||
(r("name", True, "not a concept"), False),
|
||||
(r("name", False, UserInputConcept("global_truth(1 + 1)")), False),
|
||||
])
|
||||
def test_i_can_match(self, ret_val, expected):
|
||||
context = self.get_context()
|
||||
assert PrepareEvalGlobalTruthEvaluator().matches(context, ret_val) == expected
|
||||
|
||||
@pytest.mark.parametrize("ret_val, expected", [
|
||||
(r("name", True, UserInputConcept("global_truth(1 + 1)")), "1 + 1"),
|
||||
(r("name", True, UserInputConcept(" global_truth( 1 + 1 ) ")), "1 + 1"),
|
||||
])
|
||||
def test_i_can_eval(self, ret_val, expected):
|
||||
context = self.get_context()
|
||||
sheerka = context.sheerka
|
||||
|
||||
prepare_evaluator = PrepareEvalGlobalTruthEvaluator()
|
||||
prepare_evaluator.matches(context, ret_val)
|
||||
res = prepare_evaluator.eval(context, ret_val)
|
||||
|
||||
assert res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.USER_INPUT)
|
||||
assert res.body.body == expected
|
||||
|
||||
assert BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED in context.protected_hints
|
||||
assert BuiltinConcepts.EVAL_BODY_REQUESTED in context.protected_hints
|
||||
assert BuiltinConcepts.RETURN_BODY_REQUESTED in context.protected_hints
|
||||
@@ -1,12 +1,15 @@
|
||||
import pytest
|
||||
|
||||
from core.builtin_concepts import BuiltinConcepts
|
||||
from core.concept import Concept
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from evaluators.BaseEvaluator import BaseEvaluator
|
||||
from evaluators.ResolveAmbiguityEvaluator import ResolveAmbiguityEvaluator
|
||||
|
||||
from parsers.ExactConceptParser import ExactConceptParser
|
||||
from parsers.SyaNodeParser import SyaNodeParser
|
||||
from tests.BaseTest import BaseTest
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
|
||||
|
||||
pretval = BaseTest.pretval
|
||||
|
||||
|
||||
@@ -21,6 +24,37 @@ class TestResolveAmbiguityEvaluator(TestUsingMemoryBasedSheerka):
|
||||
context = self.get_context()
|
||||
assert ResolveAmbiguityEvaluator().matches(context, return_values) == expected
|
||||
|
||||
def test_i_can_match_when_the_input_comes_from_an_evaluator(self):
|
||||
ret_val1 = pretval(Concept("foo"), source="source", parser=BaseEvaluator.get_name("evaluator"))
|
||||
ret_val2 = pretval(Concept("bar"), source="source", parser=BaseEvaluator.get_name("evaluator"))
|
||||
return_values = [ret_val1, ret_val2]
|
||||
|
||||
context = self.get_context()
|
||||
assert ResolveAmbiguityEvaluator().matches(context, return_values)
|
||||
|
||||
def test_i_can_match_when_concept_nodes(self):
|
||||
sheerka, context, a, foo_1, foo_2 = self.init_concepts(
|
||||
Concept("a"),
|
||||
Concept("foo x").def_var("x"),
|
||||
Concept("foo y").def_var("y"),
|
||||
create_new=True
|
||||
)
|
||||
|
||||
return_values = SyaNodeParser().parse(context, ParserInput("foo a"))
|
||||
assert ResolveAmbiguityEvaluator().matches(context, return_values)
|
||||
|
||||
def test_i_can_match_when_concept_node_mixed_with_concept(self):
|
||||
sheerka, context, a, foo_1, foo_a = self.init_concepts(
|
||||
Concept("a"),
|
||||
Concept("foo x").def_var("x"),
|
||||
Concept("foo a"),
|
||||
create_new=True
|
||||
)
|
||||
|
||||
sya_return_value = SyaNodeParser().parse(context, ParserInput("foo a"))
|
||||
|
||||
assert ResolveAmbiguityEvaluator().matches(context, [sya_return_value, pretval(foo_a, source="foo a")])
|
||||
|
||||
def test_i_can_manage_when_no_source(self):
|
||||
context = self.get_context()
|
||||
return_values = [BaseTest.retval(Concept("foo"))]
|
||||
@@ -53,6 +87,44 @@ class TestResolveAmbiguityEvaluator(TestUsingMemoryBasedSheerka):
|
||||
return_values[2],
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("concepts, expected", [
|
||||
([Concept("c1"), Concept("c2", where="True")], "c2"),
|
||||
([Concept("c1"), Concept("c2", pre="True")], "c2"),
|
||||
([Concept("c1"), Concept("c2", where="False")], "c1"),
|
||||
([Concept("c1"), Concept("c2", pre="False")], "c1"),
|
||||
([Concept("c1", pre="True"), Concept("c2", where="True")], "c1"),
|
||||
([Concept("c1", pre="False"), Concept("c2", where="True")], "c2"),
|
||||
([Concept("c1", pre="False"), Concept("c2", where="False")], BuiltinConcepts.NO_RESULT),
|
||||
])
|
||||
def test_i_can_eval_2(self, concepts, expected):
|
||||
context = self.get_context()
|
||||
return_values = [self.pretval(c, source="foo") for c in concepts]
|
||||
|
||||
evaluator = ResolveAmbiguityEvaluator()
|
||||
evaluator.matches(context, return_values)
|
||||
res = evaluator.eval(context, return_values)
|
||||
|
||||
assert len(res) == 1
|
||||
if expected != BuiltinConcepts.NO_RESULT:
|
||||
selected_concept = res[0].body.body
|
||||
assert selected_concept.name == expected
|
||||
else:
|
||||
assert res[0].body == BuiltinConcepts.NO_RESULT
|
||||
|
||||
@pytest.mark.parametrize("concepts", [
|
||||
[Concept("c1"), Concept("c2")],
|
||||
[Concept("c1", pre="True"), Concept("c2", pre="True")],
|
||||
])
|
||||
def test_i_can_eval_when_same_complexity(self, concepts):
|
||||
context = self.get_context()
|
||||
return_values = [self.pretval(c, "foo") for c in concepts]
|
||||
|
||||
evaluator = ResolveAmbiguityEvaluator()
|
||||
evaluator.matches(context, return_values)
|
||||
res = evaluator.eval(context, return_values)
|
||||
|
||||
assert res is None
|
||||
|
||||
def test_i_can_eval_all_fail(self):
|
||||
context = self.get_context()
|
||||
return_values = [
|
||||
@@ -91,3 +163,70 @@ class TestResolveAmbiguityEvaluator(TestUsingMemoryBasedSheerka):
|
||||
res = evaluator.eval(context, return_values)
|
||||
|
||||
assert res is None
|
||||
|
||||
def test_i_can_eval_to_the_simplest_concept(self):
|
||||
"""
|
||||
def concept foo x where x
|
||||
def concept foo a
|
||||
|
||||
When the input is foo a, 'foo x' must be discarded as concept 'foo a' is more accurate
|
||||
:return:
|
||||
"""
|
||||
|
||||
sheerka, context, a, foo_1, foo_a = self.init_concepts(
|
||||
Concept("a"),
|
||||
Concept("foo x").def_var("x"),
|
||||
Concept("foo a"),
|
||||
create_new=True
|
||||
)
|
||||
|
||||
sya_return_value = SyaNodeParser().parse(context, ParserInput("foo a"))
|
||||
exact_concept_return_value = pretval(foo_a, source="foo a")
|
||||
return_values = [sya_return_value, exact_concept_return_value]
|
||||
evaluator = ResolveAmbiguityEvaluator()
|
||||
|
||||
evaluator.matches(context, return_values)
|
||||
res = evaluator.eval(context, return_values)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].who == evaluator.name
|
||||
assert res[0].body == exact_concept_return_value.body
|
||||
assert res[0].parents == return_values
|
||||
|
||||
def test_i_can_eval_to_the_simplest_concept_when_concept_nodes(self):
|
||||
"""
|
||||
Same explanation than test_i_can_eval_to_the_simplest_concept()
|
||||
:return:
|
||||
"""
|
||||
sheerka, context, a, b, foo_1, foo_2 = self.init_concepts(
|
||||
Concept("a"),
|
||||
Concept("b"),
|
||||
Concept("foo x y").def_var("x").def_var("y"),
|
||||
Concept("foo a x").def_var("x"),
|
||||
create_new=True
|
||||
)
|
||||
|
||||
return_values = SyaNodeParser().parse(context, ParserInput("foo a b"))
|
||||
evaluator = ResolveAmbiguityEvaluator()
|
||||
|
||||
evaluator.matches(context, return_values)
|
||||
res = evaluator.eval(context, return_values)
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0].who == evaluator.name
|
||||
assert sheerka.isinstance(res[0].body.body[0].concept, foo_2)
|
||||
|
||||
def test_i_can_eval_when_non_instance_concepts(self):
|
||||
sheerka, context, foo_1, foo_2 = self.init_concepts(
|
||||
Concept("foo x", body="1", pre="True").def_var("x"),
|
||||
Concept("foo x", body="2", pre="True").def_var("x"),
|
||||
create_new=True
|
||||
)
|
||||
|
||||
exact_parser_return_values = ExactConceptParser().parse(context, ParserInput("c:foo x:"))
|
||||
evaluator = ResolveAmbiguityEvaluator()
|
||||
|
||||
evaluator.matches(context, exact_parser_return_values)
|
||||
res = evaluator.eval(context, exact_parser_return_values)
|
||||
|
||||
assert res is None # means that there is nothing to resolve as the concepts are not instances
|
||||
|
||||
@@ -185,14 +185,3 @@ class TestValidateConceptEvaluator(TestUsingMemoryBasedSheerka):
|
||||
assert not res.status
|
||||
assert sheerka.isinstance(res.body, BuiltinConcepts.FILTERED)
|
||||
assert res.body.body == ret_val.body.body
|
||||
|
||||
def test_i_can_manage_infinite_recursion(self):
|
||||
sheerka, context, a_and_b = self.init_concepts(
|
||||
Concept("a and b", where="is_question()", body="a and b").def_var("a").def_var("b"),
|
||||
create_new=True)
|
||||
evaluator = ValidateConceptEvaluator()
|
||||
|
||||
ret_val = pr_ret_val(a_and_b)
|
||||
res = evaluator.eval(context, ret_val)
|
||||
|
||||
assert res is None # infinite recursion detected, res is None to drop the validator
|
||||
|
||||
@@ -362,6 +362,7 @@ as:
|
||||
])
|
||||
def test_i_can_mix_concept_with_python_to_define_numbers(self, desc, definitions):
|
||||
sheerka = self.get_sheerka()
|
||||
sheerka.add_to_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
|
||||
|
||||
for definition in definitions:
|
||||
sheerka.evaluate_user_input(definition)
|
||||
@@ -396,6 +397,7 @@ as:
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].body == 23
|
||||
sheerka.remove_fom_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
|
||||
|
||||
def test_i_can_mix_bnf_and_isa(self):
|
||||
"""
|
||||
@@ -406,8 +408,8 @@ as:
|
||||
sheerka.evaluate_user_input("def concept one as 1")
|
||||
sheerka.evaluate_user_input("def concept two as 2")
|
||||
sheerka.evaluate_user_input("def concept number")
|
||||
sheerka.evaluate_user_input("set_isa(one, number)")
|
||||
sheerka.evaluate_user_input("set_isa(two, number)")
|
||||
sheerka.evaluate_user_input("global_truth(set_isa(one, number))")
|
||||
sheerka.evaluate_user_input("global_truth(set_isa(two, number))")
|
||||
sheerka.evaluate_user_input("def concept twenties from bnf 'twenty' number as 20 + number")
|
||||
|
||||
res = sheerka.evaluate_user_input("twenty one")
|
||||
@@ -443,6 +445,7 @@ as:
|
||||
|
||||
def test_i_can_mix_bnf_and_isa_2(self):
|
||||
sheerka = self.get_sheerka()
|
||||
sheerka.add_to_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
|
||||
|
||||
init = [
|
||||
"def concept one as 1",
|
||||
@@ -460,6 +463,7 @@ as:
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].body == 21
|
||||
sheerka.remove_fom_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED)
|
||||
|
||||
def test_i_can_use_concepts_defined_with_from(self):
|
||||
sheerka = self.get_sheerka()
|
||||
@@ -565,7 +569,7 @@ as:
|
||||
"def concept plus_one from bnf number=n1 'plus_one' as n1 + 1",
|
||||
]
|
||||
|
||||
sheerka = self.init_scenario(definitions)
|
||||
sheerka = self.init_scenario(definitions, global_truth=True)
|
||||
|
||||
res = sheerka.evaluate_user_input("eval two plus_one")
|
||||
assert len(res) == 1
|
||||
@@ -642,8 +646,6 @@ as:
|
||||
assert res[0].body == 21
|
||||
|
||||
def test_i_can_use_where_in_bnf(self):
|
||||
sheerka, context = self.init_test().unpack()
|
||||
|
||||
init = [
|
||||
"def concept one as 1",
|
||||
"def concept two as 2",
|
||||
@@ -656,8 +658,8 @@ as:
|
||||
"def concept twenties from bnf twenty number where number <= 2 as twenty + number"
|
||||
]
|
||||
|
||||
for exp in init:
|
||||
sheerka.evaluate_user_input(exp)
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
context = self.get_context(sheerka)
|
||||
|
||||
res = sheerka.evaluate_user_input("twenty one")
|
||||
assert len(res) == 1
|
||||
@@ -765,7 +767,7 @@ as:
|
||||
sheerka.evaluate_user_input("def concept two as 2")
|
||||
sheerka.evaluate_user_input("def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit")
|
||||
|
||||
res = sheerka.evaluate_user_input("set_isa(twenties, number)")
|
||||
res = sheerka.evaluate_user_input("global_truth(set_isa(twenties, number))")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
|
||||
@@ -946,7 +948,7 @@ as:
|
||||
"set_isa(twenties, number)",
|
||||
]
|
||||
|
||||
sheerka = self.init_scenario(init)
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
|
||||
# simulate that sheerka was stopped and restarted
|
||||
sheerka.clear_bnf_definition()
|
||||
@@ -967,8 +969,8 @@ as:
|
||||
res = sheerka.evaluate_user_input("set_isa(last_created_concept(), number)")
|
||||
|
||||
assert res[0].status
|
||||
assert sheerka.isinstance(res[0].body, BuiltinConcepts.SUCCESS)
|
||||
assert sheerka.isa(sheerka.new("one"), sheerka.new("number"))
|
||||
assert sheerka.isinstance(res[0].body, "one")
|
||||
assert sheerka.isa(res[0].body, sheerka.new("number"))
|
||||
|
||||
def test_i_can_evaluate_sya_and_ret_concepts(self):
|
||||
init = [
|
||||
@@ -1001,7 +1003,7 @@ as:
|
||||
# Since command is a __COMMAND, the body is auto evaluated
|
||||
# and we return the body, not the concept
|
||||
|
||||
sheerka = self.init_scenario(init)
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
res = sheerka.evaluate_user_input("command")
|
||||
assert res[0].status
|
||||
assert res[0].body == "Executed !"
|
||||
@@ -1016,7 +1018,7 @@ as:
|
||||
"def concept x is a y as set_isa(x,y)",
|
||||
]
|
||||
|
||||
sheerka = self.init_scenario(init)
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
res = sheerka.evaluate_user_input("question(one is a number)") # automatically evaluated
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
@@ -1042,7 +1044,7 @@ as:
|
||||
# So the first one should be picked.
|
||||
# the second concept 'one' 's value is an integer, to make sure that it won't be rejected because of its type
|
||||
|
||||
sheerka = self.init_scenario(init)
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
res = sheerka.evaluate_user_input("def concept x plus y where x is a number as x + y")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
@@ -1065,7 +1067,7 @@ as:
|
||||
"set_is_greater_than(BuiltinConcepts.PRECEDENCE, c:is_a:, c:q:, 'Sya')",
|
||||
]
|
||||
|
||||
sheerka = self.init_scenario(init)
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
res = sheerka.evaluate_user_input("one is a number ?") # automatically evaluated
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
@@ -1133,7 +1135,7 @@ as:
|
||||
res = sheerka.evaluate_user_input("twenty one")
|
||||
assert len(res) > 1 # not recognized
|
||||
|
||||
sheerka.evaluate_user_input("set_isa(one, number)")
|
||||
sheerka.evaluate_user_input("global_truth(set_isa(one, number))")
|
||||
res = sheerka.evaluate_user_input("twenty one")
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
@@ -1252,9 +1254,9 @@ as:
|
||||
"def concept two",
|
||||
"def concept number",
|
||||
"def concept nb times from bnf number 'times'",
|
||||
"set_isa(two, number)",
|
||||
"set_isa(two, number)", # defined after 'nb times'
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
|
||||
res = sheerka.evaluate_user_input("two times")
|
||||
|
||||
@@ -1270,7 +1272,7 @@ as:
|
||||
"def concept cars",
|
||||
"def concept quantify x from bnf number x as set_attr(x, 'qty', number) ret x"
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
|
||||
res = sheerka.evaluate_user_input("eval two cars")
|
||||
|
||||
@@ -1287,7 +1289,7 @@ as:
|
||||
"def concept cars",
|
||||
"def concept quantify x from bnf number=n1 x as set_attr(x, 'qty', n1) ret x"
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
|
||||
res = sheerka.evaluate_user_input("eval two cars")
|
||||
|
||||
@@ -1317,7 +1319,7 @@ as:
|
||||
"def concept she ret memory('isa(self, female)')",
|
||||
"girl"
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
context = self.get_context(sheerka)
|
||||
|
||||
res = sheerka.evaluate_user_input("set_attr(she, 'my_attr', 'my value')")
|
||||
@@ -1337,7 +1339,7 @@ as:
|
||||
"def concept x attribute y equals z as set_attr(x, y, z)",
|
||||
"girl"
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
context = self.get_context(sheerka)
|
||||
|
||||
res = sheerka.evaluate_user_input("eval she attribute 'my_attr' equals 'my value'")
|
||||
@@ -1392,7 +1394,7 @@ as:
|
||||
"def concept qualify x from bnf adjective x as set_attr(x, c:adjective:, adjective) ret x",
|
||||
"eval a red short",
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
|
||||
res = sheerka.evaluate_user_input("what is the color of the short ?")
|
||||
assert len(res) == 1
|
||||
|
||||
@@ -13,6 +13,34 @@ class TestSheerkaNonRegMemory2(TestUsingMemoryBasedSheerka):
|
||||
|
||||
res = sheerka.evaluate_user_input("question(foo is a foo)")
|
||||
|
||||
# assert len(res) == 1
|
||||
# assert res[0].status
|
||||
# assert res[0].value
|
||||
assert len(res) == 1
|
||||
assert res[0].status
|
||||
assert res[0].value # value is True since 'x is a foo' was chosen
|
||||
|
||||
def test_i_can_select_the_correct_concept_vs_bnf(self):
|
||||
init = [
|
||||
"def concept one as 1",
|
||||
"def concept two as 2",
|
||||
"def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit",
|
||||
"def concept twenty two as 'specific occurrence'",
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
|
||||
res = sheerka.evaluate_user_input("eval twenty one")
|
||||
assert res[0].value == 21
|
||||
|
||||
res = sheerka.evaluate_user_input("eval twenty two")
|
||||
assert res[0].value == "specific occurrence" # thanks to ExactConceptParser
|
||||
|
||||
def test_i_can_use_global_truth_when_calling_a_concept(self):
|
||||
init = [
|
||||
"def concept one",
|
||||
"def concept number",
|
||||
"def concept x is a y as set_isa(x, y)",
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
|
||||
res = sheerka.evaluate_user_input("global_truth(one is a number)")
|
||||
|
||||
assert res[0].status
|
||||
assert sheerka.isa(sheerka.new("one"), sheerka.new("number"))
|
||||
|
||||
@@ -85,7 +85,7 @@ class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
|
||||
"set_isa(thirty, number)",
|
||||
"def concept thirties from bnf thirty number where number < 10 as thirty + number",
|
||||
"set_isa(thirties, number)",
|
||||
])
|
||||
], global_truth=True)
|
||||
|
||||
sheerka = self.new_sheerka_instance()
|
||||
|
||||
|
||||
@@ -53,6 +53,45 @@ post : None
|
||||
ret : None
|
||||
vars : []
|
||||
props : {}
|
||||
"""
|
||||
|
||||
def test_i_can_display_multiple_concepts_description_when_concept_definition(self, capsys):
|
||||
init = [
|
||||
"def concept foo as 1",
|
||||
"def concept foo as 2 where True",
|
||||
]
|
||||
sheerka = self.init_scenario(init)
|
||||
capsys.readouterr()
|
||||
|
||||
sheerka.enable_process_return_values = True
|
||||
sheerka.evaluate_user_input("desc(c:foo:)")
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == """id : 1001
|
||||
name : foo
|
||||
key : foo
|
||||
definition: None
|
||||
type : None
|
||||
hash : 16f7fbb8bc509b8c652edaf3d0c0457d15a37f0a862fbe03fa357b0c77249c46
|
||||
body : 1
|
||||
where : None
|
||||
pre : None
|
||||
post : None
|
||||
ret : None
|
||||
vars : []
|
||||
props : {}
|
||||
id : 1002
|
||||
name : foo
|
||||
key : foo
|
||||
definition: None
|
||||
type : None
|
||||
hash : e8dd1af1b6bc0eca0fb4a87a6fabb16655caa4b7a6ea9dbbd1f887757e6caf89
|
||||
body : 2
|
||||
where : True
|
||||
pre : None
|
||||
post : None
|
||||
ret : None
|
||||
vars : []
|
||||
props : {}
|
||||
"""
|
||||
|
||||
def test_i_can_describe_a_rule(self, capsys):
|
||||
|
||||
@@ -35,7 +35,7 @@ class TestSheerkaNonRegPipeFunctions(TestUsingMemoryBasedSheerka):
|
||||
"add_to_memory('x', [one])"
|
||||
]
|
||||
|
||||
sheerka = self.init_scenario(init)
|
||||
sheerka = self.init_scenario(init, global_truth=True)
|
||||
res = sheerka.evaluate_user_input("x | where('isa(self, number)')")
|
||||
|
||||
assert len(res) == 1
|
||||
|
||||
@@ -98,22 +98,24 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
init_test_helper = cls().init_test(cache_only=False, ontology="#TestBnfNodeParser#")
|
||||
test_instance = cls()
|
||||
init_test_helper = test_instance.init_test(cache_only=False, ontology="#TestBnfNodeParser#")
|
||||
sheerka, context, *updated = init_test_helper.with_concepts(*cmap.values(), create_new=True).unpack()
|
||||
for i, concept_name in enumerate(cmap):
|
||||
cmap[concept_name] = updated[i]
|
||||
|
||||
# end of initialisation
|
||||
global_truth_context = test_instance.get_context(sheerka, global_truth=True)
|
||||
sheerka = TestBnfNodeParser.sheerka
|
||||
sheerka.set_isa(context, cmap["one"], cmap["number"])
|
||||
sheerka.set_isa(context, cmap["two"], cmap["number"])
|
||||
sheerka.set_isa(context, cmap["three"], cmap["number"])
|
||||
sheerka.set_isa(context, cmap["four"], cmap["number"])
|
||||
sheerka.set_isa(context, cmap["thirty"], cmap["number"])
|
||||
sheerka.set_isa(context, cmap["forty"], cmap["number"])
|
||||
sheerka.set_isa(context, cmap["fifty"], cmap["number"])
|
||||
sheerka.set_isa(context, cmap["one hundred"], cmap["number"])
|
||||
sheerka.set_isa(context, cmap["hundreds"], cmap["number"])
|
||||
sheerka.set_isa(global_truth_context, cmap["one"], cmap["number"])
|
||||
sheerka.set_isa(global_truth_context, cmap["two"], cmap["number"])
|
||||
sheerka.set_isa(global_truth_context, cmap["three"], cmap["number"])
|
||||
sheerka.set_isa(global_truth_context, cmap["four"], cmap["number"])
|
||||
sheerka.set_isa(global_truth_context, cmap["thirty"], cmap["number"])
|
||||
sheerka.set_isa(global_truth_context, cmap["forty"], cmap["number"])
|
||||
sheerka.set_isa(global_truth_context, cmap["fifty"], cmap["number"])
|
||||
sheerka.set_isa(global_truth_context, cmap["one hundred"], cmap["number"])
|
||||
sheerka.set_isa(global_truth_context, cmap["hundreds"], cmap["number"])
|
||||
|
||||
# Pay attention. 'twenties (t1 and t2) are not set as 'number'
|
||||
|
||||
@@ -122,28 +124,28 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
where="number < 10",
|
||||
body="thirty + number").def_var("thirty").def_var("number"))
|
||||
cmap["thirties"] = sheerka.create_new_concept(context, thirties).body.body
|
||||
sheerka.set_isa(context, sheerka.new("thirties"), sheerka.new("number"))
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("thirties"), sheerka.new("number"))
|
||||
|
||||
forties = cls.update_bnf(context, Concept("forties",
|
||||
definition="forty number",
|
||||
where="number < 10",
|
||||
body="forty + number").def_var("forty").def_var("number"))
|
||||
cmap["forties"] = sheerka.create_new_concept(context, forties).body.body
|
||||
sheerka.set_isa(context, sheerka.new("forties"), sheerka.new("number"))
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("forties"), sheerka.new("number"))
|
||||
|
||||
fifties = cls.update_bnf(context, Concept("fifties",
|
||||
definition="fifty number",
|
||||
where="number < 10",
|
||||
body="fifty + number").def_var("fifty").def_var("number"))
|
||||
cmap["fifties"] = sheerka.create_new_concept(context, fifties).body.body
|
||||
sheerka.set_isa(context, sheerka.new("fifties"), sheerka.new("number"))
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("fifties"), sheerka.new("number"))
|
||||
|
||||
thousands = cls.update_bnf(context, Concept("thousands",
|
||||
definition="number 'thousand'",
|
||||
where="number < 999",
|
||||
body="number * 1000").def_var("number"))
|
||||
cmap["thousands"] = sheerka.create_new_concept(context, thousands).body.body
|
||||
sheerka.set_isa(context, sheerka.new("thousands"), sheerka.new("number"))
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("thousands"), sheerka.new("number"))
|
||||
|
||||
cls.shared_ontology = sheerka.get_ontology(context)
|
||||
sheerka.pop_ontology(context)
|
||||
@@ -1217,10 +1219,11 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
"twenties": self.bnf_concept("twenties", Sequence(ConceptExpression("twenty"), ConceptExpression("number")))
|
||||
}
|
||||
sheerka, context, parser = self.init_parser(my_map)
|
||||
global_truth_context = self.get_context(sheerka, global_truth=True)
|
||||
parser.context = context
|
||||
parser.sheerka = sheerka
|
||||
sheerka.set_isa(context, sheerka.new("one"), my_map["number"])
|
||||
sheerka.set_isa(context, sheerka.new("twenty"), my_map["number"])
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("one"), my_map["number"])
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("twenty"), my_map["number"])
|
||||
|
||||
parser.concepts_grammars.clear() # make sure parsing expression is created from scratch
|
||||
|
||||
@@ -1251,9 +1254,10 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
sheerka, context, parser = self.init_parser(my_map, singleton=True)
|
||||
parser.context = context
|
||||
parser.sheerka = sheerka
|
||||
sheerka.set_isa(context, sheerka.new("one"), my_map["number"])
|
||||
sheerka.set_isa(context, sheerka.new("two"), my_map["number"])
|
||||
sheerka.set_isa(context, sheerka.new("hundreds"), my_map["number"])
|
||||
global_truth_context = self.get_context(sheerka, global_truth=True)
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("one"), my_map["number"])
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("two"), my_map["number"])
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("hundreds"), my_map["number"])
|
||||
|
||||
parser.concepts_grammars.clear() # make sure parsing expression is created from scratch
|
||||
parsing_expression = parser.get_parsing_expression(context, my_map["hundreds"])
|
||||
@@ -1281,9 +1285,10 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
sheerka, context, parser = self.init_parser(my_map, singleton=True)
|
||||
parser.context = context
|
||||
parser.sheerka = sheerka
|
||||
sheerka.set_isa(context, sheerka.new("one"), my_map["number"])
|
||||
sheerka.set_isa(context, sheerka.new("twenty"), my_map["number"])
|
||||
sheerka.set_isa(context, sheerka.new("twenties"), my_map["number"]) # <- twenties is also a number
|
||||
global_truth_context = self.get_context(sheerka, global_truth=True)
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("one"), my_map["number"])
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("twenty"), my_map["number"])
|
||||
sheerka.set_isa(global_truth_context, sheerka.new("twenties"), my_map["number"]) # <- twenties is also a number
|
||||
|
||||
parser.concepts_grammars.clear() # make sure parsing expression is created from scratch
|
||||
|
||||
@@ -1900,15 +1905,16 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
|
||||
}
|
||||
|
||||
sheerka, context, parser = self.init_parser(my_map, init_from_sheerka=True, create_new=True)
|
||||
sheerka.set_isa(context, my_map["light_red"], my_map["adjective"])
|
||||
sheerka.set_isa(context, my_map["dark_red"], my_map["adjective"])
|
||||
sheerka.set_isa(context, my_map["light_red"], my_map["color"])
|
||||
sheerka.set_isa(context, my_map["dark_red"], my_map["color"])
|
||||
sheerka.set_isa(context, my_map["light_red"], my_map["red colors"])
|
||||
sheerka.set_isa(context, my_map["dark_red"], my_map["red colors"])
|
||||
sheerka.set_isa(context, my_map["color"], my_map["adjective"])
|
||||
sheerka.set_isa(context, my_map["red colors"], my_map["color"])
|
||||
sheerka.set_isa(context, my_map["red colors"], my_map["adjective"])
|
||||
global_truth_context = self.get_context(sheerka, global_truth=True)
|
||||
sheerka.set_isa(global_truth_context, my_map["light_red"], my_map["adjective"])
|
||||
sheerka.set_isa(global_truth_context, my_map["dark_red"], my_map["adjective"])
|
||||
sheerka.set_isa(global_truth_context, my_map["light_red"], my_map["color"])
|
||||
sheerka.set_isa(global_truth_context, my_map["dark_red"], my_map["color"])
|
||||
sheerka.set_isa(global_truth_context, my_map["light_red"], my_map["red colors"])
|
||||
sheerka.set_isa(global_truth_context, my_map["dark_red"], my_map["red colors"])
|
||||
sheerka.set_isa(global_truth_context, my_map["color"], my_map["adjective"])
|
||||
sheerka.set_isa(global_truth_context, my_map["red colors"], my_map["color"])
|
||||
sheerka.set_isa(global_truth_context, my_map["red colors"], my_map["adjective"])
|
||||
|
||||
text = "light red table"
|
||||
|
||||
|
||||
@@ -144,6 +144,7 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
|
||||
assert concept_found == foo
|
||||
assert not concept_found.get_hints().need_validation
|
||||
assert concept_found.get_hints().is_evaluated
|
||||
assert not concept_found.get_hints().is_instance
|
||||
|
||||
def test_i_can_parse_concept_with_concept_tokens(self):
|
||||
sheerka, context, one, two, plus = self.init_concepts(
|
||||
|
||||
@@ -4,7 +4,7 @@ from core.builtin_concepts import BuiltinConcepts
|
||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||
from core.tokenizer import TokenKind
|
||||
from parsers.BaseExpressionParser import TrueifyVisitor, IsAQuestionVisitor, LeftPartNotFoundError, \
|
||||
ParenthesisMismatchError
|
||||
ParenthesisMismatchError, compile_disjunctions, NotNode, AndNode, OrNode
|
||||
from parsers.BaseParser import UnexpectedEofParsingError, UnexpectedTokenParsingError
|
||||
from parsers.LogicalOperatorParser import LogicalOperatorParser
|
||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||
@@ -12,6 +12,46 @@ from tests.parsers.parsers_utils import EXPR, OR, AND, NOT, \
|
||||
get_expr_node_from_test_node
|
||||
|
||||
|
||||
class DoNotCompareStartStopContextManager:
|
||||
def __init__(self):
|
||||
self.original_not_eq = None
|
||||
self.original_and_eq = None
|
||||
self.original_or_eq = None
|
||||
|
||||
@staticmethod
|
||||
def not_eq(self, other):
|
||||
if not isinstance(other, NotNode):
|
||||
return False
|
||||
return self.node == other.node
|
||||
|
||||
@staticmethod
|
||||
def and_eq(self, other):
|
||||
if not isinstance(other, AndNode):
|
||||
return False
|
||||
|
||||
return self.parts == other.parts
|
||||
|
||||
@staticmethod
|
||||
def or_eq(self, other):
|
||||
if not isinstance(other, OrNode):
|
||||
return False
|
||||
|
||||
return self.parts == other.parts
|
||||
|
||||
def __enter__(self):
|
||||
self.original_not_eq = NotNode.__eq__
|
||||
self.original_and_eq = AndNode.__eq__
|
||||
self.original_or_eq = OrNode.__eq__
|
||||
NotNode.__eq__ = self.not_eq
|
||||
AndNode.__eq__ = self.and_eq
|
||||
OrNode.__eq__ = self.or_eq
|
||||
|
||||
def __exit__(self, *args):
|
||||
NotNode.__eq__ = self.original_not_eq
|
||||
AndNode.__eq__ = self.original_and_eq
|
||||
OrNode.__eq__ = self.original_or_eq
|
||||
|
||||
|
||||
class TestLogicalOperatorParser(TestUsingMemoryBasedSheerka):
|
||||
|
||||
def init_parser(self):
|
||||
@@ -175,6 +215,50 @@ class TestLogicalOperatorParser(TestUsingMemoryBasedSheerka):
|
||||
|
||||
assert IsAQuestionVisitor().visit(expr_node) == expected
|
||||
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("a", [EXPR("a")]),
|
||||
("a and b and c", [AND(EXPR("a"), EXPR("b"), EXPR("c"))]),
|
||||
("a or b or c", [EXPR("a"),
|
||||
EXPR("b"),
|
||||
EXPR("c")]),
|
||||
("a and b or c", [AND(EXPR("a"), EXPR("b")), EXPR("c")]),
|
||||
("a or b and c", [EXPR("a"),
|
||||
AND(EXPR("b"), EXPR("c"))]),
|
||||
("(a or b) and c", [AND(EXPR("a"), EXPR("c")),
|
||||
AND(EXPR("b"), EXPR("c"))]),
|
||||
("a or (b or c) and d", [EXPR("a"),
|
||||
AND(EXPR("b"), EXPR("d")),
|
||||
AND(EXPR("c"), EXPR("d"))]),
|
||||
|
||||
("not a", [NOT(EXPR("a"))]),
|
||||
("not (a and b)", [NOT(AND(EXPR("a"), EXPR("b")))]),
|
||||
("not (a or b)", [AND(NOT(EXPR("a")), NOT(EXPR("b")))]),
|
||||
|
||||
("(a or b) and not (c or d)", [AND(EXPR("a"), NOT(EXPR("c")), NOT(EXPR("d"))),
|
||||
AND(EXPR("b"), NOT(EXPR("c")), NOT(EXPR("d")))]),
|
||||
("(a or b) or not (c or d)", [EXPR("a"),
|
||||
EXPR("b"),
|
||||
AND(NOT(EXPR("c")), NOT(EXPR("d")))]),
|
||||
|
||||
("(a and b) and not (c or d)", [AND(EXPR("a"), EXPR("b"), NOT(EXPR("c")), NOT(EXPR("d")))]),
|
||||
("(a and b) or not (c or d)", [AND(EXPR("a"), EXPR("b")),
|
||||
AND(NOT(EXPR("c")), NOT(EXPR("d")))]),
|
||||
|
||||
("a and (b and c)", [AND(EXPR("a"), EXPR("b"), EXPR("c"))]),
|
||||
("a or (b or c)", [EXPR("a"),
|
||||
EXPR("b"),
|
||||
EXPR("c")]),
|
||||
])
|
||||
def test_i_can_compile_disjunction(self, expression, expected):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
resolved_expected = [get_expr_node_from_test_node(expression, e) for e in expected]
|
||||
|
||||
expr_node = parser.parse(context, ParserInput(expression)).body.body
|
||||
|
||||
with DoNotCompareStartStopContextManager():
|
||||
res = compile_disjunctions(expr_node)
|
||||
assert res == resolved_expected
|
||||
|
||||
# @pytest.mark.parametrize("expression, expected", [
|
||||
# ("foo", "foo"),
|
||||
# ("one two", "one two"),
|
||||
|
||||
@@ -258,6 +258,23 @@ class TestSequenceNodeParser(TestUsingMemoryBasedSheerka):
|
||||
assert sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT)
|
||||
compare_with_test_object(lexer_nodes, expected_array)
|
||||
|
||||
@pytest.mark.parametrize("concept", [
|
||||
Concept("foo x", body="1").def_var("x"),
|
||||
Concept("foo"),
|
||||
])
|
||||
def test_i_can_parse_token_concepts(self, concept):
|
||||
concepts_map = {
|
||||
"foo": concept,
|
||||
}
|
||||
|
||||
sheerka, context, parser = self.init_parser(concepts_map, create_new=True, use_sheerka=True)
|
||||
res = parser.parse(context, ParserInput(f"c:{concept.name}:"))
|
||||
|
||||
assert res.status
|
||||
concept_found = res.body.body[0].concept
|
||||
assert concept_found.get_hints().is_evaluated
|
||||
assert not concept_found.get_hints().is_instance
|
||||
|
||||
@pytest.mark.parametrize("text", [
|
||||
"foo",
|
||||
f"foo one",
|
||||
|
||||
@@ -709,6 +709,65 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
|
||||
|
||||
self.compare_results(res, expected_sequences, cmap, expression)
|
||||
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("suffixed2 a b", ['a', 'b', "suffixed2"]),
|
||||
("suffixed3 a b c", ['a', 'b', 'c', "suffixed3"]),
|
||||
("a b prefixed2", ['a', 'b', "prefixed2"]),
|
||||
("a b c prefixed3", ['a', 'b', 'c', "prefixed3"]),
|
||||
("start2 a b stop", ['a', 'b', "start2"]),
|
||||
("start3 a b c stop", ['a', 'b', 'c', "start3"]),
|
||||
])
|
||||
def test_i_can_post_fix_when_multiple_parameters_are_expected(self, expression, expected):
|
||||
concepts_map = {
|
||||
"a": Concept("a"),
|
||||
"b": Concept("b"),
|
||||
"c": Concept("c"),
|
||||
"suffixed2": Concept("suffixed2 x y").def_var("x").def_var("y"),
|
||||
"suffixed3": Concept("suffixed3 x y z").def_var("x").def_var("y").def_var("z"),
|
||||
"prefixed2": Concept("x y prefixed2").def_var("x").def_var("y"),
|
||||
"prefixed3": Concept("x y z prefixed3").def_var("x").def_var("y").def_var("z"),
|
||||
"start2": Concept("start2 x y stop").def_var("x").def_var("y"),
|
||||
"start3": Concept("start3 x y z stop").def_var("x").def_var("y").def_var("z"),
|
||||
}
|
||||
sheerka, context, parser = self.init_parser(concepts_map, None)
|
||||
|
||||
res = parser.infix_to_postfix(context, ParserInput(expression))
|
||||
expected_array = compute_expected_array(concepts_map, expression, expected)
|
||||
|
||||
assert len(res) == 1
|
||||
transformed_out = get_test_obj(res[0].out, expected_array)
|
||||
assert transformed_out == expected_array
|
||||
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("suffixed3 x y z", ['x', 'y', 'z', "suffixed3"]),
|
||||
("suffixed3 a y z", ['a', 'y', 'z', "suffixed3"]),
|
||||
("suffixed3 x a z", ['x ', 'a', ' z', "suffixed3"]), # this one was not managed by the second chance
|
||||
("suffixed3 x y a", ['x', 'y', 'a', "suffixed3"]),
|
||||
("x y z prefixed3", ['x', 'y', 'z', "prefixed3"]),
|
||||
("a y z prefixed3", ['a', 'y', 'z', "prefixed3"]),
|
||||
("x a z prefixed3", ['x ', 'a', ' z', "prefixed3"]),
|
||||
("x y a prefixed3", ['x', 'y', 'a', "prefixed3"]),
|
||||
("start3 x y z stop", ['x', 'y', 'z', "start3"]),
|
||||
("start3 a y z stop", ['a', 'y', 'z', "start3"]),
|
||||
("start3 x a z stop", ['x ', 'a', ' z ', "start3"]),
|
||||
("start3 x y a stop", ['x', 'y', 'a', "start3"]),
|
||||
])
|
||||
def test_i_can_post_fix_when_multiple_parameters_are_expected_but_unrecognized_tokens(self, expression, expected):
|
||||
concepts_map = {
|
||||
"a": Concept("a"),
|
||||
"suffixed3": Concept("suffixed3 x y z").def_var("x").def_var("y").def_var("z"),
|
||||
"prefixed3": Concept("x y z prefixed3").def_var("x").def_var("y").def_var("z"),
|
||||
"start3": Concept("start3 x y z stop").def_var("x").def_var("y").def_var("z"),
|
||||
}
|
||||
sheerka, context, parser = self.init_parser(concepts_map, None)
|
||||
|
||||
res = parser.infix_to_postfix(context, ParserInput(expression))
|
||||
expected_array = compute_expected_array(concepts_map, expression, expected)
|
||||
|
||||
assert len(res) == 1
|
||||
transformed_out = get_test_obj(res[0].out, expected_array)
|
||||
assert transformed_out == expected_array
|
||||
|
||||
@pytest.mark.parametrize("expression, expected", [
|
||||
("(", ("(", 0)),
|
||||
("one plus ( 1 + ", ("(", 4)),
|
||||
@@ -1080,6 +1139,28 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
|
||||
assert isinstance(concept_plus_b[0].body.body, PythonNode)
|
||||
assert concept_suffixed_a == cmap["two"]
|
||||
|
||||
@pytest.mark.parametrize("text, expected", [
|
||||
("suffixed3 a b c", [("x", "a"), ("y", "b"), ("z", "c")]),
|
||||
("a b c prefixed3", [("x", "a"), ("y", "b"), ("z", "c")]),
|
||||
("start3 a b c stop", [("x", "a"), ("y", "b"), ("z", "c")]),
|
||||
])
|
||||
def test_i_can_parse_when_multiple_parameters_are_expected(self, text, expected):
|
||||
concepts_map = {
|
||||
"a": Concept("a"),
|
||||
"b": Concept("b"),
|
||||
"c": Concept("c"),
|
||||
"suffixed3": Concept("suffixed3 x y z").def_var("x").def_var("y").def_var("z"),
|
||||
"prefixed3": Concept("x y z prefixed3").def_var("x").def_var("y").def_var("z"),
|
||||
"start3": Concept("start3 x y z stop").def_var("x").def_var("y").def_var("z"),
|
||||
}
|
||||
sheerka, context, parser = self.init_parser(concepts_map, None)
|
||||
|
||||
res = parser.parse(context, ParserInput(text))
|
||||
lexer_nodes = res.body.body
|
||||
|
||||
assert res.status
|
||||
assert lexer_nodes[0].concept.get_metadata().variables == expected
|
||||
|
||||
@pytest.mark.parametrize("text", [
|
||||
"function(suffixed one)",
|
||||
"function(one plus two mult three)",
|
||||
|
||||
@@ -433,6 +433,10 @@ class TestUnrecognizedNodeParser(TestUsingMemoryBasedSheerka):
|
||||
compare_with_test_object(actual_nodes, expected_array)
|
||||
|
||||
def test_i_can_parse_when_multiple_atom_and_sya(self):
|
||||
"""
|
||||
Testing that the ambiguity between hello_atom and hello_sya is correctly managed
|
||||
:return:
|
||||
"""
|
||||
sheerka, context, parser = self.init_parser()
|
||||
expression = "two hello one three"
|
||||
nodes = get_input_nodes_from(concepts_map, expression,
|
||||
@@ -440,25 +444,15 @@ class TestUnrecognizedNodeParser(TestUsingMemoryBasedSheerka):
|
||||
parser_input = ParserResultConcept("parsers.xxx", source=expression, value=nodes)
|
||||
|
||||
res = parser.parse(context, parser_input)
|
||||
assert len(res) == 2
|
||||
assert res[0].status
|
||||
assert res[1].status
|
||||
assert res.status
|
||||
|
||||
actual_nodes0 = res[0].body.body
|
||||
actual_nodes0 = res.body.body
|
||||
expected_0 = compute_expected_array(concepts_map, expression, [
|
||||
CN("two", start=0, end=0),
|
||||
CN("hello_atom", source="hello one", start=2, end=4),
|
||||
CN("three", start=6, end=6)])
|
||||
compare_with_test_object(actual_nodes0, expected_0)
|
||||
|
||||
actual_nodes1 = res[1].body.body
|
||||
expected_1 = compute_expected_array(concepts_map, expression, [
|
||||
CN("two", start=0, end=0),
|
||||
CNC("hello_sya", "hello one", start=2, end=4, a="one"),
|
||||
CN("three", start=6, end=6)],
|
||||
exclude_body=True)
|
||||
compare_with_test_object(actual_nodes1, expected_1)
|
||||
|
||||
def test_i_can_parse_when_multiple_sya_concepts(self):
|
||||
sheerka, context, parser = self.init_parser()
|
||||
expression = "greetings two"
|
||||
|
||||
Reference in New Issue
Block a user