Implemented some enhancement request and fixed some bugs

Fixed #2 : Variables are not recognized when inside a rule token
Fixed #15 : Rule: rete attributes are lost when a new ontology is created
Fixed #14 : ReteNetwork: Format rules must not be added to Rete network
Fixed #16 : DefConcept: Variables are not recognized when they are keyword arguments
Fixed #4 : Comparison are not correctly set when comparison property is a concept
Fixed #14 : Parser: merge FunctionParser.NamesNode and ExpressionParser.NamesNode
Fixed #18 : Parser: Add SourceCodeNode test to UnrecognizedNodeParser
Fixed #20 : At startup Number concept is saved in db a numerous number of time
Fixed #21 : CacheManager: I can remove all elements from a ListIfNeededCache and fill it again
Fixed #22 : CacheManager: I can remove all elements from a SetCache and fill it again
Fixed #23 : HistoryManager: history() no longer works
Fixed #24 : HistoryManager: history() no longer works after creating an exec rule
Fixed #25 : SheerkaMemory: Use MemoryObject instead of sheerka.local
Fixed #26 : Debugger: add the list all available services..
Fixed #27 : CONCEPTS_GRAMMARS_ENTRY does not seems to be in use any more
Fixed #28 : Give order to services
This commit is contained in:
2021-02-12 15:15:31 +01:00
parent 3a12ea58df
commit cac2dad17f
62 changed files with 1182 additions and 480 deletions
+2
View File
@@ -1,7 +1,9 @@
#import admin #import admin
#import default #import default
#import python
#import numbers #import numbers
+4
View File
@@ -0,0 +1,4 @@
def concept x is a string pre is_question() as isinstance(x, str)
def concept x is a int pre is_question() as isinstance(x, int)
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)
+2 -2
View File
@@ -15,7 +15,7 @@ class ListIfNeededCache(BaseCache):
if isinstance(self._cache[key], list): if isinstance(self._cache[key], list):
self._cache[key].append(value) self._cache[key].append(value)
else: else:
self._cache[key] = [self._cache[key], value] self._cache[key] = value if self._cache[key] is Removed else [self._cache[key], value]
else: else:
self._sync(key) self._sync(key)
@@ -28,7 +28,7 @@ class ListIfNeededCache(BaseCache):
if isinstance(self._cache[key], list): if isinstance(self._cache[key], list):
self._cache[key].append(value) self._cache[key].append(value)
else: else:
self._cache[key] = [self._cache[key], value] self._cache[key] = value if self._cache[key] is Removed else [self._cache[key], value]
else: else:
self._cache[key] = value self._cache[key] = value
self._add_to_add(key) self._add_to_add(key)
+7 -1
View File
@@ -19,8 +19,11 @@ class SetCache(BaseCache):
def _put(self, key, value, alt_sdp): def _put(self, key, value, alt_sdp):
if key in self._cache: if key in self._cache:
if value in self._cache[key]: if self._cache[key] is Removed:
self._cache[key] = {value}
elif value in self._cache[key]:
return False return False
else:
self._cache[key].add(value) self._cache[key].add(value)
else: else:
self._sync(key) self._sync(key)
@@ -31,6 +34,9 @@ class SetCache(BaseCache):
self._cache[key] = sheerka_deepcopy(previous) self._cache[key] = sheerka_deepcopy(previous)
if key in self._cache: if key in self._cache:
if self._cache[key] == Removed:
self._cache[key] = {value}
else:
self._cache[key].add(value) self._cache[key].add(value)
else: else:
self._cache[key] = {value} self._cache[key] = {value}
+5 -1
View File
@@ -88,7 +88,11 @@ class UnreferencedVariablesVisitor(UnreferencedNamesVisitor):
""" """
def visit_Call(self, node: ast.Call): def visit_Call(self, node: ast.Call):
self.visit_selected(node, ["args"]) self.visit_selected(node, ["args", "keywords"])
def visit_keyword(self, node: ast.keyword):
self.names.add(node.arg)
self.visit_selected(node, ["value"])
class NamesWithAttributesVisitor(ast.NodeVisitor): class NamesWithAttributesVisitor(ast.NodeVisitor):
+3 -113
View File
@@ -7,13 +7,10 @@ from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, ConceptParts, DEFINITION_TYPE_BNF, concept_part_value from core.concept import Concept, ConceptParts, DEFINITION_TYPE_BNF, concept_part_value
from core.global_symbols import NotInit, NotFound from core.global_symbols import NotInit, NotFound
from core.rule import Rule from core.rule import Rule
from core.sheerka.services.SheerkaExecute import SheerkaExecute
from core.tokenizer import Keywords
from core.utils import as_bag from core.utils import as_bag
from parsers.BaseNodeParser import SourceCodeNode, ConceptNode, UnrecognizedTokensNode, SourceCodeWithConceptNode, \ from parsers.BaseNodeParser import SourceCodeNode, ConceptNode, UnrecognizedTokensNode, SourceCodeWithConceptNode, \
RuleNode RuleNode
from parsers.BaseParser import ParsingError from parsers.BaseParser import ParsingError
from parsers.PythonParser import PythonParser
PARSE_STEPS = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING] PARSE_STEPS = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING]
EVAL_STEPS = PARSE_STEPS + [BuiltinConcepts.BEFORE_EVALUATION, BuiltinConcepts.EVALUATION, EVAL_STEPS = PARSE_STEPS + [BuiltinConcepts.BEFORE_EVALUATION, BuiltinConcepts.EVALUATION,
@@ -287,109 +284,6 @@ def only_parsers_results(context, return_values):
parents=return_values) parents=return_values)
def parse_unrecognized(context, source, parsers, who=None, prop=None, filter_func=None):
"""
Try to recognize concepts or code from source using the given parsers
:param context:
:param source: ParserInput if possible
:param parsers:
:param who: who is asking the parsing ?
:param prop: Extra info, when parsing a property
:param filter_func: Once the result are found, call this function to filter them
:return:
"""
sheerka = context.sheerka
if prop:
action_context = {"prop": prop, "source": source}
desc = f"Parsing attribute '{prop}'"
else:
action_context = source
desc = f"Parsing '{source}'"
with context.push(BuiltinConcepts.PARSING, action_context, who=who, desc=desc) as sub_context:
# disable all parsers but the requested ones
if parsers != "all":
sub_context.preprocess_parsers = parsers
# sub_context.add_preprocess(BaseParser.PREFIX + "*", enabled=False)
# for parser in parsers:
# sub_context.add_preprocess(BaseParser.PREFIX + parser, enabled=True)
if prop in (Keywords.WHERE, Keywords.PRE, ConceptParts.WHERE, ConceptParts.PRE, Keywords.WHEN):
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
sub_context.add_inputs(source=source)
to_parse = sheerka.ret(context.who,
True,
sheerka.new(BuiltinConcepts.USER_INPUT, body=source))
res = sheerka.execute(sub_context, to_parse, PARSE_STEPS)
if filter_func:
res = filter_func(sub_context, res)
sub_context.add_values(return_values=res)
return res
def parse_function(context, source, tokens=None, start=0):
"""
Helper function that parses what is supposed to be a function
:param context:
:param source:
:param tokens:
:param start: start index for the source code node
:return:
"""
sheerka = context.sheerka
from parsers.FunctionParser import FunctionParser
parser = FunctionParser()
desc = f"Parsing function '{source}'"
with context.push(BuiltinConcepts.PARSE_CODE, source, desc=desc) as sub_context:
sheerka_execution = sheerka.services[SheerkaExecute.NAME]
res = parser.parse(sub_context, sheerka_execution.get_parser_input(source, tokens))
if not isinstance(res, list):
res = [res]
for r in [r for r in res if sheerka.isinstance(r.body, BuiltinConcepts.PARSER_RESULT)]:
r.body.body.start += start
r.body.body.end += start
if isinstance(r.body.body, SourceCodeWithConceptNode):
for n in [r.body.body.first, r.body.body.last] + r.body.body.nodes:
n.start += start
n.end += start
return res
def parse_python(context, source, desc=None):
"""
Helper function that parses what is known to be Python source code
:param context:
:param source:
:param desc: option description when creating the sub context
"""
desc = desc or f"Compiling python '{source}'"
with context.push(BuiltinConcepts.PARSE_CODE,
{"language": "Python", "source": source},
desc) as sub_context:
parser_input = context.sheerka.services[SheerkaExecute.NAME].get_parser_input(source)
python_parser = PythonParser()
return python_parser.parse(sub_context, parser_input)
def parse_expression(context, source, desc=None):
"""
Helper function to parser expressions with AND, OR and NOT
"""
desc = desc or f"Parsing expression '{source}'"
with context.push(BuiltinConcepts.PARSE_CODE, source, desc) as sub_context:
parser_input = context.sheerka.services[SheerkaExecute.NAME].get_parser_input(source)
from parsers.ExpressionParser import ExpressionParser
expr_parser = ExpressionParser()
return expr_parser.parse(sub_context, parser_input)
def evaluate(context, def evaluate(context,
source, source,
evaluators="all", evaluators="all",
@@ -588,7 +482,7 @@ def get_lexer_nodes_from_unrecognized(context, unrecognized_tokens_node, parsers
:return: :return:
""" """
res = parse_unrecognized(context, unrecognized_tokens_node.source, parsers) res = context.sheerka.parse_unrecognized(context, unrecognized_tokens_node.source, parsers)
res = only_parsers_results(context, res) res = only_parsers_results(context, res)
if not res.status: if not res.status:
@@ -633,7 +527,7 @@ def update_compiled(context, concept, errors, parsers=None):
errors.append(sheerka.new(BuiltinConcepts.ERROR, body=f"Cannot parse '{v.source}'")) errors.append(sheerka.new(BuiltinConcepts.ERROR, body=f"Cannot parse '{v.source}'"))
elif isinstance(v, UnrecognizedTokensNode): elif isinstance(v, UnrecognizedTokensNode):
res = parse_unrecognized(context, v.source, parsers) res = context.sheerka.parse_unrecognized(context, v.source, parsers)
res = only_successful(context, res) # only key successful parsers res = only_successful(context, res) # only key successful parsers
if res.status: if res.status:
c.get_compiled()[k] = res.body.body c.get_compiled()[k] = res.body.body
@@ -830,11 +724,7 @@ def is_a_question(context, concept):
if pre in (None, NotInit, ""): if pre in (None, NotInit, ""):
return False return False
parser_input_service = context.sheerka.services[SheerkaExecute.NAME] res = context.sheerka.parse_expression(context, pre)
from parsers.ExpressionParser import ExpressionParser
parser = ExpressionParser()
res = parser.parse(context, parser_input_service.get_parser_input(pre))
if not res.status: if not res.status:
return False return False
+2
View File
@@ -17,6 +17,8 @@ EVENT_ONTOLOGY_DELETED = "evt_o_d"
RULE_COMPARISON_CONTEXT = "Rule" RULE_COMPARISON_CONTEXT = "Rule"
CONCEPT_COMPARISON_CONTEXT = "Sya" CONCEPT_COMPARISON_CONTEXT = "Sya"
NO_MATCH = "** No Match **"
class CustomType: class CustomType:
+4
View File
@@ -83,6 +83,10 @@ class Rule:
copy.metadata.id_is_unresolved = self.metadata.id_is_unresolved copy.metadata.id_is_unresolved = self.metadata.id_is_unresolved
# copy.error_sink = self.error_sink # Uncomment this line if necessary # copy.error_sink = self.error_sink # Uncomment this line if necessary
copy.rete_net = self.rete_net
copy.rete_p_nodes = self.rete_p_nodes
copy.rete_disjunctions = self.rete_disjunctions
return copy return copy
def __copy__(self): def __copy__(self):
+1 -2
View File
@@ -4,8 +4,7 @@ import time
from core.builtin_concepts import BuiltinConcepts, ParserResultConcept from core.builtin_concepts import BuiltinConcepts, ParserResultConcept
from core.concept import Concept, get_concept_attrs from core.concept import Concept, get_concept_attrs
from core.global_symbols import EVENT_CONTEXT_DISPOSED from core.global_symbols import EVENT_CONTEXT_DISPOSED, NO_MATCH
from core.sheerka.services.SheerkaExecute import NO_MATCH
from core.sheerka.services.SheerkaMemory import SheerkaMemory from core.sheerka.services.SheerkaMemory import SheerkaMemory
from core.utils import CONSOLE_COLORS_MAP as CCM, CONSOLE_COLUMNS from core.utils import CONSOLE_COLORS_MAP as CCM, CONSOLE_COLUMNS
from sdp.sheerkaDataProvider import Event from sdp.sheerkaDataProvider import Event
-22
View File
@@ -6,7 +6,6 @@ from operator import attrgetter
import core.builtin_helpers import core.builtin_helpers
import core.utils import core.utils
from cache.Cache import Cache from cache.Cache import Cache
from cache.DictionaryCache import DictionaryCache
from cache.IncCache import IncCache from cache.IncCache import IncCache
from core.builtin_concepts import ErrorConcept, ReturnValueConcept, UnknownConcept from core.builtin_concepts import ErrorConcept, ReturnValueConcept, UnknownConcept
from core.builtin_concepts_ids import BuiltinErrors, BuiltinConcepts from core.builtin_concepts_ids import BuiltinErrors, BuiltinConcepts
@@ -66,9 +65,6 @@ class Sheerka(Concept):
CONCEPTS_BY_ID_ENTRY = "ConceptManager:Concepts_By_ID" CONCEPTS_BY_ID_ENTRY = "ConceptManager:Concepts_By_ID"
CONCEPTS_BY_NAME_ENTRY = "ConceptManager:Concepts_By_Name" CONCEPTS_BY_NAME_ENTRY = "ConceptManager:Concepts_By_Name"
CONCEPTS_SYA_DEFINITION_ENTRY = "Concepts_Sya_Definitions"
RESOLVED_CONCEPTS_SYA_DEFINITION_ENTRY = "Resolved_Concepts_Sya_Definitions"
CONCEPTS_GRAMMARS_ENTRY = "Concepts_Grammars"
CHICKEN_AND_EGG_CONCEPTS_ENTRY = "Chicken_And_Egg_Concepts" CHICKEN_AND_EGG_CONCEPTS_ENTRY = "Chicken_And_Egg_Concepts"
OBJECTS_IDS_ENTRY = "Objects_Ids" OBJECTS_IDS_ENTRY = "Objects_Ids"
@@ -119,7 +115,6 @@ class Sheerka(Concept):
"test_error": SheerkaMethod(self.test_error, False), "test_error": SheerkaMethod(self.test_error, False),
} }
self.locals = {}
self.concepts_ids = None self.concepts_ids = None
def __copy__(self): def __copy__(self):
@@ -128,13 +123,6 @@ class Sheerka(Concept):
def __deepcopy__(self, memodict={}): def __deepcopy__(self, memodict={}):
return self return self
@property
def concepts_grammars(self):
"""
Quick access to BNF grammars
"""
return self.om.current_cache_manager().caches[self.CONCEPTS_GRAMMARS_ENTRY].cache
@property @property
def chicken_and_eggs(self): def chicken_and_eggs(self):
return self.om.current_cache_manager().caches[self.CHICKEN_AND_EGG_CONCEPTS_ENTRY].cache return self.om.current_cache_manager().caches[self.CHICKEN_AND_EGG_CONCEPTS_ENTRY].cache
@@ -237,16 +225,6 @@ class Sheerka(Concept):
cache = IncCache().auto_configure(self.OBJECTS_IDS_ENTRY) cache = IncCache().auto_configure(self.OBJECTS_IDS_ENTRY)
self.om.register_cache(self.OBJECTS_IDS_ENTRY, cache) self.om.register_cache(self.OBJECTS_IDS_ENTRY, cache)
cache = DictionaryCache().auto_configure(self.CONCEPTS_SYA_DEFINITION_ENTRY)
self.om.register_cache(self.CONCEPTS_SYA_DEFINITION_ENTRY, cache)
self.om.get(self.CONCEPTS_SYA_DEFINITION_ENTRY, None) # to init from sdp
cache = DictionaryCache().auto_configure(self.RESOLVED_CONCEPTS_SYA_DEFINITION_ENTRY)
self.om.register_cache(self.RESOLVED_CONCEPTS_SYA_DEFINITION_ENTRY, cache, persist=False)
cache = Cache().auto_configure(self.CONCEPTS_GRAMMARS_ENTRY)
self.om.register_cache(self.CONCEPTS_GRAMMARS_ENTRY, cache, persist=False)
cache = Cache().auto_configure(self.CHICKEN_AND_EGG_CONCEPTS_ENTRY) cache = Cache().auto_configure(self.CHICKEN_AND_EGG_CONCEPTS_ENTRY)
self.om.register_cache(self.CHICKEN_AND_EGG_CONCEPTS_ENTRY, cache, persist=False) self.om.register_cache(self.CHICKEN_AND_EGG_CONCEPTS_ENTRY, cache, persist=False)
@@ -5,7 +5,6 @@ from cache.SetCache import SetCache
from core.concept import copy_concepts_attrs, load_concepts_attrs from core.concept import copy_concepts_attrs, load_concepts_attrs
from core.global_symbols import NotFound, Removed, EVENT_CONCEPT_CREATED, EVENT_CONCEPT_DELETED, EVENT_RULE_CREATED, \ from core.global_symbols import NotFound, Removed, EVENT_CONCEPT_CREATED, EVENT_CONCEPT_DELETED, EVENT_RULE_CREATED, \
EVENT_RULE_DELETED, EVENT_CONCEPT_ID_DELETED, EVENT_RULE_ID_DELETED EVENT_RULE_DELETED, EVENT_CONCEPT_ID_DELETED, EVENT_RULE_ID_DELETED
from core.utils import sheerka_deepcopy
from sdp.sheerkaDataProvider import SheerkaDataProvider from sdp.sheerkaDataProvider import SheerkaDataProvider
@@ -83,7 +82,6 @@ class Ontology:
self.cache_manager = cache_manager self.cache_manager = cache_manager
self.alt_sdp = alt_sdp self.alt_sdp = alt_sdp
self.concepts_attributes = None self.concepts_attributes = None
self.local_variables = None
def __repr__(self): def __repr__(self):
return f"Ontology('{self.name}')" return f"Ontology('{self.name}')"
@@ -253,13 +251,10 @@ class SheerkaOntologyManager:
""" """
# TODO persist these information ? # TODO persist these information ?
self.current_ontology().concepts_attributes = copy_concepts_attrs() self.current_ontology().concepts_attributes = copy_concepts_attrs()
self.current_ontology().local_variables = sheerka_deepcopy(self.sheerka.locals)
def reset_sheerka_state(self): def reset_sheerka_state(self):
if self.current_ontology().concepts_attributes is not None: if self.current_ontology().concepts_attributes is not None:
load_concepts_attrs(self.current_ontology().concepts_attributes) load_concepts_attrs(self.current_ontology().concepts_attributes)
if self.current_ontology().local_variables is not None:
self.sheerka.locals = self.current_ontology().local_variables
def current_cache_manager(self) -> CacheManager: def current_cache_manager(self) -> CacheManager:
return self.ontologies[0].cache_manager return self.ontologies[0].cache_manager
@@ -5,6 +5,7 @@ from os import path
from core.builtin_concepts_ids import BuiltinConcepts, BuiltinContainers from core.builtin_concepts_ids import BuiltinConcepts, BuiltinContainers
from core.builtin_helpers import ensure_concept_or_rule from core.builtin_helpers import ensure_concept_or_rule
from core.concept import Concept from core.concept import Concept
from core.sheerka.services.SheerkaHistoryManager import SheerkaHistoryManager
from core.sheerka.services.SheerkaMemory import SheerkaMemory from core.sheerka.services.SheerkaMemory import SheerkaMemory
from core.sheerka.services.sheerka_service import BaseService from core.sheerka.services.sheerka_service import BaseService
@@ -33,6 +34,7 @@ class SheerkaAdmin(BaseService):
self.sheerka.bind_service_method(self.admin_pop_ontology, True, as_name="pop_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.ontologies, False)
self.sheerka.bind_service_method(self.in_memory, False) self.sheerka.bind_service_method(self.in_memory, False)
self.sheerka.bind_service_method(self.admin_history, False, as_name="history")
def caches_names(self): def caches_names(self):
""" """
@@ -214,3 +216,7 @@ class SheerkaAdmin(BaseService):
res[k] = obj.obj res[k] = obj.obj
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.TO_DICT, body=res)) return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.TO_DICT, body=res))
def admin_history(self, depth=10, start=0):
history = self.sheerka.services[SheerkaHistoryManager.NAME].history(depth, start)
return self.sheerka.new(BuiltinConcepts.TO_LIST, body=history)
@@ -98,6 +98,8 @@ class SheerkaConceptManager(BaseService):
CONCEPTS_BY_FIRST_KEYWORD_ENTRY = "ConceptManager:Concepts_By_First_Keyword" CONCEPTS_BY_FIRST_KEYWORD_ENTRY = "ConceptManager:Concepts_By_First_Keyword"
RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY = "ConceptManager:Resolved_Concepts_By_First_Keyword" RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY = "ConceptManager:Resolved_Concepts_By_First_Keyword"
CONCEPTS_BNF_DEFINITIONS_ENTRY = "ConceptManager:Concepts_BNF_Definitions"
def __init__(self, sheerka): def __init__(self, sheerka):
super().__init__(sheerka, order=11) super().__init__(sheerka, order=11)
self.forbidden_meta = {"is_builtin", "key", "id", "props", "variables"} self.forbidden_meta = {"is_builtin", "key", "id", "props", "variables"}
@@ -117,6 +119,8 @@ class SheerkaConceptManager(BaseService):
self.sheerka.bind_service_method(self.get_by_id, False, visible=False) self.sheerka.bind_service_method(self.get_by_id, False, visible=False)
self.sheerka.bind_service_method(self.is_not_a_variable, False, visible=False) self.sheerka.bind_service_method(self.is_not_a_variable, 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_token, 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)
register_concept_cache = self.sheerka.om.register_concept_cache register_concept_cache = self.sheerka.om.register_concept_cache
@@ -141,6 +145,9 @@ class SheerkaConceptManager(BaseService):
cache = DictionaryCache().auto_configure(self.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) cache = DictionaryCache().auto_configure(self.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY)
self.sheerka.om.register_cache(self.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, cache, persist=False) self.sheerka.om.register_cache(self.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, cache, persist=False)
cache = Cache().auto_configure(self.CONCEPTS_BNF_DEFINITIONS_ENTRY)
self.sheerka.om.register_cache(self.CONCEPTS_BNF_DEFINITIONS_ENTRY, cache, persist=False)
def initialize_deferred(self, context, is_first_time): def initialize_deferred(self, context, is_first_time):
if is_first_time: if is_first_time:
self.sheerka.om.put(self.sheerka.OBJECTS_IDS_ENTRY, self.USER_CONCEPTS_IDS, 1000) self.sheerka.om.put(self.sheerka.OBJECTS_IDS_ENTRY, self.USER_CONCEPTS_IDS, 1000)
@@ -244,7 +251,7 @@ class SheerkaConceptManager(BaseService):
# TODO : this line seems to be useless # TODO : this line seems to be useless
# The grammar is never reset # The grammar is never reset
if concept.get_bnf() and init_bnf_ret_value is not None and init_bnf_ret_value.status: if concept.get_bnf() and init_bnf_ret_value is not None and init_bnf_ret_value.status:
sheerka.cache_manager.clear(sheerka.CONCEPTS_GRAMMARS_ENTRY) sheerka.cache_manager.clear(self.CONCEPTS_BNF_DEFINITIONS_ENTRY)
# publish the new concept # publish the new concept
sheerka.publish(context, EVENT_CONCEPT_CREATED, concept) sheerka.publish(context, EVENT_CONCEPT_CREATED, concept)
@@ -509,7 +516,7 @@ class SheerkaConceptManager(BaseService):
for concept_id in refs: for concept_id in refs:
# remove the grammar entry so that it can be recreated # remove the grammar entry so that it can be recreated
self.sheerka.om.delete(self.sheerka.CONCEPTS_GRAMMARS_ENTRY, concept_id) self.sheerka.om.delete(self.CONCEPTS_BNF_DEFINITIONS_ENTRY, concept_id)
# reset the bnf definition if needed # reset the bnf definition if needed
if modified_concept: if modified_concept:
@@ -559,6 +566,12 @@ class SheerkaConceptManager(BaseService):
""" """
return self.sheerka.om.get(self.sheerka.CONCEPTS_BY_NAME_ENTRY, name) is NotFound return self.sheerka.om.get(self.sheerka.CONCEPTS_BY_NAME_ENTRY, name) is NotFound
def clear_bnf_definition(self, concept_id=None):
if concept_id:
self.sheerka.om.delete(self.CONCEPTS_BNF_DEFINITIONS_ENTRY, concept_id)
else:
self.sheerka.om.clear(self.CONCEPTS_BNF_DEFINITIONS_ENTRY)
@staticmethod @staticmethod
def _name_has_changed(to_add): def _name_has_changed(to_add):
if to_add is None or "meta" not in to_add: if to_add is None or "meta" not in to_add:
@@ -839,3 +852,6 @@ class SheerkaConceptManager(BaseService):
return core.utils.make_unique(result + custom_concepts, return core.utils.make_unique(result + custom_concepts,
lambda c: c.concept.id if hasattr(c, "concept") else c.id) lambda c: c.concept.id if hasattr(c, "concept") else c.id)
def get_concepts_bnf_definitions(self):
return self.sheerka.om.current_cache_manager().caches[self.CONCEPTS_BNF_DEFINITIONS_ENTRY].cache
@@ -280,6 +280,9 @@ class DebugItem:
class SheerkaDebugManager(BaseService): class SheerkaDebugManager(BaseService):
NAME = "Debug" NAME = "Debug"
PREFIX = "debug." PREFIX = "debug."
VARS_DEBUG_TYPE = "vars"
RULES_DEBUG_TYPE = "rules"
CONCEPTS_DEBUG_TYPE = "concepts"
children_activation_regex = re.compile(r"(\d+)\+") children_activation_regex = re.compile(r"(\d+)\+")
@@ -292,6 +295,10 @@ class SheerkaDebugManager(BaseService):
self.debug_vars_settings = [] self.debug_vars_settings = []
self.debug_rules_settings = [] self.debug_rules_settings = []
self.debug_concepts_settings = [] self.debug_concepts_settings = []
self.registered_vars = [] # list of all variables that can be debugged
self.registered_rules = [] # list of all rules that can be debugged
self.registered_concepts = [] # list of all concept that can be debugged
self.state_vars = [ self.state_vars = [
"activated", "activated",
"explicit", # to remove ? "explicit", # to remove ?
@@ -302,16 +309,43 @@ class SheerkaDebugManager(BaseService):
"debug_concepts_settings" "debug_concepts_settings"
] ]
self.item_name = {
self.VARS_DEBUG_TYPE: "variable",
self.RULES_DEBUG_TYPE: "rule",
self.CONCEPTS_DEBUG_TYPE: "concept",
}
def initialize(self): def initialize(self):
self.sheerka.bind_service_method(self.set_debug, True) self.sheerka.bind_service_method(self.set_debug, True)
self.sheerka.bind_service_method(self.inspect, False) self.sheerka.bind_service_method(self.inspect, False)
self.sheerka.bind_service_method(self.get_debugger, 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.reset_debug, False)
self.sheerka.bind_service_method(self.debug_var, True) self.sheerka.bind_service_method(self.set_debug_var, True)
self.sheerka.bind_service_method(self.debug_rule, True) self.sheerka.bind_service_method(self.set_debug_rule, True)
self.sheerka.bind_service_method(self.debug_concept, 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.get_debug_settings, False, as_name="debug_settings") # self.sheerka.bind_service_method(self.get_debug_settings, False, as_name="debug_settings")
# register what can be registered
from parsers.BnfNodeParser import BnfNodeParser
from evaluators.DefConceptEvaluator import DefConceptEvaluator
from evaluators.PythonEvaluator import PythonEvaluator
from parsers.SyaNodeParser import SyaNodeParser
self.register_debug_vars(BnfNodeParser.NAME, "parse", "result")
self.register_debug_concepts(BnfNodeParser.NAME, "parse", "*")
self.register_debug_vars(DefConceptEvaluator.NAME, "matches", "*")
self.register_debug_vars(DefConceptEvaluator.NAME, "eval", "*")
self.register_debug_vars(DefConceptEvaluator.NAME, "get_variables", "names")
self.register_debug_vars(PythonEvaluator.NAME, "eval", "globals")
self.register_debug_vars(PythonEvaluator.NAME, "eval", "ret")
self.register_debug_vars("Exceptions", PythonEvaluator.NAME+"-eval", "exception")
self.register_debug_vars("Exceptions", PythonEvaluator.NAME+"-eval", "trace")
self.register_debug_vars(SyaNodeParser.NAME, "parse", "*")
def initialize_deferred(self, context, is_first_time): def initialize_deferred(self, context, is_first_time):
self.restore_state() self.restore_state()
@@ -334,6 +368,124 @@ class SheerkaDebugManager(BaseService):
def restore_state(self): def restore_state(self):
self.restore_values(*self.state_vars) self.restore_values(*self.state_vars)
def register_debug(self, item_type, service, method, item):
"""
Register a debug item, in order to east their discovery
:param item_type:
:param service:
:param method:
:param item:
:return:
"""
if item_type == self.VARS_DEBUG_TYPE:
self.registered_vars.append((service, method, item))
elif item_type == self.RULES_DEBUG_TYPE:
self.registered_rules.append((service, method, item))
elif item_type == self.CONCEPTS_DEBUG_TYPE:
self.registered_concepts.append((service, method, item))
else:
raise NotImplementedError()
def register_debug_vars(self, service, method, item):
return self.register_debug(self.VARS_DEBUG_TYPE, service, method, item)
def register_debug_rules(self, service, method, item):
return self.register_debug(self.RULES_DEBUG_TYPE, service, method, item)
def register_debug_concepts(self, service, method, item):
return self.register_debug(self.CONCEPTS_DEBUG_TYPE, service, method, item)
def filter_registered_debug(self, item_type, pattern=None, **kwargs):
"""
Filter the list of the debug item
:param pattern:
:param item_type:
:return:
"""
item_name = self.item_name[item_type]
service, method_name, item = "*", "*", "*"
if pattern:
tokens = pattern.split(".")
service = tokens[0]
method_name = "*"
item = "*"
if len(tokens) > 1:
method_name = tokens[1]
if len(tokens) > 2:
item = tokens[2]
# override with kwargs
service = kwargs.get("service", service)
method_name = kwargs.get("method", method_name)
item = kwargs.get(item_name, item)
if item_type == self.VARS_DEBUG_TYPE:
lst = self.registered_vars
elif item_type == self.RULES_DEBUG_TYPE:
lst = self.registered_rules
elif item_type == self.CONCEPTS_DEBUG_TYPE:
lst = self.registered_concepts
else:
raise NotImplementedError()
for registered in lst:
if service != "*" and service != registered[0]:
continue
if method_name != "*" and method_name != registered[1]:
continue
if item != "*" and item != registered[2]:
continue
yield registered
def list_registered(self, item_type, pattern=None, **kwargs):
"""
Return a formatted list of available registered debug items
:param item_type:
:param pattern:
:param kwargs:
:return:
"""
pattern = pattern.strip() if pattern is not None else None
lst = self.filter_registered_debug(item_type, pattern, **kwargs)
# for (service, method, item_name)
# level == 1 -> print 'service'
# level == 2 -> print 'service.method'
# level == 2 -> print 'service.method.item_name'
if pattern:
if not pattern.endswith(".*"):
pattern += ".*"
tokens = pattern.split(".")
level = len(tokens)
else:
level = 1
if "service" in kwargs.keys():
level = 2
elif {"method", "variable", "rule", "concept"}.intersection(set(kwargs.keys())):
level = 3
res = set()
for filtered in lst:
if level == 1:
res.add(filtered[0])
elif level == 2:
res.add(f"{filtered[0]}.{filtered[1]}")
else:
res.add(f"{filtered[0]}.{filtered[1]}.{filtered[2]}")
return self.sheerka.new(BuiltinConcepts.TO_LIST, body=sorted(res))
def list_debug_vars(self, pattern=None, **kwargs):
return self.list_registered(self.VARS_DEBUG_TYPE, pattern, **kwargs)
def list_debug_rules(self, pattern=None, **kwargs):
return self.list_registered(self.RULES_DEBUG_TYPE, pattern, **kwargs)
def list_debug_concepts(self, pattern=None, **kwargs):
return self.list_registered(self.CONCEPTS_DEBUG_TYPE, pattern, **kwargs)
def set_debug(self, context, value=True): def set_debug(self, context, value=True):
self.activated = value self.activated = value
self.sheerka.record_var(context, self.NAME, "activated", self.activated) self.sheerka.record_var(context, self.NAME, "activated", self.activated)
@@ -491,7 +643,7 @@ class SheerkaDebugManager(BaseService):
return self.sheerka.ret(SheerkaDebugManager.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS)) return self.sheerka.ret(SheerkaDebugManager.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
def debug_var(self, context, *args, **kwargs): def set_debug_var(self, context, *args, **kwargs):
""" """
Adds debug item for variables Adds debug item for variables
debug_var(<service>.<method>.<var>, <context_id>[+], <debug_id>) debug_var(<service>.<method>.<var>, <context_id>[+], <debug_id>)
@@ -504,7 +656,7 @@ class SheerkaDebugManager(BaseService):
i, s, m, c_id, c_children, d, e = self.parse_debug_args("variable", *args, **kwargs) i, s, m, c_id, c_children, d, e = self.parse_debug_args("variable", *args, **kwargs)
return self.add_or_update_debug_item(context, "vars", i, s, m, c_id, c_children, d, False, e) return self.add_or_update_debug_item(context, "vars", i, s, m, c_id, c_children, d, False, e)
def debug_rule(self, context, *args, **kwargs): def set_debug_rule(self, context, *args, **kwargs):
""" """
Adds debug item for rules Adds debug item for rules
debug_var(<service>.<method>.<rule>, <context_id>[+], <debug_id>) debug_var(<service>.<method>.<rule>, <context_id>[+], <debug_id>)
@@ -518,7 +670,7 @@ class SheerkaDebugManager(BaseService):
i, s, m, c_id, c_children, d, e = self.parse_debug_args("rule", *args, **kwargs) i, s, m, c_id, c_children, d, e = self.parse_debug_args("rule", *args, **kwargs)
return self.add_or_update_debug_item(context, "rules", i, s, m, c_id, c_children, d, False, e) return self.add_or_update_debug_item(context, "rules", i, s, m, c_id, c_children, d, False, e)
def debug_concept(self, context, *args, **kwargs): def set_debug_concept(self, context, *args, **kwargs):
""" """
Adds debug item for concepts Adds debug item for concepts
debug_var(<service>.<method>.<concept>, <context_id>[+], <debug_id>) debug_var(<service>.<method>.<concept>, <context_id>[+], <debug_id>)
@@ -546,7 +698,7 @@ class SheerkaDebugManager(BaseService):
Print Print
:param context: :param context:
:param args: 1st parameter is what to display, the other are the properties to display :param args: 1st parameter is what to display, the other are the properties to display
:param kwargs: how to display the result :param kwargs: how to display the result (as_bag=True, values=True)
:return: :return:
""" """
@@ -1,7 +1,7 @@
from dataclasses import dataclass from dataclasses import dataclass
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.builtin_helpers import expect_one, only_successful, parse_unrecognized, evaluate, ensure_concept from core.builtin_helpers import expect_one, only_successful, evaluate, ensure_concept
from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved, AllConceptParts, \ from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved, AllConceptParts, \
concept_part_value concept_part_value
from core.global_symbols import NotInit from core.global_symbols import NotInit
@@ -282,7 +282,7 @@ class SheerkaEvaluateConcept(BaseService):
:return: :return:
""" """
while True: while True:
return_value = parse_unrecognized(current_context, return_value = current_context.sheerka.parse_unrecognized(current_context,
s, s,
parsers="all", parsers="all",
prop=p, prop=p,
@@ -26,6 +26,11 @@ class SheerkaEvaluateRules(BaseService):
self.sheerka.subscribe(EVENT_RULE_DELETED, self.on_rule_deleted) self.sheerka.subscribe(EVENT_RULE_DELETED, self.on_rule_deleted)
self.sheerka.subscribe(EVENT_RULE_ID_DELETED, self.on_rule_deleted) self.sheerka.subscribe(EVENT_RULE_ID_DELETED, self.on_rule_deleted)
self.sheerka.register_debug_vars(self.NAME, "evaluate_rules", "results")
self.sheerka.register_debug_rules(self.NAME, "evaluate_rule", "*")
def reset_evaluators(self): def reset_evaluators(self):
# instantiate evaluators, once for all, only keep when it's enabled # instantiate evaluators, once for all, only keep when it's enabled
evaluators = [e_class() for e_class in self.sheerka.evaluators] evaluators = [e_class() for e_class in self.sheerka.evaluators]
+146 -30
View File
@@ -1,23 +1,20 @@
import core.utils import core.utils
from cache.FastCache import FastCache from cache.FastCache import FastCache
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept
from core.global_symbols import NotFound from core.concept import ConceptParts
from core.global_symbols import NotFound, NO_MATCH
from core.sheerka.services.sheerka_service import BaseService from core.sheerka.services.sheerka_service import BaseService
from core.tokenizer import Tokenizer, TokenKind, Token from core.tokenizer import Tokenizer, TokenKind, Token, Keywords
NO_MATCH = "** No Match **" PARSE_STEPS = [BuiltinConcepts.BEFORE_PARSING, BuiltinConcepts.PARSING, BuiltinConcepts.AFTER_PARSING]
EVALUATOR_STEPS = [ PARSE_AND_EVAL_STEPS = PARSE_STEPS + [BuiltinConcepts.BEFORE_EVALUATION,
BuiltinConcepts.BEFORE_PARSING,
BuiltinConcepts.AFTER_PARSING,
BuiltinConcepts.BEFORE_EVALUATION,
BuiltinConcepts.EVALUATION, BuiltinConcepts.EVALUATION,
BuiltinConcepts.AFTER_EVALUATION, BuiltinConcepts.AFTER_EVALUATION]
BuiltinConcepts.BEFORE_RENDERING, ALL_STEPS = PARSE_AND_EVAL_STEPS + [BuiltinConcepts.BEFORE_RENDERING,
BuiltinConcepts.RENDERING, BuiltinConcepts.RENDERING,
BuiltinConcepts.AFTER_RENDERING, BuiltinConcepts.AFTER_RENDERING,
BuiltinConcepts.BEFORE_RULES_EVALUATION, BuiltinConcepts.BEFORE_RULES_EVALUATION,
BuiltinConcepts.AFTER_RULES_EVALUATION, BuiltinConcepts.AFTER_RULES_EVALUATION]
]
class ParserInput: class ParserInput:
@@ -173,14 +170,15 @@ class SheerkaExecute(BaseService):
def __init__(self, sheerka): def __init__(self, sheerka):
# order must be after SheerkaEvaluateRules because of self.rules_evaluation_service # order must be after SheerkaEvaluateRules because of self.rules_evaluation_service
super().__init__(sheerka, order=5) # order must be after ConceptManager because it needs concept bnf definitions
super().__init__(sheerka, order=15)
self.pi_cache = FastCache(default=lambda key: ParserInput(key), max_size=20) self.pi_cache = FastCache(default=lambda key: ParserInput(key), max_size=20)
self.instantiated_evaluators = None self.instantiated_evaluators = None
self.evaluators_by_name = None self.evaluators_by_name = None
self.instantiated_parsers = None self.instantiated_parsers = None
self.parsers_by_name = None self.parsers_by_name = None
self.old_values = [] self.preprocessed_items_old_values = []
# cache for all preregistered evaluator combination # cache for all preregistered evaluator combination
# the key is the concatenation of the step and the name of evaluators in the group # the key is the concatenation of the step and the name of evaluators in the group
@@ -202,6 +200,10 @@ class SheerkaExecute(BaseService):
def initialize(self): def initialize(self):
self.sheerka.bind_service_method(self.execute, True, visible=False) 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.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.reset_registered_evaluators() self.reset_registered_evaluators()
self.reset_registered_parsers() self.reset_registered_parsers()
@@ -219,7 +221,7 @@ class SheerkaExecute(BaseService):
self.evaluators_by_name = {e.short_name: e for e in self.instantiated_evaluators} self.evaluators_by_name = {e.short_name: e for e in self.instantiated_evaluators}
# get default evaluators by process step # get default evaluators by process step
for process_step in EVALUATOR_STEPS: for process_step in ALL_STEPS:
self.grouped_evaluators_cache[f"{process_step}|__default"] = self.get_grouped( self.grouped_evaluators_cache[f"{process_step}|__default"] = self.get_grouped(
[e for e in self.instantiated_evaluators if process_step in e.steps]) [e for e in self.instantiated_evaluators if process_step in e.steps])
@@ -270,7 +272,7 @@ class SheerkaExecute(BaseService):
if var_name == "preprocess_name": if var_name == "preprocess_name":
continue continue
if hasattr(item, var_name): if hasattr(item, var_name):
self.old_values.append((item, var_name, getattr(item, var_name))) self.preprocessed_items_old_values.append((item, var_name, getattr(item, var_name)))
setattr(item, var_name, value) setattr(item, var_name, value)
def get_evaluators(self, context, process_step): def get_evaluators(self, context, process_step):
@@ -319,29 +321,23 @@ class SheerkaExecute(BaseService):
for priority, parsers_classes in from_cache[0].items()} for priority, parsers_classes in from_cache[0].items()}
return grouped_instances, from_cache[1] return grouped_instances, from_cache[1]
# Normal case, use all registered parsers key = self.get_parsers_key(context)
if not context.preprocess_parsers and not context.preprocess: if key:
return get_instances(self.grouped_parsers_cache["__default"])
# Other case, only use a subset of parsers
# This case is heavily used by lexer node parsers, thru parse_unrecognized
if context.preprocess_parsers and not context.preprocess:
key = "|".join(context.preprocess_parsers)
try: try:
return get_instances(self.grouped_parsers_cache[key]) return key, *get_instances(self.grouped_parsers_cache[key])
except KeyError: except KeyError:
parsers = [self.parsers_by_name[p] for p in context.preprocess_parsers if p in self.parsers_by_name] parsers = [self.parsers_by_name[p] for p in context.preprocess_parsers if p in self.parsers_by_name]
self.grouped_parsers_cache[key] = self.get_grouped(parsers, use_classes=True) self.grouped_parsers_cache[key] = self.get_grouped(parsers, use_classes=True)
return get_instances(self.grouped_parsers_cache[key]) return key, *get_instances(self.grouped_parsers_cache[key])
# final case, parsers attributes are modified by the context # else, case where parsers attributes are modified by the context
# This a the case when we want to disable a specific parser, or change the order of priority # This a the case when we want to disable a specific parser, or change the order of priority
parsers = [self.parsers_by_name[p] for p in context.preprocess_parsers if p in self.parsers_by_name] \ parsers = [self.parsers_by_name[p] for p in context.preprocess_parsers if p in self.parsers_by_name] \
if context.preprocess_parsers else self.instantiated_parsers if context.preprocess_parsers else self.instantiated_parsers
self.preprocess(parsers, context.preprocess) self.preprocess(parsers, context.preprocess)
parsers = [p for p in parsers if p.enabled] # only keep those that are still enabled parsers = [p for p in parsers if p.enabled] # only keep those that are still enabled
groups, sorted_priorities = self.get_grouped(parsers, use_classes=True) groups, sorted_priorities = self.get_grouped(parsers, use_classes=True)
return get_instances((groups, sorted_priorities)) return key, *get_instances((groups, sorted_priorities))
def get_parser_input(self, text, tokens=None): def get_parser_input(self, text, tokens=None):
""" """
@@ -366,6 +362,22 @@ class SheerkaExecute(BaseService):
self.pi_cache.put(key, pi) self.pi_cache.put(key, pi)
return pi return pi
@staticmethod
def get_parsers_key(context):
"""
From the context.preprocess_parsers and context.preprocess,
try to find a key to store the further results of the parsings
:param context:
:return:
"""
if not context.preprocess_parsers and not context.preprocess:
return "__default"
if context.preprocess_parsers and not context.preprocess:
return "|".join(context.preprocess_parsers)
return None
def call_parsers(self, context, return_values): def call_parsers(self, context, return_values):
""" """
Call all the parsers, ordered by priority Call all the parsers, ordered by priority
@@ -398,7 +410,7 @@ class SheerkaExecute(BaseService):
# keep track of the originals user inputs, as they need to be removed at the end # keep track of the originals user inputs, as they need to be removed at the end
user_inputs = to_process[:] user_inputs = to_process[:]
grouped_parsers, sorted_priorities = self.get_parsers(context) parsers_key, grouped_parsers, sorted_priorities = self.get_parsers(context)
stop_processing = False stop_processing = False
for priority in sorted_priorities: for priority in sorted_priorities:
@@ -644,10 +656,10 @@ class SheerkaExecute(BaseService):
return return_values return return_values
def undo_preprocess(self): def undo_preprocess(self):
for item, var_name, value in self.old_values: for item, var_name, value in self.preprocessed_items_old_values:
setattr(item, var_name, value) setattr(item, var_name, value)
self.old_values.clear() self.preprocessed_items_old_values.clear()
@staticmethod @staticmethod
def matches(parser_or_evaluator_name, preprocessor_name): def matches(parser_or_evaluator_name, preprocessor_name):
@@ -655,3 +667,107 @@ class SheerkaExecute(BaseService):
return parser_or_evaluator_name.startswith(preprocessor_name[:-1]) return parser_or_evaluator_name.startswith(preprocessor_name[:-1])
else: else:
return parser_or_evaluator_name == preprocessor_name return parser_or_evaluator_name == preprocessor_name
def parse_unrecognized(self, context, source, parsers, who=None, prop=None, filter_func=None):
"""
Try to recognize concepts or code from source using the given parsers
:param context:
:param source: ParserInput if possible
:param parsers:
:param who: who is asking the parsing ?
:param prop: Extra info, when parsing a property
:param filter_func: Once the result are found, call this function to filter them
:return:
"""
sheerka = context.sheerka
if prop:
action_context = {"prop": prop, "source": source}
desc = f"Parsing attribute '{prop}'"
else:
action_context = source
desc = f"Parsing '{source}'"
with context.push(BuiltinConcepts.PARSING, action_context, who=who, desc=desc) as sub_context:
# disable all parsers but the requested ones
if parsers != "all":
sub_context.preprocess_parsers = parsers
# sub_context.add_preprocess(BaseParser.PREFIX + "*", enabled=False)
# for parser in parsers:
# sub_context.add_preprocess(BaseParser.PREFIX + parser, enabled=True)
if prop in (Keywords.WHERE, Keywords.PRE, ConceptParts.WHERE, ConceptParts.PRE, Keywords.WHEN):
sub_context.protected_hints.add(BuiltinConcepts.EVAL_QUESTION_REQUESTED)
sub_context.add_inputs(source=source)
to_parse = sheerka.ret(context.who,
True,
sheerka.new(BuiltinConcepts.USER_INPUT, body=source))
res = sheerka.execute(sub_context, to_parse, PARSE_STEPS)
if filter_func:
res = filter_func(sub_context, res)
sub_context.add_values(return_values=res)
return res
def parse_function(self, context, source, tokens=None, start=0):
"""
Helper function that parses what is supposed to be a function
:param context:
:param source:
:param tokens:
:param start: start index for the source code node
:return:
"""
from parsers.BaseNodeParser import SourceCodeWithConceptNode
sheerka = context.sheerka
from parsers.FunctionParser import FunctionParser
parser = FunctionParser()
desc = f"Parsing function '{source}'"
with context.push(BuiltinConcepts.PARSE_CODE, source, desc=desc) as sub_context:
sheerka_execution = sheerka.services[SheerkaExecute.NAME]
res = parser.parse(sub_context, sheerka_execution.get_parser_input(source, tokens))
if not isinstance(res, list):
res = [res]
for r in [r for r in res if sheerka.isinstance(r.body, BuiltinConcepts.PARSER_RESULT)]:
r.body.body.start += start
r.body.body.end += start
if isinstance(r.body.body, SourceCodeWithConceptNode):
for n in [r.body.body.first, r.body.body.last] + r.body.body.nodes:
n.start += start
n.end += start
return res
def parse_python(self, context, source, desc=None):
"""
Helper function that parses what is known to be Python source code
:param context:
:param source:
:param desc: option description when creating the sub context
"""
from parsers.PythonParser import PythonParser
desc = desc or f"Compiling python '{source}'"
with context.push(BuiltinConcepts.PARSE_CODE,
{"language": "Python", "source": source},
desc) as sub_context:
parser_input = context.sheerka.services[SheerkaExecute.NAME].get_parser_input(source)
python_parser = PythonParser()
return python_parser.parse(sub_context, parser_input)
def parse_expression(self, context, source, desc=None):
"""
Helper function to parser expressions with AND, OR and NOT
"""
desc = desc or f"Parsing expression '{source}'"
with context.push(BuiltinConcepts.PARSE_CODE, source, desc) as sub_context:
parser_input = context.sheerka.services[SheerkaExecute.NAME].get_parser_input(source)
from parsers.ExpressionParser import ExpressionParser
expr_parser = ExpressionParser()
return expr_parser.parse(sub_context, parser_input)
@@ -35,6 +35,9 @@ class History:
return self.event == other.event and self.result == other.result return self.event == other.event and self.result == other.result
def __hash__(self):
return hash((self.event, self.result, self.status))
@property @property
def status(self): def status(self):
if self._status: if self._status:
@@ -56,9 +59,6 @@ class SheerkaHistoryManager(BaseService):
def __init__(self, sheerka): def __init__(self, sheerka):
super().__init__(sheerka) super().__init__(sheerka)
def initialize(self):
self.sheerka.bind_service_method(self.history, False)
def history(self, depth=10, start=0): def history(self, depth=10, start=0):
""" """
Load history Load history
@@ -90,7 +90,7 @@ class SheerkaIsAManager(BaseService):
self.sheerka.services[SheerkaConceptManager.NAME].update_references(context, concept_set) self.sheerka.services[SheerkaConceptManager.NAME].update_references(context, concept_set)
# remove the grammar entry so that it can be recreated # remove the grammar entry so that it can be recreated
self.sheerka.om.delete(self.sheerka.CONCEPTS_GRAMMARS_ENTRY, concept_set.id) self.sheerka.clear_bnf_definition(concept_set.id)
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS)) return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
@@ -31,6 +31,7 @@ class SheerkaMemory(BaseService):
self.sheerka.bind_service_method(self.add_to_memory, True, visible=False) self.sheerka.bind_service_method(self.add_to_memory, True, visible=False)
self.sheerka.bind_service_method(self.add_many_to_short_term_memory, True, visible=False) 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_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.register_object, True, visible=False)
self.sheerka.bind_service_method(self.unregister_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.commit_registered_objects, True, visible=False)
@@ -94,6 +95,21 @@ class SheerkaMemory(BaseService):
:param concept: :param concept:
:return: :return:
""" """
last = self.sheerka.om.get(SheerkaMemory.OBJECTS_ENTRY, key)
if last is NotFound:
self.sheerka.om.put(SheerkaMemory.OBJECTS_ENTRY, key, MemoryObject(context.event.get_digest(), concept))
return
if not isinstance(last, list) and last.obj == concept:
self.sheerka.om.delete(SheerkaMemory.OBJECTS_ENTRY, key, last)
self.sheerka.om.put(SheerkaMemory.OBJECTS_ENTRY, key, MemoryObject(context.event.get_digest(), concept))
return
if isinstance(last, list) and last[-1].obj == concept:
self.sheerka.om.delete(SheerkaMemory.OBJECTS_ENTRY, key, last[-1])
self.sheerka.om.put(SheerkaMemory.OBJECTS_ENTRY, key, MemoryObject(context.event.get_digest(), concept))
return
self.sheerka.om.put(SheerkaMemory.OBJECTS_ENTRY, key, MemoryObject(context.event.get_digest(), concept)) self.sheerka.om.put(SheerkaMemory.OBJECTS_ENTRY, key, MemoryObject(context.event.get_digest(), concept))
def get_from_memory(self, context, key): def get_from_memory(self, context, key):
@@ -101,6 +117,20 @@ class SheerkaMemory(BaseService):
""" """
return self.sheerka.om.get(SheerkaMemory.OBJECTS_ENTRY, key) return self.sheerka.om.get(SheerkaMemory.OBJECTS_ENTRY, key)
def get_last_from_memory(self, context, key):
"""
Return an object from memory
When there are multiple items, returns the last one
"""
res = self.sheerka.om.get(SheerkaMemory.OBJECTS_ENTRY, key)
if res is NotFound:
return res
if isinstance(res, list):
return res[-1]
return res
def register_object(self, context, key, concept): def register_object(self, context, key, concept):
""" """
Before adding memory_objects to memory, they first need to be registered Before adding memory_objects to memory, they first need to be registered
@@ -114,6 +144,8 @@ class SheerkaMemory(BaseService):
:param concept: :param concept:
:return: :return:
""" """
if self.sheerka.during_initialisation:
return
self.registration[key] = concept self.registration[key] = concept
def unregister_object(self, context, key): def unregister_object(self, context, key):
+2
View File
@@ -14,6 +14,8 @@ class SheerkaOut(BaseService):
def initialize(self): def initialize(self):
self.sheerka.bind_service_method(self.process_return_values, False) self.sheerka.bind_service_method(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")
def create_out_tree(self, context, obj): def create_out_tree(self, context, obj):
debugger = context.get_debugger("Visitor", "create_out_tree") debugger = context.get_debugger("Visitor", "create_out_tree")
@@ -6,8 +6,7 @@ from typing import Union, Set, List
from cache.Cache import Cache from cache.Cache import Cache
from cache.ListIfNeededCache import ListIfNeededCache from cache.ListIfNeededCache import ListIfNeededCache
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept
from core.builtin_helpers import parse_unrecognized, is_a_question, parse_python, \ from core.builtin_helpers import is_a_question, ensure_evaluated, expect_one
ensure_evaluated, expect_one, parse_expression
from core.concept import Concept from core.concept import Concept
from core.global_symbols import EVENT_RULE_PRECEDENCE_MODIFIED, RULE_COMPARISON_CONTEXT, NotFound, ErrorObj, \ from core.global_symbols import EVENT_RULE_PRECEDENCE_MODIFIED, RULE_COMPARISON_CONTEXT, NotFound, ErrorObj, \
EVENT_RULE_CREATED, EVENT_RULE_DELETED EVENT_RULE_CREATED, EVENT_RULE_DELETED
@@ -765,7 +764,7 @@ class SheerkaRuleManager(BaseService):
parsed = [] parsed = []
errors = [] errors = []
all_rete_disjunctions = [] all_rete_disjunctions = []
parsed_expr_ret = parse_expression(context, source) parsed_expr_ret = context.sheerka.parse_expression(context, source)
if parsed_expr_ret.status: if parsed_expr_ret.status:
conjunctions = parsed_expr_ret.body.body.parts if isinstance(parsed_expr_ret.body.body, AndNode) else \ conjunctions = parsed_expr_ret.body.body.parts if isinstance(parsed_expr_ret.body.body, AndNode) else \
[parsed_expr_ret.body.body] [parsed_expr_ret.body.body]
@@ -812,7 +811,7 @@ class SheerkaRuleManager(BaseService):
return self.sheerka.ret(self.NAME, True, parsed) return self.sheerka.ret(self.NAME, True, parsed)
def compile_exec(self, context, source): def compile_exec(self, context, source):
parsed = parse_unrecognized(context, parsed = context.sheerka.parse_unrecognized(context,
source, source,
parsers="all", parsers="all",
who=self.NAME, who=self.NAME,
@@ -1014,7 +1013,10 @@ class SheerkaRuleManager(BaseService):
return RuleCompiledPredicate(source, action, ConceptEvaluator.NAME, r, c) return RuleCompiledPredicate(source, action, ConceptEvaluator.NAME, r, c)
else: else:
to_parse = PythonCodeEmitter(context, "__ret.status").recognize_concept(c, "__ret.body").get_text() to_parse = PythonCodeEmitter(context, "__ret.status").recognize_concept(c, "__ret.body").get_text()
return RuleCompiledPredicate(source, action, PythonEvaluator.NAME, parse_python(context, to_parse), return RuleCompiledPredicate(source,
action,
PythonEvaluator.NAME,
context.sheerka.parse_python(context, to_parse),
None) None)
res = [] res = []
-6
View File
@@ -23,11 +23,5 @@ class AddToMemoryEvaluator(OneReturnValueEvaluator):
return len(context.sheerka.services[SheerkaMemory.NAME].registration) > 0 return len(context.sheerka.services[SheerkaMemory.NAME].registration) > 0
def eval(self, context, return_value): def eval(self, context, return_value):
if context.sheerka.during_initialisation:
from core.sheerka.services.SheerkaMemory import SheerkaMemory
service = context.sheerka.services[SheerkaMemory.NAME]
service.registration.clear()
return None
context.sheerka.commit_registered_objects(context) context.sheerka.commit_registered_objects(context)
return None # no need to have a second pass return None # no need to have a second pass
+9 -2
View File
@@ -168,9 +168,16 @@ class DefConceptEvaluator(OneReturnValueEvaluator):
source = ret_value.value.source.as_text() if isinstance(ret_value.value.source, source = ret_value.value.source.as_text() if isinstance(ret_value.value.source,
ParserInput) else ret_value.value.source ParserInput) else ret_value.value.source
tokens = ret_value.value.tokens or list(Tokenizer(source, yield_eof=False)) tokens = ret_value.value.tokens or list(Tokenizer(source, yield_eof=False))
tokens = [t.str_value for t in tokens] possible_vars = set()
for t in tokens:
if t.type == TokenKind.RULE:
for v in [v for v in t.value if v is not None]:
possible_vars.add(v)
else:
possible_vars.add(t.str_value)
for identifier in [i for i in concept_name if str(i).isalnum()]: for identifier in [i for i in concept_name if str(i).isalnum()]:
if identifier in tokens: if identifier in possible_vars:
variables.add(identifier) variables.add(identifier)
debugger.debug_var("names", variables, hint="from concept") debugger.debug_var("names", variables, hint="from concept")
return variables return variables
+11 -9
View File
@@ -11,9 +11,10 @@ from core.concept import ConceptParts, Concept
from core.global_symbols import NotInit, NotFound from core.global_symbols import NotInit, NotFound
from core.rule import Rule from core.rule import Rule
from core.sheerka.ExecutionContext import ExecutionContext from core.sheerka.ExecutionContext import ExecutionContext
from core.sheerka.services.SheerkaMemory import SheerkaMemory
from core.tokenizer import Token, TokenKind from core.tokenizer import Token, TokenKind
from evaluators.BaseEvaluator import OneReturnValueEvaluator from evaluators.BaseEvaluator import OneReturnValueEvaluator
from parsers.PythonParser import PythonNode, get_python_node from parsers.PythonParser import PythonNode
TO_DISABLED = ["breakpoint", "callable", "compile", "delattr", "eval", "exec", "exit", "input", "locals", "open", TO_DISABLED = ["breakpoint", "callable", "compile", "delattr", "eval", "exec", "exit", "input", "locals", "open",
"print", "quit", "setattr"] "print", "quit", "setattr"]
@@ -97,7 +98,7 @@ class PythonEvaluator(OneReturnValueEvaluator):
debugger = context.get_debugger(PythonEvaluator.NAME, "eval") debugger = context.get_debugger(PythonEvaluator.NAME, "eval")
debugger.debug_entering(node=node) debugger.debug_entering(node=node)
exception_debugger = context.get_debugger("Exceptions", PythonEvaluator.NAME + ".eval") exception_debugger = context.get_debugger("Exceptions", PythonEvaluator.NAME + "-eval")
get_trace_back = exception_debugger.is_enabled() get_trace_back = exception_debugger.is_enabled()
context.log(f"Evaluating python node {node}.", self.name) context.log(f"Evaluating python node {node}.", self.name)
@@ -140,8 +141,8 @@ class PythonEvaluator(OneReturnValueEvaluator):
context.log("Evaluating using 'exec'.", self.name) context.log("Evaluating using 'exec'.", self.name)
evaluated = self.exec_with_return(node.ast_, globals_, my_locals) evaluated = self.exec_with_return(node.ast_, globals_, my_locals)
# TODO find a better implementation using SheerkaMemory for k, v in my_locals.items():
sheerka.locals.update(my_locals) sheerka.services[SheerkaMemory.NAME].add_to_memory(context, k, v)
if not expect_success or evaluated: if not expect_success or evaluated:
break # in this first version, we stop once a success is found break # in this first version, we stop once a success is found
@@ -231,17 +232,18 @@ class PythonEvaluator(OneReturnValueEvaluator):
my_globals[name] = Expando("sheerka", bag) my_globals[name] = Expando("sheerka", bag)
continue continue
# search in local variables. To remove when local variables will be merged with memory
if name in context.sheerka.locals:
my_globals[name] = context.sheerka.locals[name]
continue
# search in short term memory # search in short term memory
if (obj := context.get_from_short_term_memory(name)) is not NotFound: if (obj := context.get_from_short_term_memory(name)) is not NotFound:
context.log(f"Resolving '{name}'. Using value found in STM.", self.name) context.log(f"Resolving '{name}'. Using value found in STM.", self.name)
my_globals[name] = obj my_globals[name] = obj
continue continue
# search in memory
if (obj := context.sheerka.get_last_from_memory(context, name)) is not NotFound:
context.log(f"Resolving '{name}'. Using value found in Long Term Memory.", self.name)
my_globals[name] = obj.obj
continue
# search in sheerka methods # search in sheerka methods
if (method := self.get_sheerka_method(context, name, expression_only)) is not None: if (method := self.get_sheerka_method(context, name, expression_only)) is not None:
my_globals[name] = method my_globals[name] = method
+13 -2
View File
@@ -231,8 +231,7 @@ class ConceptNode(LexerNode):
def clone(self): def clone(self):
# do we need to clone the concept as well ? # do we need to clone the concept as well ?
clone = ConceptNode(self.concept, self.start, self.end, self.tokens, self.source, self.underlying) return ConceptNode(self.concept, self.start, self.end, self.tokens, self.source, self.underlying)
return clone
def as_bag(self): def as_bag(self):
""" """
@@ -305,6 +304,16 @@ class SourceCodeNode(LexerNode):
def get_source_to_parse(self): def get_source_to_parse(self):
return self.python_node.source return self.python_node.source
def clone(self):
clone = SourceCodeNode(
self.start,
self.end,
self.tokens,
self.source,
self.python_node,
self.return_value)
return clone
class SourceCodeWithConceptNode(LexerNode): class SourceCodeWithConceptNode(LexerNode):
""" """
@@ -413,6 +422,8 @@ class SourceCodeWithConceptNode(LexerNode):
def clone(self): def clone(self):
clone = SourceCodeWithConceptNode(self.first, self.last, self.nodes.copy(), self.has_unrecognized) clone = SourceCodeWithConceptNode(self.first, self.last, self.nodes.copy(), self.has_unrecognized)
clone.python_node = self.python_node
clone.return_value = self.return_value
return clone return clone
def to_short_str(self): def to_short_str(self):
+1 -1
View File
@@ -1189,7 +1189,7 @@ class BnfNodeParser(BaseNodeParser):
if 'sheerka' in kwargs: if 'sheerka' in kwargs:
sheerka = kwargs.get("sheerka") sheerka = kwargs.get("sheerka")
self.concepts_grammars = sheerka.concepts_grammars self.concepts_grammars = sheerka.get_concepts_bnf_definitions()
self.sheerka = sheerka self.sheerka = sheerka
else: else:
self.concepts_grammars = Cache() self.concepts_grammars = Cache()
+1 -1
View File
@@ -211,7 +211,7 @@ class DefConceptParser(BaseCustomGrammarParser):
return None return None
source = self.sheerka.services[SheerkaExecute.NAME].get_parser_input(None, tokens[1:]) source = self.sheerka.services[SheerkaExecute.NAME].get_parser_input(None, tokens[1:])
parsed = core.builtin_helpers.parse_unrecognized(self.context, parsed = self.sheerka.parse_unrecognized(self.context,
source, source,
parsers="all", parsers="all",
who=self.name, who=self.name,
+3 -4
View File
@@ -1,8 +1,7 @@
from itertools import product from itertools import product
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.builtin_helpers import only_successful, parse_unrecognized, get_inner_body, parse_python, \ from core.builtin_helpers import only_successful, get_inner_body, get_lexer_nodes_using_positions
get_lexer_nodes_using_positions
from core.sheerka.services.SheerkaExecute import ParserInput from core.sheerka.services.SheerkaExecute import ParserInput
from core.sheerka.services.sheerka_service import FailedToCompileError from core.sheerka.services.sheerka_service import FailedToCompileError
from core.tokenizer import TokenKind, Tokenizer, Keywords from core.tokenizer import TokenKind, Tokenizer, Keywords
@@ -247,7 +246,7 @@ class ExpressionParser(BaseParser):
for conjunction in conjunctions: for conjunction in conjunctions:
# try to recognize conjunction, one by one # try to recognize conjunction, one by one
# negative conjunction can be a concept starting with 'not' # negative conjunction can be a concept starting with 'not'
parsed_ret = parse_unrecognized( parsed_ret = context.sheerka.parse_unrecognized(
context, context,
conjunction.get_value(), # we remove the 'NOT' part when needed to ease the recognition conjunction.get_value(), # we remove the 'NOT' part when needed to ease the recognition
parsers="all", parsers="all",
@@ -280,7 +279,7 @@ class ExpressionParser(BaseParser):
return_values.append(recognized_conjunctions[0]) return_values.append(recognized_conjunctions[0])
elif len(recognized_conjunctions) == 1 and recognized_conjunctions[0].who == "parsers.Python": elif len(recognized_conjunctions) == 1 and recognized_conjunctions[0].who == "parsers.Python":
# it is a negated python Node. Need to parse again # it is a negated python Node. Need to parse again
ret = parse_python(context, source=str(conjunctions[0])) ret = context.sheerka.parse_python(context, source=str(conjunctions[0]))
if ret.status: if ret.status:
return_values.append(ret) return_values.append(ret)
else: else:
+18 -54
View File
@@ -1,22 +1,20 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import List
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.builtin_helpers import get_lexer_nodes_from_unrecognized, update_compiled from core.builtin_helpers import get_lexer_nodes_from_unrecognized, update_compiled
from core.concept import Concept from core.concept import Concept
from core.sheerka.services.SheerkaExecute import ParserInput from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import TokenKind, Token from core.tokenizer import TokenKind
from core.utils import get_n_clones from core.utils import get_n_clones
from parsers.SequenceNodeParser import SequenceNodeParser
from parsers.BaseNodeParser import SourceCodeNode, SourceCodeWithConceptNode, UnrecognizedTokensNode from parsers.BaseNodeParser import SourceCodeNode, SourceCodeWithConceptNode, UnrecognizedTokensNode
from parsers.BaseParser import BaseParser, UnexpectedTokenParsingError, UnexpectedEofParsingError, Node from parsers.BaseParser import BaseParser, UnexpectedTokenParsingError, UnexpectedEofParsingError, Node
from parsers.BnfNodeParser import BnfNodeParser from parsers.BnfNodeParser import BnfNodeParser
from parsers.PythonWithConceptsParser import PythonWithConceptsParser from parsers.PythonWithConceptsParser import PythonWithConceptsParser
from parsers.RuleParser import RuleParser from parsers.RuleParser import RuleParser
from parsers.SequenceNodeParser import SequenceNodeParser
from parsers.SyaNodeParser import SyaNodeParser from parsers.SyaNodeParser import SyaNodeParser
from parsers.expressions import NameExprNode
# No need to check for Python code as the source code node will resolve to python code anyway
# I only look for concepts, so
PARSERS = [RuleParser.NAME, PARSERS = [RuleParser.NAME,
SequenceNodeParser.NAME, SequenceNodeParser.NAME,
BnfNodeParser.NAME, BnfNodeParser.NAME,
@@ -28,49 +26,16 @@ class FunctionParserNode(Node):
pass pass
@dataclass()
class NamesNode(FunctionParserNode):
start: int # index of the first token
end: int # index of the last token
tokens: List[Token]
def __repr__(self):
return f"NameNode('{self.str_value()}')"
def str_value(self):
if self.tokens is None:
return None
return "".join([t.str_value for t in self.tokens])
def to_unrecognized(self):
"""
UnrecognizedTokensNode with all tokens
"""
return UnrecognizedTokensNode(self.start, self.end, self.tokens).fix_source()
def to_str_unrecognized(self):
"""
UnrecognizedTokensNode with one token, which is a string token of all the tokens
"""
token = Token(TokenKind.STRING,
"'" + self.str_value() + "'",
self.tokens[0].index,
self.tokens[0].line,
self.tokens[0].column)
return UnrecognizedTokensNode(self.start, self.end, [token]).fix_source()
@dataclass() @dataclass()
class FunctionParameter: class FunctionParameter:
""" """
class the represent result of the parameter parsing class the represent result of the parameter parsing
""" """
value: NamesNode # value parsed value: NameExprNode # value parsed
separator: NamesNode = None # holds the value and the position of the separator separator: NameExprNode = None # holds the value and the position of the separator
def add_sep(self, start, end, tokens): def add_sep(self, start, end, tokens):
self.separator = NamesNode(start, end, tokens) self.separator = NameExprNode(start, end, tokens)
def value_to_unrecognized(self): def value_to_unrecognized(self):
return UnrecognizedTokensNode(self.value.start, self.value.end, self.value.tokens).fix_source() return UnrecognizedTokensNode(self.value.start, self.value.end, self.value.tokens).fix_source()
@@ -83,8 +48,8 @@ class FunctionParameter:
@dataclass @dataclass
class FunctionNode(FunctionParserNode): class FunctionNode(FunctionParserNode):
first: NamesNode # beginning of the function (it should represent the name of the function) first: NameExprNode # beginning of the function (it should represent the name of the function)
last: NamesNode # last part of the function (it should be the trailing parenthesis) last: NameExprNode # last part of the function (it should be the trailing parenthesis)
parameters: list parameters: list
@@ -95,11 +60,11 @@ class FN(FunctionNode):
Thereby, Thereby,
FN("first", "last", ["param1," ...]) can be compared to FN("first", "last", ["param1," ...]) can be compared to
FunctionNode(NamesNode("first"), NamesNode("second"), [FunctionParameter(NamesNodes("param1"), NamesNodes(", ")]) FunctionNode(NameExprNode("first"), NameExprNode("second"), [FunctionParameter(NamesNodes("param1"), NamesNodes(", ")])
Note that FunctionParameter can easily be defined with a single string Note that FunctionParameter can easily be defined with a single string
* "param" -> FunctionParameter(NamesNode("param"), None) * "param" -> FunctionParameter(NameExprNode("param"), None)
* "param, " -> FunctionParameter(NamesNode("param"), NamesNode(", ")) * "param, " -> FunctionParameter(NameExprNode("param"), NameExprNode(", "))
For more complicated situations, you can use a tuple (value, sep) to define the value part and the separator part For more complicated situations, you can use a tuple (value, sep) to define the value part and the separator part
""" """
@@ -123,14 +88,13 @@ class FN(FunctionNode):
return self.first == other.first and self.last == other.last and self.parameters == other.parameters return self.first == other.first and self.last == other.last and self.parameters == other.parameters
if isinstance(other, FunctionNode): if isinstance(other, FunctionNode):
if self.first != other.first.str_value() or self.last != other.last.str_value(): if self.first != other.first.value or self.last != other.last.value:
return False return False
if len(self.parameters) != len(other.parameters): if len(self.parameters) != len(other.parameters):
return False return False
for self_parameter, other_parameter in zip(self.parameters, other.parameters): for self_parameter, other_parameter in zip(self.parameters, other.parameters):
value = other_parameter.value.str_value() if isinstance(self_parameter[0], value = other_parameter.value.value if isinstance(self_parameter[0], str) else other_parameter.value
str) else other_parameter.value sep = other_parameter.separator.value if other_parameter.separator else None
sep = other_parameter.separator.str_value() if other_parameter.separator else None
if self_parameter[0] != value or self_parameter[1] != sep: if self_parameter[0] != value or self_parameter[1] != sep:
return False return False
@@ -244,7 +208,7 @@ class FunctionParser(BaseParser):
[TokenKind.LPAR])) [TokenKind.LPAR]))
return None return None
start_node = NamesNode(start, start + 1, self.parser_input.tokens[start:start + 2]) start_node = NameExprNode(start, start + 1, self.parser_input.tokens[start:start + 2])
if not self.parser_input.next_token(): if not self.parser_input.next_token():
self.add_error(UnexpectedEofParsingError(f"Unexpected EOF after left parenthesis")) self.add_error(UnexpectedEofParsingError(f"Unexpected EOF after left parenthesis"))
return FunctionNode(start_node, None, None) return FunctionNode(start_node, None, None)
@@ -261,7 +225,7 @@ class FunctionParser(BaseParser):
return FunctionNode(start_node, None, params) return FunctionNode(start_node, None, params)
return FunctionNode(start_node, return FunctionNode(start_node,
NamesNode(self.parser_input.pos, self.parser_input.pos, [token]), NameExprNode(self.parser_input.pos, self.parser_input.pos, [token]),
params) params)
def parse_parameters(self): def parse_parameters(self):
@@ -319,7 +283,7 @@ class FunctionParser(BaseParser):
if not self.parser_input.next_token(skip_whitespace=False): if not self.parser_input.next_token(skip_whitespace=False):
break break
return NamesNode(start_pos, self.parser_input.pos - 1, tokens) if len(tokens) else None return NameExprNode(start_pos, self.parser_input.pos - 1, tokens) if len(tokens) else None
def to_source_code_node(self, function_node: FunctionNode): def to_source_code_node(self, function_node: FunctionNode):
python_parser = PythonWithConceptsParser() python_parser = PythonWithConceptsParser()
@@ -350,7 +314,7 @@ class FunctionParser(BaseParser):
# try to recognize every parameter, one by one # try to recognize every parameter, one by one
for param in function_node.parameters: for param in function_node.parameters:
if isinstance(param.value, NamesNode): if isinstance(param.value, NameExprNode):
# try to recognize concepts # try to recognize concepts
unrecognized = param.value.to_unrecognized() unrecognized = param.value.to_unrecognized()
nodes_sequences = get_lexer_nodes_from_unrecognized(self.context, nodes_sequences = get_lexer_nodes_from_unrecognized(self.context,
+2 -2
View File
@@ -1,5 +1,5 @@
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.builtin_helpers import parse_python, CreateObjectIdentifiers from core.builtin_helpers import CreateObjectIdentifiers
from parsers.BaseNodeParser import ConceptNode, RuleNode from parsers.BaseNodeParser import ConceptNode, RuleNode
from parsers.BaseNodeParser import SourceCodeWithConceptNode from parsers.BaseNodeParser import SourceCodeWithConceptNode
from parsers.BaseParser import BaseParser from parsers.BaseParser import BaseParser
@@ -71,7 +71,7 @@ class PythonWithConceptsParser(BaseParser):
if hasattr(node, "get_python_node"): if hasattr(node, "get_python_node"):
python_ids_mappings.update(node.get_python_node().objects) python_ids_mappings.update(node.get_python_node().objects)
result = parse_python(context, to_parse, "Trying Python for '" + to_parse + "'") result = context.sheerka.parse_python(context, to_parse, "Trying Python for '" + to_parse + "'")
if result.status: if result.status:
python_node = result.body.body python_node = result.body.body
+1 -2
View File
@@ -5,7 +5,6 @@ from typing import List
from core import builtin_helpers from core import builtin_helpers
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.builtin_helpers import parse_function
from core.concept import Concept, DEFINITION_TYPE_BNF from core.concept import Concept, DEFINITION_TYPE_BNF
from core.global_symbols import CONCEPT_COMPARISON_CONTEXT from core.global_symbols import CONCEPT_COMPARISON_CONTEXT
from core.sheerka.services.SheerkaComparisonManager import SheerkaComparisonManager from core.sheerka.services.SheerkaComparisonManager import SheerkaComparisonManager
@@ -833,7 +832,7 @@ class InFixToPostFix:
if self.unrecognized_tokens.parenthesis_count == 0: if self.unrecognized_tokens.parenthesis_count == 0:
self.unrecognized_tokens.fix_source() self.unrecognized_tokens.fix_source()
res = parse_function(self.context, res = self.context.sheerka.parse_function(self.context,
self.unrecognized_tokens.source, self.unrecognized_tokens.source,
self.unrecognized_tokens.tokens[:], self.unrecognized_tokens.tokens[:],
self.unrecognized_tokens.start) self.unrecognized_tokens.start)
+3 -3
View File
@@ -2,11 +2,11 @@ from dataclasses import dataclass
import core.utils import core.utils
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.builtin_helpers import only_successful, parse_unrecognized, get_lexer_nodes, update_compiled from core.builtin_helpers import only_successful, get_lexer_nodes, update_compiled
from parsers.SequenceNodeParser import SequenceNodeParser
from parsers.BaseNodeParser import ConceptNode, UnrecognizedTokensNode, SourceCodeNode, SourceCodeWithConceptNode from parsers.BaseNodeParser import ConceptNode, UnrecognizedTokensNode, SourceCodeNode, SourceCodeWithConceptNode
from parsers.BaseParser import BaseParser, ParsingError from parsers.BaseParser import BaseParser, ParsingError
from parsers.BnfNodeParser import BnfNodeParser from parsers.BnfNodeParser import BnfNodeParser
from parsers.SequenceNodeParser import SequenceNodeParser
from parsers.SyaNodeParser import SyaNodeParser from parsers.SyaNodeParser import SyaNodeParser
PARSERS = ["EmptyString", PARSERS = ["EmptyString",
@@ -56,7 +56,7 @@ class UnrecognizedNodeParser(BaseParser):
sequences_found = core.utils.sheerka_product(sequences_found, [res.body]) sequences_found = core.utils.sheerka_product(sequences_found, [res.body])
elif isinstance(node, UnrecognizedTokensNode): elif isinstance(node, UnrecognizedTokensNode):
res = parse_unrecognized(context, node.source, PARSERS) res = context.sheerka.parse_unrecognized(context, node.source, PARSERS)
res = only_successful(context, res) res = only_successful(context, res)
if res.status: if res.status:
lexer_nodes = get_lexer_nodes(res.body.body, node.start, node.tokens) lexer_nodes = get_lexer_nodes(res.body.body, node.start, node.tokens)
+18
View File
@@ -3,6 +3,7 @@ from typing import List, Tuple
from core.tokenizer import Token, TokenKind, Tokenizer from core.tokenizer import Token, TokenKind, Tokenizer
from core.utils import tokens_are_matching from core.utils import tokens_are_matching
from parsers.BaseNodeParser import UnrecognizedTokensNode
from parsers.BaseParser import Node, ParsingError from parsers.BaseParser import Node, ParsingError
@@ -86,6 +87,23 @@ class NameExprNode(ExprNode):
def __hash__(self): def __hash__(self):
return super().__hash__() return super().__hash__()
def to_unrecognized(self):
"""
UnrecognizedTokensNode with all tokens
"""
return UnrecognizedTokensNode(self.start, self.end, self.tokens).fix_source()
def to_str_unrecognized(self):
"""
UnrecognizedTokensNode with one token, which is a string token of all the tokens
"""
token = Token(TokenKind.STRING,
"'" + self.str_value() + "'",
self.tokens[0].index,
self.tokens[0].line,
self.tokens[0].column)
return UnrecognizedTokensNode(self.start, self.end, [token]).fix_source()
@dataclass(init=False) @dataclass(init=False)
class AndNode(ExprNode): class AndNode(ExprNode):
+4 -12
View File
@@ -2,10 +2,9 @@ import hashlib
import json import json
import shutil import shutil
import time import time
from dataclasses import dataclass
from datetime import datetime, date from datetime import datetime, date
from threading import RLock
from os import path from os import path
from threading import RLock
from core.global_symbols import NotFound from core.global_symbols import NotFound
from core.sheerka_logger import get_logger from core.sheerka_logger import get_logger
@@ -115,16 +114,6 @@ class SheerkaDataProviderDuplicateKeyError(Exception):
self.obj = obj self.obj = obj
@dataclass
class SheerkaDataProviderResult:
"""
Object that is returned after adding, setting or modifying an entry
"""
entry: str # entry where the object is put
key: str # key to use to retrieve the object
digest: str # digest used to store the reference
class SheerkaDataProviderTransaction: class SheerkaDataProviderTransaction:
def __init__(self, sdp, event): def __init__(self, sdp, event):
@@ -231,6 +220,9 @@ class SheerkaDataProvider:
snapshot = self.get_snapshot(SheerkaDataProvider.HeadFile) snapshot = self.get_snapshot(SheerkaDataProvider.HeadFile)
self.state = self.load_state(snapshot) self.state = self.load_state(snapshot)
def __repr__(self):
return f"SheerkaDataProvider(name={self.name})"
@staticmethod @staticmethod
def get_stream_digest(stream): def get_stream_digest(stream):
sha256_hash = hashlib.sha256() sha256_hash = hashlib.sha256()
+24
View File
@@ -8,6 +8,7 @@ from core.sheerka.Sheerka import Sheerka
from core.sheerka.services.SheerkaExecute import ParserInput from core.sheerka.services.SheerkaExecute import ParserInput
from evaluators.BaseEvaluator import BaseEvaluator from evaluators.BaseEvaluator import BaseEvaluator
from parsers.BaseParser import BaseParser from parsers.BaseParser import BaseParser
from parsers.DefRuleParser import DefRuleNode, DefExecRuleNode, DefFormatRuleNode
from parsers.PythonParser import PythonNode from parsers.PythonParser import PythonNode
from sheerkapickle.handlers import BaseHandler, registry from sheerkapickle.handlers import BaseHandler, registry
@@ -213,6 +214,26 @@ class PythonNodeHandler(BaseHandler):
return instance return instance
class DefRuleNodeHandler(BaseHandler):
def flatten(self, obj, data):
pickler = self.context
data["tokens"] = pickler.flatten(obj.tokens)
data["name"] = pickler.flatten(obj.name)
return data
def new(self, data):
return DefRuleNode.__new__(DefRuleNode)
def restore(self, data, instance):
pickler = self.context
instance.__init__(data["source"], objects=pickler.restore(data["objects"]))
instance.tokens = pickler.restore(data["tokens"])
instance.name = pickler.restore(data["name"])
return instance
def initialize_pickle_handlers(): def initialize_pickle_handlers():
registry.register(Concept, ConceptHandler, True) registry.register(Concept, ConceptHandler, True)
registry.register(UserInputConcept, UserInputHandler, True) registry.register(UserInputConcept, UserInputHandler, True)
@@ -221,3 +242,6 @@ def initialize_pickle_handlers():
registry.register(ExecutionContext, ExecutionContextHandler, True) registry.register(ExecutionContext, ExecutionContextHandler, True)
registry.register(Rule, RuleContextHandler, True) registry.register(Rule, RuleContextHandler, True)
registry.register(PythonNode, PythonNodeHandler, True) registry.register(PythonNode, PythonNodeHandler, True)
registry.register(DefRuleNode, DefRuleNodeHandler, True)
registry.register(DefExecRuleNode, DefRuleNodeHandler, True) # TODO: fix inheritance that does not work
registry.register(DefFormatRuleNode, DefRuleNodeHandler, True) # TODO: fix inheritance that does not work
+4 -2
View File
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, Generator, Union
from core.concept import Concept from core.concept import Concept
from core.global_symbols import NotInit from core.global_symbols import NotInit
from core.rule import Rule from core.rule import Rule, ACTION_TYPE_PRINT
from core.utils import as_bag from core.utils import as_bag
from sheerkarete.alpha import AlphaMemory from sheerkarete.alpha import AlphaMemory
from sheerkarete.beta import ReteNode, BetaMemory from sheerkarete.beta import ReteNode, BetaMemory
@@ -282,7 +282,9 @@ class ReteNetwork:
if rule.id is None: if rule.id is None:
raise ValueError("Rule has no id, cannot add") raise ValueError("Rule has no id, cannot add")
if not rule.metadata.is_enabled or not rule.metadata.is_compiled: if (not rule.metadata.is_enabled or
not rule.metadata.is_compiled or
rule.metadata.action_type == ACTION_TYPE_PRINT):
return return
if rule.rete_net: if rule.rete_net:
+9 -2
View File
@@ -104,8 +104,12 @@ class BaseTest:
def get_sheerka(self, **kwargs) -> Sheerka: def get_sheerka(self, **kwargs) -> Sheerka:
pass pass
def get_context(self, sheerka=None, eval_body=False, eval_where=False): def get_context(self, sheerka=None, eval_body=False, eval_where=False, message=""):
context = ExecutionContext("test", Event(), sheerka or self.get_sheerka(), BuiltinConcepts.TESTING, None) context = ExecutionContext("test",
Event(message=message),
sheerka or self.get_sheerka(),
BuiltinConcepts.TESTING,
None)
if eval_body: if eval_body:
context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
if eval_where: if eval_where:
@@ -158,6 +162,9 @@ class BaseTest:
def init_format_rules(self, *rules, **kwargs): def init_format_rules(self, *rules, **kwargs):
return self.init_test(**kwargs).with_format_rules(*rules, **kwargs).unpack() return self.init_test(**kwargs).with_format_rules(*rules, **kwargs).unpack()
def init_exec_rules(self, *rules, **kwargs):
return self.init_test(**kwargs).with_exec_rules(*rules, **kwargs).unpack()
@staticmethod @staticmethod
def get_concept_instance(sheerka, concept, **kwargs): def get_concept_instance(sheerka, concept, **kwargs):
""" """
+4
View File
@@ -15,6 +15,10 @@ class TestUsingMemoryBasedSheerka(BaseTest):
while TestUsingMemoryBasedSheerka.sheerka.om.current_ontology().name != self.root_ontology_name: while TestUsingMemoryBasedSheerka.sheerka.om.current_ontology().name != self.root_ontology_name:
TestUsingMemoryBasedSheerka.sheerka.pop_ontology(self.context) TestUsingMemoryBasedSheerka.sheerka.pop_ontology(self.context)
for service_name, service in TestUsingMemoryBasedSheerka.sheerka.services.items():
if hasattr(service, "reset_state"):
service.reset_state()
@staticmethod @staticmethod
def new_sheerka_instance(cache_only): def new_sheerka_instance(cache_only):
sheerka = Sheerka(cache_only=cache_only) sheerka = Sheerka(cache_only=cache_only)
+83 -4
View File
@@ -418,7 +418,22 @@ class TestListIfNeededCache(TestUsingMemoryBasedSheerka):
assert cache.to_remove == set() assert cache.to_remove == set()
assert cache.to_add == {"key"} assert cache.to_add == {"key"}
def test_i_can_delete_when_alt_sdp_a_value_from_cache_remaining_values(self): def test_i_can_delete_when_alt_sdp_a_value_from_cache_and_then_put_back(self):
# There is a value in alt_cache_manager,
# No remaining value in current cache after deletion
# The key must be flagged as Removed
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
cache.put("key", "value")
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "xxx", extend_exists=lambda cache_name, key: True)
cache.delete("key", value="value", alt_sdp=alt_sdp) # remove all values
cache.put("key", "value")
assert cache.copy() == {"key": "value"}
assert cache.to_remove == set()
assert cache.to_add == {"key"}
def test_i_can_delete_when_alt_sdp_a_value_from_cache_remaining_one_value(self):
# There is a value in alt_cache_manager, # There is a value in alt_cache_manager,
# But this, there are remaining values in current cache after deletion # But this, there are remaining values in current cache after deletion
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name") cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
@@ -431,11 +446,26 @@ class TestListIfNeededCache(TestUsingMemoryBasedSheerka):
assert cache.to_remove == set() assert cache.to_remove == set()
assert cache.to_add == {"key"} assert cache.to_add == {"key"}
def test_i_can_delete_when_alt_sdp_a_value_from_cache_remaining_values(self):
# There is a value in alt_cache_manager,
# But this, there are remaining values in current cache after deletion
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
cache.put("key", "value")
cache.put("key", "value2")
cache.put("key", "value3")
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "xxx", extend_exists=lambda cache_name, key: True)
cache.delete("key", value="value", alt_sdp=alt_sdp)
assert cache.copy() == {"key": ['value2', 'value3']}
assert cache.to_remove == set()
assert cache.to_add == {"key"}
def test_i_can_delete_when_alt_sdp_a_key_from_remote_repository(self): def test_i_can_delete_when_alt_sdp_a_key_from_remote_repository(self):
# There is a value in alt_cache_manager, # There is a value in alt_cache_manager,
# No remaining value in current cache after deletion # No remaining value in current cache after deletion
# The key must be flagged as Removed # The key must be flagged as Removed
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: ["value1", "value2"])).auto_configure("cache_name") cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: ["value1", "value2"])).auto_configure(
"cache_name")
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "xxx", extend_exists=lambda cache_name, key: True) alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "xxx", extend_exists=lambda cache_name, key: True)
cache.delete("key", value=None, alt_sdp=alt_sdp) cache.delete("key", value=None, alt_sdp=alt_sdp)
@@ -455,10 +485,23 @@ class TestListIfNeededCache(TestUsingMemoryBasedSheerka):
assert cache.to_remove == set() assert cache.to_remove == set()
assert cache.to_add == {"key"} assert cache.to_add == {"key"}
def test_i_can_delete_when_alt_sdp_a_value_from_remote_repository_remaining_values(self): def test_i_can_delete_when_alt_sdp_a_key_from_remote_repository_and_then_put_back(self):
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: ["value1", "value2"])).auto_configure(
"cache_name")
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "xxx", extend_exists=lambda cache_name, key: True)
cache.delete("key", value=None, alt_sdp=alt_sdp) # remove all values
cache.put("key", "value")
assert cache.copy() == {"key": "value"}
assert cache.to_remove == set()
assert cache.to_add == {"key"}
def test_i_can_delete_when_alt_sdp_a_value_from_remote_repository_remaining_one_value(self):
# There is a value in alt_cache_manager, # There is a value in alt_cache_manager,
# But this, there are remaining values in current cache after deletion # But this, there are remaining values in current cache after deletion
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: ["value1", "value2"])).auto_configure("cache_name") cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: ["value1", "value2"])).auto_configure(
"cache_name")
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "xxx", extend_exists=lambda cache_name, key: True) alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "xxx", extend_exists=lambda cache_name, key: True)
cache.delete("key", value="value1", alt_sdp=alt_sdp) cache.delete("key", value="value1", alt_sdp=alt_sdp)
@@ -492,6 +535,21 @@ class TestListIfNeededCache(TestUsingMemoryBasedSheerka):
assert cache.to_add == {"key"} assert cache.to_add == {"key"}
assert cache.to_remove == set() assert cache.to_remove == set()
def test_i_can_delete_when_alt_sdp_a_value_from_alt_sdp_and_then_put_back(self):
# alt_cache_manager is used because no value in cache or in remote repository
# After value deletion, the key is empty
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "value1",
extend_exists=lambda cache_name, key: True)
cache.delete("key", value="value1", alt_sdp=alt_sdp)
cache.put("key", "value")
assert cache.copy() == {"key": "value"}
assert cache.to_add == {"key"}
assert cache.to_remove == set()
def test_i_can_delete_when_alt_sdp_a_value_from_alt_sdp_one_value_remaining(self): def test_i_can_delete_when_alt_sdp_a_value_from_alt_sdp_one_value_remaining(self):
# alt_cache_manager is used because no value in cache or in remote repository # alt_cache_manager is used because no value in cache or in remote repository
# After value deletion, one value remains in the cache # After value deletion, one value remains in the cache
@@ -567,3 +625,24 @@ class TestListIfNeededCache(TestUsingMemoryBasedSheerka):
assert cache.copy() == {} assert cache.copy() == {}
assert cache.to_add == set() assert cache.to_add == set()
assert cache.to_remove == set() assert cache.to_remove == set()
def test_i_can_add_when_alt_sdp_from_a_removed_remote_repository(self):
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: Removed)).auto_configure("cache_name")
cache.put("key", "value")
assert cache.copy() == {"key": "value"}
assert cache.to_remove == set()
assert cache.to_add == {"key"}
def test_i_can_add_when_alt_sdp_from_a_removed_remote_repository_from_alt_sdp(self):
# The key is removed in the sub layers
# We can put it back
cache = ListIfNeededCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: Removed,
extend_exists=lambda cache_name, key: False)
cache.put("key", "value", alt_sdp=alt_sdp)
assert cache.copy() == {"key": "value"}
assert cache.to_remove == set()
assert cache.to_add == {"key"}
+63
View File
@@ -337,6 +337,20 @@ class TestSetCache(TestUsingMemoryBasedSheerka):
assert cache.to_remove == set() assert cache.to_remove == set()
assert cache.to_add == {"key"} assert cache.to_add == {"key"}
def test_i_can_delete_when_alt_sdp_a_value_from_cache_and_then_put_back(self):
# There is a value in alt_cache_manager,
# No remaining value in current cache after deletion
cache = SetCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
cache.put("key", "value")
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: "xxx", extend_exists=lambda cache_name, key: True)
cache.delete("key", value="value", alt_sdp=alt_sdp)
cache.put("key", "value")
assert cache.copy() == {"key": {"value"}}
assert cache.to_remove == set()
assert cache.to_add == {"key"}
def test_i_can_delete_when_alt_sdp_a_value_from_cache_remaining_values(self): def test_i_can_delete_when_alt_sdp_a_value_from_cache_remaining_values(self):
# There is a value in alt_cache_manager, # There is a value in alt_cache_manager,
# But there is a value in the current cache after deletion # But there is a value in the current cache after deletion
@@ -371,6 +385,19 @@ class TestSetCache(TestUsingMemoryBasedSheerka):
assert cache.to_remove == set() assert cache.to_remove == set()
assert cache.to_add == {"key"} assert cache.to_add == {"key"}
def test_i_can_delete_when_alt_sdp_a_value_from_remote_repository_and_then_put_back(self):
# There is a value in alt_cache_manager,
# No remaining value in current cache after deletion
# The key must be flagged as Removed
cache = SetCache(sdp=FakeSdp(get_value=lambda entry, k: {"value1", "value2"})).auto_configure("cache_name")
cache.delete("key", value=None, alt_sdp=FakeSdp(extend_exists=lambda cache_name, key: True))
cache.put("key", "value")
assert cache.copy() == {"key": {"value"}}
assert cache.to_remove == set()
assert cache.to_add == {"key"}
def test_i_can_delete_when_alt_sdp_a_value_from_remote_repository_remaining_values(self): def test_i_can_delete_when_alt_sdp_a_value_from_remote_repository_remaining_values(self):
# There is a value in alt_cache_manager, # There is a value in alt_cache_manager,
# But there is a value in the current cache after deletion # But there is a value in the current cache after deletion
@@ -407,6 +434,21 @@ class TestSetCache(TestUsingMemoryBasedSheerka):
assert cache.to_add == {"key"} assert cache.to_add == {"key"}
assert cache.to_remove == set() assert cache.to_remove == set()
def test_i_can_delete_when_alt_sdp_a_value_from_alt_sdp_and_then_put_back(self):
# alt_cache_manager is used because no value in cache or in remote repository
# After value deletion, the key is empty
cache = SetCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: {"value1"},
extend_exists=lambda cache_name, key: True)
cache.delete("key", value="value1", alt_sdp=alt_sdp)
cache.put("key", "value")
assert cache.copy() == {"key": {"value"}}
assert cache.to_remove == set()
assert cache.to_add == {"key"}
def test_i_can_delete_when_alt_sdp_a_value_from_alt_sdp_one_value_remaining(self): def test_i_can_delete_when_alt_sdp_a_value_from_alt_sdp_one_value_remaining(self):
# alt_cache_manager is used because no value in cache or in remote repository # alt_cache_manager is used because no value in cache or in remote repository
# After value deletion, the key is empty # After value deletion, the key is empty
@@ -475,3 +517,24 @@ class TestSetCache(TestUsingMemoryBasedSheerka):
assert cache.copy() == {} assert cache.copy() == {}
assert cache.to_add == set() assert cache.to_add == set()
assert cache.to_remove == set() assert cache.to_remove == set()
def test_i_can_add_when_alt_sdp_from_a_removed_remote_repository(self):
cache = SetCache(sdp=FakeSdp(get_value=lambda entry, k: Removed)).auto_configure("cache_name")
cache.put("key", "value")
assert cache.copy() == {"key": {"value"}}
assert cache.to_remove == set()
assert cache.to_add == {"key"}
def test_i_can_add_when_alt_sdp_from_a_removed_remote_repository_from_alt_sdp(self):
# The key is removed in the sub layers
# We can put it back
cache = SetCache(sdp=FakeSdp(get_value=lambda entry, k: NotFound)).auto_configure("cache_name")
alt_sdp = FakeSdp(get_alt_value=lambda cache_name, key: Removed,
extend_exists=lambda cache_name, key: False)
cache.put("key", "value", alt_sdp=alt_sdp)
assert cache.copy() == {"key": {"value"}}
assert cache.to_remove == set()
assert cache.to_add == {"key"}
+23 -1
View File
@@ -3,7 +3,7 @@ import pytest
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept from core.concept import Concept
from core.global_symbols import EVENT_CONCEPT_PRECEDENCE_MODIFIED, CONCEPT_COMPARISON_CONTEXT, \ from core.global_symbols import EVENT_CONCEPT_PRECEDENCE_MODIFIED, CONCEPT_COMPARISON_CONTEXT, \
EVENT_RULE_PRECEDENCE_MODIFIED, RULE_COMPARISON_CONTEXT EVENT_RULE_PRECEDENCE_MODIFIED, RULE_COMPARISON_CONTEXT, NotFound
from core.sheerka.services.SheerkaComparisonManager import SheerkaComparisonManager, ComparisonObj from core.sheerka.services.SheerkaComparisonManager import SheerkaComparisonManager, ComparisonObj
from core.sheerka.services.SheerkaConceptManager import ChickenAndEggError from core.sheerka.services.SheerkaConceptManager import ChickenAndEggError
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -732,3 +732,25 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
assert not res.status assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.IS_LESSER_CONSTRAINT_ERROR) assert sheerka.isinstance(res.body, BuiltinConcepts.IS_LESSER_CONSTRAINT_ERROR)
def test_i_can_seamlessly_use_concept_name_or_concept_itself_when_builtin_concept_to_define_comparison(self):
sheerka, context, foo, bar, baz = self.init_concepts("foo", "bar", "baz")
prec_as_concept = sheerka.new(BuiltinConcepts.PRECEDENCE)
sheerka.set_is_greater_than(context, BuiltinConcepts.PRECEDENCE, foo, bar)
sheerka.set_is_greater_than(context, prec_as_concept, foo, baz)
assert sheerka.om.get(SheerkaComparisonManager.COMPARISON_ENTRY, f"{BuiltinConcepts.PRECEDENCE}|#") == [
ComparisonObj(context.event.get_digest(), BuiltinConcepts.PRECEDENCE, foo.str_id, bar.str_id, ">", "#"),
ComparisonObj(context.event.get_digest(), BuiltinConcepts.PRECEDENCE, foo.str_id, baz.str_id, ">", "#"),
]
assert sheerka.om.get(SheerkaComparisonManager.COMPARISON_ENTRY, f"{prec_as_concept.str_id}|#") is NotFound
def test_i_can_seamlessly_use_concept_id_or_concept_itself_to_define_comparison(self):
sheerka, context, foo, bar, baz, op = self.init_concepts("foo", "bar", "baz", "op")
sheerka.set_is_greater_than(context, op.str_id, foo, bar)
sheerka.set_is_greater_than(context, op, foo, baz)
assert sheerka.om.get(SheerkaComparisonManager.COMPARISON_ENTRY, f"{op.str_id}|#") == [
ComparisonObj(context.event.get_digest(), op.str_id, foo.str_id, bar.str_id, ">", "#"),
ComparisonObj(context.event.get_digest(), op.str_id, foo.str_id, baz.str_id, ">", "#"),
]
+1 -1
View File
@@ -884,7 +884,7 @@ class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
sheerka.set_isa(context, sheerka.new("twenties"), number) sheerka.set_isa(context, sheerka.new("twenties"), number)
sheerka.set_isa(context, sheerka.new("hundreds"), number) sheerka.set_isa(context, sheerka.new("hundreds"), number)
sheerka.concepts_grammars.clear() # reset all the grammar to simulate Sheerka restart sheerka.clear_bnf_definition() # reset all the grammar to simulate Sheerka restart
# cbft : concept_by_first_token (I usually don't use abbreviation) # cbft : concept_by_first_token (I usually don't use abbreviation)
cbft = compute_concepts_by_first_token(context, [number] + concepts).body cbft = compute_concepts_by_first_token(context, [number] + concepts).body
+164 -16
View File
@@ -19,14 +19,32 @@ class DummyObj:
class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka): class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
return_value_id = 0 return_value_id = 0
rv = None
rr = None
rc = None
@classmethod @classmethod
def setup(cls): def setup(cls):
sheerka = cls().get_sheerka() sheerka = cls().get_sheerka()
cls.return_value_id = sheerka.get_by_key("__RETURN_VALUE").id cls.return_value_id = sheerka.get_by_key("__RETURN_VALUE").id
def backup_registered(self, service):
self.rv = service.registered_vars.copy(),
self.rr = service.registered_rules.copy(),
self.rc = service.registered_concepts.copy(),
service.registered_vars.clear()
service.registered_rules.clear()
service.registered_concepts.clear()
def restore_registered(self, service):
service.registered_vars.clear()
service.registered_rules.clear()
service.registered_concepts.clear()
service.registered_vars.extend(self.rv)
service.registered_vars.extend(self.rr)
service.registered_vars.extend(self.rc)
@pytest.mark.parametrize("item_type", [ @pytest.mark.parametrize("item_type", [
"vars", "rules", "concepts" "vars", "rules", "concepts"
]) ])
@@ -387,7 +405,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
sheerka, context = self.init_concepts() sheerka, context = self.init_concepts()
service = sheerka.services[SheerkaDebugManager.NAME] service = sheerka.services[SheerkaDebugManager.NAME]
sheerka.debug_var(context, "s.m.v", "1+", 10, variable="my_var") sheerka.set_debug_var(context, "s.m.v", "1+", 10, variable="my_var")
assert service.debug_vars_settings == [ assert service.debug_vars_settings == [
DebugItem("my_var", "s", "m", 1, True, 10, False, True) DebugItem("my_var", "s", "m", 1, True, 10, False, True)
] ]
@@ -398,7 +416,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
sheerka, context = self.init_concepts() sheerka, context = self.init_concepts()
service = sheerka.services[SheerkaDebugManager.NAME] service = sheerka.services[SheerkaDebugManager.NAME]
sheerka.debug_rule(context, "s.m.v", "1+", 10, rule="my_rule") sheerka.set_debug_rule(context, "s.m.v", "1+", 10, rule="my_rule")
assert service.debug_rules_settings == [ assert service.debug_rules_settings == [
DebugItem("my_rule", "s", "m", 1, True, 10, False, True) DebugItem("my_rule", "s", "m", 1, True, 10, False, True)
] ]
@@ -409,7 +427,7 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
sheerka, context = self.init_concepts() sheerka, context = self.init_concepts()
service = sheerka.services[SheerkaDebugManager.NAME] service = sheerka.services[SheerkaDebugManager.NAME]
sheerka.debug_concept(context, "s.m.v", "1+", 10, concept="my_concept") sheerka.set_debug_concept(context, "s.m.v", "1+", 10, concept="my_concept")
assert service.debug_concepts_settings == [ assert service.debug_concepts_settings == [
DebugItem("my_concept", "s", "m", 1, True, 10, False, True) DebugItem("my_concept", "s", "m", 1, True, 10, False, True)
] ]
@@ -422,9 +440,9 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
root_context = self.get_context(sheerka) root_context = self.get_context(sheerka)
sheerka.set_debug(root_context, True) sheerka.set_debug(root_context, True)
sheerka.debug_var(root_context, "service_name.*.var") sheerka.set_debug_var(root_context, "service_name.*.var")
sheerka.debug_rule(root_context, 1) sheerka.set_debug_rule(root_context, 1)
sheerka.debug_concept(root_context, 1001) sheerka.set_debug_concept(root_context, 1001)
another_service = SheerkaDebugManager(sheerka) another_service = SheerkaDebugManager(sheerka)
another_service.initialize_deferred(root_context, True) another_service.initialize_deferred(root_context, True)
@@ -705,9 +723,9 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
sheerka.push_ontology(context, "new ontology") sheerka.push_ontology(context, "new ontology")
service.set_debug(context) service.set_debug(context)
service.debug_var(context, "var_service.var_method.var_name", "1+", 1) service.set_debug_var(context, "var_service.var_method.var_name", "1+", 1)
service.debug_rule(context, "rule_service.rule_method.rule_name", "2+", 2) service.set_debug_rule(context, "rule_service.rule_method.rule_name", "2+", 2)
service.debug_concept(context, "concept_service.concept_method.concept_name", "3+", 3) service.set_debug_concept(context, "concept_service.concept_method.concept_name", "3+", 3)
# sanity check # sanity check
assert service.activated assert service.activated
@@ -728,17 +746,17 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
service = sheerka.services[SheerkaDebugManager.NAME] service = sheerka.services[SheerkaDebugManager.NAME]
service.set_debug(context) service.set_debug(context)
service.debug_var(context, "v_service.v_method.v_name", "1+", 1) service.set_debug_var(context, "v_service.v_method.v_name", "1+", 1)
service.debug_rule(context, "r_service.r_method.r_name", "2+", 2) service.set_debug_rule(context, "r_service.r_method.r_name", "2+", 2)
service.debug_concept(context, "c_serv.c_method.c_name", "3+", 3) service.set_debug_concept(context, "c_serv.c_method.c_name", "3+", 3)
sheerka.push_ontology(context, "new ontology") sheerka.push_ontology(context, "new ontology")
# modify the state # modify the state
service.set_debug(context, False) service.set_debug(context, False)
service.debug_var(context, "var_service2.var_method2.var_name2", "11+", 11) service.set_debug_var(context, "var_service2.var_method2.var_name2", "11+", 11)
service.debug_rule(context, "rule_service2.rule_method2.rule_name2", "22+", 22) service.set_debug_rule(context, "rule_service2.rule_method2.rule_name2", "22+", 22)
service.debug_concept(context, "concept_service2.concept_method2.concept_name2", "33+", 33) service.set_debug_concept(context, "concept_service2.concept_method2.concept_name2", "33+", 33)
# sanity # sanity
assert not service.activated assert not service.activated
@@ -752,3 +770,133 @@ class TestSheerkaDebugManager(TestUsingMemoryBasedSheerka):
assert service.debug_vars_settings == [DebugItem("v_name", "v_service", "v_method", 1, True, 1, False, True)] assert service.debug_vars_settings == [DebugItem("v_name", "v_service", "v_method", 1, True, 1, False, True)]
assert service.debug_rules_settings == [DebugItem("r_name", "r_service", "r_method", 2, True, 2, False, True)] assert service.debug_rules_settings == [DebugItem("r_name", "r_service", "r_method", 2, True, 2, False, True)]
assert service.debug_concepts_settings == [DebugItem("c_name", "c_serv", "c_method", 3, True, 3, False, True)] assert service.debug_concepts_settings == [DebugItem("c_name", "c_serv", "c_method", 3, True, 3, False, True)]
def test_i_can_register_debug_item(self):
sheerka, context = self.init_concepts()
service = sheerka.services[SheerkaDebugManager.NAME]
try:
self.backup_registered(service)
service.register_debug(service.VARS_DEBUG_TYPE, "service", "method", "var_name")
assert service.registered_vars == [("service", "method", "var_name")]
service.register_debug(service.RULES_DEBUG_TYPE, "service", "method", "rule_name")
assert service.registered_rules == [("service", "method", "rule_name")]
service.register_debug(service.CONCEPTS_DEBUG_TYPE, "service", "method", "concept_name")
assert service.registered_concepts == [("service", "method", "concept_name")]
finally:
self.restore_registered(service)
def test_i_can_filter_registered_debug_item(self):
sheerka, context = self.init_concepts()
service = sheerka.services[SheerkaDebugManager.NAME]
try:
self.backup_registered(service)
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method1", "var_name1")
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method1", "var_name2")
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method2", "var_name1")
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method2", "var_name2")
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method1", "var_name1")
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method1", "var_name2")
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method2", "var_name1")
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method2", "var_name2")
assert list(service.filter_registered_debug(service.VARS_DEBUG_TYPE, "service1")) == [
("service1", "method1", "var_name1"),
("service1", "method1", "var_name2"),
("service1", "method2", "var_name1"),
("service1", "method2", "var_name2"),
]
assert list(service.filter_registered_debug(service.VARS_DEBUG_TYPE, "service1.method2")) == [
("service1", "method2", "var_name1"),
("service1", "method2", "var_name2"),
]
assert list(service.filter_registered_debug(service.VARS_DEBUG_TYPE, "service1.method2.var_name1")) == [
("service1", "method2", "var_name1"),
]
assert list(service.filter_registered_debug(service.VARS_DEBUG_TYPE, "*.*.var_name1")) == [
("service1", "method1", "var_name1"),
("service1", "method2", "var_name1"),
("service2", "method1", "var_name1"),
("service2", "method2", "var_name1"),
]
assert list(service.filter_registered_debug(service.VARS_DEBUG_TYPE, "*.method2.*")) == [
("service1", "method2", "var_name1"),
("service1", "method2", "var_name2"),
("service2", "method2", "var_name1"),
("service2", "method2", "var_name2"),
]
assert list(service.filter_registered_debug(service.VARS_DEBUG_TYPE, method="method1")) == [
("service1", "method1", "var_name1"),
("service1", "method1", "var_name2"),
("service2", "method1", "var_name1"),
("service2", "method1", "var_name2"),
]
finally:
self.restore_registered(service)
def test_i_can_list_registered_debug(self):
sheerka, context = self.init_concepts()
service = sheerka.services[SheerkaDebugManager.NAME]
try:
self.backup_registered(service)
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method1", "var_name1")
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method1", "var_name2")
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method2", "var_name3")
service.register_debug(service.VARS_DEBUG_TYPE, "service1", "method2", "var_name4")
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method3", "var_name5")
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method3", "var_name6")
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method1", "var_name7")
service.register_debug(service.VARS_DEBUG_TYPE, "service2", "method1", "var_name8")
res = service.list_registered(service.VARS_DEBUG_TYPE)
assert sheerka.isinstance(res, BuiltinConcepts.TO_LIST)
assert list(res.body) == ["service1", "service2"]
res = service.list_registered(service.VARS_DEBUG_TYPE, "service2")
assert sheerka.isinstance(res, BuiltinConcepts.TO_LIST)
assert list(res.body) == ["service2.method1", "service2.method3"]
res = service.list_registered(service.VARS_DEBUG_TYPE, "service2.method3")
assert sheerka.isinstance(res, BuiltinConcepts.TO_LIST)
assert list(res.body) == ["service2.method3.var_name5", "service2.method3.var_name6"]
res = service.list_registered(service.VARS_DEBUG_TYPE, "*.method1")
assert sheerka.isinstance(res, BuiltinConcepts.TO_LIST)
assert list(res.body) == [
"service1.method1.var_name1",
"service1.method1.var_name2",
"service2.method1.var_name7",
"service2.method1.var_name8",
]
res = service.list_registered(service.VARS_DEBUG_TYPE, method="method1")
assert sheerka.isinstance(res, BuiltinConcepts.TO_LIST)
assert list(res.body) == [
"service1.method1.var_name1",
"service1.method1.var_name2",
"service2.method1.var_name7",
"service2.method1.var_name8",
]
res = service.list_registered(service.VARS_DEBUG_TYPE, "*.*.var_name7")
assert sheerka.isinstance(res, BuiltinConcepts.TO_LIST)
assert list(res.body) == [
"service2.method1.var_name7",
]
res = service.list_registered(service.VARS_DEBUG_TYPE, variable="var_name7")
assert sheerka.isinstance(res, BuiltinConcepts.TO_LIST)
assert list(res.body) == [
"service2.method1.var_name7",
]
finally:
self.restore_registered(service)
+4 -6
View File
@@ -1,15 +1,13 @@
from dataclasses import dataclass
import pytest import pytest
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, ParserResultConcept from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, ParserResultConcept
from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved, CB, \ from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved, CB, \
concept_part_value, DEFINITION_TYPE_DEF concept_part_value, DEFINITION_TYPE_DEF
from core.global_symbols import NotInit from core.global_symbols import NotInit, NotFound
from core.sheerka.services.SheerkaEvaluateConcept import SheerkaEvaluateConcept from core.sheerka.services.SheerkaEvaluateConcept import SheerkaEvaluateConcept
from core.sheerka.services.SheerkaMemory import SheerkaMemory from core.sheerka.services.SheerkaMemory import SheerkaMemory
from parsers.BaseParser import BaseParser from parsers.BaseParser import BaseParser
from parsers.PythonParser import PythonNode, PythonParser from parsers.PythonParser import PythonNode, PythonParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.evaluators.EvaluatorTestsUtils import pr_ret_val, python_ret_val from tests.evaluators.EvaluatorTestsUtils import pr_ret_val, python_ret_val
@@ -778,12 +776,12 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(context, command) evaluated = sheerka.evaluate_concept(context, command)
assert evaluated.key == command.key assert evaluated.key == command.key
assert "a" not in sheerka.locals assert sheerka.get_from_memory(context, "a") == NotFound
sheerka.set_isa(context, command, sheerka.new(BuiltinConcepts.AUTO_EVAL)) sheerka.set_isa(context, command, sheerka.new(BuiltinConcepts.AUTO_EVAL))
evaluated = sheerka.evaluate_concept(context, sheerka.new("command")) evaluated = sheerka.evaluate_concept(context, sheerka.new("command"))
assert evaluated.key == command.key assert evaluated.key == command.key
assert "a" in sheerka.locals assert sheerka.get_from_memory(context, "a").obj == 10
@pytest.mark.parametrize("metadata", [ @pytest.mark.parametrize("metadata", [
ConceptParts.WHERE, ConceptParts.WHERE,
+5 -4
View File
@@ -1,10 +1,11 @@
from core.sheerka.services.SheerkaHistoryManager import hist from core.sheerka.services.SheerkaHistoryManager import hist, SheerkaHistoryManager
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
class TestSheerkaHistoryManager(TestUsingFileBasedSheerka): class TestSheerkaHistoryManager(TestUsingFileBasedSheerka):
def test_i_can_retrieve_history(self): def test_i_can_retrieve_history(self):
sheerka = self.get_sheerka() sheerka = self.get_sheerka()
service = sheerka.services[SheerkaHistoryManager.NAME]
sheerka.save_execution_context = True sheerka.save_execution_context = True
sheerka.evaluate_user_input("def concept one as 1") sheerka.evaluate_user_input("def concept one as 1")
@@ -19,7 +20,7 @@ class TestSheerkaHistoryManager(TestUsingFileBasedSheerka):
sheerka.evaluate_user_input("def concept five as 5") sheerka.evaluate_user_input("def concept five as 5")
sheerka.evaluate_user_input("five") sheerka.evaluate_user_input("five")
h = list(sheerka.history(-1)) # all h = list(service.history(-1)) # all
assert h == [ assert h == [
hist("five", True), hist("five", True),
hist("def concept five as 5", True), hist("def concept five as 5", True),
@@ -35,13 +36,13 @@ class TestSheerkaHistoryManager(TestUsingFileBasedSheerka):
hist("Initializing Sheerka.", None) hist("Initializing Sheerka.", None)
] ]
h = list(sheerka.history(2)) h = list(service.history(2))
assert h == [ assert h == [
hist("five", True), hist("five", True),
hist("def concept five as 5", True) hist("def concept five as 5", True)
] ]
h = list(sheerka.history(2, 2)) h = list(service.history(2, 2))
assert h == [ assert h == [
hist("four", True), hist("four", True),
hist("def concept four as 4", True), hist("def concept four as 4", True),
+2 -4
View File
@@ -1,5 +1,3 @@
import pytest
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept from core.concept import Concept
from core.sheerka.services.SheerkaIsAManager import SheerkaIsAManager from core.sheerka.services.SheerkaIsAManager import SheerkaIsAManager
@@ -278,7 +276,7 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
assert [c.id for c in concepts_in_cache] == [one.id] assert [c.id for c in concepts_in_cache] == [one.id]
# pretend that number has been updated in sheerka.concepts_grammar # pretend that number has been updated in sheerka.concepts_grammar
sheerka.concepts_grammars.put(number.id, "some parsing expression with 'one' only") sheerka.get_concepts_bnf_definitions().put(number.id, "some parsing expression with 'one' only")
# add another element to number # add another element to number
sheerka.set_isa(context, sheerka.new("two"), number) sheerka.set_isa(context, sheerka.new("two"), number)
@@ -289,7 +287,7 @@ class TestSheerkaIsAManager(TestUsingMemoryBasedSheerka):
assert {c.id for c in concepts_in_cache} == {one.id, two.id} assert {c.id for c in concepts_in_cache} == {one.id, two.id}
# make sure the bnf definition is also updated # make sure the bnf definition is also updated
assert number.id not in sheerka.concepts_grammars assert number.id not in sheerka.get_concepts_bnf_definitions()
def test_i_can_get_and_set_isa_when_multiple_ontology_layers(self): 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_concepts(
+63 -1
View File
@@ -88,7 +88,6 @@ class TestSheerkaMemory(TestUsingMemoryBasedSheerka):
assert sheerka.om.copy(SheerkaMemory.OBJECTS_ENTRY) == {"a": MemoryObject(context.event.get_digest(), foo)} assert sheerka.om.copy(SheerkaMemory.OBJECTS_ENTRY) == {"a": MemoryObject(context.event.get_digest(), foo)}
assert id(sheerka.get_from_memory(context, "a").obj) == id(foo) assert id(sheerka.get_from_memory(context, "a").obj) == id(foo)
def test_i_can_use_memory_with_a_string(self): def test_i_can_use_memory_with_a_string(self):
sheerka, context = self.init_test().unpack() sheerka, context = self.init_test().unpack()
@@ -129,6 +128,69 @@ class TestSheerkaMemory(TestUsingMemoryBasedSheerka):
assert len(sheerka.om.get_all(SheerkaMemory.OBJECTS_ENTRY)) == 0 assert len(sheerka.om.get_all(SheerkaMemory.OBJECTS_ENTRY)) == 0
def test_adding_the_same_object_with_same_context_has_no_effect_when_one_element(self):
sheerka, context, foo = self.init_concepts("foo")
service = sheerka.services[SheerkaMemory.NAME]
sheerka.add_to_memory(context, "item", foo)
from_memory = service.get_from_memory(context, "item")
sheerka.add_to_memory(context, "item", foo)
from_memory_again = service.get_from_memory(context, "item")
assert from_memory_again == from_memory
def test_adding_the_same_object_with_same_context_has_no_effect_when_multiple_elements(self):
sheerka, context, foo, bar, baz = self.init_concepts("foo", "bar", "baz")
service = sheerka.services[SheerkaMemory.NAME]
sheerka.add_to_memory(context, "item", foo)
sheerka.add_to_memory(context, "item", bar)
sheerka.add_to_memory(context, "item", baz)
from_memory = service.get_from_memory(context, "item").copy()
sheerka.add_to_memory(context, "item", baz)
from_memory_again = service.get_from_memory(context, "item")
assert from_memory_again == from_memory
def test_adding_the_same_object_with_a_different_context_updates_event_id_when_one_element(self):
sheerka, context1, foo = self.init_concepts("foo")
service = sheerka.services[SheerkaMemory.NAME]
sheerka.add_to_memory(context1, "item", foo)
from_memory = service.get_from_memory(context1, "item")
context2 = self.get_context(self.sheerka, message="another message")
sheerka.add_to_memory(context2, "item", foo)
from_memory_again = service.get_from_memory(context2, "item")
assert from_memory_again != from_memory
assert not isinstance(from_memory_again, list)
assert from_memory_again.obj == from_memory.obj
assert from_memory_again.event_id == context2.event.get_digest()
assert from_memory.event_id == context1.event.get_digest()
def test_adding_the_same_object_with_a_different_context_updates_event_id_when_multiple_elements(self):
sheerka, context, foo, bar, baz = self.init_concepts("foo", "bar", "baz")
service = sheerka.services[SheerkaMemory.NAME]
sheerka.add_to_memory(context, "item", foo)
sheerka.add_to_memory(context, "item", bar)
sheerka.add_to_memory(context, "item", baz)
from_memory = service.get_from_memory(context, "item").copy()
context2 = self.get_context(self.sheerka, message="another message")
sheerka.add_to_memory(context2, "item", baz)
from_memory_again = service.get_from_memory(context2, "item")
assert isinstance(from_memory_again, list)
assert len(from_memory) == len(from_memory_again)
for mo, mo_again in zip(from_memory, from_memory_again[:-1]):
assert mo == mo_again
assert from_memory[-1].obj == from_memory_again[-1].obj
assert from_memory[-1].event_id != from_memory_again[-1].event_id
class TestSheerkaMemoryUsingFileBase(TestUsingFileBasedSheerka): class TestSheerkaMemoryUsingFileBase(TestUsingFileBasedSheerka):
def test_i_can_record_memory_objects(self): def test_i_can_record_memory_objects(self):
+12
View File
@@ -991,6 +991,18 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
assert isinstance(res[0], AndConditions) assert isinstance(res[0], AndConditions)
assert res[0].conditions == [Condition(V("__x_00__"), "__name__", "__ret")] assert res[0].conditions == [Condition(V("__x_00__"), "__name__", "__ret")]
def test_i_can_properly_copy_a_rule(self):
sheerka, context = self.init_test().unpack()
service = sheerka.services[SheerkaRuleManager.NAME]
rule = Rule(ACTION_TYPE_EXEC, "name", "id.attr == 'value'", 'test()')
service.init_rule(context, rule)
service.create_new_rule(context, rule)
clone = rule.__deepcopy__({})
for k, v in vars(rule).items():
assert getattr(clone, k) == getattr(rule, k)
class TestSheerkaRuleManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka): class TestSheerkaRuleManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
def test_rules_are_initialized_at_startup(self): def test_rules_are_initialized_at_startup(self):
+5 -4
View File
@@ -1,8 +1,8 @@
import ast import ast
import pytest import pytest
from core.ast_helpers import UnreferencedNamesVisitor, UnreferencedVariablesVisitor
from core.ast_helpers import UnreferencedNamesVisitor, UnreferencedVariablesVisitor
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -13,7 +13,8 @@ class TestAstHelper(TestUsingMemoryBasedSheerka):
("date.today()", {"date"}), ("date.today()", {"date"}),
("test()", {"test"}), ("test()", {"test"}),
("sheerka.test()", {"sheerka"}), ("sheerka.test()", {"sheerka"}),
("for i in range(10): pass", set()) ("for i in range(10): pass", set()),
("func(x=a, y=b)", {"func", "a", "b"}),
]) ])
def test_i_can_get_unreferenced_names_from_simple_expressions(self, source, expected): def test_i_can_get_unreferenced_names_from_simple_expressions(self, source, expected):
@@ -31,8 +32,8 @@ class TestAstHelper(TestUsingMemoryBasedSheerka):
("date.today()", set()), ("date.today()", set()),
("test()", set()), ("test()", set()),
("sheerka.test()", set()), ("sheerka.test()", set()),
("for i in range(10): pass", set()) ("for i in range(10): pass", set()),
("func(x=a, y=b)", {"a", "b", "x", "y"}),
]) ])
def test_i_can_get_unreferenced_variables_from_simple_expressions(self, source, expected): def test_i_can_get_unreferenced_variables_from_simple_expressions(self, source, expected):
context = self.get_context() context = self.get_context()
-8
View File
@@ -8,10 +8,8 @@ from core.builtin_concepts_ids import AllBuiltinConcepts
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, ConceptParts, get_concept_attrs from core.concept import Concept, PROPERTIES_TO_SERIALIZE, ConceptParts, get_concept_attrs
from core.global_symbols import NotInit from core.global_symbols import NotInit
from core.sheerka.Sheerka import Sheerka, BASE_NODE_PARSER_CLASS from core.sheerka.Sheerka import Sheerka, BASE_NODE_PARSER_CLASS
from core.sheerka.SheerkaOntologyManager import OntologyAlreadyExists
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
from core.tokenizer import Token, TokenKind from core.tokenizer import Token, TokenKind
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -370,12 +368,10 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS) assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
foo = sheerka.create_new_concept(context, Concept("foo").def_var("a").def_var("b")).body.body foo = sheerka.create_new_concept(context, Concept("foo").def_var("a").def_var("b")).body.body
sheerka.locals = {"key1": "value1"}
# sanity check # sanity check
assert sheerka.get_by_name("foo") == foo assert sheerka.get_by_name("foo") == foo
assert not sheerka.is_known(sheerka.get_by_name("bar")) assert not sheerka.is_known(sheerka.get_by_name("bar"))
assert sheerka.locals == {"key1": "value1"}
assert get_concept_attrs(foo) == ["a", "b"] assert get_concept_attrs(foo) == ["a", "b"]
# record the ontology # record the ontology
@@ -386,12 +382,10 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
sheerka.push_ontology(context, "another ontology") sheerka.push_ontology(context, "another ontology")
foo2 = sheerka.create_new_concept(context, Concept("foo").def_var("a").def_var("b").def_var("c")).body.body foo2 = sheerka.create_new_concept(context, Concept("foo").def_var("a").def_var("b").def_var("c")).body.body
bar = sheerka.create_new_concept(context, Concept("bar")).body.body bar = sheerka.create_new_concept(context, Concept("bar")).body.body
sheerka.locals = {"key2": "value2"}
# sanity check # sanity check
assert sheerka.get_by_name("foo") == foo2 assert sheerka.get_by_name("foo") == foo2
assert sheerka.get_by_name("bar") == bar assert sheerka.get_by_name("bar") == bar
assert sheerka.locals == {"key2": "value2"}
assert get_concept_attrs(foo) == ["a", "b", "c"] assert get_concept_attrs(foo) == ["a", "b", "c"]
# put pack the previous ontology # put pack the previous ontology
@@ -399,14 +393,12 @@ class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
assert sheerka.get_by_name("foo") == foo # not [foo, foo2], foo2 is not seen !!! assert sheerka.get_by_name("foo") == foo # not [foo, foo2], foo2 is not seen !!!
assert sheerka.get_by_name("bar") == bar assert sheerka.get_by_name("bar") == bar
assert sheerka.locals == {"key1": "value1"}
assert get_concept_attrs(foo) == ["a", "b"] assert get_concept_attrs(foo) == ["a", "b"]
# sanity check # sanity check
sheerka.pop_ontology(context) sheerka.pop_ontology(context)
assert sheerka.get_by_name("foo") == foo2 assert sheerka.get_by_name("foo") == foo2
assert sheerka.get_by_name("bar") == bar assert sheerka.get_by_name("bar") == bar
assert sheerka.locals == {"key2": "value2"}
assert get_concept_attrs(foo) == ["a", "b", "c"] assert get_concept_attrs(foo) == ["a", "b", "c"]
def test_adding_the_same_ontology_twice_has_no_effect(self): def test_adding_the_same_ontology_twice_has_no_effect(self):
+6 -3
View File
@@ -151,7 +151,8 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
service = SheerkaExecute(sheerka) service = SheerkaExecute(sheerka)
service.reset_registered_parsers() service.reset_registered_parsers()
groups, sorted_priorities = service.get_parsers(context) parsers_key, groups, sorted_priorities = service.get_parsers(context)
assert parsers_key == "__default"
assert groups == {80: [Enabled80FalseParser()], 90: [Enabled90FalseParser()]} assert groups == {80: [Enabled80FalseParser()], 90: [Enabled90FalseParser()]}
assert sorted_priorities == [90, 80] assert sorted_priorities == [90, 80]
@@ -169,7 +170,8 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
parsers_names = ["Enabled50True", "Enabled70False", "Disabled"] parsers_names = ["Enabled50True", "Enabled70False", "Disabled"]
context.preprocess_parsers = parsers_names context.preprocess_parsers = parsers_names
groups, sorted_priorities = service.get_parsers(context) parsers_key, groups, sorted_priorities = service.get_parsers(context)
assert parsers_key == "Enabled50True|Enabled70False|Disabled"
assert groups == {50: [Enabled50TrueParser()], 70: [Enabled70FalseParser()]} assert groups == {50: [Enabled50TrueParser()], 70: [Enabled70FalseParser()]}
assert sorted_priorities == [70, 50] # Disabled parser does not appear assert sorted_priorities == [70, 50] # Disabled parser does not appear
@@ -195,7 +197,8 @@ class TestSheerkaExecuteParsers(TestUsingMemoryBasedSheerka):
context.add_preprocess(BaseParser.get_name("Enabled90False"), enabled=False) context.add_preprocess(BaseParser.get_name("Enabled90False"), enabled=False)
context.add_preprocess(BaseParser.get_name("Enabled50True"), priority=80) context.add_preprocess(BaseParser.get_name("Enabled50True"), priority=80)
groups, sorted_priorities = service.get_parsers(context) parsers_key, groups, sorted_priorities = service.get_parsers(context)
assert parsers_key is None
assert groups == {80: [Enabled50TrueParser()], 70: [Enabled70FalseParser()]} assert groups == {80: [Enabled50TrueParser()], 70: [Enabled70FalseParser()]}
assert sorted_priorities == [80, 70] # Disabled parsers does not appear assert sorted_priorities == [80, 70] # Disabled parsers does not appear
+35 -2
View File
@@ -1,16 +1,17 @@
import ast import ast
import pytest import pytest
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
from core.concept import VARIABLE_PREFIX, Concept, DEFINITION_TYPE_BNF, DEFINITION_TYPE_DEF from core.concept import VARIABLE_PREFIX, Concept, DEFINITION_TYPE_BNF, DEFINITION_TYPE_DEF
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Tokenizer from core.tokenizer import Tokenizer
from evaluators.DefConceptEvaluator import DefConceptEvaluator from evaluators.DefConceptEvaluator import DefConceptEvaluator
from parsers.BaseParser import BaseParser from parsers.BaseParser import BaseParser
from parsers.BnfDefinitionParser import BnfDefinitionParser from parsers.BnfDefinitionParser import BnfDefinitionParser
from parsers.BnfNodeParser import Sequence, StrMatch, ZeroOrMore, ConceptExpression from parsers.BnfNodeParser import Sequence, StrMatch, ZeroOrMore, ConceptExpression
from parsers.DefConceptParser import DefConceptNode, NameNode from parsers.DefConceptParser import DefConceptNode, NameNode, DefConceptParser
from parsers.PythonParser import PythonNode, PythonParser from parsers.PythonParser import PythonNode, PythonParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -244,3 +245,35 @@ class TestDefConceptEvaluator(TestUsingMemoryBasedSheerka):
assert new_concept.get_metadata().body == 'foo' assert new_concept.get_metadata().body == 'foo'
assert new_concept.values() == {} assert new_concept.values() == {}
assert new_concept.get_metadata().variables == [] assert new_concept.get_metadata().variables == []
def test_i_can_get_variable_when_rule_is_defined(self):
sheerka, context = self.init_test().unpack()
def_concept_parser = DefConceptParser()
parsed_ret_val = def_concept_parser.parse(context, ParserInput("def concept rule x as r:|x:"))
assert parsed_ret_val.status # sanity check
evaluated = DefConceptEvaluator().eval(context, parsed_ret_val)
assert evaluated.status
assert evaluated.body.body.key == "rule __var__0"
assert evaluated.body.body.get_metadata().variables == [("x", None)]
def test_i_can_recognize_variable_when_keyword_argument(self):
sheerka, context = self.init_test().unpack()
def_concept_parser = DefConceptParser()
parsed_ret_val = def_concept_parser.parse(context, ParserInput("def concept foo1 x as func(param=x)"))
assert parsed_ret_val.status # sanity check
evaluated = DefConceptEvaluator().eval(context, parsed_ret_val)
assert evaluated.status
assert evaluated.body.body.key == "foo1 __var__0"
assert evaluated.body.body.get_metadata().variables == [("x", None)]
parsed_ret_val = def_concept_parser.parse(context, ParserInput("def concept foo2 x as func(x=value)"))
assert parsed_ret_val.status # sanity check
evaluated = DefConceptEvaluator().eval(context, parsed_ret_val)
assert evaluated.status
assert evaluated.body.body.key == "foo2 __var__0"
assert evaluated.body.body.get_metadata().variables == [("x", None)]
+21 -16
View File
@@ -12,7 +12,6 @@ from evaluators.PythonEvaluator import PythonEvaluator, PythonEvalError, NamesWi
from parsers.BaseNodeParser import SourceCodeNode, SourceCodeWithConceptNode from parsers.BaseNodeParser import SourceCodeNode, SourceCodeWithConceptNode
from parsers.FunctionParser import FunctionParser from parsers.FunctionParser import FunctionParser
from parsers.PythonParser import PythonNode, PythonParser from parsers.PythonParser import PythonNode, PythonParser
from parsers.PythonWithConceptsParser import PythonWithConceptsParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -293,21 +292,6 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
assert error1.error.args[0] == 'can only concatenate str (not "int") to str' assert error1.error.args[0] == 'can only concatenate str (not "int") to str'
assert error1.concepts == {'foo': 'string'} assert error1.concepts == {'foo': 'string'}
def test_i_can_use_sheerka_locals(self):
sheerka, context = self.init_test().unpack()
def func(i):
return i + 1
sheerka.locals["func"] = func
parsed = PythonParser().parse(context, ParserInput("func(10)"))
python_evaluator = PythonEvaluator()
evaluated = python_evaluator.eval(context, parsed)
assert evaluated.status
assert evaluated.value == 11
def test_i_can_eval_concept_with_ret(self): def test_i_can_eval_concept_with_ret(self):
sheerka, context, one, the = self.init_concepts("one", Concept("the a", ret="a").def_var("a")) sheerka, context, one, the = self.init_concepts("one", Concept("the a", ret="a").def_var("a"))
ret_val = get_ret_val_from_source_code(context, "test_using_context(the one)", { ret_val = get_ret_val_from_source_code(context, "test_using_context(the one)", {
@@ -339,6 +323,17 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
assert evaluated.status assert evaluated.status
assert evaluated.value == "Print return values" assert evaluated.value == "Print return values"
def test_i_can_update_sheerka_memory_using_assignation(self):
sheerka, context = self.init_test().unpack()
parsed = PythonParser().parse(context, ParserInput("a = 10"))
python_evaluator = PythonEvaluator()
evaluated = python_evaluator.eval(context, parsed)
assert evaluated.status
from_memory = sheerka.get_from_memory(context, "a")
assert from_memory.obj == 10
@pytest.mark.parametrize("method, expected_status", [ @pytest.mark.parametrize("method, expected_status", [
("return_return_value(True)", True), ("return_return_value(True)", True),
("return_return_value(False)", False), ("return_return_value(False)", False),
@@ -389,3 +384,13 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
assert evaluated.status assert evaluated.status
assert evaluated.value == context.sheerka.get_rule_by_id(str(value)).name assert evaluated.value == context.sheerka.get_rule_by_id(str(value)).name
def test_something(self):
def func(**kwargs):
for k, v in kwargs.items():
print(f"{k=}, {v=}")
to_compile = "func(x=y)"
ast_ = ast.parse(to_compile, mode="eval")
compiled = compile(ast_, "<test>", mode="eval")
eval(compiled, {"x": "hello", "y": "world", "func": func})
+16 -21
View File
@@ -1,4 +1,5 @@
import pytest import pytest
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, simplec, CMV, CC from core.concept import Concept, PROPERTIES_TO_SERIALIZE, simplec, CMV, CC
from core.global_symbols import NotInit from core.global_symbols import NotInit
@@ -6,9 +7,7 @@ from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
from evaluators.OneSuccessEvaluator import OneSuccessEvaluator from evaluators.OneSuccessEvaluator import OneSuccessEvaluator
from evaluators.PythonEvaluator import PythonEvalError from evaluators.PythonEvaluator import PythonEvalError
from parsers.BaseNodeParser import SyaAssociativity
from parsers.BnfNodeParser import Sequence, StrMatch, OrderedChoice, Optional, ConceptExpression from parsers.BnfNodeParser import Sequence, StrMatch, OrderedChoice, Optional, ConceptExpression
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -949,7 +948,7 @@ as:
sheerka = self.init_scenario(init) sheerka = self.init_scenario(init)
# simulate that sheerka was stopped and restarted # simulate that sheerka was stopped and restarted
sheerka.om.clear(sheerka.CONCEPTS_GRAMMARS_ENTRY) sheerka.clear_bnf_definition()
sheerka.om.get(SheerkaConceptManager.CONCEPTS_BY_KEY_ENTRY, "twenties").set_compiled({}) sheerka.om.get(SheerkaConceptManager.CONCEPTS_BY_KEY_ENTRY, "twenties").set_compiled({})
res = sheerka.evaluate_user_input("eval twenty one") res = sheerka.evaluate_user_input("eval twenty one")
@@ -1114,23 +1113,6 @@ as:
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
def test_i_can_eval_concepts_fed_with_functions(self):
init = [
"def concept inc a as a + 1",
"def concept one as 1"
]
def times_five(i):
return i * 5
sheerka = self.init_scenario(init)
sheerka.locals["times_five"] = times_five
res = sheerka.evaluate_user_input("eval inc times_five(one)")
assert len(res) == 1
assert res[0].status
assert res[0].body == 6
def test_i_can_define_a_concept_when_where_clause_contains_the_name_of_the_variable(self): def test_i_can_define_a_concept_when_where_clause_contains_the_name_of_the_variable(self):
init = [ init = [
"def concept x is a y as isa(x,y) pre is_question()", "def concept x is a y as isa(x,y) pre is_question()",
@@ -1231,7 +1213,8 @@ as:
def test_i_can_define_rules_priorities(self): def test_i_can_define_rules_priorities(self):
sheerka, context, r1, r2 = self.init_test().with_format_rules(("True", "True"), ("False", "False")).unpack() sheerka, context, r1, r2 = self.init_test().with_format_rules(("True", "True"), ("False", "False")).unpack()
sheerka.evaluate_user_input("def concept rule x > rule y where isinstance(x, int) and isinstance(y, int) as set_is_greater_than(__PRECEDENCE, r:|x:, r:|y:, 'Rule')") sheerka.evaluate_user_input(
"def concept rule x > rule y where isinstance(x, int) and isinstance(y, int) as set_is_greater_than(__PRECEDENCE, r:|x:, r:|y:, 'Rule')")
res = sheerka.evaluate_user_input(f"eval rule {r1.id} > rule {r2.id}") res = sheerka.evaluate_user_input(f"eval rule {r1.id} > rule {r2.id}")
@@ -1242,6 +1225,18 @@ as:
weights = sheerka.get_weights(BuiltinConcepts.PRECEDENCE, 'Rule') weights = sheerka.get_weights(BuiltinConcepts.PRECEDENCE, 'Rule')
assert weights[r1.str_id] == weights[r2.str_id] + 1 assert weights[r1.str_id] == weights[r2.str_id] + 1
def test_i_can_get_history_after_def_rule_parser(self):
sheerka = self.get_sheerka()
sheerka.save_execution_context = True
sheerka.evaluate_user_input("when True then answer('that is true')")
res = sheerka.evaluate_user_input("history()")
assert len(res) == 1
assert res[0].status
l = list(res[0].body.body)
assert len(l) > 0
sheerka.save_execution_context = False
class TestSheerkaNonRegFile(TestUsingFileBasedSheerka): class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
def test_i_can_def_several_concepts(self): def test_i_can_def_several_concepts(self):
+17
View File
@@ -122,3 +122,20 @@ __default__
assert captured.out == """one: (1001)one assert captured.out == """one: (1001)one
two: (1002)two two: (1002)two
""" """
def test_i_can_retrieve_history(self, capsys):
init = [
"test()",
]
sheerka = self.init_scenario(init)
capsys.readouterr()
sheerka.enable_process_return_values = True
res = sheerka.evaluate_user_input(f"history()")
assert len(res) == 1
assert res[0].status
captured = capsys.readouterr()
assert " : test()" in captured.out
assert " : history()" in captured.out
+5 -5
View File
@@ -1169,7 +1169,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
:return: :return:
""" """
sheerka, context, parser = self.init_parser(init_from_sheerka=True) sheerka, context, parser = self.init_parser(init_from_sheerka=True)
sheerka.concepts_grammars.clear() # to simulate restart sheerka.clear_bnf_definition() # to simulate restart
text = "one thousand" text = "one thousand"
one = CC("one", body=DoNotResolve("one")) one = CC("one", body=DoNotResolve("one"))
@@ -1195,7 +1195,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
:return: :return:
""" """
sheerka, context, parser = self.init_parser(init_from_sheerka=True) sheerka, context, parser = self.init_parser(init_from_sheerka=True)
sheerka.concepts_grammars.clear() # to simulate restart sheerka.clear_bnf_definition() # to simulate restart
text = "fifty one thousand" text = "fifty one thousand"
one = CC("one", body=DoNotResolve("one")) one = CC("one", body=DoNotResolve("one"))
@@ -1233,7 +1233,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
def test_i_can_parse_one_hundred_thousand(self): def test_i_can_parse_one_hundred_thousand(self):
sheerka, context, parser = self.init_parser(init_from_sheerka=True) sheerka, context, parser = self.init_parser(init_from_sheerka=True)
sheerka.concepts_grammars.clear() # to simulate restart sheerka.clear_bnf_definition() # to simulate restart
text = "one hundred thousand" text = "one hundred thousand"
res = parser.parse(context, ParserInput(text)) res = parser.parse(context, ParserInput(text))
@@ -1244,7 +1244,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
def test_i_can_parse_hundreds_like_expression(self): def test_i_can_parse_hundreds_like_expression(self):
sheerka, context, parser = self.init_parser(init_from_sheerka=True) sheerka, context, parser = self.init_parser(init_from_sheerka=True)
sheerka.concepts_grammars.clear() sheerka.clear_bnf_definition() # to simulate restart
text = "three hundred and thirty two" text = "three hundred and thirty two"
three = CC("three", body=DoNotResolve("three")) three = CC("three", body=DoNotResolve("three"))
@@ -1280,7 +1280,7 @@ class TestBnfNodeParser(TestUsingMemoryBasedSheerka):
def test_i_can_parse_bnf_concept_mixed_with_isa_after_restart(self): def test_i_can_parse_bnf_concept_mixed_with_isa_after_restart(self):
sheerka, context, parser = self.init_parser(init_from_sheerka=True) sheerka, context, parser = self.init_parser(init_from_sheerka=True)
sheerka.concepts_grammars.clear() # simulate restart sheerka.clear_bnf_definition() # to simulate restart
for c in cmap.values(): for c in cmap.values():
sheerka.get_by_id(c.id).set_bnf(None) sheerka.get_by_id(c.id).set_bnf(None)
+1 -2
View File
@@ -1,11 +1,10 @@
import pytest import pytest
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept from core.concept import Concept
from core.rule import Rule
from core.sheerka.services.SheerkaExecute import ParserInput from core.sheerka.services.SheerkaExecute import ParserInput
from parsers.BaseNodeParser import SCN, SCWC, CN, UTN, CNC, RN from parsers.BaseNodeParser import SCN, SCWC, CN, UTN, CNC, RN
from parsers.FunctionParser import FunctionParser, FN from parsers.FunctionParser import FunctionParser, FN
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.parsers.parsers_utils import compute_expected_array from tests.parsers.parsers_utils import compute_expected_array
+2 -2
View File
@@ -968,7 +968,7 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
def test_i_can_debug(self, expression, expected_debugs): def test_i_can_debug(self, expression, expected_debugs):
sheerka, context, parser = self.init_parser() sheerka, context, parser = self.init_parser()
sheerka.set_debug(context, True) sheerka.set_debug(context, True)
sheerka.debug_var(context, "Sya") sheerka.set_debug_var(context, "Sya")
res = parser.infix_to_postfix(context, ParserInput(expression)) res = parser.infix_to_postfix(context, ParserInput(expression))
assert len(res) == len(expected_debugs) assert len(res) == len(expected_debugs)
@@ -983,7 +983,7 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
def test_i_can_debug_can_pop_using_star(self, settings): def test_i_can_debug_can_pop_using_star(self, settings):
sheerka, context, parser = self.init_parser() sheerka, context, parser = self.init_parser()
sheerka.set_debug(context, True) sheerka.set_debug(context, True)
sheerka.debug_var(context, settings) sheerka.set_debug_var(context, settings)
res = parser.infix_to_postfix(context, ParserInput("one plus two mult three")) res = parser.infix_to_postfix(context, ParserInput("one plus two mult three"))
debug = [str(di) for di in res[0].debug] debug = [str(di) for di in res[0].debug]
+58 -44
View File
@@ -1,13 +1,12 @@
from core.builtin_concepts import ParserResultConcept, BuiltinConcepts from core.builtin_concepts import ParserResultConcept, BuiltinConcepts
from core.concept import Concept, CC from core.concept import Concept, CC
from core.tokenizer import Tokenizer, TokenKind from core.tokenizer import Tokenizer, TokenKind
from parsers.SequenceNodeParser import SequenceNodeParser
from parsers.BaseNodeParser import ConceptNode, UnrecognizedTokensNode, scnode, cnode, \ from parsers.BaseNodeParser import ConceptNode, UnrecognizedTokensNode, scnode, cnode, \
utnode, SyaAssociativity, CN, CNC, UTN, SourceCodeWithConceptNode, SCWC, SourceCodeNode utnode, CN, CNC, UTN, SourceCodeWithConceptNode, SCWC, SourceCodeNode
from parsers.BnfNodeParser import BnfNodeParser from parsers.BnfNodeParser import BnfNodeParser
from parsers.SequenceNodeParser import SequenceNodeParser
from parsers.SyaNodeParser import SyaNodeParser from parsers.SyaNodeParser import SyaNodeParser
from parsers.UnrecognizedNodeParser import UnrecognizedNodeParser from parsers.UnrecognizedNodeParser import UnrecognizedNodeParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
from tests.parsers.parsers_utils import compute_expected_array, get_node from tests.parsers.parsers_utils import compute_expected_array, get_node
@@ -208,49 +207,64 @@ class TestUnrecognizedNodeParser(TestUsingMemoryBasedSheerka):
[CNC("twenties", source="twenty two", unit="two")]) [CNC("twenties", source="twenty two", unit="two")])
assert res.body.concept.get_compiled()["b"].get_compiled()["b"][0].body.body == expected_nodes assert res.body.concept.get_compiled()["b"].get_compiled()["b"][0].body.body == expected_nodes
# def test_i_can_validate_and_evaluate_a_concept_node_with_python(self): def test_i_can_validate_and_evaluate_a_concept_node_with_python(self):
# sheerka, context, parser = self.init_parser() sheerka, context, parser = self.init_parser()
#
# node = get_input_nodes_from( node = get_input_nodes_from(
# concepts_map, concepts_map,
# "one plus 1 + 1", "one plus 1 + 1",
# CNC("plus", CNC("plus",
# a=UTN("one "), a=UTN("one "),
# b=UTN("1 + 1")))[0] b=UTN("1 + 1")))[0]
#
# res = UnrecognizedNodeParser().validate_concept_node(context, node) res = UnrecognizedNodeParser().validate_concept_node(context, node)
#
# assert res.status assert res.status
# assert res.body.concept == concepts_map["plus"] concept_found = res.body.concept
# assert res.body.concept.get_compiled()["a"] == concepts_map["one"] compiled = concept_found.get_compiled()
# assert len(res.body.concept.get_compiled()["b"]) == 1 assert concept_found == concepts_map["plus"]
# assert sheerka.isinstance(res.body.concept.get_compiled()["b"][0], BuiltinConcepts.RETURN_VALUE) assert len(compiled["a"]) == 1
# assert res.body.concept.get_compiled()["b"][0].status assert sheerka.isinstance(compiled["a"][0], BuiltinConcepts.RETURN_VALUE)
# assert res.body.concept.get_compiled()["b"][0].who == "parsers.Python" assert compiled["a"][0].body.body[0].concept.id == concepts_map["one"].id
# assert res.body.concept.get_compiled()["b"][0].body.source == "1 + 1"
# assert len(compiled["b"]) == 1
# # # evaluate assert sheerka.isinstance(compiled["b"][0], BuiltinConcepts.RETURN_VALUE)
# # context = self.get_context(sheerka, eval_body=True) assert compiled["b"][0].status
# # evaluated = sheerka.evaluate_concept(context, res.body.concept) assert compiled["b"][0].who == "parsers.Python"
# # assert evaluated.body == 3 assert compiled["b"][0].body.source == "1 + 1"
# def test_i_can_validate_and_evaluate_concept_when_bnf_concept(self):
# sheerka, context, parser = self.init_parser()
# node = get_concept_node(concepts_map, "one plus twenty one", "plus", "one", "twenty one")
#
# res = UnrecognizedNodeParser().validate_concept_node(context, node)
#
# assert res.status
# assert res.body.concept == concepts_map["plus"]
# assert res.body.concept.get_compiled()["a"] == concepts_map["one"]
# assert len(res.body.concept.get_compiled()["b"]) == 1
# assert res.body.concept.get_compiled()["b"][0].status
# assert res.body.concept.get_compiled()["b"][0].who == "parsers.BnfNode"
#
# # evaluate # # evaluate
# context = self.get_context(sheerka, eval_body=True) context = self.get_context(sheerka, eval_body=True)
# evaluated = sheerka.evaluate_concept(context, res.body.concept) evaluated = sheerka.evaluate_concept(context, res.body.concept)
# assert evaluated.body == 22 assert evaluated.body == 3
def test_i_can_validate_and_evaluate_concept_when_bnf_concept(self):
sheerka, context, parser = self.init_parser()
node = get_input_nodes_from(
concepts_map,
"one plus twenty one",
CNC("plus",
a=UTN("one "),
b=UTN("twenty one")))[0]
res = UnrecognizedNodeParser().validate_concept_node(context, node)
assert res.status
concept_found = res.body.concept
compiled = concept_found.get_compiled()
assert concept_found == concepts_map["plus"]
assert len(compiled["a"]) == 1
assert sheerka.isinstance(compiled["a"][0], BuiltinConcepts.RETURN_VALUE)
assert compiled["a"][0].body.body[0].concept.id == concepts_map["one"].id
assert len(compiled["b"]) == 1
assert compiled["b"][0].status
assert compiled["b"][0].who == "parsers.Bnf"
# evaluate
context = self.get_context(sheerka, eval_body=True)
evaluated = sheerka.evaluate_concept(context, res.body.concept)
assert evaluated.body == 22
def test_i_can_parse_and_evaluate_unrecognized_python_node(self): def test_i_can_parse_and_evaluate_unrecognized_python_node(self):
sheerka, context, parser = self.init_parser() sheerka, context, parser = self.init_parser()
+4 -2
View File
@@ -245,8 +245,10 @@ class TestReteConditions(TestUsingMemoryBasedSheerka):
matches = list(network.matches) matches = list(network.matches)
assert len(matches) == 2 assert len(matches) == 2
assert matches[0].token.wmes == [wme3, wme2] # assert matches[0].token.wmes == [wme3, wme2]
assert matches[1].token.wmes == [wme1, wme3] # assert matches[1].token.wmes == [wme1, wme3]
assert len(matches[0].token.wmes) == 2
assert len(matches[1].token.wmes) == 2
def test_i_can_manage_binding_conditions(self): def test_i_can_manage_binding_conditions(self):
network = ReteNetwork() network = ReteNetwork()
+22 -2
View File
@@ -638,15 +638,26 @@ class TestReteNetwork(TestUsingMemoryBasedSheerka):
network.remove_rule(rule3) network.remove_rule(rule3)
assert len(list(p_node3.activations)) == 0 assert len(list(p_node3.activations)) == 0
def test_rule_is_added_to_rete_network_when_it_is_created(self): def test_exec_rule_is_added_to_rete_network_when_it_is_created(self):
sheerka, context, rule = self.init_test().with_exec_rules(("rule_name", "id.attr == 'value'", 'True')).unpack() sheerka, context, rule = self.init_test().with_exec_rules(("rule_name", "id.attr == 'value'", 'True')).unpack()
evaluation_service = sheerka.services[SheerkaEvaluateRules.NAME] evaluation_service = sheerka.services[SheerkaEvaluateRules.NAME]
rete_network = evaluation_service.network rete_network = evaluation_service.network
assert len(rete_network.pnodes) == 1 assert len(rete_network.pnodes) == 1
assert rete_network.pnodes[0].rules[0] == rule assert rete_network.pnodes[0].rules[0] == rule
assert rule.rete_net == rete_network
assert len(rule.rete_p_nodes) > 0
def test_rule_is_removed_to_rete_network_when_it_is_deleted(self): def test_format_rule_is_not_added_to_rete_network_when_it_is_created(self):
sheerka, context, rule = self.init_test().with_format_rules(("rule_name", "id.attr == 'value'", 'True')).unpack()
evaluation_service = sheerka.services[SheerkaEvaluateRules.NAME]
rete_network = evaluation_service.network
assert len(rete_network.pnodes) == 0
assert rule.rete_net is None
assert len(rule.rete_p_nodes) == 0
def test_rule_is_removed_from_rete_network_when_it_is_deleted(self):
sheerka, context, rule = self.init_test().with_exec_rules(("id.attr == 'value'", 'True')).unpack() sheerka, context, rule = self.init_test().with_exec_rules(("id.attr == 'value'", 'True')).unpack()
evaluation_service = sheerka.services[SheerkaEvaluateRules.NAME] evaluation_service = sheerka.services[SheerkaEvaluateRules.NAME]
rete_network = evaluation_service.network rete_network = evaluation_service.network
@@ -654,6 +665,15 @@ class TestReteNetwork(TestUsingMemoryBasedSheerka):
sheerka.remove_rule(context, rule) sheerka.remove_rule(context, rule)
assert len(rete_network.pnodes) == 0 assert len(rete_network.pnodes) == 0
def test_rule_is_removed_from_rete_network_when_it_is_deleted_from_another_ontology(self):
sheerka, context, rule = self.init_test().with_exec_rules(("id.attr == 'value'", 'True')).unpack()
evaluation_service = sheerka.services[SheerkaEvaluateRules.NAME]
rete_network = evaluation_service.network
sheerka.push_ontology(context, "new ontology")
sheerka.remove_rule(context, rule)
assert len(rete_network.pnodes) == 0
def test_rules_are_removed_upon_ontology_removal(self): def test_rules_are_removed_upon_ontology_removal(self):
sheerka, context = self.init_test().unpack() sheerka, context = self.init_test().unpack()
service = sheerka.services[SheerkaRuleManager.NAME] service = sheerka.services[SheerkaRuleManager.NAME]