Implemented ConceptManager with concept creation, modification and deletion
This commit is contained in:
@@ -35,7 +35,6 @@ set_auto_eval(c:debug variable x:)
|
|||||||
def concept debug method x as debug_var(method=x)
|
def concept debug method x as debug_var(method=x)
|
||||||
set_auto_eval(c:debug method x:)
|
set_auto_eval(c:debug method x:)
|
||||||
|
|
||||||
set_auto_eval(c:activate debug on x:)
|
|
||||||
def concept deactivate debug on x as debug_var(x, enabled=False) where x
|
def concept deactivate debug on x as debug_var(x, enabled=False) where x
|
||||||
set_auto_eval(c:deactivate debug on x:)
|
set_auto_eval(c:deactivate debug on x:)
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
@@ -27,5 +27,6 @@ class Cache(BaseCache):
|
|||||||
|
|
||||||
def _delete(self, key, value):
|
def _delete(self, key, value):
|
||||||
del(self._cache[key])
|
del(self._cache[key])
|
||||||
|
self._current_size -= 1
|
||||||
self._add_to_remove(key)
|
self._add_to_remove(key)
|
||||||
|
|
||||||
|
|||||||
Vendored
+33
-2
@@ -6,14 +6,22 @@ from cache.BaseCache import BaseCache
|
|||||||
from core.concept import Concept
|
from core.concept import Concept
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
class MultipleEntryError(Exception):
|
class MultipleEntryError(Exception):
|
||||||
"""
|
"""
|
||||||
Exception raised when trying to alter an entry with multiple element
|
Exception raised when trying to alter an entry with multiple element
|
||||||
without giving the origin of the element
|
without giving the origin of the element
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, key):
|
key: str
|
||||||
self.key = key
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ConceptNotFound(Exception):
|
||||||
|
"""
|
||||||
|
Thrown when you try to remove a concept that is not found
|
||||||
|
"""
|
||||||
|
concept: object
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -127,6 +135,29 @@ class CacheManager:
|
|||||||
# pass
|
# pass
|
||||||
# self.is_dirty = True
|
# self.is_dirty = True
|
||||||
|
|
||||||
|
def remove_concept(self, concept):
|
||||||
|
"""
|
||||||
|
Remove a concept from all caches
|
||||||
|
:param concept:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
with self._lock:
|
||||||
|
# the first concept cache must the one where all concept are unique
|
||||||
|
# eg it has to be the concept by id
|
||||||
|
ref_cache_def = self.caches[self.concept_caches[0]]
|
||||||
|
concept_id = ref_cache_def.get_key(concept)
|
||||||
|
ref_concept = ref_cache_def.cache.get(concept_id)
|
||||||
|
|
||||||
|
if ref_concept is None:
|
||||||
|
raise ConceptNotFound(concept)
|
||||||
|
|
||||||
|
for cache_name in self.concept_caches:
|
||||||
|
cache_def = self.caches[cache_name]
|
||||||
|
key = cache_def.get_key(ref_concept)
|
||||||
|
cache_def.cache.delete(key, ref_concept)
|
||||||
|
|
||||||
|
self.is_dirty = True
|
||||||
|
|
||||||
def get(self, cache_name, key):
|
def get(self, cache_name, key):
|
||||||
"""
|
"""
|
||||||
From concept cache, get an entry
|
From concept cache, get an entry
|
||||||
|
|||||||
Vendored
+20
@@ -54,3 +54,23 @@ class ListIfNeededCache(BaseCache):
|
|||||||
else:
|
else:
|
||||||
self._cache[new_key] = new_value
|
self._cache[new_key] = new_value
|
||||||
self._add_to_add(new_key)
|
self._add_to_add(new_key)
|
||||||
|
|
||||||
|
def _delete(self, key, value):
|
||||||
|
if value is None:
|
||||||
|
self._current_size -= len(self._cache[key])
|
||||||
|
del self._cache[key]
|
||||||
|
self._add_to_remove(key)
|
||||||
|
else:
|
||||||
|
previous = self._cache[key]
|
||||||
|
if isinstance(previous, list):
|
||||||
|
previous.remove(value)
|
||||||
|
if len(previous) == 1:
|
||||||
|
self._cache[key] = previous[0]
|
||||||
|
self._current_size -= 1
|
||||||
|
self.to_add.add(key)
|
||||||
|
else:
|
||||||
|
if previous == value:
|
||||||
|
del self._cache[key]
|
||||||
|
self._current_size -= 1
|
||||||
|
self.to_remove.add(key)
|
||||||
|
|
||||||
|
|||||||
Vendored
+14
@@ -49,3 +49,17 @@ class SetCache(BaseCache):
|
|||||||
self._cache[new_key].remove(old_value)
|
self._cache[new_key].remove(old_value)
|
||||||
self._put(new_key, new_value)
|
self._put(new_key, new_value)
|
||||||
self._add_to_add(new_key)
|
self._add_to_add(new_key)
|
||||||
|
|
||||||
|
def _delete(self, key, value):
|
||||||
|
if value is None:
|
||||||
|
self._current_size -= len(self._cache[key])
|
||||||
|
del self._cache[key]
|
||||||
|
self._add_to_remove(key)
|
||||||
|
else:
|
||||||
|
self._cache[key].remove(value)
|
||||||
|
self._current_size -= 1
|
||||||
|
if len(self._cache[key]) == 0:
|
||||||
|
del self._cache[key]
|
||||||
|
self._add_to_remove(key)
|
||||||
|
else:
|
||||||
|
self._add_to_add(key)
|
||||||
|
|||||||
+87
-248
@@ -8,10 +8,7 @@ from cache.Cache import Cache
|
|||||||
from cache.CacheManager import CacheManager
|
from cache.CacheManager import CacheManager
|
||||||
from cache.DictionaryCache import DictionaryCache
|
from cache.DictionaryCache import DictionaryCache
|
||||||
from cache.IncCache import IncCache
|
from cache.IncCache import IncCache
|
||||||
from cache.ListIfNeededCache import ListIfNeededCache
|
from core.builtin_concepts import BuiltinConcepts, ErrorConcept, ReturnValueConcept, BuiltinErrors, UnknownConcept
|
||||||
from cache.SetCache import SetCache
|
|
||||||
from core.builtin_concepts import BuiltinConcepts, ErrorConcept, ReturnValueConcept, BuiltinErrors, BuiltinUnique, \
|
|
||||||
UnknownConcept, AllBuiltinConcepts
|
|
||||||
from core.concept import Concept, ConceptParts, NotInit, get_concept_attrs
|
from core.concept import Concept, ConceptParts, NotInit, get_concept_attrs
|
||||||
from core.error import ErrorObj
|
from core.error import ErrorObj
|
||||||
from core.global_symbols import EVENT_USER_INPUT_EVALUATED
|
from core.global_symbols import EVENT_USER_INPUT_EVALUATED
|
||||||
@@ -49,12 +46,8 @@ class Sheerka(Concept):
|
|||||||
Main controller for the project
|
Main controller for the project
|
||||||
"""
|
"""
|
||||||
|
|
||||||
CONCEPTS_BY_ID_ENTRY = "Concepts_By_ID" # to store all the concepts
|
CONCEPTS_BY_ID_ENTRY = "ConceptManager:Concepts_By_ID"
|
||||||
CONCEPTS_BY_KEY_ENTRY = "Concepts_By_Key"
|
CONCEPTS_BY_NAME_ENTRY = "ConceptManager:Concepts_By_Name"
|
||||||
CONCEPTS_BY_NAME_ENTRY = "Concepts_By_Name"
|
|
||||||
CONCEPTS_BY_HASH_ENTRY = "Concepts_By_Hash" # store hash of concepts definitions (not values)
|
|
||||||
|
|
||||||
CONCEPTS_REFERENCES_ENTRY = "Concepts_References" # tracks references between concepts
|
|
||||||
|
|
||||||
CONCEPTS_BY_FIRST_KEYWORD_ENTRY = "Concepts_By_First_Keyword"
|
CONCEPTS_BY_FIRST_KEYWORD_ENTRY = "Concepts_By_First_Keyword"
|
||||||
RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY = "Resolved_Concepts_By_First_Keyword"
|
RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY = "Resolved_Concepts_By_First_Keyword"
|
||||||
@@ -63,13 +56,10 @@ class Sheerka(Concept):
|
|||||||
CONCEPTS_GRAMMARS_ENTRY = "Concepts_Grammars"
|
CONCEPTS_GRAMMARS_ENTRY = "Concepts_Grammars"
|
||||||
CHICKEN_AND_EGG_CONCEPTS_ENTRY = "Chicken_And_Egg_Concepts"
|
CHICKEN_AND_EGG_CONCEPTS_ENTRY = "Chicken_And_Egg_Concepts"
|
||||||
|
|
||||||
CONCEPTS_KEYS_ENTRY = "Concepts_Keys"
|
OBJECTS_IDS_ENTRY = "Objects_Ids"
|
||||||
BUILTIN_CONCEPTS_KEYS = "Builtins_Concepts" # sequential key for builtin concepts
|
BUILTIN_CONCEPTS_KEYS = "Builtins_Concepts" # sequential key for builtin concepts
|
||||||
USER_CONCEPTS_KEYS = "User_Concepts" # sequential key for user defined concepts
|
USER_CONCEPTS_KEYS = "User_Concepts" # sequential key for user defined concepts
|
||||||
|
|
||||||
MAX_EXECUTION_HISTORY = 100
|
|
||||||
MAX_RETURN_VALUES_HISTORY = 100
|
|
||||||
|
|
||||||
ALL_ATTRIBUTES = []
|
ALL_ATTRIBUTES = []
|
||||||
|
|
||||||
def __init__(self, cache_only=False, debug=False, loggers=None):
|
def __init__(self, cache_only=False, debug=False, loggers=None):
|
||||||
@@ -191,6 +181,8 @@ class Sheerka(Concept):
|
|||||||
initialize_pickle_handlers()
|
initialize_pickle_handlers()
|
||||||
|
|
||||||
self.sdp = SheerkaDataProvider(root_folder, self)
|
self.sdp = SheerkaDataProvider(root_folder, self)
|
||||||
|
self.builtin_cache = self.get_builtins_classes_as_dict()
|
||||||
|
|
||||||
self.initialize_caching()
|
self.initialize_caching()
|
||||||
self.get_builtin_parsers()
|
self.get_builtin_parsers()
|
||||||
self.get_builtin_evaluators()
|
self.get_builtin_evaluators()
|
||||||
@@ -233,31 +225,8 @@ class Sheerka(Concept):
|
|||||||
|
|
||||||
def initialize_caching(self):
|
def initialize_caching(self):
|
||||||
|
|
||||||
def params(cache_name):
|
cache = IncCache(default=lambda k: self.sdp.get(self.OBJECTS_IDS_ENTRY, k))
|
||||||
return {
|
self.cache_manager.register_cache(self.OBJECTS_IDS_ENTRY, cache)
|
||||||
'default': lambda k: self.sdp.get(cache_name, k),
|
|
||||||
'extend_exists': lambda k: self.sdp.exists(cache_name, k)
|
|
||||||
}
|
|
||||||
|
|
||||||
cache = IncCache(default=lambda k: self.sdp.get(self.CONCEPTS_KEYS_ENTRY, k))
|
|
||||||
self.cache_manager.register_cache(self.CONCEPTS_KEYS_ENTRY, cache)
|
|
||||||
|
|
||||||
register_concept_cache = self.cache_manager.register_concept_cache
|
|
||||||
|
|
||||||
cache = Cache(**params(self.CONCEPTS_BY_ID_ENTRY))
|
|
||||||
register_concept_cache(self.CONCEPTS_BY_ID_ENTRY, cache, lambda c: c.id, True)
|
|
||||||
|
|
||||||
cache = ListIfNeededCache(**params(self.CONCEPTS_BY_KEY_ENTRY))
|
|
||||||
register_concept_cache(self.CONCEPTS_BY_KEY_ENTRY, cache, lambda c: c.key, True)
|
|
||||||
|
|
||||||
cache = ListIfNeededCache(**params(self.CONCEPTS_BY_NAME_ENTRY))
|
|
||||||
register_concept_cache(self.CONCEPTS_BY_NAME_ENTRY, cache, lambda c: c.name, True)
|
|
||||||
|
|
||||||
cache = ListIfNeededCache(**params(self.CONCEPTS_BY_HASH_ENTRY))
|
|
||||||
register_concept_cache(self.CONCEPTS_BY_HASH_ENTRY, cache, lambda c: c.get_definition_hash(), True)
|
|
||||||
|
|
||||||
cache = SetCache(default=lambda k: self.sdp.get(self.CONCEPTS_REFERENCES_ENTRY, k))
|
|
||||||
self.cache_manager.register_cache(self.CONCEPTS_REFERENCES_ENTRY, cache)
|
|
||||||
|
|
||||||
cache = DictionaryCache(default=lambda k: self.sdp.get(self.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, k))
|
cache = DictionaryCache(default=lambda k: self.sdp.get(self.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, k))
|
||||||
self.cache_manager.register_cache(self.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, cache)
|
self.cache_manager.register_cache(self.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, cache)
|
||||||
@@ -307,8 +276,6 @@ class Sheerka(Concept):
|
|||||||
service.initialize_deferred(context, is_first_time)
|
service.initialize_deferred(context, is_first_time)
|
||||||
|
|
||||||
def first_time_initialisation(self, context):
|
def first_time_initialisation(self, context):
|
||||||
|
|
||||||
self.cache_manager.put(self.CONCEPTS_KEYS_ENTRY, self.USER_CONCEPTS_KEYS, 1000)
|
|
||||||
self.record_var(context, self.name, "save_execution_context", True)
|
self.record_var(context, self.name, "save_execution_context", True)
|
||||||
|
|
||||||
def initialize_builtin_concepts(self):
|
def initialize_builtin_concepts(self):
|
||||||
@@ -317,38 +284,11 @@ class Sheerka(Concept):
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
# self.init_log.debug("Initializing builtin concepts")
|
# self.init_log.debug("Initializing builtin concepts")
|
||||||
builtins_classes = self.get_builtins_classes_as_dict()
|
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||||
|
concept_service = self.services[SheerkaConceptManager.NAME]
|
||||||
# this all initialization of the builtins seems to be little bit complicated
|
concepts_ids = concept_service.initialize_builtin_concepts()
|
||||||
# why do we need to update it from DB ?
|
self.return_value_concept_id = concepts_ids[BuiltinConcepts.RETURN_VALUE]
|
||||||
for key in AllBuiltinConcepts:
|
self.error_concept_id = concepts_ids[BuiltinConcepts.ERROR]
|
||||||
concept = self if key == BuiltinConcepts.SHEERKA \
|
|
||||||
else builtins_classes[str(key)]() if str(key) in builtins_classes \
|
|
||||||
else Concept(key, True, False, key)
|
|
||||||
|
|
||||||
if key in BuiltinUnique:
|
|
||||||
concept._metadata.is_unique = True
|
|
||||||
concept._metadata.is_evaluated = True
|
|
||||||
|
|
||||||
if not concept._metadata.is_unique and str(key) in builtins_classes:
|
|
||||||
self.builtin_cache[key] = builtins_classes[str(key)]
|
|
||||||
|
|
||||||
from_db = self.cache_manager.get(self.CONCEPTS_BY_KEY_ENTRY, concept._metadata.key)
|
|
||||||
if from_db is None:
|
|
||||||
# self.init_log.debug(f"'{concept.name}' concept is not found in db. Adding.")
|
|
||||||
self.set_id_if_needed(concept, True)
|
|
||||||
self.cache_manager.add_concept(concept)
|
|
||||||
|
|
||||||
if key == BuiltinConcepts.RETURN_VALUE:
|
|
||||||
self.return_value_concept_id = concept.id
|
|
||||||
elif key == BuiltinConcepts.ERROR:
|
|
||||||
self.error_concept_id = concept.id
|
|
||||||
|
|
||||||
else:
|
|
||||||
# self.init_log.debug(f"Found concept '{from_db}' in db. Updating.")
|
|
||||||
concept.update_from(from_db)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def get_builtin_parsers(self):
|
def get_builtin_parsers(self):
|
||||||
"""
|
"""
|
||||||
@@ -479,114 +419,6 @@ class Sheerka(Concept):
|
|||||||
"""
|
"""
|
||||||
self.printer_handler.print(result, instructions)
|
self.printer_handler.print(result, instructions)
|
||||||
|
|
||||||
def set_id_if_needed(self, obj: Concept, is_builtin: bool):
|
|
||||||
"""
|
|
||||||
Set the key for the concept if needed
|
|
||||||
:param obj:
|
|
||||||
:param is_builtin:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if obj._metadata.id is not None:
|
|
||||||
return
|
|
||||||
|
|
||||||
key = self.BUILTIN_CONCEPTS_KEYS if is_builtin else self.USER_CONCEPTS_KEYS
|
|
||||||
obj._metadata.id = str(self.cache_manager.get(self.CONCEPTS_KEYS_ENTRY, key))
|
|
||||||
# self.log.debug(f"Setting id '{obj.metadata.id}' to concept '{obj.metadata.name}'.")
|
|
||||||
|
|
||||||
def force_sya_def(self, context, list_of_def):
|
|
||||||
"""
|
|
||||||
Set the precedence and/or the associativity of a concept
|
|
||||||
FOR TESTS PURPOSE. TO REMOVE EVENTUALLY
|
|
||||||
:param context:
|
|
||||||
:param list_of_def list of tuple(concept_id, precedence (int), SyaAssociativity)
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
# validate the entries
|
|
||||||
# If one entry is an invalid concept, rollback everything
|
|
||||||
for concept_id, precedence, associativity in list_of_def:
|
|
||||||
if concept_id == BuiltinConcepts.UNKNOWN_CONCEPT:
|
|
||||||
return self.ret(self.name,
|
|
||||||
False,
|
|
||||||
self.new(BuiltinConcepts.ERROR, body=f"Concept {concept_id} is not known"))
|
|
||||||
|
|
||||||
sya_def = self.cache_manager.copy(self.RESOLVED_CONCEPTS_SYA_DEFINITION_ENTRY) or {}
|
|
||||||
|
|
||||||
# update the definitions
|
|
||||||
for concept_id, precedence, associativity in list_of_def:
|
|
||||||
if precedence is None and associativity is None:
|
|
||||||
try:
|
|
||||||
del self.sya_definitions[concept_id]
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
sya_def[concept_id] = (precedence, associativity)
|
|
||||||
|
|
||||||
# put in cache
|
|
||||||
self.cache_manager.put(self.RESOLVED_CONCEPTS_SYA_DEFINITION_ENTRY, False, sya_def)
|
|
||||||
|
|
||||||
return self.ret(self.name, True, self.new(BuiltinConcepts.SUCCESS))
|
|
||||||
|
|
||||||
def add_in_cache(self, concept: Concept):
|
|
||||||
"""
|
|
||||||
Adds a concept template in cache.
|
|
||||||
The cache is used as a proxy before looking at sdp
|
|
||||||
:param concept:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
# sanity check
|
|
||||||
if concept.key is None:
|
|
||||||
concept.init_key()
|
|
||||||
|
|
||||||
if concept.key is None:
|
|
||||||
raise KeyError()
|
|
||||||
|
|
||||||
self.cache_manager.add_concept(concept)
|
|
||||||
|
|
||||||
return concept
|
|
||||||
|
|
||||||
def get_by_key(self, concept_key, concept_id=None):
|
|
||||||
concept_key = str(concept_key) if isinstance(concept_key, BuiltinConcepts) else concept_key
|
|
||||||
return self.internal_get("key", concept_key, self.CONCEPTS_BY_KEY_ENTRY, concept_id)
|
|
||||||
|
|
||||||
def get_by_name(self, concept_name, concept_id=None):
|
|
||||||
return self.internal_get("name", concept_name, self.CONCEPTS_BY_NAME_ENTRY, concept_id)
|
|
||||||
|
|
||||||
def get_by_hash(self, concept_hash, concept_id=None):
|
|
||||||
return self.internal_get("hash", concept_hash, self.CONCEPTS_BY_HASH_ENTRY, concept_id)
|
|
||||||
|
|
||||||
def get_by_id(self, concept_id):
|
|
||||||
return self.internal_get("id", concept_id, self.CONCEPTS_BY_ID_ENTRY, None)
|
|
||||||
|
|
||||||
def internal_get(self, index_name, key, cache_name, concept_id=None):
|
|
||||||
"""
|
|
||||||
Tries to find an entry
|
|
||||||
:param index_name: name of the index (ex by_id, by_key...)
|
|
||||||
:param key: index value
|
|
||||||
:param cache_name: name of the cache (ex Concepts_By_ID...)
|
|
||||||
:param concept_id: id of the concept if none, in case where there are multiple results
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
if key is None:
|
|
||||||
return ErrorConcept(f"Concept '{key}' is undefined.")
|
|
||||||
|
|
||||||
concepts = self.cache_manager.get(cache_name, key)
|
|
||||||
if concepts:
|
|
||||||
if concept_id is None:
|
|
||||||
return concepts
|
|
||||||
|
|
||||||
if not hasattr(concepts, "__iter__"):
|
|
||||||
return concepts
|
|
||||||
|
|
||||||
for c in concepts:
|
|
||||||
if c.id == concept_id:
|
|
||||||
return c
|
|
||||||
|
|
||||||
metadata = [(index_name, key), ("id", concept_id)] if concept_id else (index_name, key)
|
|
||||||
return self.get_unknown(metadata)
|
|
||||||
|
|
||||||
def resolve(self, concept):
|
def resolve(self, concept):
|
||||||
"""
|
"""
|
||||||
Try to find a concept by its name, id, or c:: definition
|
Try to find a concept by its name, id, or c:: definition
|
||||||
@@ -655,12 +487,19 @@ class Sheerka(Concept):
|
|||||||
if isinstance(key, Token):
|
if isinstance(key, Token):
|
||||||
if key.type == TokenKind.RULE: # do not recognize rules !!!
|
if key.type == TokenKind.RULE: # do not recognize rules !!!
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if key.value[1]:
|
|
||||||
concept = self.cache_manager.get(self.CONCEPTS_BY_ID_ENTRY, key.value[1])
|
|
||||||
else:
|
else:
|
||||||
concept = self.cache_manager.get(self.CONCEPTS_BY_NAME_ENTRY, key.value[0])
|
key = key.value
|
||||||
|
elif isinstance(key, str) and key.startswith("c:"):
|
||||||
|
key = core.utils.unstr_concept(key)
|
||||||
|
|
||||||
|
if isinstance(key, tuple):
|
||||||
|
if key == (None, None):
|
||||||
|
return None
|
||||||
|
|
||||||
|
if key[1]:
|
||||||
|
concept = self.cache_manager.get(self.CONCEPTS_BY_ID_ENTRY, key[1])
|
||||||
|
else:
|
||||||
|
concept = self.cache_manager.get(self.CONCEPTS_BY_NAME_ENTRY, key[0])
|
||||||
else:
|
else:
|
||||||
concept = self.cache_manager.get(self.CONCEPTS_BY_NAME_ENTRY, key)
|
concept = self.cache_manager.get(self.CONCEPTS_BY_NAME_ENTRY, key)
|
||||||
|
|
||||||
@@ -668,44 +507,6 @@ class Sheerka(Concept):
|
|||||||
return None
|
return None
|
||||||
return new_instances(concept) if return_new else concept
|
return new_instances(concept) if return_new else concept
|
||||||
|
|
||||||
def has_id(self, concept_id):
|
|
||||||
"""
|
|
||||||
Returns True if a concept with this id exists in cache
|
|
||||||
It does not search in the remote repository
|
|
||||||
:param concept_id:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if concept_id is None:
|
|
||||||
return False
|
|
||||||
return self.cache_manager.has(self.CONCEPTS_BY_ID_ENTRY, concept_id)
|
|
||||||
|
|
||||||
def has_key(self, concept_key):
|
|
||||||
"""
|
|
||||||
Returns True if concept(s) with this key exist in cache
|
|
||||||
It does not search in the remote repository
|
|
||||||
:param concept_key:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
return self.cache_manager.has(self.CONCEPTS_BY_KEY_ENTRY, concept_key)
|
|
||||||
|
|
||||||
def has_name(self, concept_name):
|
|
||||||
"""
|
|
||||||
Returns True if concept(s) with this name exist in cache
|
|
||||||
It does not search in the remote repository
|
|
||||||
:param concept_name:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
return self.cache_manager.has(self.CONCEPTS_BY_NAME_ENTRY, concept_name)
|
|
||||||
|
|
||||||
def has_hash(self, concept_hash):
|
|
||||||
"""
|
|
||||||
Returns True if concept(s) with this hash exist in cache
|
|
||||||
It does not search in the remote repository
|
|
||||||
:param concept_hash:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
return self.cache_manager.has(self.CONCEPTS_BY_HASH_ENTRY, concept_hash)
|
|
||||||
|
|
||||||
def new(self, concept_key, **kwargs):
|
def new(self, concept_key, **kwargs):
|
||||||
"""
|
"""
|
||||||
Returns an instance of a new concept
|
Returns an instance of a new concept
|
||||||
@@ -816,21 +617,6 @@ class Sheerka(Concept):
|
|||||||
|
|
||||||
return (self.objvalue(obj) for obj in objs.body)
|
return (self.objvalue(obj) for obj in objs.body)
|
||||||
|
|
||||||
def value_by_concept(self, obj, concept):
|
|
||||||
if obj is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if not isinstance(obj, Concept):
|
|
||||||
return None
|
|
||||||
|
|
||||||
if isinstance(concept, tuple) and obj.key in [str(key) for key in concept]:
|
|
||||||
return obj
|
|
||||||
|
|
||||||
if obj.key == str(concept):
|
|
||||||
return obj
|
|
||||||
|
|
||||||
return self.value_by_concept(obj.body, concept)
|
|
||||||
|
|
||||||
def get_error(self, obj):
|
def get_error(self, obj):
|
||||||
if isinstance(obj, Concept) and obj._metadata.is_builtin and obj.key in BuiltinErrors:
|
if isinstance(obj, Concept) and obj._metadata.is_builtin and obj.key in BuiltinErrors:
|
||||||
return obj
|
return obj
|
||||||
@@ -863,16 +649,6 @@ class Sheerka(Concept):
|
|||||||
|
|
||||||
return self.parsers_prefix + name
|
return self.parsers_prefix + name
|
||||||
|
|
||||||
def test(self):
|
|
||||||
return f"I have access to Sheerka !"
|
|
||||||
|
|
||||||
def test_using_context(self, context, param):
|
|
||||||
event = context.event.get_digest()
|
|
||||||
return f"I have access to Sheerka ! {param=}, {event=}."
|
|
||||||
|
|
||||||
def test_error(self):
|
|
||||||
raise Exception("I can raise an error")
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_success(obj):
|
def is_success(obj):
|
||||||
if isinstance(obj, bool): # quick win
|
if isinstance(obj, bool): # quick win
|
||||||
@@ -1014,6 +790,69 @@ class Sheerka(Concept):
|
|||||||
}
|
}
|
||||||
return self.new(BuiltinConcepts.TO_DICT, body=bag)
|
return self.new(BuiltinConcepts.TO_DICT, body=bag)
|
||||||
|
|
||||||
|
def test(self):
|
||||||
|
return f"I have access to Sheerka !"
|
||||||
|
|
||||||
|
def test_using_context(self, context, param):
|
||||||
|
event = context.event.get_digest()
|
||||||
|
return f"I have access to Sheerka ! {param=}, {event=}."
|
||||||
|
|
||||||
|
def test_error(self):
|
||||||
|
raise Exception("I can raise an error")
|
||||||
|
|
||||||
|
def test_only_force_sya_def(self, context, list_of_def):
|
||||||
|
"""
|
||||||
|
Set the precedence and/or the associativity of a concept
|
||||||
|
FOR TESTS PURPOSE. TO REMOVE EVENTUALLY
|
||||||
|
:param context:
|
||||||
|
:param list_of_def list of tuple(concept_id, precedence (int), SyaAssociativity)
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
# validate the entries
|
||||||
|
# If one entry is an invalid concept, rollback everything
|
||||||
|
for concept_id, precedence, associativity in list_of_def:
|
||||||
|
if concept_id == BuiltinConcepts.UNKNOWN_CONCEPT:
|
||||||
|
return self.ret(self.name,
|
||||||
|
False,
|
||||||
|
self.new(BuiltinConcepts.ERROR, body=f"Concept {concept_id} is not known"))
|
||||||
|
|
||||||
|
sya_def = self.cache_manager.copy(self.RESOLVED_CONCEPTS_SYA_DEFINITION_ENTRY) or {}
|
||||||
|
|
||||||
|
# update the definitions
|
||||||
|
for concept_id, precedence, associativity in list_of_def:
|
||||||
|
if precedence is None and associativity is None:
|
||||||
|
try:
|
||||||
|
del self.sya_definitions[concept_id]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
sya_def[concept_id] = (precedence, associativity)
|
||||||
|
|
||||||
|
# put in cache
|
||||||
|
self.cache_manager.put(self.RESOLVED_CONCEPTS_SYA_DEFINITION_ENTRY, False, sya_def)
|
||||||
|
|
||||||
|
return self.ret(self.name, True, self.new(BuiltinConcepts.SUCCESS))
|
||||||
|
|
||||||
|
def test_only_add_in_cache(self, concept: Concept):
|
||||||
|
"""
|
||||||
|
Adds a concept template in cache.
|
||||||
|
The cache is used as a proxy before looking at sdp
|
||||||
|
:param concept:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
# sanity check
|
||||||
|
if concept.key is None:
|
||||||
|
concept.init_key()
|
||||||
|
|
||||||
|
if concept.key is None:
|
||||||
|
raise KeyError()
|
||||||
|
|
||||||
|
self.cache_manager.add_concept(concept)
|
||||||
|
|
||||||
|
return concept
|
||||||
|
|
||||||
|
|
||||||
def to_profile():
|
def to_profile():
|
||||||
sheerka = Sheerka()
|
sheerka = Sheerka()
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ class SheerkaComparisonManager(BaseService):
|
|||||||
|
|
||||||
cycles = self.detect_cycles(new)
|
cycles = self.detect_cycles(new)
|
||||||
if cycles:
|
if cycles:
|
||||||
concepts_in_cycle = [self.sheerka.resolve(c) for c in cycles]
|
concepts_in_cycle = [self.sheerka.fast_resolve(c) for c in cycles]
|
||||||
chicken_an_egg = self.sheerka.new(BuiltinConcepts.CHICKEN_AND_EGG, body=concepts_in_cycle)
|
chicken_an_egg = self.sheerka.new(BuiltinConcepts.CHICKEN_AND_EGG, body=concepts_in_cycle)
|
||||||
return self.sheerka.ret(self.NAME, False, chicken_an_egg)
|
return self.sheerka.ret(self.NAME, False, chicken_an_egg)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,632 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
import core.utils
|
||||||
|
from cache.Cache import Cache
|
||||||
|
from cache.CacheManager import ConceptNotFound
|
||||||
|
from cache.ListIfNeededCache import ListIfNeededCache
|
||||||
|
from cache.SetCache import SetCache
|
||||||
|
from core.builtin_concepts import BuiltinConcepts, ErrorConcept, AllBuiltinConcepts, BuiltinUnique
|
||||||
|
from core.builtin_helpers import ensure_concept
|
||||||
|
from core.concept import Concept, DEFINITION_TYPE_DEF, DEFINITION_TYPE_BNF, freeze_concept_attrs, NotInit, \
|
||||||
|
ConceptMetadata
|
||||||
|
from core.error import ErrorObj
|
||||||
|
from core.global_symbols import EVENT_CONCEPT_CREATED
|
||||||
|
from core.sheerka.services.sheerka_service import BaseService
|
||||||
|
from core.tokenizer import Tokenizer, TokenKind
|
||||||
|
from sdp.sheerkaDataProvider import SheerkaDataProviderDuplicateKeyError
|
||||||
|
|
||||||
|
BASE_NODE_PARSER_CLASS = "parsers.BaseNodeParser.BaseNodeParser"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class NoModificationFound(ErrorObj):
|
||||||
|
"""
|
||||||
|
Trying to modify a concept without modifying it
|
||||||
|
"""
|
||||||
|
concept: Concept
|
||||||
|
attrs: dict = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ForbiddenAttribute(ErrorObj):
|
||||||
|
"""
|
||||||
|
When trying to modify an attribute that must not be modified
|
||||||
|
"""
|
||||||
|
attr: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class UnknownAttribute(ErrorObj):
|
||||||
|
"""
|
||||||
|
When trying to modify an attribute that does not exist
|
||||||
|
"""
|
||||||
|
attr: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class CannotRemoveMeta(ErrorObj):
|
||||||
|
"""
|
||||||
|
When trying to remove a metadata attribute (ConceptMeta is a class, you cannot remove attr form it)
|
||||||
|
"""
|
||||||
|
attrs: dict
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ValueNotFound(ErrorObj):
|
||||||
|
"""
|
||||||
|
When trying to remove a value that does not exists (but the props/variable exists)
|
||||||
|
"""
|
||||||
|
item: str
|
||||||
|
value: object
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ConceptIsReferenced(ErrorObj):
|
||||||
|
"""
|
||||||
|
When trying to remove a concept that is referenced by other concept(s)
|
||||||
|
"""
|
||||||
|
references: list
|
||||||
|
|
||||||
|
|
||||||
|
class SheerkaConceptManager(BaseService):
|
||||||
|
NAME = "ConceptManager"
|
||||||
|
|
||||||
|
BUILTIN_CONCEPTS_IDS = "Builtins_Concepts_IDs" # sequential key for builtin concepts
|
||||||
|
USER_CONCEPTS_IDS = "User_Concepts_IDs" # sequential key for user defined concepts
|
||||||
|
|
||||||
|
CONCEPTS_IDS_ENTRY = "ConceptManager:Concepts_IDs"
|
||||||
|
|
||||||
|
CONCEPTS_BY_ID_ENTRY = "ConceptManager:Concepts_By_ID" # to store all the concepts
|
||||||
|
CONCEPTS_BY_KEY_ENTRY = "ConceptManager:Concepts_By_Key"
|
||||||
|
CONCEPTS_BY_NAME_ENTRY = "ConceptManager:Concepts_By_Name"
|
||||||
|
CONCEPTS_BY_HASH_ENTRY = "ConceptManager:Concepts_By_Hash" # store hash of concepts definitions (not values)
|
||||||
|
CONCEPTS_REFERENCES_ENTRY = "ConceptManager:Concepts_References" # tracks references between concepts
|
||||||
|
|
||||||
|
def __init__(self, sheerka):
|
||||||
|
super().__init__(sheerka)
|
||||||
|
self.bnp = core.utils.get_class(BASE_NODE_PARSER_CLASS) # BaseNodeParser
|
||||||
|
self.forbidden_meta = {"is_builtin", "key", "id", "props", "variables"}
|
||||||
|
self.allowed_meta = {attr for attr in vars(ConceptMetadata) if
|
||||||
|
not attr.startswith("_") and attr not in self.forbidden_meta}
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
|
self.sheerka.bind_service_method(self.create_new_concept, True)
|
||||||
|
self.sheerka.bind_service_method(self.modify_concept, True)
|
||||||
|
self.sheerka.bind_service_method(self.remove_concept, True)
|
||||||
|
self.sheerka.bind_service_method(self.set_id_if_needed, True)
|
||||||
|
self.sheerka.bind_service_method(self.set_attr, True)
|
||||||
|
self.sheerka.bind_service_method(self.get_attr, False)
|
||||||
|
self.sheerka.bind_service_method(self.get_by_key, False, visible=False)
|
||||||
|
self.sheerka.bind_service_method(self.get_by_name, False, visible=False)
|
||||||
|
self.sheerka.bind_service_method(self.get_by_hash, False, visible=False)
|
||||||
|
self.sheerka.bind_service_method(self.get_by_id, False, visible=False)
|
||||||
|
self.sheerka.bind_service_method(self.not_is_variable, False, visible=False)
|
||||||
|
|
||||||
|
def params(cache_name):
|
||||||
|
return {
|
||||||
|
'default': lambda k: self.sheerka.sdp.get(cache_name, k),
|
||||||
|
'extend_exists': lambda k: self.sheerka.sdp.exists(cache_name, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
register_concept_cache = self.sheerka.cache_manager.register_concept_cache
|
||||||
|
|
||||||
|
cache = Cache(**params(self.CONCEPTS_BY_ID_ENTRY))
|
||||||
|
register_concept_cache(self.CONCEPTS_BY_ID_ENTRY, cache, lambda c: c.id, True)
|
||||||
|
|
||||||
|
cache = ListIfNeededCache(**params(self.CONCEPTS_BY_KEY_ENTRY))
|
||||||
|
register_concept_cache(self.CONCEPTS_BY_KEY_ENTRY, cache, lambda c: c.key, True)
|
||||||
|
|
||||||
|
cache = ListIfNeededCache(**params(self.CONCEPTS_BY_NAME_ENTRY))
|
||||||
|
register_concept_cache(self.CONCEPTS_BY_NAME_ENTRY, cache, lambda c: c.name, True)
|
||||||
|
|
||||||
|
cache = ListIfNeededCache(**params(self.CONCEPTS_BY_HASH_ENTRY))
|
||||||
|
register_concept_cache(self.CONCEPTS_BY_HASH_ENTRY, cache, lambda c: c.get_definition_hash(), True)
|
||||||
|
|
||||||
|
cache = SetCache(default=lambda k: self.sheerka.sdp.get(self.CONCEPTS_REFERENCES_ENTRY, k))
|
||||||
|
self.sheerka.cache_manager.register_cache(self.CONCEPTS_REFERENCES_ENTRY, cache)
|
||||||
|
|
||||||
|
def initialize_deferred(self, context, is_first_time):
|
||||||
|
if is_first_time:
|
||||||
|
self.sheerka.cache_manager.put(self.sheerka.OBJECTS_IDS_ENTRY, self.USER_CONCEPTS_IDS, 1000)
|
||||||
|
|
||||||
|
def initialize_builtin_concepts(self):
|
||||||
|
"""
|
||||||
|
Initializes the builtin concepts
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
builtin_concepts_ids = {}
|
||||||
|
|
||||||
|
for key in AllBuiltinConcepts:
|
||||||
|
concept = self.sheerka if key == BuiltinConcepts.SHEERKA \
|
||||||
|
else self.sheerka.builtin_cache[str(key)]() if str(key) in self.sheerka.builtin_cache \
|
||||||
|
else Concept(key, True, False, key)
|
||||||
|
|
||||||
|
if key in BuiltinUnique:
|
||||||
|
concept.get_metadata().is_unique = True
|
||||||
|
concept.get_metadata().is_evaluated = True
|
||||||
|
|
||||||
|
from_db = self.sheerka.cache_manager.get(self.CONCEPTS_BY_KEY_ENTRY, concept.get_metadata().key)
|
||||||
|
if from_db is None:
|
||||||
|
# self.init_log.debug(f"'{concept.name}' concept is not found in db. Adding.")
|
||||||
|
self.set_id_if_needed(concept, True)
|
||||||
|
self.sheerka.cache_manager.add_concept(concept)
|
||||||
|
else:
|
||||||
|
# self.init_log.debug(f"Found concept '{from_db}' in db. Updating.")
|
||||||
|
concept.update_from(from_db)
|
||||||
|
|
||||||
|
builtin_concepts_ids[key] = concept.id
|
||||||
|
|
||||||
|
return builtin_concepts_ids
|
||||||
|
|
||||||
|
def create_new_concept(self, context, concept: Concept):
|
||||||
|
"""
|
||||||
|
Adds a new concept to the system
|
||||||
|
:param context:
|
||||||
|
:param concept: DefConceptNode
|
||||||
|
:return: digest of the new concept
|
||||||
|
"""
|
||||||
|
ensure_concept(concept)
|
||||||
|
|
||||||
|
sheerka = self.sheerka
|
||||||
|
|
||||||
|
concept.init_key()
|
||||||
|
init_bnf_ret_value = None
|
||||||
|
|
||||||
|
cache_manager = sheerka.cache_manager
|
||||||
|
|
||||||
|
if cache_manager.exists(self.CONCEPTS_BY_HASH_ENTRY, concept.get_definition_hash()):
|
||||||
|
error = SheerkaDataProviderDuplicateKeyError(self.CONCEPTS_BY_KEY_ENTRY + "." + concept.key, concept)
|
||||||
|
return sheerka.ret(
|
||||||
|
self.NAME,
|
||||||
|
False,
|
||||||
|
sheerka.new(BuiltinConcepts.CONCEPT_ALREADY_DEFINED, body=concept),
|
||||||
|
error.args[0])
|
||||||
|
|
||||||
|
# set id before saving in db
|
||||||
|
sheerka.set_id_if_needed(concept, False)
|
||||||
|
|
||||||
|
# freeze attributes
|
||||||
|
freeze_concept_attrs(concept)
|
||||||
|
|
||||||
|
# check if the bnf definition is correctly computed
|
||||||
|
try:
|
||||||
|
self.bnp.ensure_bnf(context, concept)
|
||||||
|
except Exception as ex:
|
||||||
|
return sheerka.ret(self.NAME, False, ex.args[0])
|
||||||
|
|
||||||
|
# compute new concepts_by_first_keyword
|
||||||
|
init_ret_value = self.bnp.get_concepts_by_first_token(context, [concept], True)
|
||||||
|
if not init_ret_value.status:
|
||||||
|
return sheerka.ret(self.NAME, False, ErrorConcept(init_ret_value.value))
|
||||||
|
concepts_by_first_keyword = init_ret_value.body
|
||||||
|
|
||||||
|
# computes resolved concepts_by_first_keyword
|
||||||
|
init_ret_value = self.bnp.resolve_concepts_by_first_keyword(context, concepts_by_first_keyword)
|
||||||
|
if not init_ret_value.status:
|
||||||
|
return sheerka.ret(self.NAME, False, ErrorConcept(init_ret_value.value))
|
||||||
|
resolved_concepts_by_first_keyword = init_ret_value.body
|
||||||
|
|
||||||
|
# if everything is fine
|
||||||
|
concept.freeze_definition_hash()
|
||||||
|
cache_manager.add_concept(concept)
|
||||||
|
cache_manager.put(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, False, concepts_by_first_keyword)
|
||||||
|
cache_manager.put(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, False, resolved_concepts_by_first_keyword)
|
||||||
|
|
||||||
|
if concept.get_metadata().definition_type == DEFINITION_TYPE_DEF and concept.get_metadata().definition != concept.name:
|
||||||
|
# allow search by definition when definition relevant
|
||||||
|
cache_manager.put(self.sheerka.CONCEPTS_BY_NAME_ENTRY, concept.get_metadata().definition, concept)
|
||||||
|
|
||||||
|
# update references
|
||||||
|
for ref in self.compute_references(concept):
|
||||||
|
cache_manager.put(self.CONCEPTS_REFERENCES_ENTRY, ref, concept.id)
|
||||||
|
|
||||||
|
# TODO : this line seems to be useless
|
||||||
|
# The grammar is never reset
|
||||||
|
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)
|
||||||
|
|
||||||
|
# publish the new concept
|
||||||
|
sheerka.publish(context, EVENT_CONCEPT_CREATED, concept)
|
||||||
|
|
||||||
|
# process the return if needed
|
||||||
|
ret = sheerka.ret(self.NAME, True, sheerka.new(BuiltinConcepts.NEW_CONCEPT, body=concept))
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def modify_concept(self, context, concept, to_add=None, to_remove=None, modify_source=False):
|
||||||
|
"""
|
||||||
|
Modify the definition of a concept
|
||||||
|
:param context:
|
||||||
|
:param concept: concept to modify
|
||||||
|
:param to_add: meta, props or variables to add/update
|
||||||
|
:param to_remove: props or variables to remove
|
||||||
|
:param modify_source: update or not the concept given in parameter
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
# to_add is a dictionary
|
||||||
|
# to_add = {
|
||||||
|
# 'meta' : {<key, value>} of metadata to add/update,
|
||||||
|
# 'props' : {<key, value>} of properties to add/update,
|
||||||
|
# 'variables': {<key, value>} of variables to add/update,
|
||||||
|
# }
|
||||||
|
# if the <key> already exists, the entry is updated, otherwise a new value is created
|
||||||
|
# for props, if the <key> already exists, a new entry is added to the set
|
||||||
|
#
|
||||||
|
# to_remove = {
|
||||||
|
# 'props' : {<key, [value]>} entries to remove. 'value' can be a list or a single entry
|
||||||
|
# 'variables': [<key>] list of keys to remove
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
sheerka = self.sheerka
|
||||||
|
cache_manager = self.sheerka.cache_manager
|
||||||
|
|
||||||
|
if not to_add and not to_remove:
|
||||||
|
return sheerka.ret(self.NAME, False, sheerka.err(NoModificationFound(concept)))
|
||||||
|
|
||||||
|
if not sheerka.cache_manager.exists(self.CONCEPTS_BY_ID_ENTRY, concept.id):
|
||||||
|
return sheerka.ret(self.NAME, False, sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT, body=concept))
|
||||||
|
|
||||||
|
# modify the metadata. Almost all ConceptMetadata attributes except variables and props
|
||||||
|
new_concept = sheerka.new_from_template(concept, concept.key) # reload from cache or database ?
|
||||||
|
|
||||||
|
res = self._update_concept(context, new_concept, to_add, to_remove)
|
||||||
|
if res is not None:
|
||||||
|
return res
|
||||||
|
|
||||||
|
freeze_concept_attrs(new_concept)
|
||||||
|
|
||||||
|
# To update concept by first keyword
|
||||||
|
# first remove the old references
|
||||||
|
keywords = self.bnp.get_first_tokens(sheerka, concept) # keyword of the old concept
|
||||||
|
concepts_by_first_keyword = cache_manager.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY)
|
||||||
|
for keyword in keywords:
|
||||||
|
try:
|
||||||
|
concepts_by_first_keyword[keyword].remove(concept.id)
|
||||||
|
if len(concepts_by_first_keyword[keyword]) == 0:
|
||||||
|
del concepts_by_first_keyword[keyword]
|
||||||
|
except KeyError: # only occurs in unit tests when concepts are created without create_new()
|
||||||
|
pass
|
||||||
|
|
||||||
|
# and then update
|
||||||
|
init_ret_value = self.bnp.get_concepts_by_first_token(context, [new_concept], False, concepts_by_first_keyword)
|
||||||
|
if not init_ret_value.status:
|
||||||
|
return sheerka.ret(self.NAME, False, ErrorConcept(init_ret_value.value))
|
||||||
|
concepts_by_first_keyword = init_ret_value.body
|
||||||
|
|
||||||
|
# computes resolved concepts_by_first_keyword
|
||||||
|
init_ret_value = self.bnp.resolve_concepts_by_first_keyword(context,
|
||||||
|
concepts_by_first_keyword,
|
||||||
|
{new_concept.id: new_concept})
|
||||||
|
if not init_ret_value.status:
|
||||||
|
return sheerka.ret(self.NAME, False, ErrorConcept(init_ret_value.value))
|
||||||
|
resolved_concepts_by_first_keyword = init_ret_value.body
|
||||||
|
|
||||||
|
# update concept that referenced the old concept and clear old references
|
||||||
|
self.update_references(context, concept, new_concept, to_add)
|
||||||
|
for ref in self.compute_references(concept):
|
||||||
|
cache_manager.delete(self.CONCEPTS_REFERENCES_ENTRY, ref, concept.id)
|
||||||
|
|
||||||
|
# compute new references
|
||||||
|
for ref in self.compute_references(new_concept):
|
||||||
|
cache_manager.put(self.CONCEPTS_REFERENCES_ENTRY, ref, new_concept.id)
|
||||||
|
|
||||||
|
cache_manager.update_concept(concept, new_concept)
|
||||||
|
cache_manager.put(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, False, concepts_by_first_keyword)
|
||||||
|
cache_manager.put(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, False,
|
||||||
|
resolved_concepts_by_first_keyword)
|
||||||
|
|
||||||
|
# TODO : update when definition_type = DEFINITION_TYPE_DEF : have a look at update_references() below
|
||||||
|
# TODO : Update concepts grammars : have a look at update_references() below
|
||||||
|
if modify_source:
|
||||||
|
self._update_concept(context, concept, to_add, to_remove)
|
||||||
|
|
||||||
|
ret = sheerka.ret(self.NAME, True, sheerka.new(BuiltinConcepts.NEW_CONCEPT, body=new_concept))
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def remove_concept(self, context, concept):
|
||||||
|
"""
|
||||||
|
Remove a concept
|
||||||
|
:param context:
|
||||||
|
:param concept:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
sheerka = context.sheerka
|
||||||
|
refs = self.sheerka.cache_manager.get(self.CONCEPTS_REFERENCES_ENTRY, concept.id)
|
||||||
|
if refs:
|
||||||
|
refs_instances = [sheerka.new_from_template(c, c.key) for c in [self.get_by_id(ref) for ref in refs]]
|
||||||
|
return sheerka.ret(self.NAME, False, sheerka.err(ConceptIsReferenced(refs_instances)))
|
||||||
|
|
||||||
|
try:
|
||||||
|
sheerka.cache_manager.remove_concept(concept)
|
||||||
|
return sheerka.ret(self.NAME, True, sheerka.new(BuiltinConcepts.SUCCESS))
|
||||||
|
except ConceptNotFound as ex:
|
||||||
|
return sheerka.ret(self.NAME, False, sheerka.err(ex))
|
||||||
|
|
||||||
|
def set_attr(self, concept, attribute, value):
|
||||||
|
"""
|
||||||
|
Modifies an attribute of a concept (concept.values)
|
||||||
|
:param context:
|
||||||
|
:param concept:
|
||||||
|
:param attribute:
|
||||||
|
:param value:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
ensure_concept(concept)
|
||||||
|
|
||||||
|
attr = attribute.str_id if isinstance(attribute, Concept) else attribute
|
||||||
|
concept.set_value(attr, value)
|
||||||
|
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
|
||||||
|
|
||||||
|
def get_attr(self, concept, attribute):
|
||||||
|
"""
|
||||||
|
Returns the attribute of a concept
|
||||||
|
:param context:
|
||||||
|
:param concept:
|
||||||
|
:param attribute:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
ensure_concept()
|
||||||
|
if not self.sheerka.is_success(concept):
|
||||||
|
return concept
|
||||||
|
|
||||||
|
attr = attribute.str_id if isinstance(attribute, Concept) else attribute
|
||||||
|
|
||||||
|
if (value := concept.get_value(attr)) == NotInit:
|
||||||
|
return self.sheerka.new(BuiltinConcepts.NOT_FOUND, body={"#concept": concept, "#attr": attribute})
|
||||||
|
return value
|
||||||
|
|
||||||
|
def set_id_if_needed(self, obj: Concept, is_builtin: bool):
|
||||||
|
"""
|
||||||
|
Set the key for the concept if needed
|
||||||
|
:param obj:
|
||||||
|
:param is_builtin:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if obj.get_metadata().id is not None:
|
||||||
|
return
|
||||||
|
|
||||||
|
entry_key = self.BUILTIN_CONCEPTS_IDS if is_builtin else self.USER_CONCEPTS_IDS
|
||||||
|
obj.get_metadata().id = str(self.sheerka.cache_manager.get(self.sheerka.OBJECTS_IDS_ENTRY, entry_key))
|
||||||
|
# self.log.debug(f"Setting id '{obj.metadata.id}' to concept '{obj.metadata.name}'.")
|
||||||
|
|
||||||
|
def get_by_key(self, concept_key, concept_id=None):
|
||||||
|
concept_key = str(concept_key) if isinstance(concept_key, BuiltinConcepts) else concept_key
|
||||||
|
return self.internal_get("key", concept_key, self.CONCEPTS_BY_KEY_ENTRY, concept_id)
|
||||||
|
|
||||||
|
def get_by_name(self, concept_name, concept_id=None):
|
||||||
|
return self.internal_get("name", concept_name, self.CONCEPTS_BY_NAME_ENTRY, concept_id)
|
||||||
|
|
||||||
|
def get_by_hash(self, concept_hash, concept_id=None):
|
||||||
|
return self.internal_get("hash", concept_hash, self.CONCEPTS_BY_HASH_ENTRY, concept_id)
|
||||||
|
|
||||||
|
def get_by_id(self, concept_id):
|
||||||
|
return self.internal_get("id", concept_id, self.CONCEPTS_BY_ID_ENTRY, None)
|
||||||
|
|
||||||
|
def has_id(self, concept_id):
|
||||||
|
"""
|
||||||
|
Returns True if a concept with this id exists in cache
|
||||||
|
It does not search in the remote repository
|
||||||
|
:param concept_id:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if concept_id is None:
|
||||||
|
return False
|
||||||
|
return self.sheerka.cache_manager.has(self.CONCEPTS_BY_ID_ENTRY, concept_id)
|
||||||
|
|
||||||
|
def has_key(self, concept_key):
|
||||||
|
"""
|
||||||
|
Returns True if concept(s) with this key exist in cache
|
||||||
|
It does not search in the remote repository
|
||||||
|
:param concept_key:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return self.sheerka.cache_manager.has(self.CONCEPTS_BY_KEY_ENTRY, concept_key)
|
||||||
|
|
||||||
|
def has_name(self, concept_name):
|
||||||
|
"""
|
||||||
|
Returns True if concept(s) with this name exist in cache
|
||||||
|
It does not search in the remote repository
|
||||||
|
:param concept_name:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return self.sheerka.cache_manager.has(self.CONCEPTS_BY_NAME_ENTRY, concept_name)
|
||||||
|
|
||||||
|
def has_hash(self, concept_hash):
|
||||||
|
"""
|
||||||
|
Returns True if concept(s) with this hash exist in cache
|
||||||
|
It does not search in the remote repository
|
||||||
|
:param concept_hash:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return self.sheerka.cache_manager.has(self.CONCEPTS_BY_HASH_ENTRY, concept_hash)
|
||||||
|
|
||||||
|
def internal_get(self, index_name, key, cache_name, concept_id=None):
|
||||||
|
"""
|
||||||
|
Tries to find an entry
|
||||||
|
:param index_name: name of the index (ex by_id, by_key...)
|
||||||
|
:param key: index value
|
||||||
|
:param cache_name: name of the cache (ex Concepts_By_ID...)
|
||||||
|
:param concept_id: id of the concept if none, in case where there are multiple results
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
if key is None:
|
||||||
|
return ErrorConcept(f"Concept '{key}' is undefined.")
|
||||||
|
|
||||||
|
concepts = self.sheerka.cache_manager.get(cache_name, key)
|
||||||
|
if concepts:
|
||||||
|
if concept_id is None:
|
||||||
|
return concepts
|
||||||
|
|
||||||
|
if not hasattr(concepts, "__iter__"):
|
||||||
|
return concepts
|
||||||
|
|
||||||
|
for c in concepts:
|
||||||
|
if c.id == concept_id:
|
||||||
|
return c
|
||||||
|
|
||||||
|
metadata = [(index_name, key), ("id", concept_id)] if concept_id else (index_name, key)
|
||||||
|
return self.sheerka.get_unknown(metadata)
|
||||||
|
|
||||||
|
def update_references(self, context, concept, modified_concept=None, modifications=None):
|
||||||
|
"""
|
||||||
|
Updates all the concepts that reference concept
|
||||||
|
:param context:
|
||||||
|
:param concept:
|
||||||
|
:param modified_concept:
|
||||||
|
:param modifications:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
refs = self.sheerka.cache_manager.get(self.CONCEPTS_REFERENCES_ENTRY, concept.id)
|
||||||
|
if not refs:
|
||||||
|
return
|
||||||
|
|
||||||
|
for concept_id in refs:
|
||||||
|
# remove the grammar entry so that it can be recreated
|
||||||
|
self.sheerka.cache_manager.delete(self.sheerka.CONCEPTS_GRAMMARS_ENTRY, concept_id)
|
||||||
|
|
||||||
|
# reset the bnf definition if needed
|
||||||
|
if modified_concept:
|
||||||
|
if self.has_id(concept_id):
|
||||||
|
to_update = self.get_by_id(concept_id)
|
||||||
|
metadata = to_update.get_metadata()
|
||||||
|
if metadata.definition_type == DEFINITION_TYPE_BNF and self._name_has_changed(modifications):
|
||||||
|
tokens = list(Tokenizer(metadata.definition))
|
||||||
|
modified = False
|
||||||
|
for i, token in enumerate(tokens):
|
||||||
|
if token.type == TokenKind.IDENTIFIER and token.value == concept.name:
|
||||||
|
clone = token.clone()
|
||||||
|
clone.value = modified_concept.name
|
||||||
|
tokens[i] = clone
|
||||||
|
modified = True
|
||||||
|
|
||||||
|
if modified:
|
||||||
|
to_update.get_metadata().definition = core.utils.get_text_from_tokens(tokens)
|
||||||
|
to_update.set_bnf(None)
|
||||||
|
|
||||||
|
def compute_references(self, concept):
|
||||||
|
"""
|
||||||
|
We need to keep a track of all concepts used by the current concept
|
||||||
|
So that if one of these are modified, we can modify the current concept accordingly
|
||||||
|
:param concept:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
refs = set()
|
||||||
|
|
||||||
|
if concept.get_metadata().definition_type == DEFINITION_TYPE_BNF:
|
||||||
|
from parsers.BnfNodeParser import BnfNodeConceptExpressionVisitor
|
||||||
|
other_concepts_visitor = BnfNodeConceptExpressionVisitor()
|
||||||
|
other_concepts_visitor.visit(concept.get_bnf())
|
||||||
|
|
||||||
|
for concept in other_concepts_visitor.references:
|
||||||
|
if isinstance(concept, str):
|
||||||
|
concept = self.sheerka.get_by_key(concept)
|
||||||
|
refs.add(concept.id)
|
||||||
|
|
||||||
|
return refs
|
||||||
|
|
||||||
|
def not_is_variable(self, name):
|
||||||
|
"""
|
||||||
|
Given a name tells if it refers to a variable name
|
||||||
|
:param name:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return not self.sheerka.cache_manager.get(self.sheerka.CONCEPTS_BY_NAME_ENTRY, name)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _name_has_changed(to_add):
|
||||||
|
if to_add is None or "meta" not in to_add:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return "name" in to_add["meta"]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _definition_has_changed(to_add):
|
||||||
|
if to_add is None or "meta" not in to_add:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return "definition" in to_add["meta"]
|
||||||
|
|
||||||
|
def _update_concept(self, context, concept, to_add, to_remove):
|
||||||
|
sheerka = context.sheerka
|
||||||
|
same_values = {}
|
||||||
|
|
||||||
|
if to_add:
|
||||||
|
if "meta" in to_add:
|
||||||
|
# All modifications must be allowed
|
||||||
|
metadata = concept.get_metadata()
|
||||||
|
|
||||||
|
for k, v in to_add["meta"].items():
|
||||||
|
if k in self.forbidden_meta:
|
||||||
|
return sheerka.ret(self.NAME, False, sheerka.err(ForbiddenAttribute(k)))
|
||||||
|
|
||||||
|
try:
|
||||||
|
if getattr(metadata, k) == v:
|
||||||
|
same_values[k] = v
|
||||||
|
else:
|
||||||
|
setattr(metadata, k, v)
|
||||||
|
except AttributeError:
|
||||||
|
return sheerka.ret(self.NAME, False, sheerka.err(UnknownAttribute(k)))
|
||||||
|
|
||||||
|
if same_values == to_add["meta"]:
|
||||||
|
return sheerka.ret(self.NAME, False,
|
||||||
|
sheerka.err(NoModificationFound(concept, same_values)))
|
||||||
|
|
||||||
|
if "props" in to_add:
|
||||||
|
for k, v in to_add["props"].items():
|
||||||
|
concept.add_prop(k, v)
|
||||||
|
|
||||||
|
if "variables" in to_add:
|
||||||
|
for k, v in to_add["variables"].items():
|
||||||
|
# update existing or add new
|
||||||
|
for i, var in enumerate(concept.get_metadata().variables):
|
||||||
|
if var[0] == k:
|
||||||
|
concept.get_metadata().variables[i] = (k, v)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
concept.def_var(k, v)
|
||||||
|
|
||||||
|
if to_remove:
|
||||||
|
if "meta" in to_remove:
|
||||||
|
return sheerka.ret(self.NAME, False, sheerka.err(CannotRemoveMeta(to_remove["meta"])))
|
||||||
|
|
||||||
|
if "props" in to_remove:
|
||||||
|
for k, v in to_remove["props"].items():
|
||||||
|
if k not in concept.get_metadata().props:
|
||||||
|
return sheerka.ret(self.NAME, False, sheerka.err(UnknownAttribute(k)))
|
||||||
|
|
||||||
|
props = concept.get_metadata().props[k]
|
||||||
|
try:
|
||||||
|
if isinstance(v, (set, list, tuple)):
|
||||||
|
for item in v:
|
||||||
|
props.remove(item)
|
||||||
|
else:
|
||||||
|
props.remove(v)
|
||||||
|
|
||||||
|
# remove empty sets
|
||||||
|
if len(props) == 0:
|
||||||
|
del concept.get_metadata().props[k]
|
||||||
|
except KeyError:
|
||||||
|
return sheerka.ret(self.NAME, False, sheerka.err(ValueNotFound(k, v)))
|
||||||
|
|
||||||
|
if "variables" in to_remove:
|
||||||
|
variables_to_remove = []
|
||||||
|
for k in to_remove["variables"]:
|
||||||
|
for var_def in concept.get_metadata().variables:
|
||||||
|
if var_def[0] == k:
|
||||||
|
variables_to_remove.append(var_def)
|
||||||
|
delattr(concept, var_def[0])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
return sheerka.ret(self.NAME, False, sheerka.err(UnknownAttribute(k)))
|
||||||
|
core.utils.remove_list_from_list(concept.get_metadata().variables, variables_to_remove)
|
||||||
|
|
||||||
|
concept.get_metadata().key = None
|
||||||
|
if self._definition_has_changed(to_add) and concept.get_metadata().definition_type == DEFINITION_TYPE_BNF:
|
||||||
|
concept.set_bnf(None)
|
||||||
|
self.bnp.ensure_bnf(context, concept)
|
||||||
|
|
||||||
|
concept.init_key()
|
||||||
|
|
||||||
|
return
|
||||||
@@ -5,6 +5,7 @@ from core.builtin_concepts import BuiltinConcepts
|
|||||||
from core.builtin_helpers import ensure_concept
|
from core.builtin_helpers import ensure_concept
|
||||||
from core.concept import Concept
|
from core.concept import Concept
|
||||||
from core.sheerka.Sheerka import Sheerka
|
from core.sheerka.Sheerka import Sheerka
|
||||||
|
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||||
from core.sheerka.services.sheerka_service import BaseService
|
from core.sheerka.services.sheerka_service import BaseService
|
||||||
|
|
||||||
PROPERTIES_TO_COMPUTE = [BuiltinConcepts.ISA, BuiltinConcepts.HASA]
|
PROPERTIES_TO_COMPUTE = [BuiltinConcepts.ISA, BuiltinConcepts.HASA]
|
||||||
@@ -118,8 +119,10 @@ class SheerkaConceptsAlgebra(BaseService):
|
|||||||
if nb_props == 0:
|
if nb_props == 0:
|
||||||
return res
|
return res
|
||||||
|
|
||||||
all_concepts = self.sheerka.cache_manager.copy(Sheerka.CONCEPTS_BY_ID_ENTRY).values() \
|
concepts_service = self.sheerka.services[SheerkaConceptManager.NAME]
|
||||||
if self.sheerka.cache_manager.cache_only else self.sheerka.sdp.list(self.sheerka.CONCEPTS_BY_ID_ENTRY)
|
|
||||||
|
all_concepts = self.sheerka.cache_manager.copy(concepts_service.CONCEPTS_BY_ID_ENTRY).values() \
|
||||||
|
if self.sheerka.cache_manager.cache_only else self.sheerka.sdp.list(concepts_service.CONCEPTS_BY_ID_ENTRY)
|
||||||
|
|
||||||
for c in all_concepts:
|
for c in all_concepts:
|
||||||
score = self._compute_score(c, concept, step_b=round(1 / nb_props, 2))
|
score = self._compute_score(c, concept, step_b=round(1 / nb_props, 2))
|
||||||
|
|||||||
@@ -1,123 +0,0 @@
|
|||||||
import core.utils
|
|
||||||
from core.builtin_concepts import BuiltinConcepts, ErrorConcept
|
|
||||||
from core.builtin_helpers import ensure_concept
|
|
||||||
from core.concept import Concept, DEFINITION_TYPE_DEF, DEFINITION_TYPE_BNF, freeze_concept_attrs
|
|
||||||
from core.global_symbols import EVENT_CONCEPT_CREATED
|
|
||||||
from core.sheerka.services.sheerka_service import BaseService
|
|
||||||
from sdp.sheerkaDataProvider import SheerkaDataProviderDuplicateKeyError
|
|
||||||
|
|
||||||
BASE_NODE_PARSER_CLASS = "parsers.BaseNodeParser.BaseNodeParser"
|
|
||||||
|
|
||||||
|
|
||||||
class SheerkaCreateNewConcept(BaseService):
|
|
||||||
"""
|
|
||||||
Manages the creation of a new concept
|
|
||||||
"""
|
|
||||||
|
|
||||||
NAME = "CreateNewConcept"
|
|
||||||
|
|
||||||
def __init__(self, sheerka):
|
|
||||||
super().__init__(sheerka)
|
|
||||||
self.bnp = core.utils.get_class(BASE_NODE_PARSER_CLASS) # BaseNodeParser
|
|
||||||
|
|
||||||
def initialize(self):
|
|
||||||
self.sheerka.bind_service_method(self.create_new_concept, True)
|
|
||||||
self.sheerka.bind_service_method(self.not_is_variable, False, visible=False)
|
|
||||||
|
|
||||||
def create_new_concept(self, context, concept: Concept):
|
|
||||||
"""
|
|
||||||
Adds a new concept to the system
|
|
||||||
:param context:
|
|
||||||
:param concept: DefConceptNode
|
|
||||||
:return: digest of the new concept
|
|
||||||
"""
|
|
||||||
ensure_concept(concept)
|
|
||||||
|
|
||||||
sheerka = self.sheerka
|
|
||||||
|
|
||||||
concept.init_key()
|
|
||||||
init_bnf_ret_value = None
|
|
||||||
|
|
||||||
cache_manager = sheerka.cache_manager
|
|
||||||
|
|
||||||
if cache_manager.exists(sheerka.CONCEPTS_BY_HASH_ENTRY, concept.get_definition_hash()):
|
|
||||||
error = SheerkaDataProviderDuplicateKeyError(sheerka.CONCEPTS_BY_KEY_ENTRY + "." + concept.key,
|
|
||||||
concept)
|
|
||||||
return sheerka.ret(
|
|
||||||
self.NAME,
|
|
||||||
False,
|
|
||||||
sheerka.new(BuiltinConcepts.CONCEPT_ALREADY_DEFINED, body=concept),
|
|
||||||
error.args[0])
|
|
||||||
|
|
||||||
# set id before saving in db
|
|
||||||
sheerka.set_id_if_needed(concept, False)
|
|
||||||
|
|
||||||
# freeze attributes
|
|
||||||
freeze_concept_attrs(concept)
|
|
||||||
|
|
||||||
# compute new concepts_by_first_keyword
|
|
||||||
init_ret_value = self.bnp.get_concepts_by_first_token(context, [concept], True)
|
|
||||||
if not init_ret_value.status:
|
|
||||||
return sheerka.ret(self.NAME, False, ErrorConcept(init_ret_value.value))
|
|
||||||
concepts_by_first_keyword = init_ret_value.body
|
|
||||||
|
|
||||||
# computes resolved concepts_by_first_keyword
|
|
||||||
init_ret_value = self.bnp.resolve_concepts_by_first_keyword(context, concepts_by_first_keyword)
|
|
||||||
if not init_ret_value.status:
|
|
||||||
return sheerka.ret(self.NAME, False, ErrorConcept(init_ret_value.value))
|
|
||||||
resolved_concepts_by_first_keyword = init_ret_value.body
|
|
||||||
|
|
||||||
# if everything is fine
|
|
||||||
concept.freeze_definition_hash()
|
|
||||||
cache_manager.add_concept(concept)
|
|
||||||
cache_manager.put(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, False, concepts_by_first_keyword)
|
|
||||||
cache_manager.put(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, False, resolved_concepts_by_first_keyword)
|
|
||||||
|
|
||||||
if concept.get_metadata().definition_type == DEFINITION_TYPE_DEF and concept.get_metadata().definition != concept.name:
|
|
||||||
# allow search by definition when definition relevant
|
|
||||||
cache_manager.put(self.sheerka.CONCEPTS_BY_NAME_ENTRY, concept.get_metadata().definition, concept)
|
|
||||||
|
|
||||||
# update references
|
|
||||||
for ref in self.compute_references(concept):
|
|
||||||
cache_manager.put(sheerka.CONCEPTS_REFERENCES_ENTRY, ref, concept.id)
|
|
||||||
|
|
||||||
# TODO : this line seems to be useless
|
|
||||||
# The grammar is never reset
|
|
||||||
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)
|
|
||||||
|
|
||||||
# publish the new concept
|
|
||||||
sheerka.publish(context, EVENT_CONCEPT_CREATED, concept)
|
|
||||||
|
|
||||||
# process the return if needed
|
|
||||||
ret = sheerka.ret(self.NAME, True, sheerka.new(BuiltinConcepts.NEW_CONCEPT, body=concept))
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def compute_references(self, concept):
|
|
||||||
"""
|
|
||||||
We need to keep a track of all concepts used by the current concept
|
|
||||||
So that if one of these are modified, we can modify the current concept accordingly
|
|
||||||
:param concept:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
refs = set()
|
|
||||||
|
|
||||||
if concept.get_metadata().definition_type == DEFINITION_TYPE_BNF:
|
|
||||||
from parsers.BnfNodeParser import BnfNodeConceptExpressionVisitor
|
|
||||||
other_concepts_visitor = BnfNodeConceptExpressionVisitor()
|
|
||||||
other_concepts_visitor.visit(concept.get_bnf())
|
|
||||||
|
|
||||||
for concept in other_concepts_visitor.references:
|
|
||||||
if isinstance(concept, str):
|
|
||||||
concept = self.sheerka.get_by_key(concept)
|
|
||||||
refs.add(concept.id)
|
|
||||||
|
|
||||||
return refs
|
|
||||||
|
|
||||||
def not_is_variable(self, name):
|
|
||||||
"""
|
|
||||||
Given a name tells if it refers to a variable name
|
|
||||||
:param name:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
return not self.sheerka.cache_manager.get(self.sheerka.CONCEPTS_BY_NAME_ENTRY, name)
|
|
||||||
@@ -4,6 +4,7 @@ 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, parse_unrecognized, evaluate, ensure_concept
|
||||||
from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved, NotInit, AllConceptParts, \
|
from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved, NotInit, AllConceptParts, \
|
||||||
concept_part_value
|
concept_part_value
|
||||||
|
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||||
from core.sheerka.services.sheerka_service import BaseService
|
from core.sheerka.services.sheerka_service import BaseService
|
||||||
from core.tokenizer import Tokenizer
|
from core.tokenizer import Tokenizer
|
||||||
@@ -224,13 +225,12 @@ class SheerkaEvaluateConcept(BaseService):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def is_only_successful(r):
|
def is_only_successful(r):
|
||||||
# return False
|
|
||||||
return context.sheerka.isinstance(r, BuiltinConcepts.RETURN_VALUE) and \
|
return context.sheerka.isinstance(r, BuiltinConcepts.RETURN_VALUE) and \
|
||||||
context.sheerka.isinstance(r.body, BuiltinConcepts.ONLY_SUCCESSFUL)
|
context.sheerka.isinstance(r.body, BuiltinConcepts.ONLY_SUCCESSFUL)
|
||||||
|
|
||||||
def parse_token_concept(s):
|
def parse_token_concept(s):
|
||||||
if s.startswith("c:") and (identifier := unstr_concept(s)) != (None, None):
|
if s.startswith("c:") and (identifier := unstr_concept(s)) != (None, None):
|
||||||
return self.sheerka.resolve(identifier)
|
return self.sheerka.fast_resolve(identifier)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for part_key in AllConceptParts:
|
for part_key in AllConceptParts:
|
||||||
@@ -247,11 +247,12 @@ class SheerkaEvaluateConcept(BaseService):
|
|||||||
if source.strip() == "":
|
if source.strip() == "":
|
||||||
concept.get_compiled()[part_key] = DoNotResolve(source)
|
concept.get_compiled()[part_key] = DoNotResolve(source)
|
||||||
else:
|
else:
|
||||||
# first case, when the metadata references another concept via c:xxx: keyword
|
|
||||||
if concept_found := parse_token_concept(source):
|
if concept_found := parse_token_concept(source):
|
||||||
|
# the compiled can be a reference to another concept...
|
||||||
context.log(f"Recognized concept '{concept_found}'", self.NAME)
|
context.log(f"Recognized concept '{concept_found}'", self.NAME)
|
||||||
concept.get_compiled()[part_key] = concept_found
|
concept.get_compiled()[part_key] = concept_found
|
||||||
else:
|
else:
|
||||||
|
# ...or a list of ReturnValueConcept to resolve
|
||||||
res = parse_unrecognized(context,
|
res = parse_unrecognized(context,
|
||||||
source,
|
source,
|
||||||
parsers="all",
|
parsers="all",
|
||||||
@@ -272,11 +273,12 @@ class SheerkaEvaluateConcept(BaseService):
|
|||||||
if default_value.strip() == "":
|
if default_value.strip() == "":
|
||||||
concept.get_compiled()[var_name] = DoNotResolve(default_value)
|
concept.get_compiled()[var_name] = DoNotResolve(default_value)
|
||||||
else:
|
else:
|
||||||
# first case, when the metadata references another concept via c:xxx: keyword
|
|
||||||
if concept_found := parse_token_concept(default_value):
|
if concept_found := parse_token_concept(default_value):
|
||||||
|
# the compiled can be a reference to another concept...
|
||||||
context.log(f"Recognized concept '{concept_found}'", self.NAME)
|
context.log(f"Recognized concept '{concept_found}'", self.NAME)
|
||||||
concept.get_compiled()[var_name] = concept_found
|
concept.get_compiled()[var_name] = concept_found
|
||||||
else:
|
else:
|
||||||
|
# ...or a list of ReturnValueConcept to resolve
|
||||||
res = parse_unrecognized(context,
|
res = parse_unrecognized(context,
|
||||||
default_value,
|
default_value,
|
||||||
parsers="all",
|
parsers="all",
|
||||||
@@ -285,7 +287,9 @@ class SheerkaEvaluateConcept(BaseService):
|
|||||||
concept.get_compiled()[var_name] = res.body.body if is_only_successful(res) else res
|
concept.get_compiled()[var_name] = res.body.body if is_only_successful(res) else res
|
||||||
|
|
||||||
# Updates the cache of concepts when possible
|
# Updates the cache of concepts when possible
|
||||||
if self.sheerka.has_id(concept.id):
|
# This piece of code is not used, a the compile part is removed by sheerka.new_from_template()
|
||||||
|
service = context.sheerka.services[SheerkaConceptManager.NAME]
|
||||||
|
if service.has_id(concept.id):
|
||||||
self.sheerka.get_by_id(concept.id).set_compiled(concept.get_compiled())
|
self.sheerka.get_by_id(concept.id).set_compiled(concept.get_compiled())
|
||||||
|
|
||||||
def resolve(self,
|
def resolve(self,
|
||||||
|
|||||||
@@ -35,9 +35,8 @@ class SheerkaHasAManager(BaseService):
|
|||||||
name=BuiltinConcepts.HASA,
|
name=BuiltinConcepts.HASA,
|
||||||
concept=concept_a))
|
concept=concept_a))
|
||||||
|
|
||||||
concept_a.add_prop(BuiltinConcepts.HASA, concept_b)
|
to_add = {"props": {BuiltinConcepts.HASA: concept_b}}
|
||||||
|
return self.sheerka.modify_concept(context, concept_a, to_add, modify_source=True)
|
||||||
return self.sheerka.modify_concept(context, concept_a)
|
|
||||||
|
|
||||||
def hasa(self, concept_a, concept_b):
|
def hasa(self, concept_a, concept_b):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,110 +0,0 @@
|
|||||||
from core.builtin_concepts import BuiltinConcepts
|
|
||||||
from core.builtin_helpers import ensure_concept
|
|
||||||
from core.concept import NotInit, freeze_concept_attrs, Concept
|
|
||||||
from core.sheerka.services.sheerka_service import BaseService
|
|
||||||
|
|
||||||
|
|
||||||
class SheerkaModifyConcept(BaseService):
|
|
||||||
NAME = "ModifyConcept"
|
|
||||||
|
|
||||||
def __init__(self, sheerka):
|
|
||||||
super().__init__(sheerka)
|
|
||||||
|
|
||||||
def initialize(self):
|
|
||||||
self.sheerka.bind_service_method(self.modify_concept, True)
|
|
||||||
self.sheerka.bind_service_method(self.set_attr, True)
|
|
||||||
self.sheerka.bind_service_method(self.get_attr, False)
|
|
||||||
|
|
||||||
def modify_concept(self, context, concept):
|
|
||||||
"""
|
|
||||||
Modify the definition of a concept
|
|
||||||
:param context:
|
|
||||||
:param concept:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
old_version = self.sheerka.get_by_id(concept.id)
|
|
||||||
|
|
||||||
if old_version is None:
|
|
||||||
# nothing found in cache
|
|
||||||
return self.sheerka.ret(
|
|
||||||
self.NAME, False,
|
|
||||||
self.sheerka.new(
|
|
||||||
BuiltinConcepts.UNKNOWN_CONCEPT,
|
|
||||||
body=[("key", concept.key), ("id", concept.id)]))
|
|
||||||
|
|
||||||
if not self.sheerka.is_success(old_version) and concept.key != old_version.key:
|
|
||||||
# an error concept is returned
|
|
||||||
return self.sheerka.ret(
|
|
||||||
self.NAME, False,
|
|
||||||
old_version)
|
|
||||||
|
|
||||||
if old_version == concept:
|
|
||||||
# the concept is not modified
|
|
||||||
# This is an important sanity check. Do no remove because you don't understand it
|
|
||||||
return self.sheerka.ret(
|
|
||||||
self.NAME, False,
|
|
||||||
self.sheerka.new(
|
|
||||||
BuiltinConcepts.CONCEPT_ALREADY_DEFINED,
|
|
||||||
body=concept))
|
|
||||||
|
|
||||||
# update attributes
|
|
||||||
freeze_concept_attrs(concept)
|
|
||||||
|
|
||||||
self.sheerka.cache_manager.update_concept(old_version, concept)
|
|
||||||
|
|
||||||
# TODO : update concept by first keyword : have a look at update_references() below
|
|
||||||
# TODO : update resolved by first keyword : have a look at update_references() below
|
|
||||||
# TODO : update when definition_type = DEFINITION_TYPE_DEF : have a look at update_references() below
|
|
||||||
# TODO : Update concepts grammars : have a look at update_references() below
|
|
||||||
|
|
||||||
ret = self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.NEW_CONCEPT, body=concept))
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def update_references(self, context, concept):
|
|
||||||
"""
|
|
||||||
Updates all the concepts that reference concept
|
|
||||||
:param context:
|
|
||||||
:param concept:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
refs = self.sheerka.cache_manager.get(self.sheerka.CONCEPTS_REFERENCES_ENTRY, concept.id)
|
|
||||||
if not refs:
|
|
||||||
return
|
|
||||||
|
|
||||||
for concept_id in refs:
|
|
||||||
# remove the grammar entry so that it can be recreated
|
|
||||||
self.sheerka.cache_manager.delete(self.sheerka.CONCEPTS_GRAMMARS_ENTRY, concept_id)
|
|
||||||
|
|
||||||
def set_attr(self, concept, attribute, value):
|
|
||||||
"""
|
|
||||||
Modifies an attribute of a concept (concept.values)
|
|
||||||
:param context:
|
|
||||||
:param concept:
|
|
||||||
:param attribute:
|
|
||||||
:param value:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
ensure_concept(concept)
|
|
||||||
|
|
||||||
attr = attribute.str_id if isinstance(attribute, Concept) else attribute
|
|
||||||
concept.set_value(attr, value)
|
|
||||||
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
|
|
||||||
|
|
||||||
def get_attr(self, concept, attribute):
|
|
||||||
"""
|
|
||||||
Returns the attribute of a concept
|
|
||||||
:param context:
|
|
||||||
:param concept:
|
|
||||||
:param attribute:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
ensure_concept()
|
|
||||||
if not self.sheerka.is_success(concept):
|
|
||||||
return concept
|
|
||||||
|
|
||||||
attr = attribute.str_id if isinstance(attribute, Concept) else attribute
|
|
||||||
|
|
||||||
if (value := concept.get_value(attr)) == NotInit:
|
|
||||||
return self.sheerka.new(BuiltinConcepts.NOT_FOUND, body={"#concept": concept, "#attr": attribute})
|
|
||||||
return value
|
|
||||||
@@ -623,7 +623,7 @@ class SheerkaRuleManager(BaseService):
|
|||||||
if rule.metadata.id is not None:
|
if rule.metadata.id is not None:
|
||||||
return
|
return
|
||||||
|
|
||||||
rule.metadata.id = str(self.sheerka.cache_manager.get(self.sheerka.CONCEPTS_KEYS_ENTRY, self.RULE_IDS))
|
rule.metadata.id = str(self.sheerka.cache_manager.get(self.sheerka.OBJECTS_IDS_ENTRY, self.RULE_IDS))
|
||||||
|
|
||||||
def create_new_rule(self, context, rule):
|
def create_new_rule(self, context, rule):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from cache.SetCache import SetCache
|
|||||||
from core.ast_helpers import UnreferencedVariablesVisitor
|
from core.ast_helpers import UnreferencedVariablesVisitor
|
||||||
from core.builtin_concepts import BuiltinConcepts
|
from core.builtin_concepts import BuiltinConcepts
|
||||||
from core.concept import Concept, ConceptParts, DEFINITION_TYPE_BNF
|
from core.concept import Concept, ConceptParts, DEFINITION_TYPE_BNF
|
||||||
from core.sheerka.services.SheerkaModifyConcept import SheerkaModifyConcept
|
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||||
from core.sheerka.services.sheerka_service import BaseService
|
from core.sheerka.services.sheerka_service import BaseService
|
||||||
|
|
||||||
GROUP_PREFIX = 'All_'
|
GROUP_PREFIX = 'All_'
|
||||||
@@ -43,7 +43,6 @@ class SheerkaSetsManager(BaseService):
|
|||||||
context.log(f"Setting concept {concept} is a {concept_set}", who=self.NAME)
|
context.log(f"Setting concept {concept} is a {concept_set}", who=self.NAME)
|
||||||
core.builtin_helpers.ensure_concept(concept, concept_set)
|
core.builtin_helpers.ensure_concept(concept, concept_set)
|
||||||
|
|
||||||
|
|
||||||
if BuiltinConcepts.ISA in concept.get_metadata().props and concept_set in concept.get_metadata().props[
|
if BuiltinConcepts.ISA in concept.get_metadata().props and concept_set in concept.get_metadata().props[
|
||||||
BuiltinConcepts.ISA]:
|
BuiltinConcepts.ISA]:
|
||||||
return self.sheerka.ret(
|
return self.sheerka.ret(
|
||||||
@@ -53,11 +52,12 @@ class SheerkaSetsManager(BaseService):
|
|||||||
|
|
||||||
# KSI 20200709 add the concept, not its 'id' or 'key'
|
# KSI 20200709 add the concept, not its 'id' or 'key'
|
||||||
# It will allow conditions handling if concept set has its WHERE or PRE set to something
|
# It will allow conditions handling if concept set has its WHERE or PRE set to something
|
||||||
concept.add_prop(BuiltinConcepts.ISA, concept_set)
|
to_add = {"props": {BuiltinConcepts.ISA: concept_set}}
|
||||||
|
res = self.sheerka.modify_concept(context, concept, to_add, modify_source=True)
|
||||||
res = self.sheerka.modify_concept(context, concept)
|
|
||||||
if not res.status:
|
if not res.status:
|
||||||
return res
|
return res
|
||||||
|
else:
|
||||||
|
concept = res.body.body
|
||||||
|
|
||||||
res = self.add_concept_to_set(context, concept, concept_set)
|
res = self.add_concept_to_set(context, concept, concept_set)
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ class SheerkaSetsManager(BaseService):
|
|||||||
self.concepts_in_set.delete(concept_set.id)
|
self.concepts_in_set.delete(concept_set.id)
|
||||||
|
|
||||||
# update concept_set references
|
# update concept_set references
|
||||||
self.sheerka.services[SheerkaModifyConcept.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.cache_manager.delete(self.sheerka.CONCEPTS_GRAMMARS_ENTRY, concept_set.id)
|
self.sheerka.cache_manager.delete(self.sheerka.CONCEPTS_GRAMMARS_ENTRY, concept_set.id)
|
||||||
|
|||||||
@@ -56,10 +56,6 @@ class AddConceptInSetEvaluator(OneReturnValueEvaluator):
|
|||||||
parents=[return_value])
|
parents=[return_value])
|
||||||
concept = res.value
|
concept = res.value
|
||||||
|
|
||||||
if sheerka.has_id(concept.id) and id(concept) == id(sheerka.get_by_id(concept.id)):
|
|
||||||
# hack because it is not possible to use sheerka.modify_concept() on a cache instance
|
|
||||||
concept = sheerka.new((concept.name, concept.id))
|
|
||||||
|
|
||||||
res = _resolve(isa_node.set)
|
res = _resolve(isa_node.set)
|
||||||
if not res.status:
|
if not res.status:
|
||||||
return sheerka.ret(
|
return sheerka.ret(
|
||||||
|
|||||||
@@ -158,7 +158,11 @@ class PythonEvaluator(OneReturnValueEvaluator):
|
|||||||
|
|
||||||
context.log(f"{evaluated=}", self.name)
|
context.log(f"{evaluated=}", self.name)
|
||||||
debugger.debug_var("ret", evaluated)
|
debugger.debug_var("ret", evaluated)
|
||||||
return sheerka.ret(self.name, True, evaluated, parents=[return_value])
|
|
||||||
|
if sheerka.isinstance(evaluated, BuiltinConcepts.RETURN_VALUE):
|
||||||
|
return sheerka.ret(self.name, evaluated.status, evaluated.body, parents=[return_value, evaluated])
|
||||||
|
else:
|
||||||
|
return sheerka.ret(self.name, True, evaluated, parents=[return_value])
|
||||||
|
|
||||||
def get_globals(self, context, node, expression_only):
|
def get_globals(self, context, node, expression_only):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -846,6 +846,7 @@ class BaseNodeParser(BaseParser):
|
|||||||
def get_concepts(self, token, to_keep, custom=None, to_map=None, strip_quotes=False):
|
def get_concepts(self, token, to_keep, custom=None, to_map=None, strip_quotes=False):
|
||||||
"""
|
"""
|
||||||
Tries to find if there are concepts that match the value of the token
|
Tries to find if there are concepts that match the value of the token
|
||||||
|
Caution: Returns the actual cache, not a copy
|
||||||
:param token:
|
:param token:
|
||||||
:param to_keep: predicate to tell if the concept is eligible
|
:param to_keep: predicate to tell if the concept is eligible
|
||||||
:param custom: lambda name -> List[Concepts] that gives extra concepts, according to the name
|
:param custom: lambda name -> List[Concepts] that gives extra concepts, according to the name
|
||||||
@@ -882,16 +883,17 @@ class BaseNodeParser(BaseParser):
|
|||||||
return custom_concepts if custom else None
|
return custom_concepts if custom else None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_concepts_by_first_token(context, concepts, use_sheerka=False):
|
def get_concepts_by_first_token(context, concepts, use_sheerka=False, previous_entries=None):
|
||||||
"""
|
"""
|
||||||
Create the map describing the first token expected by a concept
|
Create the map describing the first token expected by a concept
|
||||||
:param context:
|
:param context:
|
||||||
:param concepts: lists of concepts to parse
|
:param concepts: lists of concepts to parse
|
||||||
:param use_sheerka: if True, update concepts_by_first_keyword from sheerka
|
:param use_sheerka: if True, update concepts_by_first_keyword from sheerka
|
||||||
|
:param previous_entries:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
sheerka = context.sheerka
|
sheerka = context.sheerka
|
||||||
res = sheerka.cache_manager.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) if use_sheerka else {}
|
res = sheerka.cache_manager.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) if use_sheerka else (previous_entries or {})
|
||||||
for concept in concepts:
|
for concept in concepts:
|
||||||
keywords = BaseNodeParser.get_first_tokens(sheerka, concept)
|
keywords = BaseNodeParser.get_first_tokens(sheerka, concept)
|
||||||
|
|
||||||
@@ -909,10 +911,15 @@ class BaseNodeParser(BaseParser):
|
|||||||
return sheerka.ret("BaseNodeParser", True, res)
|
return sheerka.ret("BaseNodeParser", True, res)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_concepts_by_first_keyword(context, concepts_by_first_keyword):
|
def resolve_concepts_by_first_keyword(context, concepts_by_first_keyword, modified_concepts=None):
|
||||||
sheerka = context.sheerka
|
sheerka = context.sheerka
|
||||||
res = {}
|
res = {}
|
||||||
|
|
||||||
|
def get_by_id(c_id):
|
||||||
|
if modified_concepts and c_id in modified_concepts:
|
||||||
|
return modified_concepts[c_id]
|
||||||
|
return sheerka.get_by_id(c_id)
|
||||||
|
|
||||||
def resolve_concepts(concept_str):
|
def resolve_concepts(concept_str):
|
||||||
c_key, c_id = core.utils.unstr_concept(concept_str)
|
c_key, c_id = core.utils.unstr_concept(concept_str)
|
||||||
if c_id in already_seen:
|
if c_id in already_seen:
|
||||||
@@ -924,7 +931,7 @@ class BaseNodeParser(BaseParser):
|
|||||||
to_resolve = set()
|
to_resolve = set()
|
||||||
chicken_and_egg = set()
|
chicken_and_egg = set()
|
||||||
|
|
||||||
concept = sheerka.get_by_id(c_id)
|
concept = get_by_id(c_id)
|
||||||
|
|
||||||
if sheerka.isaset(context, concept):
|
if sheerka.isaset(context, concept):
|
||||||
concepts = sheerka.get_set_elements(context, concept)
|
concepts = sheerka.get_set_elements(context, concept)
|
||||||
|
|||||||
@@ -76,15 +76,10 @@ class ExactConceptParser(BaseParser):
|
|||||||
value = words[i]
|
value = words[i]
|
||||||
concept.def_var_by_index(index, str_concept(value) if isinstance(value, tuple) else value)
|
concept.def_var_by_index(index, str_concept(value) if isinstance(value, tuple) else value)
|
||||||
concept.get_metadata().need_validation = True
|
concept.get_metadata().need_validation = True
|
||||||
# if self.verbose_log.isEnabledFor(logging.DEBUG):
|
|
||||||
# prop_name = concept.get_metadata().variables[index][0]
|
|
||||||
# context.log(
|
|
||||||
# f"Added variable {index}: {prop_name}='{words[i]}'.",
|
|
||||||
# self.name)
|
|
||||||
|
|
||||||
already_recognized.append(concept)
|
already_recognized.append(concept)
|
||||||
|
|
||||||
by_name = sheerka.resolve(parser_input.as_text())
|
by_name = sheerka.fast_resolve(parser_input.as_text())
|
||||||
core.builtin_helpers.set_is_evaluated(by_name)
|
core.builtin_helpers.set_is_evaluated(by_name)
|
||||||
recognized = self.merge_concepts(already_recognized, by_name)
|
recognized = self.merge_concepts(already_recognized, by_name)
|
||||||
|
|
||||||
|
|||||||
@@ -261,6 +261,13 @@ class SequenceNodeParser(BaseNodeParser):
|
|||||||
return make_unique(concepts_by_name + concepts_by_first_keyword, lambda c: c.id)
|
return make_unique(concepts_by_name + concepts_by_first_keyword, lambda c: c.id)
|
||||||
|
|
||||||
def get_concepts_sequences(self):
|
def get_concepts_sequences(self):
|
||||||
|
"""
|
||||||
|
Tries to find the concept.
|
||||||
|
TODO: KSI 20201206
|
||||||
|
I think that the code can be optimized as we create a new instance of each concept before validating
|
||||||
|
that we are going to keep it.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
forked = []
|
forked = []
|
||||||
|
|
||||||
|
|||||||
+3
-5
@@ -79,7 +79,7 @@ class BaseTest:
|
|||||||
else:
|
else:
|
||||||
c.init_key()
|
c.init_key()
|
||||||
sheerka.set_id_if_needed(c, False)
|
sheerka.set_id_if_needed(c, False)
|
||||||
sheerka.add_in_cache(c)
|
sheerka.test_only_add_in_cache(c)
|
||||||
|
|
||||||
result.append(c)
|
result.append(c)
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ class BaseTest:
|
|||||||
|
|
||||||
if create_new:
|
if create_new:
|
||||||
sheerka.cache_manager.caches[SheerkaRuleManager.FORMAT_RULE_ENTRY].cache.clear()
|
sheerka.cache_manager.caches[SheerkaRuleManager.FORMAT_RULE_ENTRY].cache.clear()
|
||||||
sheerka.cache_manager.delete(sheerka.CONCEPTS_KEYS_ENTRY, SheerkaRuleManager.RULE_IDS)
|
sheerka.cache_manager.delete(sheerka.OBJECTS_IDS_ENTRY, SheerkaRuleManager.RULE_IDS)
|
||||||
with sheerka.sdp.get_transaction(context.event.get_digest()) as transaction:
|
with sheerka.sdp.get_transaction(context.event.get_digest()) as transaction:
|
||||||
transaction.clear(SheerkaRuleManager.FORMAT_RULE_ENTRY)
|
transaction.clear(SheerkaRuleManager.FORMAT_RULE_ENTRY)
|
||||||
|
|
||||||
@@ -146,8 +146,6 @@ class BaseTest:
|
|||||||
"""True ret_val + add concept in cache"""
|
"""True ret_val + add concept in cache"""
|
||||||
if isinstance(obj, Concept):
|
if isinstance(obj, Concept):
|
||||||
obj.init_key()
|
obj.init_key()
|
||||||
if sheerka.has_key(obj.key):
|
|
||||||
sheerka.add_in_cache(obj)
|
|
||||||
return sheerka.ret(who, True, obj)
|
return sheerka.ret(who, True, obj)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -180,7 +178,7 @@ class BaseTest:
|
|||||||
concept.get_metadata().definition_type = DEFINITION_TYPE_BNF
|
concept.get_metadata().definition_type = DEFINITION_TYPE_BNF
|
||||||
concept.init_key()
|
concept.init_key()
|
||||||
sheerka.set_id_if_needed(concept, False)
|
sheerka.set_id_if_needed(concept, False)
|
||||||
sheerka.add_in_cache(concept)
|
sheerka.test_only_add_in_cache(concept)
|
||||||
return concept
|
return concept
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
Vendored
+113
-1
@@ -539,9 +539,121 @@ class TestCache(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
assert cache.get("key") == "value"
|
assert cache.get("key") == "value"
|
||||||
cache.delete("key")
|
cache.delete("key")
|
||||||
assert cache.get("value") is None
|
assert cache.get("key") is None
|
||||||
assert cache.to_remove == {"key"}
|
assert cache.to_remove == {"key"}
|
||||||
|
|
||||||
|
def test_i_can_delete_values_from_set_cache(self):
|
||||||
|
cache = SetCache()
|
||||||
|
cache.put("key", "value1")
|
||||||
|
cache.put("key", "value2")
|
||||||
|
cache.reset_events()
|
||||||
|
|
||||||
|
cache.delete("key", "fake_value")
|
||||||
|
assert cache.get("key") == {"value1", "value2"}
|
||||||
|
assert len(cache) == 2
|
||||||
|
assert cache.to_add == set()
|
||||||
|
assert cache.to_remove == set()
|
||||||
|
|
||||||
|
cache.delete("key", "value1")
|
||||||
|
assert cache.get("key") == {"value2"}
|
||||||
|
assert cache.to_add == {"key"}
|
||||||
|
assert len(cache) == 1
|
||||||
|
|
||||||
|
cache.delete("key", "value2")
|
||||||
|
assert cache.get("key") is None
|
||||||
|
assert cache.to_remove == {"key"}
|
||||||
|
assert len(cache) == 0
|
||||||
|
|
||||||
|
def test_i_can_delete_key_from_set_cache(self):
|
||||||
|
cache = SetCache()
|
||||||
|
cache.put("key", "value1")
|
||||||
|
cache.put("key", "value2")
|
||||||
|
|
||||||
|
cache.delete("key")
|
||||||
|
assert cache.get("key") is None
|
||||||
|
assert cache.to_remove == {"key"}
|
||||||
|
assert len(cache) == 0
|
||||||
|
|
||||||
|
def test_i_can_delete_a_key_that_does_not_exists(self):
|
||||||
|
cache = SetCache()
|
||||||
|
cache.delete("key")
|
||||||
|
|
||||||
|
assert cache.to_add == set()
|
||||||
|
assert cache.to_remove == set()
|
||||||
|
|
||||||
|
def test_i_can_delete_from_a_key_from_list_id_needed(self):
|
||||||
|
cache = ListIfNeededCache()
|
||||||
|
cache.put("key", "value1")
|
||||||
|
cache.put("key", "value11")
|
||||||
|
cache.put("key2", "value2")
|
||||||
|
cache.put("key2", "value22")
|
||||||
|
cache.put("key2", "value222")
|
||||||
|
cache.put("key3", "value3")
|
||||||
|
cache.put("key3", "value33")
|
||||||
|
cache.put("key4", "value4")
|
||||||
|
cache.reset_events()
|
||||||
|
|
||||||
|
assert len(cache) == 8
|
||||||
|
|
||||||
|
# I can remove a whole key
|
||||||
|
cache.delete("key")
|
||||||
|
assert cache.get("key") is None
|
||||||
|
assert len(cache) == 6
|
||||||
|
assert cache.to_remove == {"key"}
|
||||||
|
assert cache.to_add == set()
|
||||||
|
|
||||||
|
# I can remove an element while a list is remaining
|
||||||
|
cache.reset_events()
|
||||||
|
cache.delete("key2", "value22")
|
||||||
|
assert cache.get("key2") == ["value2", "value222"]
|
||||||
|
assert len(cache) == 5
|
||||||
|
assert cache.to_add == {"key2"}
|
||||||
|
assert cache.to_remove == set()
|
||||||
|
|
||||||
|
# I can remove an element while a single element is remaining
|
||||||
|
cache.reset_events()
|
||||||
|
cache.delete("key3", "value33")
|
||||||
|
assert cache.get("key3") == "value3"
|
||||||
|
assert len(cache) == 4
|
||||||
|
assert cache.to_add == {"key3"}
|
||||||
|
assert cache.to_remove == set()
|
||||||
|
|
||||||
|
# I can remove an element while nothing remains
|
||||||
|
cache.reset_events()
|
||||||
|
cache.delete("key4", "value4")
|
||||||
|
assert cache.get("key4") is None
|
||||||
|
assert len(cache) == 3
|
||||||
|
assert cache.to_remove == {"key4"}
|
||||||
|
assert cache.to_add == set()
|
||||||
|
|
||||||
|
# I do not remove when the value is not the same
|
||||||
|
cache.reset_events()
|
||||||
|
cache.delete("key3", "value33") # value33 was already remove
|
||||||
|
assert cache.get("key3") == "value3"
|
||||||
|
assert len(cache) == 3
|
||||||
|
assert cache.to_add == set()
|
||||||
|
assert cache.to_remove == set()
|
||||||
|
|
||||||
|
def test_deleting_a_list_if_need_entry_that_does_not_exist_is_not_an_error(self):
|
||||||
|
cache = ListIfNeededCache()
|
||||||
|
cache.put("key", "value1")
|
||||||
|
|
||||||
|
cache.reset_events()
|
||||||
|
cache.delete("key3")
|
||||||
|
assert len(cache) == 1
|
||||||
|
assert cache.to_add == set()
|
||||||
|
assert cache.to_remove == set()
|
||||||
|
|
||||||
|
cache.delete("key3", "value")
|
||||||
|
assert len(cache) == 1
|
||||||
|
assert cache.to_add == set()
|
||||||
|
assert cache.to_remove == set()
|
||||||
|
|
||||||
|
cache.delete("key", "value2")
|
||||||
|
assert len(cache) == 1
|
||||||
|
assert cache.to_add == set()
|
||||||
|
assert cache.to_remove == set()
|
||||||
|
|
||||||
def test_initialized_key_is_removed_when_the_entry_is_found(self):
|
def test_initialized_key_is_removed_when_the_entry_is_found(self):
|
||||||
caches = [Cache(), ListCache(), ListIfNeededCache(), SetCache()]
|
caches = [Cache(), ListCache(), ListIfNeededCache(), SetCache()]
|
||||||
|
|
||||||
|
|||||||
Vendored
+47
-1
@@ -1,7 +1,10 @@
|
|||||||
|
import pytest
|
||||||
from cache.Cache import Cache
|
from cache.Cache import Cache
|
||||||
from cache.CacheManager import CacheManager
|
from cache.CacheManager import CacheManager, ConceptNotFound
|
||||||
from cache.DictionaryCache import DictionaryCache
|
from cache.DictionaryCache import DictionaryCache
|
||||||
from cache.ListCache import ListCache
|
from cache.ListCache import ListCache
|
||||||
|
from cache.ListIfNeededCache import ListIfNeededCache
|
||||||
|
from core.concept import Concept
|
||||||
|
|
||||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||||
|
|
||||||
@@ -109,3 +112,46 @@ class TestCacheManager(TestUsingMemoryBasedSheerka):
|
|||||||
cache.put(False, {"key": "value", "key2": "value2", "key3": "value3"})
|
cache.put(False, {"key": "value", "key2": "value2", "key3": "value3"})
|
||||||
cache_manager.commit(context)
|
cache_manager.commit(context)
|
||||||
assert sheerka.sdp.get("test") == {"key": "value", "key2": "value2", "key3": "value3"}
|
assert sheerka.sdp.get("test") == {"key": "value", "key2": "value2", "key3": "value3"}
|
||||||
|
|
||||||
|
def test_i_can_remove_a_concept_from_concepts_caches(self):
|
||||||
|
cache_manager = CacheManager(True)
|
||||||
|
cache_manager.register_concept_cache("id", Cache(), lambda c: c.id, True)
|
||||||
|
cache_manager.register_concept_cache("key", ListIfNeededCache(), lambda c: c.key, True)
|
||||||
|
|
||||||
|
sheerka, context, one, two, three, two_bis = self.init_concepts("one", "two", "three", Concept("two", body="2"))
|
||||||
|
|
||||||
|
for concept in [one, two, three, two_bis]:
|
||||||
|
cache_manager.add_concept(concept)
|
||||||
|
|
||||||
|
# sanity check
|
||||||
|
cache_def = cache_manager.caches["id"]
|
||||||
|
assert cache_def.cache.copy() == {one.id: one, two.id: two, three.id: three, two_bis.id: two_bis}
|
||||||
|
cache_def = cache_manager.caches["key"]
|
||||||
|
assert cache_def.cache.copy() == {one.key: one, two.key: [two, two_bis], three.key: three}
|
||||||
|
|
||||||
|
for cache_name in cache_manager.concept_caches:
|
||||||
|
cache_manager.caches[cache_name].cache.reset_events()
|
||||||
|
|
||||||
|
cache_manager.remove_concept(sheerka.new(("two", two_bis.id)))
|
||||||
|
|
||||||
|
cache_def = cache_manager.caches["id"]
|
||||||
|
assert cache_def.cache.copy() == {one.id: one, two.id: two, three.id: three}
|
||||||
|
assert cache_def.cache.to_remove == {two_bis.id}
|
||||||
|
assert cache_def.cache.to_add == set()
|
||||||
|
assert len(cache_def.cache) == 3
|
||||||
|
|
||||||
|
cache_def = cache_manager.caches["key"]
|
||||||
|
assert cache_def.cache.copy() == {one.key: one, two.key: two, three.key: three}
|
||||||
|
assert cache_def.cache.to_remove == set()
|
||||||
|
assert cache_def.cache.to_add == {"two"}
|
||||||
|
assert len(cache_def.cache) == 3
|
||||||
|
|
||||||
|
def test_i_cannot_remove_a_concept_that_does_not_exists(self):
|
||||||
|
cache_manager = CacheManager(True)
|
||||||
|
cache_manager.register_concept_cache("id", Cache(), lambda c: c.id, True)
|
||||||
|
cache_manager.register_concept_cache("key", ListIfNeededCache(), lambda c: c.key, True)
|
||||||
|
|
||||||
|
with pytest.raises(ConceptNotFound) as ex:
|
||||||
|
cache_manager.remove_concept(Concept("foo", id="1001"))
|
||||||
|
|
||||||
|
assert ex.value.concept == Concept("foo", id="1001")
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
assert isinstance(res, Concept)
|
assert isinstance(res, Concept)
|
||||||
assert res.get_metadata().props == {BuiltinConcepts.ISA: {male, human},
|
assert res.get_metadata().props == {BuiltinConcepts.ISA: {male, human},
|
||||||
BuiltinConcepts.HASA: {car, licence}, }
|
BuiltinConcepts.HASA: {car, licence}, }
|
||||||
|
|
||||||
def test_can_add_concepts_when_property_already_exist(self):
|
def test_can_add_concepts_when_property_already_exist(self):
|
||||||
sheerka, context, man, human, king, male = self.init_concepts(
|
sheerka, context, man, human, king, male = self.init_concepts(
|
||||||
@@ -58,7 +58,7 @@ class TestSheerkaConceptsAlgebra(TestUsingMemoryBasedSheerka):
|
|||||||
res = sheerka.csub(context, new_foo, new_bar)
|
res = sheerka.csub(context, new_foo, new_bar)
|
||||||
assert isinstance(res, Concept)
|
assert isinstance(res, Concept)
|
||||||
assert res.get_metadata().props == {BuiltinConcepts.ISA: {isa2},
|
assert res.get_metadata().props == {BuiltinConcepts.ISA: {isa2},
|
||||||
BuiltinConcepts.HASA: {hasa2}, }
|
BuiltinConcepts.HASA: {hasa2}, }
|
||||||
|
|
||||||
def test_i_can_recognize_myself_when_using_sdp_repository(self):
|
def test_i_can_recognize_myself_when_using_sdp_repository(self):
|
||||||
sheerka, context, foo, isa1, hasa1, = self.init_concepts("foo", "isa1", "has1",
|
sheerka, context, foo, isa1, hasa1, = self.init_concepts("foo", "isa1", "has1",
|
||||||
|
|||||||
@@ -0,0 +1,739 @@
|
|||||||
|
import pytest
|
||||||
|
from cache.CacheManager import ConceptNotFound
|
||||||
|
from core.builtin_concepts import BuiltinConcepts
|
||||||
|
from core.concept import PROPERTIES_TO_SERIALIZE, Concept, DEFINITION_TYPE_DEF, get_concept_attrs, NotInit, \
|
||||||
|
DEFINITION_TYPE_BNF
|
||||||
|
from core.sheerka.Sheerka import Sheerka
|
||||||
|
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager, NoModificationFound, ForbiddenAttribute, \
|
||||||
|
UnknownAttribute, CannotRemoveMeta, ValueNotFound, ConceptIsReferenced
|
||||||
|
from parsers.BaseNodeParser import BaseNodeParser
|
||||||
|
from parsers.BnfNodeParser import Sequence, StrMatch, ConceptExpression
|
||||||
|
|
||||||
|
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
||||||
|
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||||
|
|
||||||
|
|
||||||
|
class TestSheerkaConceptManager(TestUsingMemoryBasedSheerka):
|
||||||
|
def test_i_can_create_a_concept(self):
|
||||||
|
sheerka = self.get_sheerka(cache_only=False)
|
||||||
|
context = self.get_context(sheerka)
|
||||||
|
concept = self.get_default_concept()
|
||||||
|
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||||
|
|
||||||
|
res = sheerka.create_new_concept(context, concept)
|
||||||
|
sheerka.cache_manager.commit(context)
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.value, BuiltinConcepts.NEW_CONCEPT)
|
||||||
|
|
||||||
|
concept_found = res.value.body
|
||||||
|
for prop in PROPERTIES_TO_SERIALIZE:
|
||||||
|
assert getattr(concept_found.get_metadata(), prop) == getattr(concept.get_metadata(), prop)
|
||||||
|
|
||||||
|
assert concept_found.key == "__var__0 + __var__1"
|
||||||
|
assert concept_found.id == "1001"
|
||||||
|
assert get_concept_attrs(concept) == ['a', 'b']
|
||||||
|
|
||||||
|
# saved in cache
|
||||||
|
assert service.has_id(concept.id)
|
||||||
|
assert service.has_key(concept.key)
|
||||||
|
assert service.has_name(concept.name)
|
||||||
|
assert service.has_hash(concept.get_definition_hash())
|
||||||
|
|
||||||
|
# I can get the concept using various index
|
||||||
|
assert sheerka.get_by_id(concept.id) == concept
|
||||||
|
assert sheerka.get_by_key(concept.key) == concept
|
||||||
|
assert sheerka.get_by_name(concept.name) == concept
|
||||||
|
assert sheerka.get_by_hash(concept.get_definition_hash()) == concept
|
||||||
|
|
||||||
|
# I can get by the first entry
|
||||||
|
assert sheerka.cache_manager.get(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "+") == [concept.id]
|
||||||
|
assert sheerka.cache_manager.get(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "+") == [concept.id]
|
||||||
|
|
||||||
|
# saved in sdp
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_ID_ENTRY, concept.id)
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_KEY_ENTRY, concept.key)
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_NAME_ENTRY, concept.name)
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_HASH_ENTRY, concept.get_definition_hash())
|
||||||
|
assert sheerka.sdp.exists(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "+")
|
||||||
|
|
||||||
|
def test_i_cannot_create_a_bnf_concept_that_references_a_concept_that_cannot_be_resolved(self):
|
||||||
|
sheerka, context, one_1, one_1_0 = self.init_concepts(Concept("one", body="1"), Concept("one", body="1.0"))
|
||||||
|
twenty_one = Concept("twenty one", definition="'twenty' one", definition_type=DEFINITION_TYPE_BNF)
|
||||||
|
|
||||||
|
res = sheerka.create_new_concept(context, twenty_one)
|
||||||
|
|
||||||
|
assert not res.status
|
||||||
|
assert context.sheerka.isinstance(res.value, BuiltinConcepts.CANNOT_RESOLVE_CONCEPT)
|
||||||
|
assert res.value.body == ("key", "one")
|
||||||
|
|
||||||
|
def test_i_can_add_a_concept_when_name_differs_from_the_key(self):
|
||||||
|
sheerka = self.get_sheerka(cache_only=False)
|
||||||
|
context = self.get_context(sheerka)
|
||||||
|
concept = Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a")
|
||||||
|
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||||
|
|
||||||
|
res = sheerka.create_new_concept(self.get_context(sheerka), concept)
|
||||||
|
sheerka.cache_manager.commit(context)
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.value, BuiltinConcepts.NEW_CONCEPT)
|
||||||
|
|
||||||
|
concept_found = res.value.body
|
||||||
|
for prop in PROPERTIES_TO_SERIALIZE:
|
||||||
|
assert getattr(concept_found.get_metadata(), prop) == getattr(concept.get_metadata(), prop)
|
||||||
|
|
||||||
|
assert concept_found.key == "hello __var__0"
|
||||||
|
assert concept_found.id == "1001"
|
||||||
|
|
||||||
|
# saved in cache
|
||||||
|
assert service.has_id(concept.id)
|
||||||
|
assert service.has_key(concept.key)
|
||||||
|
assert service.has_name(concept.name)
|
||||||
|
assert service.has_hash(concept.get_definition_hash())
|
||||||
|
|
||||||
|
# I can get the concept using various index
|
||||||
|
assert sheerka.get_by_id(concept.id) == concept
|
||||||
|
assert sheerka.get_by_key(concept.key) == concept
|
||||||
|
assert sheerka.get_by_name(concept.name) == concept
|
||||||
|
assert sheerka.get_by_hash(concept.get_definition_hash()) == concept
|
||||||
|
|
||||||
|
# saved in sdp
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_ID_ENTRY, concept.id)
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_KEY_ENTRY, concept.key)
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_NAME_ENTRY, concept.name)
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_HASH_ENTRY, concept.get_definition_hash())
|
||||||
|
assert sheerka.sdp.exists(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "hello")
|
||||||
|
|
||||||
|
def test_i_cannot_add_the_same_concept_twice(self):
|
||||||
|
"""
|
||||||
|
Checks that duplicated concepts are managed by sheerka, not by sheerka.sdp
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
sheerka = self.get_sheerka()
|
||||||
|
concept = self.get_default_concept()
|
||||||
|
|
||||||
|
sheerka.create_new_concept(self.get_context(sheerka), concept)
|
||||||
|
res = sheerka.create_new_concept(self.get_context(sheerka), concept)
|
||||||
|
|
||||||
|
assert not res.status
|
||||||
|
assert sheerka.isinstance(res.value, BuiltinConcepts.CONCEPT_ALREADY_DEFINED)
|
||||||
|
assert res.value.body == concept
|
||||||
|
|
||||||
|
def test_i_can_get_a_newly_created_concept(self):
|
||||||
|
sheerka = self.get_sheerka()
|
||||||
|
concept = self.get_default_concept()
|
||||||
|
|
||||||
|
sheerka.create_new_concept(self.get_context(sheerka), concept)
|
||||||
|
|
||||||
|
from_cache = sheerka.get_by_key(concept.key)
|
||||||
|
assert from_cache is not None
|
||||||
|
assert from_cache == concept
|
||||||
|
|
||||||
|
from_cache = sheerka.get_by_id(concept.id)
|
||||||
|
assert from_cache is not None
|
||||||
|
assert from_cache == concept
|
||||||
|
|
||||||
|
def test_i_can_get_list_of_concept_when_same_key_using_cache(self):
|
||||||
|
sheerka = self.get_sheerka()
|
||||||
|
concept1 = self.get_default_concept()
|
||||||
|
concept2 = self.get_default_concept()
|
||||||
|
concept2.get_metadata().body = "a+b"
|
||||||
|
|
||||||
|
res1 = sheerka.create_new_concept(self.get_context(sheerka), concept1)
|
||||||
|
res2 = sheerka.create_new_concept(self.get_context(sheerka), concept2)
|
||||||
|
|
||||||
|
assert res1.value.body.key == res2.value.body.key # same key
|
||||||
|
|
||||||
|
result = sheerka.get_by_key(concept1.key)
|
||||||
|
assert len(result) == 2
|
||||||
|
assert result[0] == concept1
|
||||||
|
assert result[1] == concept2
|
||||||
|
|
||||||
|
def test_concept_that_references_itself_is_correctly_created(self):
|
||||||
|
sheerka = self.get_sheerka()
|
||||||
|
concept = Concept("foo", body="foo")
|
||||||
|
|
||||||
|
res = sheerka.create_new_concept(self.get_context(sheerka), concept)
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
|
||||||
|
def test_i_can_get_by_name_when_created_with_def_definition(self):
|
||||||
|
sheerka = self.get_sheerka(cache_only=False)
|
||||||
|
context = self.get_context(sheerka)
|
||||||
|
concept = self.from_def_concept("plus", "a plus b", ["a", "b"])
|
||||||
|
|
||||||
|
res = sheerka.create_new_concept(context, concept)
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.get_by_name(concept.name) == concept
|
||||||
|
assert sheerka.get_by_name(concept.get_metadata().definition) == concept
|
||||||
|
|
||||||
|
concept = Concept(name="foo", definition="foo", definition_type=DEFINITION_TYPE_DEF)
|
||||||
|
res = sheerka.create_new_concept(context, concept)
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.get_by_name(concept.name) == concept # it's not a list, ie the entry is not duplicated
|
||||||
|
|
||||||
|
def test_i_can_get_first_token_when_not_a_letter(self):
|
||||||
|
sheerka = self.get_sheerka(cache_only=False)
|
||||||
|
context = self.get_context(sheerka)
|
||||||
|
concept = Concept("--filter a").def_var("a")
|
||||||
|
|
||||||
|
res = sheerka.create_new_concept(context, concept)
|
||||||
|
assert res.status
|
||||||
|
|
||||||
|
# I can get by the first entry
|
||||||
|
assert sheerka.cache_manager.get(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [concept.id]
|
||||||
|
assert sheerka.cache_manager.get(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [concept.id]
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("expression", [
|
||||||
|
"--'filter' ('one' | 'two') ",
|
||||||
|
"'--filter' ('one' | 'two') ",
|
||||||
|
])
|
||||||
|
def test_i_can_get_first_token_when_bnf_concept_and_not_a_letter(self, expression):
|
||||||
|
sheerka, context, bnf_concept = self.init_concepts(
|
||||||
|
Concept("foo", definition=expression),
|
||||||
|
create_new=True)
|
||||||
|
|
||||||
|
# I can get by the first entry
|
||||||
|
assert sheerka.cache_manager.get(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [bnf_concept.id]
|
||||||
|
assert sheerka.cache_manager.get(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [bnf_concept.id]
|
||||||
|
|
||||||
|
def test_concept_references_are_updated_1(self):
|
||||||
|
sheerka, context, one, two, number, twenty, twenties = self.init_concepts(
|
||||||
|
"one",
|
||||||
|
"two",
|
||||||
|
"number",
|
||||||
|
"twenty",
|
||||||
|
Concept("twenties", definition="twenty one | two 'hundred'"),
|
||||||
|
create_new=True
|
||||||
|
)
|
||||||
|
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||||
|
|
||||||
|
assert sheerka.cache_manager.get(service.CONCEPTS_REFERENCES_ENTRY, one.id) == {twenties.id}
|
||||||
|
assert sheerka.cache_manager.get(service.CONCEPTS_REFERENCES_ENTRY, two.id) == {twenties.id}
|
||||||
|
assert sheerka.cache_manager.get(service.CONCEPTS_REFERENCES_ENTRY, number.id) is None
|
||||||
|
assert sheerka.cache_manager.get(service.CONCEPTS_REFERENCES_ENTRY, twenty.id) == {twenties.id}
|
||||||
|
assert sheerka.cache_manager.get(service.CONCEPTS_REFERENCES_ENTRY, twenties.id) is None
|
||||||
|
|
||||||
|
def test_concept_references_are_updated_2(self):
|
||||||
|
sheerka, context, one, two, number, twenty, twenties = self.init_concepts(
|
||||||
|
"one",
|
||||||
|
"two",
|
||||||
|
"number",
|
||||||
|
"twenty",
|
||||||
|
Concept("twenties", definition="twenty number"),
|
||||||
|
create_new=True
|
||||||
|
)
|
||||||
|
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||||
|
|
||||||
|
assert sheerka.cache_manager.get(service.CONCEPTS_REFERENCES_ENTRY, one.id) is None
|
||||||
|
assert sheerka.cache_manager.get(service.CONCEPTS_REFERENCES_ENTRY, two.id) is None
|
||||||
|
assert sheerka.cache_manager.get(service.CONCEPTS_REFERENCES_ENTRY, number.id) == {twenties.id}
|
||||||
|
assert sheerka.cache_manager.get(service.CONCEPTS_REFERENCES_ENTRY, twenty.id) == {twenties.id}
|
||||||
|
assert sheerka.cache_manager.get(service.CONCEPTS_REFERENCES_ENTRY, twenties.id) is None
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("attr", [
|
||||||
|
"name",
|
||||||
|
"is_unique",
|
||||||
|
"body",
|
||||||
|
"where",
|
||||||
|
"pre",
|
||||||
|
"post",
|
||||||
|
"ret",
|
||||||
|
"definition",
|
||||||
|
"definition_type",
|
||||||
|
"desc",
|
||||||
|
"is_evaluated",
|
||||||
|
"need_validation",
|
||||||
|
"full_serialization",
|
||||||
|
])
|
||||||
|
def test_i_can_modify_a_metadata_attribute(self, attr):
|
||||||
|
sheerka, context, foo = self.init_concepts("foo")
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add={"meta": {attr: "new value"}})
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_CONCEPT)
|
||||||
|
assert getattr(res.body.body.get_metadata(), attr) == "new value"
|
||||||
|
|
||||||
|
def test_i_can_modify_a_concept_when_at_least_one_attr_is_different(self):
|
||||||
|
sheerka, context, foo = self.init_concepts(Concept("foo", body="a body"))
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add={"meta": {"name": "foo", "body": "a body", "pre": "new pre"}})
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_CONCEPT)
|
||||||
|
assert getattr(res.body.body.get_metadata(), "name") == "foo"
|
||||||
|
assert getattr(res.body.body.get_metadata(), "body") == "a body"
|
||||||
|
assert getattr(res.body.body.get_metadata(), "pre") == "new pre"
|
||||||
|
|
||||||
|
def test_i_can_modify_add_a_property(self):
|
||||||
|
sheerka, context, one, foo = self.init_concepts("one", Concept("foo", props={BuiltinConcepts.ISA: {"value"}}))
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add={"props": {BuiltinConcepts.ISA: "value2",
|
||||||
|
BuiltinConcepts.HASA: one}})
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_CONCEPT)
|
||||||
|
assert res.body.body.get_prop(BuiltinConcepts.ISA) == {"value", "value2"}
|
||||||
|
assert res.body.body.get_prop(BuiltinConcepts.HASA) == {sheerka.new("one")}
|
||||||
|
|
||||||
|
def test_i_can_modify_remove_a_property(self):
|
||||||
|
sheerka, context, foo = self.init_concepts(
|
||||||
|
Concept("foo", props={"a": {"value1", "value2", "value3"},
|
||||||
|
"b": {"value4"}}))
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_remove={"props": {"a": {"value2", "value3"},
|
||||||
|
"b": "value4"}})
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_CONCEPT)
|
||||||
|
assert res.body.body.get_prop("a") == {"value1"}
|
||||||
|
assert res.body.body.get_prop("b") is None
|
||||||
|
|
||||||
|
def test_i_can_modify_add_variables(self):
|
||||||
|
sheerka, context, foo = self.init_concepts(Concept("foo").def_var("a", "value"))
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add={"variables": {"b": "some_value",
|
||||||
|
"a": "new_value",
|
||||||
|
"c": None}})
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_CONCEPT)
|
||||||
|
assert res.body.body.get_metadata().variables == [("a", "new_value"), ("b", "some_value"), ("c", None)]
|
||||||
|
assert res.body.body.values() == {"a": NotInit, "b": NotInit, "c": NotInit}
|
||||||
|
|
||||||
|
def test_i_can_modify_remove_variables(self):
|
||||||
|
sheerka, context, foo = self.init_concepts(Concept("foo").def_var("a").def_var("b", "value").def_var("c"))
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_remove={"variables": ["a", "c"]})
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_CONCEPT)
|
||||||
|
assert res.body.body.get_metadata().variables == [("b", "value")]
|
||||||
|
assert res.body.body.values() == {"b": NotInit}
|
||||||
|
|
||||||
|
def test_i_can_modify_the_concept_source(self):
|
||||||
|
sheerka, context, foo, bar = self.init_concepts("foo", "bar")
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add={"meta": {"body": "new value"}})
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_CONCEPT)
|
||||||
|
assert getattr(foo.get_metadata(), "body") is None
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, bar, to_add={"meta": {"body": "new value"}}, modify_source=True)
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_CONCEPT)
|
||||||
|
assert getattr(bar.get_metadata(), "body") == "new value"
|
||||||
|
|
||||||
|
def test_caches_are_updated_when_i_modify_the_properties_and_the_variables(self):
|
||||||
|
sheerka, context, foo, bar = self.init_concepts("foo", "bar", cache_only=False)
|
||||||
|
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||||
|
|
||||||
|
to_add = {"meta": {"body": "metadata value"},
|
||||||
|
"variables": {"var_name": "default value"},
|
||||||
|
"props": {BuiltinConcepts.ISA: bar}}
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add)
|
||||||
|
new_concept = res.body.body
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_CONCEPT)
|
||||||
|
assert new_concept.get_metadata().body == "metadata value"
|
||||||
|
assert new_concept.get_metadata().variables == [("var_name", "default value")]
|
||||||
|
assert new_concept.get_prop(BuiltinConcepts.ISA) == {bar}
|
||||||
|
|
||||||
|
# test that object
|
||||||
|
foo_from_sheerka = sheerka.get_by_key(new_concept.key)
|
||||||
|
assert foo_from_sheerka.get_metadata().body == "metadata value"
|
||||||
|
assert foo_from_sheerka.get_metadata().variables == [("var_name", "default value")]
|
||||||
|
assert foo_from_sheerka.get_prop(BuiltinConcepts.ISA) == {bar}
|
||||||
|
|
||||||
|
# other caches are also updated
|
||||||
|
assert sheerka.get_by_id(new_concept.id).get_metadata().body == "metadata value"
|
||||||
|
assert sheerka.get_by_name(new_concept.name).get_metadata().body == "metadata value"
|
||||||
|
assert sheerka.get_by_hash(new_concept.get_definition_hash()).get_metadata().body == "metadata value"
|
||||||
|
|
||||||
|
# sdp is updated
|
||||||
|
sheerka.cache_manager.commit(context)
|
||||||
|
from_sdp = sheerka.sdp.get(service.CONCEPTS_BY_ID_ENTRY, new_concept.id)
|
||||||
|
assert from_sdp.get_metadata().body == "metadata value"
|
||||||
|
assert from_sdp.get_metadata().variables == [("var_name", "default value")]
|
||||||
|
assert from_sdp.get_prop(BuiltinConcepts.ISA) == {bar}
|
||||||
|
|
||||||
|
assert sheerka.sdp.get(service.CONCEPTS_BY_NAME_ENTRY, new_concept.name).get_metadata().body == "metadata value"
|
||||||
|
assert sheerka.sdp.get(service.CONCEPTS_BY_KEY_ENTRY, new_concept.key).get_metadata().body == "metadata value"
|
||||||
|
assert sheerka.sdp.get(service.CONCEPTS_BY_HASH_ENTRY,
|
||||||
|
new_concept.get_definition_hash()).get_metadata().body == "metadata value"
|
||||||
|
|
||||||
|
def test_caches_are_update_when_i_modify_the_name(self):
|
||||||
|
sheerka, context, foo = self.init_concepts("foo", cache_only=False)
|
||||||
|
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||||
|
|
||||||
|
sheerka.is_known(sheerka.get_by_name(foo.name))
|
||||||
|
sheerka.is_known(sheerka.get_by_key(foo.key))
|
||||||
|
sheerka.get_by_hash(foo.get_definition_hash())
|
||||||
|
|
||||||
|
to_add = {"meta": {"name": "bar"}}
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add)
|
||||||
|
new_concept = res.body.body
|
||||||
|
|
||||||
|
assert new_concept.name == "bar"
|
||||||
|
assert sheerka.get_by_id(new_concept.id).name == "bar"
|
||||||
|
assert sheerka.get_by_key(new_concept.key).name == "bar"
|
||||||
|
assert sheerka.get_by_name(new_concept.name).name == "bar"
|
||||||
|
assert sheerka.get_by_hash(new_concept.get_definition_hash()).name == "bar"
|
||||||
|
|
||||||
|
assert not sheerka.is_known(sheerka.get_by_name(foo.name))
|
||||||
|
assert not sheerka.is_known(sheerka.get_by_key(foo.key))
|
||||||
|
assert not sheerka.is_known(sheerka.get_by_hash(foo.get_definition_hash()))
|
||||||
|
|
||||||
|
sheerka.cache_manager.commit(context)
|
||||||
|
assert sheerka.sdp.get(service.CONCEPTS_BY_ID_ENTRY, new_concept.id).name == "bar"
|
||||||
|
assert sheerka.sdp.get(service.CONCEPTS_BY_KEY_ENTRY, new_concept.key).name == "bar"
|
||||||
|
assert sheerka.sdp.get(service.CONCEPTS_BY_NAME_ENTRY, new_concept.name).name == "bar"
|
||||||
|
assert sheerka.sdp.get(service.CONCEPTS_BY_HASH_ENTRY, new_concept.get_definition_hash()).name == "bar"
|
||||||
|
assert sheerka.sdp.get(service.CONCEPTS_BY_KEY_ENTRY, foo.key) is None
|
||||||
|
assert sheerka.sdp.get(service.CONCEPTS_BY_NAME_ENTRY, foo.name) is None
|
||||||
|
assert sheerka.sdp.get(service.CONCEPTS_BY_HASH_ENTRY, foo.get_definition_hash()) is None
|
||||||
|
|
||||||
|
def test_i_can_modify_a_concept_from_a_list_of_concepts(self):
|
||||||
|
sheerka, context, foo1, foo2 = self.init_concepts(
|
||||||
|
Concept("foo", body="1"),
|
||||||
|
Concept("foo", body="2"))
|
||||||
|
|
||||||
|
to_add = {"meta": {"body": "new_value"}}
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo1, to_add)
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_CONCEPT)
|
||||||
|
|
||||||
|
new_concept = res.body.body
|
||||||
|
|
||||||
|
assert new_concept.id == foo1.id
|
||||||
|
assert res.body.body.get_metadata().body == "new_value"
|
||||||
|
|
||||||
|
assert sheerka.get_by_id(foo1.id).get_metadata().body == "new_value"
|
||||||
|
assert sheerka.get_by_id(foo2.id).get_metadata().body == "2"
|
||||||
|
|
||||||
|
def test_values_are_modified_when_variables_are_added_or_removed(self):
|
||||||
|
sheerka, context, foo = self.init_concepts(Concept("foo").def_var("a").def_var("b"))
|
||||||
|
|
||||||
|
to_add = {"meta": {"body": "metadata value"},
|
||||||
|
"variables": {"c": "default value"}}
|
||||||
|
|
||||||
|
to_remove = {"variables": ["a"]}
|
||||||
|
|
||||||
|
assert get_concept_attrs(foo) == ["a", "b"]
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add, to_remove)
|
||||||
|
new_concept = res.body.body
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert get_concept_attrs(foo) == ["b", "c"]
|
||||||
|
assert get_concept_attrs(new_concept) == ["b", "c"]
|
||||||
|
|
||||||
|
def test_key_is_modified_when_modifying_name_or_variables(self):
|
||||||
|
sheerka, context, foo = self.init_concepts(Concept("foo a b").def_var("a").def_var("b"))
|
||||||
|
|
||||||
|
to_add = {"meta": {"name": "b bar c d"},
|
||||||
|
"variables": {"c": None, "d": None}}
|
||||||
|
|
||||||
|
to_remove = {"variables": ["a"]}
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add, to_remove)
|
||||||
|
new_concept = res.body.body
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert new_concept.key == "__var__0 bar __var__1 __var__2"
|
||||||
|
|
||||||
|
def test_key_is_modified_when_modifying_the_definition(self):
|
||||||
|
sheerka, context, foo = self.init_concepts(
|
||||||
|
Concept(name="foo", definition="foo a b", definition_type=DEFINITION_TYPE_DEF).def_var("a").def_var("b"))
|
||||||
|
|
||||||
|
to_add = {"meta": {"definition": "b bar c d"},
|
||||||
|
"variables": {"c": None, "d": None}}
|
||||||
|
|
||||||
|
to_remove = {"variables": ["a"]}
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add, to_remove)
|
||||||
|
new_concept = res.body.body
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert new_concept.key == "__var__0 bar __var__1 __var__2"
|
||||||
|
|
||||||
|
def test_bnf_is_modified_when_modifying_the_definition(self):
|
||||||
|
sheerka, context, one, two, foo = self.init_concepts(
|
||||||
|
"one",
|
||||||
|
"two",
|
||||||
|
Concept(name="foo", definition="'twenty' one"),
|
||||||
|
create_new=True
|
||||||
|
)
|
||||||
|
|
||||||
|
to_add = {"meta": {"definition": "'twenty' two"}}
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add)
|
||||||
|
new_concept = res.body.body
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert new_concept.get_metadata().definition == "'twenty' two"
|
||||||
|
assert new_concept.get_bnf() == Sequence(StrMatch('twenty'), ConceptExpression(two, rule_name='two'))
|
||||||
|
|
||||||
|
def test_concept_by_first_keyword_is_updated_after_concept_modification(self):
|
||||||
|
sheerka, context, foo, bar, baz = self.init_concepts(
|
||||||
|
Concept("foo"),
|
||||||
|
Concept("bar"),
|
||||||
|
Concept("baz", definition="foo"),
|
||||||
|
create_new=True)
|
||||||
|
|
||||||
|
assert sheerka.cache_manager.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
|
||||||
|
"foo": ["1001"],
|
||||||
|
"bar": ["1002"],
|
||||||
|
'c:|1001:': ['1003']}
|
||||||
|
assert sheerka.cache_manager.copy(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
|
||||||
|
'foo': ['1001', '1003'],
|
||||||
|
'bar': ['1002']}
|
||||||
|
|
||||||
|
to_add = {"meta": {"name": "bar"}}
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add)
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.cache_manager.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
|
||||||
|
"bar": ["1002", "1001"],
|
||||||
|
'c:|1001:': ['1003']}
|
||||||
|
assert sheerka.cache_manager.copy(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
|
||||||
|
'bar': ['1002', '1001', '1003']}
|
||||||
|
|
||||||
|
def test_references_are_updated_after_concept_modification(self):
|
||||||
|
sheerka, context, one, twenty_one = self.init_concepts(
|
||||||
|
"onz",
|
||||||
|
Concept("twenty one", definition="'twenty' onz"),
|
||||||
|
create_new=True
|
||||||
|
)
|
||||||
|
|
||||||
|
assert twenty_one.get_bnf() == Sequence(StrMatch('twenty'), ConceptExpression(one, rule_name='onz'))
|
||||||
|
|
||||||
|
to_add = {"meta": {"name": "one"}}
|
||||||
|
res = sheerka.modify_concept(context, one, to_add)
|
||||||
|
modified = res.body.body
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
|
||||||
|
twenty_one = sheerka.get_by_name("twenty one")
|
||||||
|
assert twenty_one.get_metadata().definition == "'twenty' one"
|
||||||
|
assert twenty_one.get_bnf() is None
|
||||||
|
|
||||||
|
BaseNodeParser.ensure_bnf(context, twenty_one)
|
||||||
|
assert twenty_one.get_bnf() == Sequence(StrMatch('twenty'), ConceptExpression(modified, rule_name='one'))
|
||||||
|
|
||||||
|
def test_i_cannot_modify_without_any_modification(self):
|
||||||
|
sheerka, context, foo = self.init_concepts("foo")
|
||||||
|
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||||
|
|
||||||
|
res = service.modify_concept(context, foo)
|
||||||
|
|
||||||
|
assert not res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||||
|
assert res.body.body == NoModificationFound(foo)
|
||||||
|
|
||||||
|
def test_i_cannot_modify_forbidden_attributes(self):
|
||||||
|
sheerka, context, foo = self.init_concepts("foo")
|
||||||
|
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||||
|
|
||||||
|
for attr in service.forbidden_meta:
|
||||||
|
res = service.modify_concept(context, foo, to_add={"meta": {attr: "new value"}})
|
||||||
|
assert not res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||||
|
assert res.body.body == ForbiddenAttribute(attr)
|
||||||
|
|
||||||
|
def test_i_cannot_modify_unknown_attributes(self):
|
||||||
|
sheerka, context, foo = self.init_concepts("foo")
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add={"meta": {"dummy": "new value"}})
|
||||||
|
assert not res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||||
|
assert res.body.body == UnknownAttribute("dummy")
|
||||||
|
|
||||||
|
def test_i_cannot_modify_if_all_new_values_are_the_same(self):
|
||||||
|
sheerka, context, foo = self.init_concepts(Concept("foo", body="a body"))
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add={"meta": {"name": "foo", "body": "a body"}})
|
||||||
|
|
||||||
|
assert not res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||||
|
assert res.body.body == NoModificationFound(foo, {"name": "foo", "body": "a body"})
|
||||||
|
|
||||||
|
def test_i_cannot_remove_meta_attributes(self):
|
||||||
|
sheerka, context, foo = self.init_concepts(Concept("foo"))
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_remove={"meta": {"any_value": "foo"}})
|
||||||
|
|
||||||
|
assert not res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||||
|
assert res.body.body == CannotRemoveMeta({"any_value": "foo"})
|
||||||
|
|
||||||
|
def test_i_cannot_remove_props_that_does_not_exists(self):
|
||||||
|
sheerka, context, foo = self.init_concepts(Concept("foo"))
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_remove={"props": {"any_value": "foo"}})
|
||||||
|
|
||||||
|
assert not res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||||
|
assert res.body.body == UnknownAttribute("any_value")
|
||||||
|
|
||||||
|
def test_i_cannot_remove_props_value_that_does_not_exists(self):
|
||||||
|
# Need to returns an error, otherwise, we will save a concept that is not modified
|
||||||
|
sheerka, context, foo = self.init_concepts(Concept("foo", props={"a": {"value"}}))
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_remove={"props": {"a": "dummy"}})
|
||||||
|
|
||||||
|
assert not res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||||
|
assert res.body.body == ValueNotFound("a", "dummy")
|
||||||
|
|
||||||
|
def test_i_cannot_remove_variable_that_does_not_exists(self):
|
||||||
|
sheerka, context, foo = self.init_concepts(Concept("foo").def_var("a"))
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_remove={"variables": ["b"]})
|
||||||
|
|
||||||
|
assert not res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||||
|
assert res.body.body == UnknownAttribute("b")
|
||||||
|
|
||||||
|
def test_i_cannot_modify_a_concept_that_is_not_known(self):
|
||||||
|
sheerka, context = self.init_concepts()
|
||||||
|
foo = Concept("foo")
|
||||||
|
sheerka.set_id_if_needed(foo, False)
|
||||||
|
|
||||||
|
res = sheerka.modify_concept(context, foo, to_add={"meta": {"body": "new value"}})
|
||||||
|
|
||||||
|
assert not res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.UNKNOWN_CONCEPT)
|
||||||
|
|
||||||
|
def test_i_can_get_and_set_attribute(self):
|
||||||
|
sheerka, context = self.init_concepts()
|
||||||
|
foo = Concept("foo")
|
||||||
|
prop = Concept("property")
|
||||||
|
bar = Concept("bar")
|
||||||
|
|
||||||
|
res = sheerka.set_attr(foo, prop, bar)
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
|
||||||
|
|
||||||
|
assert sheerka.get_attr(foo, prop) == bar
|
||||||
|
|
||||||
|
def test_i_cannot_remove_a_concept_which_has_reference(self):
|
||||||
|
sheerka, context, one, twenty_one = self.init_concepts(
|
||||||
|
Concept("one"),
|
||||||
|
Concept("twenty one", definition="'twenty' one"),
|
||||||
|
create_new=True)
|
||||||
|
|
||||||
|
res = sheerka.remove_concept(context, one)
|
||||||
|
|
||||||
|
assert not res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||||
|
assert res.body.body == ConceptIsReferenced([twenty_one])
|
||||||
|
|
||||||
|
def test_i_can_remove_a_concept(self):
|
||||||
|
sheerka, context, one = self.init_concepts(
|
||||||
|
Concept("one"),
|
||||||
|
create_new=True)
|
||||||
|
|
||||||
|
# sanity check
|
||||||
|
assert sheerka.get_by_id(one.id) == one
|
||||||
|
assert sheerka.get_by_name(one.name) == one
|
||||||
|
assert sheerka.get_by_key(one.key) == one
|
||||||
|
assert sheerka.get_by_hash(one.get_definition_hash()) == one
|
||||||
|
|
||||||
|
res = sheerka.remove_concept(context, one)
|
||||||
|
|
||||||
|
assert res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
|
||||||
|
|
||||||
|
assert sheerka.isinstance(sheerka.get_by_id(one.id), BuiltinConcepts.UNKNOWN_CONCEPT)
|
||||||
|
assert sheerka.isinstance(sheerka.get_by_name(one.name), BuiltinConcepts.UNKNOWN_CONCEPT)
|
||||||
|
assert sheerka.isinstance(sheerka.get_by_key(one.key), BuiltinConcepts.UNKNOWN_CONCEPT)
|
||||||
|
assert sheerka.isinstance(sheerka.get_by_hash(one.get_definition_hash()), BuiltinConcepts.UNKNOWN_CONCEPT)
|
||||||
|
|
||||||
|
def test_i_cannot_remove_a_concept_that_does_not_exist(self):
|
||||||
|
sheerka, context = self.init_concepts()
|
||||||
|
one = Concept("one", id="1001")
|
||||||
|
|
||||||
|
res = sheerka.remove_concept(context, one)
|
||||||
|
|
||||||
|
assert not res.status
|
||||||
|
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
||||||
|
assert res.body.body == ConceptNotFound(one)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSheerkaConceptManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
|
||||||
|
def test_i_can_add_several_concepts(self):
|
||||||
|
sheerka = self.get_sheerka()
|
||||||
|
context = self.get_context(sheerka)
|
||||||
|
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||||
|
|
||||||
|
hello = Concept("Hello world a").def_var("a")
|
||||||
|
res = sheerka.create_new_concept(context, hello)
|
||||||
|
sheerka.cache_manager.commit(context)
|
||||||
|
assert res.status
|
||||||
|
|
||||||
|
sheerka = self.get_sheerka() # another instance
|
||||||
|
context = self.get_context(sheerka)
|
||||||
|
greeting = Concept("Greeting a").def_var("a")
|
||||||
|
res = sheerka.create_new_concept(context, greeting)
|
||||||
|
sheerka.cache_manager.commit(context)
|
||||||
|
assert res.status
|
||||||
|
|
||||||
|
sheerka = self.get_sheerka() # another instance again
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_KEY_ENTRY, hello.key)
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_KEY_ENTRY, greeting.key)
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_ID_ENTRY, hello.id)
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_ID_ENTRY, greeting.id)
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_NAME_ENTRY, "Hello world a")
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_NAME_ENTRY, "Greeting a")
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_HASH_ENTRY, hello.get_definition_hash())
|
||||||
|
assert sheerka.sdp.exists(service.CONCEPTS_BY_HASH_ENTRY, greeting.get_definition_hash())
|
||||||
|
|
||||||
|
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "Hello")
|
||||||
|
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "Greeting")
|
||||||
|
|
||||||
|
def test_i_cannot_add_the_same_concept_twice_using_sdp(self):
|
||||||
|
"""
|
||||||
|
Checks that duplicated concepts are managed by sheerka, not by sheerka.sdp
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
sheerka = self.get_sheerka(cache_only=False)
|
||||||
|
context = self.get_context(sheerka)
|
||||||
|
concept = self.get_default_concept()
|
||||||
|
|
||||||
|
sheerka.create_new_concept(context, concept)
|
||||||
|
sheerka.cache_manager.commit(context)
|
||||||
|
|
||||||
|
sheerka.cache_manager.clear()
|
||||||
|
res = sheerka.create_new_concept(context, concept)
|
||||||
|
|
||||||
|
assert not res.status
|
||||||
|
assert sheerka.isinstance(res.value, BuiltinConcepts.CONCEPT_ALREADY_DEFINED)
|
||||||
|
assert res.value.body == concept
|
||||||
|
|
||||||
|
def test_new_entry_does_not_override_the_previous_ones(self):
|
||||||
|
sheerka = self.get_sheerka()
|
||||||
|
context = self.get_context(sheerka)
|
||||||
|
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||||
|
|
||||||
|
sheerka.create_new_concept(context, Concept("foo", body="1"))
|
||||||
|
sheerka.create_new_concept(context, Concept("foo", body="2"))
|
||||||
|
sheerka.cache_manager.commit(context)
|
||||||
|
|
||||||
|
assert len(sheerka.sdp.get(service.CONCEPTS_BY_KEY_ENTRY, "foo")) == 2
|
||||||
|
|
||||||
|
sheerka = self.get_sheerka() # new instance
|
||||||
|
context = self.get_context(sheerka)
|
||||||
|
sheerka.create_new_concept(context, Concept("foo", body="3"))
|
||||||
|
sheerka.cache_manager.commit(context)
|
||||||
|
|
||||||
|
assert len(sheerka.sdp.get(service.CONCEPTS_BY_KEY_ENTRY, "foo")) == 3
|
||||||
@@ -1,281 +0,0 @@
|
|||||||
import pytest
|
|
||||||
from core.builtin_concepts import BuiltinConcepts
|
|
||||||
from core.concept import PROPERTIES_TO_SERIALIZE, Concept, DEFINITION_TYPE_DEF, get_concept_attrs
|
|
||||||
from core.sheerka.Sheerka import Sheerka
|
|
||||||
|
|
||||||
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
|
||||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
|
||||||
|
|
||||||
|
|
||||||
class TestSheerkaCreateNewConcept(TestUsingMemoryBasedSheerka):
|
|
||||||
|
|
||||||
def test_i_can_create_a_concept(self):
|
|
||||||
sheerka = self.get_sheerka(cache_only=False)
|
|
||||||
context = self.get_context(sheerka)
|
|
||||||
concept = self.get_default_concept()
|
|
||||||
|
|
||||||
res = sheerka.create_new_concept(context, concept)
|
|
||||||
sheerka.cache_manager.commit(context)
|
|
||||||
|
|
||||||
assert res.status
|
|
||||||
assert sheerka.isinstance(res.value, BuiltinConcepts.NEW_CONCEPT)
|
|
||||||
|
|
||||||
concept_found = res.value.body
|
|
||||||
for prop in PROPERTIES_TO_SERIALIZE:
|
|
||||||
assert getattr(concept_found.get_metadata(), prop) == getattr(concept.get_metadata(), prop)
|
|
||||||
|
|
||||||
assert concept_found.key == "__var__0 + __var__1"
|
|
||||||
assert concept_found.id == "1001"
|
|
||||||
assert get_concept_attrs(concept) == ['a', 'b']
|
|
||||||
|
|
||||||
# saved in cache
|
|
||||||
assert sheerka.has_id(concept.id)
|
|
||||||
assert sheerka.has_key(concept.key)
|
|
||||||
assert sheerka.has_name(concept.name)
|
|
||||||
assert sheerka.has_hash(concept.get_definition_hash())
|
|
||||||
|
|
||||||
# I can get the concept using various index
|
|
||||||
assert sheerka.get_by_id(concept.id) == concept
|
|
||||||
assert sheerka.get_by_key(concept.key) == concept
|
|
||||||
assert sheerka.get_by_name(concept.name) == concept
|
|
||||||
assert sheerka.get_by_hash(concept.get_definition_hash()) == concept
|
|
||||||
|
|
||||||
# I can get by the first entry
|
|
||||||
assert sheerka.cache_manager.get(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "+") == [concept.id]
|
|
||||||
assert sheerka.cache_manager.get(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "+") == [concept.id]
|
|
||||||
|
|
||||||
# saved in sdp
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_ID_ENTRY, concept.id)
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_KEY_ENTRY, concept.key)
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_NAME_ENTRY, concept.name)
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_HASH_ENTRY, concept.get_definition_hash())
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "+")
|
|
||||||
|
|
||||||
def test_i_can_add_a_concept_when_name_differs_from_the_key(self):
|
|
||||||
sheerka = self.get_sheerka(cache_only=False)
|
|
||||||
context = self.get_context(sheerka)
|
|
||||||
concept = Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a")
|
|
||||||
|
|
||||||
res = sheerka.create_new_concept(self.get_context(sheerka), concept)
|
|
||||||
sheerka.cache_manager.commit(context)
|
|
||||||
|
|
||||||
assert res.status
|
|
||||||
assert sheerka.isinstance(res.value, BuiltinConcepts.NEW_CONCEPT)
|
|
||||||
|
|
||||||
concept_found = res.value.body
|
|
||||||
for prop in PROPERTIES_TO_SERIALIZE:
|
|
||||||
assert getattr(concept_found.get_metadata(), prop) == getattr(concept.get_metadata(), prop)
|
|
||||||
|
|
||||||
assert concept_found.key == "hello __var__0"
|
|
||||||
assert concept_found.id == "1001"
|
|
||||||
|
|
||||||
# saved in cache
|
|
||||||
assert sheerka.has_id(concept.id)
|
|
||||||
assert sheerka.has_key(concept.key)
|
|
||||||
assert sheerka.has_name(concept.name)
|
|
||||||
assert sheerka.has_hash(concept.get_definition_hash())
|
|
||||||
|
|
||||||
# I can get the concept using various index
|
|
||||||
assert sheerka.get_by_id(concept.id) == concept
|
|
||||||
assert sheerka.get_by_key(concept.key) == concept
|
|
||||||
assert sheerka.get_by_name(concept.name) == concept
|
|
||||||
assert sheerka.get_by_hash(concept.get_definition_hash()) == concept
|
|
||||||
|
|
||||||
# saved in sdp
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_ID_ENTRY, concept.id)
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_KEY_ENTRY, concept.key)
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_NAME_ENTRY, concept.name)
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_HASH_ENTRY, concept.get_definition_hash())
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "hello")
|
|
||||||
|
|
||||||
def test_i_cannot_add_the_same_concept_twice(self):
|
|
||||||
"""
|
|
||||||
Checks that duplicated concepts are managed by sheerka, not by sheerka.sdp
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
sheerka = self.get_sheerka()
|
|
||||||
concept = self.get_default_concept()
|
|
||||||
|
|
||||||
sheerka.create_new_concept(self.get_context(sheerka), concept)
|
|
||||||
res = sheerka.create_new_concept(self.get_context(sheerka), concept)
|
|
||||||
|
|
||||||
assert not res.status
|
|
||||||
assert sheerka.isinstance(res.value, BuiltinConcepts.CONCEPT_ALREADY_DEFINED)
|
|
||||||
assert res.value.body == concept
|
|
||||||
|
|
||||||
def test_i_can_get_a_newly_created_concept(self):
|
|
||||||
sheerka = self.get_sheerka()
|
|
||||||
concept = self.get_default_concept()
|
|
||||||
|
|
||||||
sheerka.create_new_concept(self.get_context(sheerka), concept)
|
|
||||||
|
|
||||||
from_cache = sheerka.get_by_key(concept.key)
|
|
||||||
assert from_cache is not None
|
|
||||||
assert from_cache == concept
|
|
||||||
|
|
||||||
from_cache = sheerka.get_by_id(concept.id)
|
|
||||||
assert from_cache is not None
|
|
||||||
assert from_cache == concept
|
|
||||||
|
|
||||||
def test_i_can_get_list_of_concept_when_same_key_using_cache(self):
|
|
||||||
sheerka = self.get_sheerka()
|
|
||||||
concept1 = self.get_default_concept()
|
|
||||||
concept2 = self.get_default_concept()
|
|
||||||
concept2.get_metadata().body = "a+b"
|
|
||||||
|
|
||||||
res1 = sheerka.create_new_concept(self.get_context(sheerka), concept1)
|
|
||||||
res2 = sheerka.create_new_concept(self.get_context(sheerka), concept2)
|
|
||||||
|
|
||||||
assert res1.value.body.key == res2.value.body.key # same key
|
|
||||||
|
|
||||||
result = sheerka.get_by_key(concept1.key)
|
|
||||||
assert len(result) == 2
|
|
||||||
assert result[0] == concept1
|
|
||||||
assert result[1] == concept2
|
|
||||||
|
|
||||||
def test_concept_that_references_itself_is_correctly_created(self):
|
|
||||||
sheerka = self.get_sheerka()
|
|
||||||
concept = Concept("foo", body="foo")
|
|
||||||
|
|
||||||
res = sheerka.create_new_concept(self.get_context(sheerka), concept)
|
|
||||||
|
|
||||||
assert res.status
|
|
||||||
|
|
||||||
def test_i_can_get_by_name_when_created_with_def_definition(self):
|
|
||||||
sheerka = self.get_sheerka(cache_only=False)
|
|
||||||
context = self.get_context(sheerka)
|
|
||||||
concept = self.from_def_concept("plus", "a plus b", ["a", "b"])
|
|
||||||
|
|
||||||
res = sheerka.create_new_concept(context, concept)
|
|
||||||
|
|
||||||
assert res.status
|
|
||||||
assert sheerka.get_by_name(concept.name) == concept
|
|
||||||
assert sheerka.get_by_name(concept.get_metadata().definition) == concept
|
|
||||||
|
|
||||||
concept = Concept(name="foo", definition="foo", definition_type=DEFINITION_TYPE_DEF)
|
|
||||||
res = sheerka.create_new_concept(context, concept)
|
|
||||||
|
|
||||||
assert res.status
|
|
||||||
assert sheerka.get_by_name(concept.name) == concept # it's not a list, ie the entry is not duplicated
|
|
||||||
|
|
||||||
def test_i_can_get_first_token_when_not_a_letter(self):
|
|
||||||
sheerka = self.get_sheerka(cache_only=False)
|
|
||||||
context = self.get_context(sheerka)
|
|
||||||
concept = Concept("--filter a").def_var("a")
|
|
||||||
|
|
||||||
res = sheerka.create_new_concept(context, concept)
|
|
||||||
assert res.status
|
|
||||||
|
|
||||||
# I can get by the first entry
|
|
||||||
assert sheerka.cache_manager.get(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [concept.id]
|
|
||||||
assert sheerka.cache_manager.get(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [concept.id]
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("expression", [
|
|
||||||
"--'filter' ('one' | 'two') ",
|
|
||||||
"'--filter' ('one' | 'two') ",
|
|
||||||
])
|
|
||||||
def test_i_can_get_first_token_when_bnf_concept_and_not_a_letter(self, expression):
|
|
||||||
sheerka, context, bnf_concept = self.init_concepts(
|
|
||||||
Concept("foo", definition=expression),
|
|
||||||
create_new=True)
|
|
||||||
|
|
||||||
# I can get by the first entry
|
|
||||||
assert sheerka.cache_manager.get(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [bnf_concept.id]
|
|
||||||
assert sheerka.cache_manager.get(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "-") == [bnf_concept.id]
|
|
||||||
|
|
||||||
def test_concept_references_are_updated_1(self):
|
|
||||||
sheerka, context, one, two, number, twenty, twenties = self.init_concepts(
|
|
||||||
"one",
|
|
||||||
"two",
|
|
||||||
"number",
|
|
||||||
"twenty",
|
|
||||||
Concept("twenties", definition="twenty one | two 'hundred'"),
|
|
||||||
create_new=True
|
|
||||||
)
|
|
||||||
|
|
||||||
assert sheerka.cache_manager.get(sheerka.CONCEPTS_REFERENCES_ENTRY, one.id) == {twenties.id}
|
|
||||||
assert sheerka.cache_manager.get(sheerka.CONCEPTS_REFERENCES_ENTRY, two.id) == {twenties.id}
|
|
||||||
assert sheerka.cache_manager.get(sheerka.CONCEPTS_REFERENCES_ENTRY, number.id) is None
|
|
||||||
assert sheerka.cache_manager.get(sheerka.CONCEPTS_REFERENCES_ENTRY, twenty.id) == {twenties.id}
|
|
||||||
assert sheerka.cache_manager.get(sheerka.CONCEPTS_REFERENCES_ENTRY, twenties.id) is None
|
|
||||||
|
|
||||||
def test_concept_references_are_updated_2(self):
|
|
||||||
sheerka, context, one, two, number, twenty, twenties = self.init_concepts(
|
|
||||||
"one",
|
|
||||||
"two",
|
|
||||||
"number",
|
|
||||||
"twenty",
|
|
||||||
Concept("twenties", definition="twenty number"),
|
|
||||||
create_new=True
|
|
||||||
)
|
|
||||||
|
|
||||||
assert sheerka.cache_manager.get(sheerka.CONCEPTS_REFERENCES_ENTRY, one.id) is None
|
|
||||||
assert sheerka.cache_manager.get(sheerka.CONCEPTS_REFERENCES_ENTRY, two.id) is None
|
|
||||||
assert sheerka.cache_manager.get(sheerka.CONCEPTS_REFERENCES_ENTRY, number.id) == {twenties.id}
|
|
||||||
assert sheerka.cache_manager.get(sheerka.CONCEPTS_REFERENCES_ENTRY, twenty.id) == {twenties.id}
|
|
||||||
assert sheerka.cache_manager.get(sheerka.CONCEPTS_REFERENCES_ENTRY, twenties.id) is None
|
|
||||||
|
|
||||||
|
|
||||||
class TestSheerkaCreateNewConceptFileBased(TestUsingFileBasedSheerka):
|
|
||||||
def test_i_can_add_several_concepts(self):
|
|
||||||
sheerka = self.get_sheerka()
|
|
||||||
context = self.get_context(sheerka)
|
|
||||||
hello = Concept("Hello world a").def_var("a")
|
|
||||||
res = sheerka.create_new_concept(context, hello)
|
|
||||||
sheerka.cache_manager.commit(context)
|
|
||||||
assert res.status
|
|
||||||
|
|
||||||
sheerka = self.get_sheerka() # another instance
|
|
||||||
context = self.get_context(sheerka)
|
|
||||||
greeting = Concept("Greeting a").def_var("a")
|
|
||||||
res = sheerka.create_new_concept(context, greeting)
|
|
||||||
sheerka.cache_manager.commit(context)
|
|
||||||
assert res.status
|
|
||||||
|
|
||||||
sheerka = self.get_sheerka() # another instance again
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_KEY_ENTRY, hello.key)
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_KEY_ENTRY, greeting.key)
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_ID_ENTRY, hello.id)
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_ID_ENTRY, greeting.id)
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_NAME_ENTRY, "Hello world a")
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_NAME_ENTRY, "Greeting a")
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_HASH_ENTRY, hello.get_definition_hash())
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_HASH_ENTRY, greeting.get_definition_hash())
|
|
||||||
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "Hello")
|
|
||||||
assert sheerka.sdp.exists(Sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY, "Greeting")
|
|
||||||
|
|
||||||
def test_i_cannot_add_the_same_concept_twice_using_sdp(self):
|
|
||||||
"""
|
|
||||||
Checks that duplicated concepts are managed by sheerka, not by sheerka.sdp
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
sheerka = self.get_sheerka(cache_only=False)
|
|
||||||
context = self.get_context(sheerka)
|
|
||||||
concept = self.get_default_concept()
|
|
||||||
|
|
||||||
sheerka.create_new_concept(context, concept)
|
|
||||||
sheerka.cache_manager.commit(context)
|
|
||||||
|
|
||||||
sheerka.cache_manager.clear()
|
|
||||||
res = sheerka.create_new_concept(context, concept)
|
|
||||||
|
|
||||||
assert not res.status
|
|
||||||
assert sheerka.isinstance(res.value, BuiltinConcepts.CONCEPT_ALREADY_DEFINED)
|
|
||||||
assert res.value.body == concept
|
|
||||||
|
|
||||||
def test_new_entry_does_not_override_the_previous_ones(self):
|
|
||||||
sheerka = self.get_sheerka()
|
|
||||||
context = self.get_context(sheerka)
|
|
||||||
sheerka.create_new_concept(context, Concept("foo", body="1"))
|
|
||||||
sheerka.create_new_concept(context, Concept("foo", body="2"))
|
|
||||||
sheerka.cache_manager.commit(context)
|
|
||||||
|
|
||||||
assert len(sheerka.sdp.get(Sheerka.CONCEPTS_BY_KEY_ENTRY, "foo")) == 2
|
|
||||||
|
|
||||||
sheerka = self.get_sheerka() # new instance
|
|
||||||
context = self.get_context(sheerka)
|
|
||||||
sheerka.create_new_concept(context, Concept("foo", body="3"))
|
|
||||||
sheerka.cache_manager.commit(context)
|
|
||||||
|
|
||||||
assert len(sheerka.sdp.get(Sheerka.CONCEPTS_BY_KEY_ENTRY, "foo")) == 3
|
|
||||||
@@ -375,6 +375,26 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
|||||||
assert evaluated.get_metadata().is_evaluated
|
assert evaluated.get_metadata().is_evaluated
|
||||||
assert sheerka.objvalue(evaluated) == 2
|
assert sheerka.objvalue(evaluated) == 2
|
||||||
|
|
||||||
|
def test_i_can_evaluate_a_concept_that_references_another_concept_twice(self):
|
||||||
|
"""
|
||||||
|
Test that a new instance of concept is return when the metadata refers to a concept
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
sheerka, context, predicate, foo = self.init_concepts(
|
||||||
|
Concept("Sometimes True", body="in_context('a')"),
|
||||||
|
Concept("foo", pre="c:Sometimes True:"))
|
||||||
|
|
||||||
|
foo1 = sheerka.new("foo")
|
||||||
|
foo1 = sheerka.evaluate_concept(context, foo1) # 'a' is not in context, so it fails
|
||||||
|
|
||||||
|
context2 = self.get_context(sheerka)
|
||||||
|
context2.add_to_protected_hints('a')
|
||||||
|
foo2 = sheerka.new("foo")
|
||||||
|
foo2 = sheerka.evaluate_concept(context2, foo2) # 'a' in context + new instance of 'Sometimes True'
|
||||||
|
|
||||||
|
assert sheerka.isinstance(foo1, BuiltinConcepts.CONDITION_FAILED)
|
||||||
|
assert sheerka.isinstance(foo2, "foo")
|
||||||
|
|
||||||
def test_i_can_reference_sheerka(self):
|
def test_i_can_reference_sheerka(self):
|
||||||
sheerka = self.get_sheerka()
|
sheerka = self.get_sheerka()
|
||||||
|
|
||||||
@@ -624,8 +644,8 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
|
|||||||
eval_body=True
|
eval_body=True
|
||||||
)
|
)
|
||||||
|
|
||||||
sheerka.add_in_cache(one_str)
|
sheerka.test_only_add_in_cache(one_str)
|
||||||
sheerka.add_in_cache(one_digit)
|
sheerka.test_only_add_in_cache(one_digit)
|
||||||
|
|
||||||
evaluated = sheerka.evaluate_concept(context, one_digit)
|
evaluated = sheerka.evaluate_concept(context, one_digit)
|
||||||
assert evaluated.key == one_digit.key
|
assert evaluated.key == one_digit.key
|
||||||
|
|||||||
@@ -1,121 +0,0 @@
|
|||||||
from core.builtin_concepts import BuiltinConcepts
|
|
||||||
from core.concept import Concept, ConceptParts, get_concept_attrs
|
|
||||||
|
|
||||||
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
|
||||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
|
||||||
|
|
||||||
|
|
||||||
class TestSheerkaModifyConcept(TestUsingMemoryBasedSheerka):
|
|
||||||
|
|
||||||
def test_i_can_modify_a_concept(self):
|
|
||||||
sheerka, context, foo, bar = self.init_concepts("foo", "bar", create_new=True, cache_only=False)
|
|
||||||
|
|
||||||
assert get_concept_attrs(foo) == []
|
|
||||||
|
|
||||||
foo_instance = sheerka.new("foo")
|
|
||||||
foo_instance.get_metadata().body = "metadata value" # modify metadata
|
|
||||||
foo_instance.def_var("var_name", "default value") # modify definition of variables
|
|
||||||
foo_instance.add_prop(BuiltinConcepts.ISA, bar) # modify property
|
|
||||||
foo_instance.set_value(ConceptParts.BODY, "body value") # modify value
|
|
||||||
foo_instance.set_value("var_name", "var value") # modify value
|
|
||||||
res = sheerka.modify_concept(context, foo_instance)
|
|
||||||
|
|
||||||
assert res.status
|
|
||||||
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_CONCEPT)
|
|
||||||
assert res.body.body.get_metadata().body == "metadata value"
|
|
||||||
assert res.body.body.get_metadata().variables == [("var_name", "default value")]
|
|
||||||
assert res.body.body.get_prop(BuiltinConcepts.ISA) == {bar}
|
|
||||||
assert res.body.body.body == "body value"
|
|
||||||
assert res.body.body.get_value("var_name") == "var value"
|
|
||||||
assert get_concept_attrs(foo) == ["var_name"]
|
|
||||||
|
|
||||||
# test that object
|
|
||||||
foo_from_sheerka = sheerka.get_by_key("foo")
|
|
||||||
assert foo_from_sheerka.get_metadata().body == "metadata value"
|
|
||||||
assert foo_from_sheerka.get_metadata().variables == [("var_name", "default value")]
|
|
||||||
assert foo_from_sheerka.get_prop(BuiltinConcepts.ISA) == {bar}
|
|
||||||
assert foo_from_sheerka.body == "body value"
|
|
||||||
assert foo_from_sheerka.get_value("var_name") == "var value"
|
|
||||||
|
|
||||||
# other caches are also updated
|
|
||||||
assert sheerka.get_by_id(foo.id).get_metadata().body == "metadata value"
|
|
||||||
assert sheerka.get_by_name(foo.name).get_metadata().body == "metadata value"
|
|
||||||
assert sheerka.get_by_hash(foo_instance.get_definition_hash()).get_metadata().body == "metadata value"
|
|
||||||
|
|
||||||
# sdp can be updated
|
|
||||||
sheerka.cache_manager.commit(context)
|
|
||||||
from_sdp = sheerka.sdp.get(sheerka.CONCEPTS_BY_ID_ENTRY, foo.id)
|
|
||||||
assert from_sdp.get_metadata().body == "metadata value"
|
|
||||||
assert from_sdp.get_metadata().variables == [("var_name", "default value")]
|
|
||||||
assert from_sdp.get_prop(BuiltinConcepts.ISA) == {bar}
|
|
||||||
assert from_sdp.body == "body value"
|
|
||||||
assert from_sdp.get_value("var_name") == "var value"
|
|
||||||
|
|
||||||
def test_i_cannot_modify_a_concept_that_does_not_exists(self):
|
|
||||||
sheerka, context = self.init_concepts()
|
|
||||||
|
|
||||||
foo = Concept("foo").init_key()
|
|
||||||
sheerka.set_id_if_needed(foo, False)
|
|
||||||
|
|
||||||
res = sheerka.modify_concept(context, foo)
|
|
||||||
assert not res.status
|
|
||||||
assert sheerka.isinstance(res.body, BuiltinConcepts.UNKNOWN_CONCEPT)
|
|
||||||
assert res.body.body == ("id", foo.id)
|
|
||||||
|
|
||||||
def test_i_cannot_modify_a_concept_that_returns_an_error(self):
|
|
||||||
sheerka, context = self.init_concepts()
|
|
||||||
|
|
||||||
foo = Concept("foo").init_key()
|
|
||||||
res = sheerka.modify_concept(context, foo)
|
|
||||||
|
|
||||||
assert not res.status
|
|
||||||
assert sheerka.isinstance(res.body, BuiltinConcepts.ERROR)
|
|
||||||
|
|
||||||
def test_i_cannot_modify_if_the_concept_has_not_changed(self):
|
|
||||||
sheerka, context, foo = self.init_concepts("foo", create_new=True)
|
|
||||||
res = sheerka.modify_concept(context, foo)
|
|
||||||
|
|
||||||
assert not res.status
|
|
||||||
assert sheerka.isinstance(res.body, BuiltinConcepts.CONCEPT_ALREADY_DEFINED)
|
|
||||||
|
|
||||||
def test_i_can_modify_a_concept_that_is_in_a_list(self):
|
|
||||||
sheerka, context, foo1, foo2 = self.init_concepts(
|
|
||||||
Concept("foo", body="1"),
|
|
||||||
Concept("foo", body="2"), create_new=True)
|
|
||||||
|
|
||||||
foo2_instance = sheerka.new("foo")[1]
|
|
||||||
foo2_instance.get_metadata().body = "value"
|
|
||||||
|
|
||||||
res = sheerka.modify_concept(context, foo2_instance)
|
|
||||||
assert res.status
|
|
||||||
assert sheerka.isinstance(res.body, BuiltinConcepts.NEW_CONCEPT)
|
|
||||||
assert res.body.body.get_metadata().body == "value"
|
|
||||||
|
|
||||||
foo_from_sheerka = sheerka.new("foo")
|
|
||||||
assert foo_from_sheerka[0].get_metadata().body == "1"
|
|
||||||
assert foo_from_sheerka[1].get_metadata().body == "value"
|
|
||||||
|
|
||||||
def test_i_can_get_and_set_attribute(self):
|
|
||||||
sheerka, context = self.init_concepts()
|
|
||||||
foo = Concept("foo")
|
|
||||||
prop = Concept("property")
|
|
||||||
bar = Concept("bar")
|
|
||||||
|
|
||||||
res = sheerka.set_attr(foo, prop, bar)
|
|
||||||
assert res.status
|
|
||||||
assert sheerka.isinstance(res.body, BuiltinConcepts.SUCCESS)
|
|
||||||
|
|
||||||
assert sheerka.get_attr(foo, prop) == bar
|
|
||||||
|
|
||||||
|
|
||||||
class TestSheerkaModifyConceptUsingFile(TestUsingFileBasedSheerka):
|
|
||||||
|
|
||||||
def test_i_can_modify_a_concept_from_a_new_sheerka(self):
|
|
||||||
sheerka, context, foo = self.init_concepts("foo", create_new=True)
|
|
||||||
sheerka.cache_manager.commit(context)
|
|
||||||
|
|
||||||
sheerka = self.get_sheerka()
|
|
||||||
foo.add_prop("a", "b")
|
|
||||||
res = sheerka.modify_concept(context, foo)
|
|
||||||
|
|
||||||
assert res.status
|
|
||||||
@@ -33,7 +33,7 @@ class TestSheerkaRuleManager(TestUsingMemoryBasedSheerka):
|
|||||||
])
|
])
|
||||||
def test_i_can_create_a_new_rule(self, action_type, cache_entry):
|
def test_i_can_create_a_new_rule(self, action_type, cache_entry):
|
||||||
sheerka, context = self.init_concepts(cache_only=False)
|
sheerka, context = self.init_concepts(cache_only=False)
|
||||||
previous_rules_number = sheerka.cache_manager.caches[sheerka.CONCEPTS_KEYS_ENTRY].cache.copy()[
|
previous_rules_number = sheerka.cache_manager.caches[sheerka.OBJECTS_IDS_ENTRY].cache.copy()[
|
||||||
SheerkaRuleManager.RULE_IDS]
|
SheerkaRuleManager.RULE_IDS]
|
||||||
|
|
||||||
rule = Rule(action_type, "name", "True", "Hello world")
|
rule = Rule(action_type, "name", "True", "Hello world")
|
||||||
|
|||||||
+14
-10
@@ -4,6 +4,7 @@ import pytest
|
|||||||
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept, AllBuiltinConcepts
|
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept, AllBuiltinConcepts
|
||||||
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, ConceptParts, NotInit
|
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, ConceptParts, NotInit
|
||||||
from core.sheerka.Sheerka import Sheerka, BASE_NODE_PARSER_CLASS
|
from core.sheerka.Sheerka import Sheerka, BASE_NODE_PARSER_CLASS
|
||||||
|
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
|
||||||
@@ -342,16 +343,17 @@ class TestSheerkaUsingFileBasedSheerka(TestUsingFileBasedSheerka):
|
|||||||
|
|
||||||
def test_builtin_concepts_are_initialized(self):
|
def test_builtin_concepts_are_initialized(self):
|
||||||
sheerka = self.get_sheerka()
|
sheerka = self.get_sheerka()
|
||||||
|
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||||
for concept_name in AllBuiltinConcepts:
|
for concept_name in AllBuiltinConcepts:
|
||||||
assert sheerka.has_key(str(concept_name))
|
assert service.has_key(str(concept_name))
|
||||||
assert sheerka.sdp.get(sheerka.CONCEPTS_BY_KEY_ENTRY, str(concept_name)) is not None
|
assert sheerka.sdp.get(service.CONCEPTS_BY_KEY_ENTRY, str(concept_name)) is not None
|
||||||
|
|
||||||
# I can get back data from the sdp when the cache is empty
|
# I can get back data from the sdp when the cache is empty
|
||||||
sheerka.cache_manager.clear()
|
sheerka.cache_manager.clear()
|
||||||
|
|
||||||
# caches are empty
|
# caches are empty
|
||||||
assert not sheerka.has_id("1")
|
assert not service.has_id("1")
|
||||||
assert not sheerka.has_key(str(BuiltinConcepts.SHEERKA))
|
assert not service.has_key(str(BuiltinConcepts.SHEERKA))
|
||||||
|
|
||||||
assert sheerka.get_by_id("1") == sheerka # use sdp
|
assert sheerka.get_by_id("1") == sheerka # use sdp
|
||||||
|
|
||||||
@@ -359,11 +361,12 @@ class TestSheerkaUsingFileBasedSheerka(TestUsingFileBasedSheerka):
|
|||||||
|
|
||||||
def test_builtin_concepts_can_be_updated(self):
|
def test_builtin_concepts_can_be_updated(self):
|
||||||
sheerka = self.get_sheerka()
|
sheerka = self.get_sheerka()
|
||||||
|
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||||
before_parsing = sheerka.get_by_key(BuiltinConcepts.BEFORE_PARSING)
|
before_parsing = sheerka.get_by_key(BuiltinConcepts.BEFORE_PARSING)
|
||||||
before_parsing.get_metadata().desc = "I have a description"
|
before_parsing.get_metadata().desc = "I have a description"
|
||||||
before_parsing.get_metadata().full_serialization = True
|
before_parsing.get_metadata().full_serialization = True
|
||||||
with sheerka.sdp.get_transaction("Test") as transac:
|
with sheerka.sdp.get_transaction("Test") as transac:
|
||||||
transac.add(sheerka.CONCEPTS_BY_KEY_ENTRY, before_parsing.key, before_parsing, use_ref=True)
|
transac.add(service.CONCEPTS_BY_KEY_ENTRY, before_parsing.key, before_parsing, use_ref=True)
|
||||||
|
|
||||||
sheerka = self.get_sheerka() # another fresh new instance
|
sheerka = self.get_sheerka() # another fresh new instance
|
||||||
before_parsing = sheerka.get_by_key(BuiltinConcepts.BEFORE_PARSING)
|
before_parsing = sheerka.get_by_key(BuiltinConcepts.BEFORE_PARSING)
|
||||||
@@ -390,11 +393,12 @@ class TestSheerkaUsingFileBasedSheerka(TestUsingFileBasedSheerka):
|
|||||||
|
|
||||||
def test_i_can_retrieve_from_sdp_when_cache_is_reset(self):
|
def test_i_can_retrieve_from_sdp_when_cache_is_reset(self):
|
||||||
sheerka, context, concept = self.init_concepts(Concept("foo", body="1"))
|
sheerka, context, concept = self.init_concepts(Concept("foo", body="1"))
|
||||||
|
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||||
sheerka.cache_manager.commit(context)
|
sheerka.cache_manager.commit(context)
|
||||||
|
|
||||||
sheerka.cache_manager.clear()
|
sheerka.cache_manager.clear()
|
||||||
sheerka.get_by_key("foo")
|
sheerka.get_by_key("foo")
|
||||||
assert sheerka.has_key("foo")
|
assert service.has_key("foo")
|
||||||
|
|
||||||
# It's also updated when sdp returns more than one element
|
# It's also updated when sdp returns more than one element
|
||||||
concept2 = Concept("foo", body="2")
|
concept2 = Concept("foo", body="2")
|
||||||
@@ -403,20 +407,20 @@ class TestSheerkaUsingFileBasedSheerka(TestUsingFileBasedSheerka):
|
|||||||
|
|
||||||
sheerka.cache_manager.clear()
|
sheerka.cache_manager.clear()
|
||||||
assert len(sheerka.get_by_key("foo")) == 2
|
assert len(sheerka.get_by_key("foo")) == 2
|
||||||
assert sheerka.has_key("foo")
|
assert service.has_key("foo")
|
||||||
|
|
||||||
# updated when by_id
|
# updated when by_id
|
||||||
sheerka.cache_manager.clear()
|
sheerka.cache_manager.clear()
|
||||||
assert sheerka.get_by_id("1001") == concept
|
assert sheerka.get_by_id("1001") == concept
|
||||||
assert sheerka.has_id("1001")
|
assert service.has_id("1001")
|
||||||
|
|
||||||
sheerka.cache_manager.clear()
|
sheerka.cache_manager.clear()
|
||||||
assert sheerka.get_by_name("foo") == [concept, concept2]
|
assert sheerka.get_by_name("foo") == [concept, concept2]
|
||||||
assert sheerka.has_name("foo")
|
assert service.has_name("foo")
|
||||||
|
|
||||||
sheerka.cache_manager.clear()
|
sheerka.cache_manager.clear()
|
||||||
assert sheerka.get_by_hash(concept.get_definition_hash()) == concept
|
assert sheerka.get_by_hash(concept.get_definition_hash()) == concept
|
||||||
assert sheerka.has_hash(concept.get_definition_hash())
|
assert service.has_hash(concept.get_definition_hash())
|
||||||
|
|
||||||
def test_get_by_key_retrieve_all_elements(self):
|
def test_get_by_key_retrieve_all_elements(self):
|
||||||
sheerka, context, *concepts = self.init_concepts(
|
sheerka, context, *concepts = self.init_concepts(
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class TestAddConceptInSetEvaluator(TestUsingMemoryBasedSheerka):
|
|||||||
context = self.get_context()
|
context = self.get_context()
|
||||||
foo = Concept("foo")
|
foo = Concept("foo")
|
||||||
context.sheerka.set_id_if_needed(foo, False)
|
context.sheerka.set_id_if_needed(foo, False)
|
||||||
context.sheerka.add_in_cache(foo)
|
context.sheerka.test_only_add_in_cache(foo)
|
||||||
|
|
||||||
ret_val = get_isa_ret_val("foo", "bar")
|
ret_val = get_isa_ret_val("foo", "bar")
|
||||||
res = AddConceptInSetEvaluator().eval(context, ret_val)
|
res = AddConceptInSetEvaluator().eval(context, ret_val)
|
||||||
|
|||||||
@@ -93,10 +93,10 @@ class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
|
|||||||
def test_i_cannot_recognize_a_concept_if_one_of_the_prop_is_unknown(self):
|
def test_i_cannot_recognize_a_concept_if_one_of_the_prop_is_unknown(self):
|
||||||
context = self.get_context()
|
context = self.get_context()
|
||||||
context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED)
|
||||||
context.sheerka.add_in_cache(Concept(name="one").init_key())
|
context.sheerka.test_only_add_in_cache(Concept(name="one").init_key())
|
||||||
concept_plus = context.sheerka.add_in_cache(Concept(name="a plus b")
|
concept_plus = context.sheerka.test_only_add_in_cache(Concept(name="a plus b")
|
||||||
.def_var("a", "one")
|
.def_var("a", "one")
|
||||||
.def_var("b", "two").init_key())
|
.def_var("b", "two").init_key())
|
||||||
|
|
||||||
evaluator = ConceptEvaluator()
|
evaluator = ConceptEvaluator()
|
||||||
item = self.pretval(concept_plus)
|
item = self.pretval(concept_plus)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ 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 Concept, CB
|
from core.concept import Concept, CB
|
||||||
|
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
|
||||||
from core.sheerka.services.SheerkaExecute import ParserInput
|
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||||
from core.tokenizer import Tokenizer
|
from core.tokenizer import Tokenizer
|
||||||
from evaluators.PythonEvaluator import PythonEvaluator, PythonEvalError, NamesWithAttributesVisitor
|
from evaluators.PythonEvaluator import PythonEvaluator, PythonEvalError, NamesWithAttributesVisitor
|
||||||
@@ -18,6 +19,10 @@ def get_obj_name(obj):
|
|||||||
return obj.name
|
return obj.name
|
||||||
|
|
||||||
|
|
||||||
|
def return_return_value(status):
|
||||||
|
return ReturnValueConcept("who", status, f"the value is {status}")
|
||||||
|
|
||||||
|
|
||||||
def get_source_code_node(source_code, concepts=None):
|
def get_source_code_node(source_code, concepts=None):
|
||||||
if concepts:
|
if concepts:
|
||||||
for concept_name, concept in sorted(concepts.items(), key=lambda kv: len(kv[0]), reverse=True):
|
for concept_name, concept in sorted(concepts.items(), key=lambda kv: len(kv[0]), reverse=True):
|
||||||
@@ -132,8 +137,7 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
|
|||||||
evaluated = PythonEvaluator().eval(context, parsed)
|
evaluated = PythonEvaluator().eval(context, parsed)
|
||||||
|
|
||||||
assert evaluated.status
|
assert evaluated.status
|
||||||
assert sheerka.has_key("foo")
|
assert sheerka.services[SheerkaConceptManager.NAME].has_key("foo")
|
||||||
|
|
||||||
|
|
||||||
def test_i_can_eval_ast_expression_that_references_concepts(self):
|
def test_i_can_eval_ast_expression_that_references_concepts(self):
|
||||||
"""
|
"""
|
||||||
@@ -141,7 +145,7 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
context = self.get_context()
|
context = self.get_context()
|
||||||
context.sheerka.add_in_cache(Concept("foo", body="1"))
|
context.sheerka.test_only_add_in_cache(Concept("foo", body="1"))
|
||||||
|
|
||||||
parsed = PythonParser().parse(context, ParserInput("foo + 2"))
|
parsed = PythonParser().parse(context, ParserInput("foo + 2"))
|
||||||
evaluated = PythonEvaluator().eval(context, parsed)
|
evaluated = PythonEvaluator().eval(context, parsed)
|
||||||
@@ -155,7 +159,7 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
context = self.get_context()
|
context = self.get_context()
|
||||||
context.sheerka.add_in_cache(Concept("foo"))
|
context.sheerka.test_only_add_in_cache(Concept("foo"))
|
||||||
|
|
||||||
parsed = PythonParser().parse(context, ParserInput("def a(b):\n return b\na(c:foo:)"))
|
parsed = PythonParser().parse(context, ParserInput("def a(b):\n return b\na(c:foo:)"))
|
||||||
evaluated = PythonEvaluator().eval(context, parsed)
|
evaluated = PythonEvaluator().eval(context, parsed)
|
||||||
@@ -178,7 +182,7 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
def test_i_can_eval_concept_token(self):
|
def test_i_can_eval_concept_token(self):
|
||||||
context = self.get_context()
|
context = self.get_context()
|
||||||
context.sheerka.add_in_cache(Concept("foo", body="2"))
|
context.sheerka.test_only_add_in_cache(Concept("foo", body="2"))
|
||||||
context.add_to_short_term_memory("get_obj_name", get_obj_name)
|
context.add_to_short_term_memory("get_obj_name", get_obj_name)
|
||||||
|
|
||||||
parsed = PythonParser().parse(context, ParserInput("get_obj_name(c:foo:)"))
|
parsed = PythonParser().parse(context, ParserInput("get_obj_name(c:foo:)"))
|
||||||
@@ -190,7 +194,7 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
def test_i_can_eval_when_expect_success(self):
|
def test_i_can_eval_when_expect_success(self):
|
||||||
context = self.get_context()
|
context = self.get_context()
|
||||||
context.sheerka.add_in_cache(Concept("foo", body="2"))
|
context.sheerka.test_only_add_in_cache(Concept("foo", body="2"))
|
||||||
|
|
||||||
parsed = PythonParser().parse(context, ParserInput("foo==2"))
|
parsed = PythonParser().parse(context, ParserInput("foo==2"))
|
||||||
python_evaluator = PythonEvaluator()
|
python_evaluator = PythonEvaluator()
|
||||||
@@ -334,6 +338,23 @@ class TestPythonEvaluator(TestUsingMemoryBasedSheerka):
|
|||||||
assert evaluated.status
|
assert evaluated.status
|
||||||
assert evaluated.value == "Print return values"
|
assert evaluated.value == "Print return values"
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("method, expected_status", [
|
||||||
|
("return_return_value(True)", True),
|
||||||
|
("return_return_value(False)", False),
|
||||||
|
])
|
||||||
|
def test_i_can_eval_a_function_that_returns_a_return_value(self, method, expected_status):
|
||||||
|
context = self.get_context()
|
||||||
|
context.add_to_short_term_memory("return_return_value", return_return_value)
|
||||||
|
|
||||||
|
parsed = FunctionParser().parse(context, ParserInput(method))
|
||||||
|
python_evaluator = PythonEvaluator()
|
||||||
|
evaluated = python_evaluator.eval(context, parsed)
|
||||||
|
ret_val = return_return_value(expected_status)
|
||||||
|
|
||||||
|
assert evaluated.status == expected_status
|
||||||
|
assert evaluated.value == ret_val.body
|
||||||
|
assert ret_val in evaluated.parents
|
||||||
|
|
||||||
@pytest.mark.parametrize("text, expected", [
|
@pytest.mark.parametrize("text, expected", [
|
||||||
("foo.bar.baz", [["foo", "bar", "baz"]]),
|
("foo.bar.baz", [["foo", "bar", "baz"]]),
|
||||||
("foo.bar.baz; one.two.three", [["foo", "bar", "baz"]]),
|
("foo.bar.baz; one.two.three", [["foo", "bar", "baz"]]),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
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, NotInit, CC
|
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, simplec, CMV, NotInit, CC
|
||||||
|
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
|
||||||
@@ -29,7 +30,7 @@ class TestSheerkaNonRegMemory(TestUsingMemoryBasedSheerka):
|
|||||||
def test_i_can_recognize_concept_with_python_body(self):
|
def test_i_can_recognize_concept_with_python_body(self):
|
||||||
sheerka = self.get_sheerka()
|
sheerka = self.get_sheerka()
|
||||||
concept = Concept(name="one", body="1")
|
concept = Concept(name="one", body="1")
|
||||||
sheerka.add_in_cache(concept)
|
sheerka.test_only_add_in_cache(concept)
|
||||||
|
|
||||||
text = "one"
|
text = "one"
|
||||||
res = sheerka.evaluate_user_input(text)
|
res = sheerka.evaluate_user_input(text)
|
||||||
@@ -45,8 +46,8 @@ class TestSheerkaNonRegMemory(TestUsingMemoryBasedSheerka):
|
|||||||
sheerka = self.get_sheerka()
|
sheerka = self.get_sheerka()
|
||||||
concept_one = Concept(name="one")
|
concept_one = Concept(name="one")
|
||||||
concept_un = Concept(name="un", body="one")
|
concept_un = Concept(name="un", body="one")
|
||||||
sheerka.add_in_cache(concept_one)
|
sheerka.test_only_add_in_cache(concept_one)
|
||||||
sheerka.add_in_cache(concept_un)
|
sheerka.test_only_add_in_cache(concept_un)
|
||||||
|
|
||||||
res = sheerka.evaluate_user_input("un")
|
res = sheerka.evaluate_user_input("un")
|
||||||
return_value = res[0].value
|
return_value = res[0].value
|
||||||
@@ -61,7 +62,7 @@ class TestSheerkaNonRegMemory(TestUsingMemoryBasedSheerka):
|
|||||||
def test_i_can_recognize_concept_with_no_body(self):
|
def test_i_can_recognize_concept_with_no_body(self):
|
||||||
sheerka = self.get_sheerka()
|
sheerka = self.get_sheerka()
|
||||||
concept = Concept(name="one")
|
concept = Concept(name="one")
|
||||||
sheerka.add_in_cache(concept)
|
sheerka.test_only_add_in_cache(concept)
|
||||||
|
|
||||||
text = "one"
|
text = "one"
|
||||||
res = sheerka.evaluate_user_input(text)
|
res = sheerka.evaluate_user_input(text)
|
||||||
@@ -73,7 +74,7 @@ class TestSheerkaNonRegMemory(TestUsingMemoryBasedSheerka):
|
|||||||
def test_is_unique_property_is_used_when_evaluating(self):
|
def test_is_unique_property_is_used_when_evaluating(self):
|
||||||
sheerka = self.get_sheerka()
|
sheerka = self.get_sheerka()
|
||||||
concept = Concept(name="one", is_unique=True)
|
concept = Concept(name="one", is_unique=True)
|
||||||
sheerka.add_in_cache(concept)
|
sheerka.test_only_add_in_cache(concept)
|
||||||
|
|
||||||
text = "one"
|
text = "one"
|
||||||
res = sheerka.evaluate_user_input(text)
|
res = sheerka.evaluate_user_input(text)
|
||||||
@@ -113,14 +114,15 @@ as:
|
|||||||
assert getattr(concept_saved.get_metadata(), prop) == getattr(expected.get_metadata(), prop)
|
assert getattr(concept_saved.get_metadata(), prop) == getattr(expected.get_metadata(), prop)
|
||||||
|
|
||||||
# cache is up to date
|
# cache is up to date
|
||||||
assert sheerka.has_key(concept_saved.key)
|
service = sheerka.services[SheerkaConceptManager.NAME]
|
||||||
assert sheerka.has_id(concept_saved.id)
|
assert service.has_key(concept_saved.key)
|
||||||
assert sheerka.has_name(concept_saved.name)
|
assert service.has_id(concept_saved.id)
|
||||||
assert sheerka.has_hash(concept_saved.get_definition_hash())
|
assert service.has_name(concept_saved.name)
|
||||||
|
assert service.has_hash(concept_saved.get_definition_hash())
|
||||||
assert sheerka.cache_manager.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {'+': ['1001']}
|
assert sheerka.cache_manager.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {'+': ['1001']}
|
||||||
|
|
||||||
# sdp is up to date
|
# sdp is up to date
|
||||||
assert sheerka.sdp.exists(sheerka.CONCEPTS_BY_KEY_ENTRY, expected.key)
|
assert sheerka.sdp.exists(SheerkaConceptManager.CONCEPTS_BY_KEY_ENTRY, expected.key)
|
||||||
|
|
||||||
def test_i_can_evaluate_def_concept_part_when_one_part_is_a_ref_of_another_concept(self):
|
def test_i_can_evaluate_def_concept_part_when_one_part_is_a_ref_of_another_concept(self):
|
||||||
"""
|
"""
|
||||||
@@ -132,7 +134,7 @@ as:
|
|||||||
|
|
||||||
# concept 'a plus b' is known
|
# concept 'a plus b' is known
|
||||||
concept_a_plus_b = Concept(name="a plus b").def_var("a").def_var("b").init_key()
|
concept_a_plus_b = Concept(name="a plus b").def_var("a").def_var("b").init_key()
|
||||||
sheerka.add_in_cache(concept_a_plus_b)
|
sheerka.test_only_add_in_cache(concept_a_plus_b)
|
||||||
|
|
||||||
res = sheerka.evaluate_user_input("def concept a xx b as a plus b")
|
res = sheerka.evaluate_user_input("def concept a xx b as a plus b")
|
||||||
expected = Concept(name="a xx b", body="a plus b").def_var("a").def_var("b").init_key()
|
expected = Concept(name="a xx b", body="a plus b").def_var("a").def_var("b").init_key()
|
||||||
@@ -147,7 +149,7 @@ as:
|
|||||||
for prop in PROPERTIES_TO_SERIALIZE:
|
for prop in PROPERTIES_TO_SERIALIZE:
|
||||||
assert getattr(concept_saved.get_metadata(), prop) == getattr(expected.get_metadata(), prop)
|
assert getattr(concept_saved.get_metadata(), prop) == getattr(expected.get_metadata(), prop)
|
||||||
|
|
||||||
assert sheerka.has_key(concept_saved.key)
|
assert sheerka.services[SheerkaConceptManager.NAME].has_key(concept_saved.key)
|
||||||
|
|
||||||
def test_i_cannot_evaluate_the_same_def_concept_twice(self):
|
def test_i_cannot_evaluate_the_same_def_concept_twice(self):
|
||||||
text = """
|
text = """
|
||||||
@@ -201,8 +203,8 @@ as:
|
|||||||
|
|
||||||
def test_i_can_recognize_concept_with_variable_and_python_as_body(self):
|
def test_i_can_recognize_concept_with_variable_and_python_as_body(self):
|
||||||
sheerka = self.get_sheerka()
|
sheerka = self.get_sheerka()
|
||||||
hello_a = sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").def_var("a"))
|
hello_a = sheerka.test_only_add_in_cache(Concept(name="hello a", body="'hello ' + a").def_var("a"))
|
||||||
sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
|
sheerka.test_only_add_in_cache(Concept(name="foo", body="'foo'"))
|
||||||
|
|
||||||
res = sheerka.evaluate_user_input("hello foo")
|
res = sheerka.evaluate_user_input("hello foo")
|
||||||
assert len(res) == 1
|
assert len(res) == 1
|
||||||
@@ -600,7 +602,7 @@ as:
|
|||||||
])
|
])
|
||||||
def test_i_can_manage_tokenizer_error(self, text):
|
def test_i_can_manage_tokenizer_error(self, text):
|
||||||
sheerka = self.get_sheerka()
|
sheerka = self.get_sheerka()
|
||||||
sheerka.add_in_cache(Concept("foo"))
|
sheerka.test_only_add_in_cache(Concept("foo"))
|
||||||
|
|
||||||
res = sheerka.evaluate_user_input(text)
|
res = sheerka.evaluate_user_input(text)
|
||||||
|
|
||||||
@@ -610,7 +612,7 @@ as:
|
|||||||
|
|
||||||
def test_i_can_recognize_concept_from_string(self):
|
def test_i_can_recognize_concept_from_string(self):
|
||||||
sheerka = self.get_sheerka()
|
sheerka = self.get_sheerka()
|
||||||
sheerka.add_in_cache(Concept("one", body="1"))
|
sheerka.test_only_add_in_cache(Concept("one", body="1"))
|
||||||
|
|
||||||
res = sheerka.evaluate_user_input("'one'")
|
res = sheerka.evaluate_user_input("'one'")
|
||||||
|
|
||||||
@@ -792,7 +794,7 @@ as:
|
|||||||
|
|
||||||
sheerka = self.init_scenario(definitions)
|
sheerka = self.init_scenario(definitions)
|
||||||
context = self.get_context(sheerka)
|
context = self.get_context(sheerka)
|
||||||
sheerka.force_sya_def(context, [
|
sheerka.test_only_force_sya_def(context, [
|
||||||
(sheerka.get_by_name("mult").id, 20, SyaAssociativity.Right),
|
(sheerka.get_by_name("mult").id, 20, SyaAssociativity.Right),
|
||||||
(sheerka.get_by_name("plus").id, 10, SyaAssociativity.Right),
|
(sheerka.get_by_name("plus").id, 10, SyaAssociativity.Right),
|
||||||
])
|
])
|
||||||
@@ -954,7 +956,7 @@ as:
|
|||||||
|
|
||||||
# simulate that sheerka was stopped and restarted
|
# simulate that sheerka was stopped and restarted
|
||||||
sheerka.cache_manager.clear(sheerka.CONCEPTS_GRAMMARS_ENTRY)
|
sheerka.cache_manager.clear(sheerka.CONCEPTS_GRAMMARS_ENTRY)
|
||||||
sheerka.cache_manager.get(sheerka.CONCEPTS_BY_KEY_ENTRY, "twenties").set_compiled({})
|
sheerka.cache_manager.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")
|
||||||
assert res[0].status
|
assert res[0].status
|
||||||
@@ -971,6 +973,7 @@ as:
|
|||||||
res = sheerka.evaluate_user_input("set_isa(last_created_concept(), number)")
|
res = sheerka.evaluate_user_input("set_isa(last_created_concept(), number)")
|
||||||
|
|
||||||
assert res[0].status
|
assert res[0].status
|
||||||
|
assert sheerka.isinstance(res[0].body, BuiltinConcepts.SUCCESS)
|
||||||
assert sheerka.isa(sheerka.new("one"), sheerka.new("number"))
|
assert sheerka.isa(sheerka.new("one"), sheerka.new("number"))
|
||||||
|
|
||||||
def test_i_can_evaluate_sya_and_ret_concepts(self):
|
def test_i_can_evaluate_sya_and_ret_concepts(self):
|
||||||
@@ -1219,7 +1222,7 @@ class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
|
|||||||
assert res[0].status
|
assert res[0].status
|
||||||
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
|
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
|
||||||
|
|
||||||
saved_concept = sheerka.sdp.get(sheerka.CONCEPTS_BY_KEY_ENTRY, "plus")
|
saved_concept = sheerka.sdp.get(SheerkaConceptManager.CONCEPTS_BY_KEY_ENTRY, "plus")
|
||||||
assert saved_concept.key == "plus"
|
assert saved_concept.key == "plus"
|
||||||
assert saved_concept.get_metadata().definition == "a ('plus' plus)?"
|
assert saved_concept.get_metadata().definition == "a ('plus' plus)?"
|
||||||
assert "a" in saved_concept.values()
|
assert "a" in saved_concept.values()
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class TestBaseNodeParser(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
bar = Concept("bar").init_key()
|
bar = Concept("bar").init_key()
|
||||||
sheerka.set_id_if_needed(bar, False)
|
sheerka.set_id_if_needed(bar, False)
|
||||||
sheerka.add_in_cache(bar)
|
sheerka.test_only_add_in_cache(bar)
|
||||||
|
|
||||||
concept = Concept("foo").init_key()
|
concept = Concept("foo").init_key()
|
||||||
concept.set_bnf(bnf)
|
concept.set_bnf(bnf)
|
||||||
@@ -65,11 +65,11 @@ class TestBaseNodeParser(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
bar = Concept("bar").init_key()
|
bar = Concept("bar").init_key()
|
||||||
sheerka.set_id_if_needed(bar, False)
|
sheerka.set_id_if_needed(bar, False)
|
||||||
sheerka.add_in_cache(bar)
|
sheerka.test_only_add_in_cache(bar)
|
||||||
|
|
||||||
baz = Concept("baz").init_key()
|
baz = Concept("baz").init_key()
|
||||||
sheerka.set_id_if_needed(baz, False)
|
sheerka.set_id_if_needed(baz, False)
|
||||||
sheerka.add_in_cache(baz)
|
sheerka.test_only_add_in_cache(baz)
|
||||||
|
|
||||||
foo = Concept("foo").init_key()
|
foo = Concept("foo").init_key()
|
||||||
foo.set_bnf(OrderedChoice(ConceptExpression("bar"), ConceptExpression("baz"), StrMatch("qux")))
|
foo.set_bnf(OrderedChoice(ConceptExpression("bar"), ConceptExpression("baz"), StrMatch("qux")))
|
||||||
@@ -96,7 +96,7 @@ class TestBaseNodeParser(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
bar = Concept("bar").init_key()
|
bar = Concept("bar").init_key()
|
||||||
sheerka.set_id_if_needed(bar, False)
|
sheerka.set_id_if_needed(bar, False)
|
||||||
sheerka.add_in_cache(bar)
|
sheerka.test_only_add_in_cache(bar)
|
||||||
|
|
||||||
foo = Concept("foo").init_key()
|
foo = Concept("foo").init_key()
|
||||||
foo.set_bnf(OrderedChoice(ConceptExpression("one"), ConceptExpression("bar"), StrMatch("qux")))
|
foo.set_bnf(OrderedChoice(ConceptExpression("one"), ConceptExpression("bar"), StrMatch("qux")))
|
||||||
|
|||||||
@@ -503,6 +503,15 @@ from give me the date !
|
|||||||
assert context.sheerka.isinstance(res.value, BuiltinConcepts.UNKNOWN_CONCEPT)
|
assert context.sheerka.isinstance(res.value, BuiltinConcepts.UNKNOWN_CONCEPT)
|
||||||
assert res.value.body == ("key", "unknown")
|
assert res.value.body == ("key", "unknown")
|
||||||
|
|
||||||
|
def test_i_cannot_parse_bnf_definition_referencing_multiple_concepts_sharing_the_same_name(self):
|
||||||
|
text = "def concept twenty one from bnf 'twenty' one"
|
||||||
|
sheerka, context, parser, *concepts = self.init_parser(Concept("one", body="1"), Concept("one", body="1.0"))
|
||||||
|
res = parser.parse(context, ParserInput(text))
|
||||||
|
|
||||||
|
assert not res.status
|
||||||
|
assert context.sheerka.isinstance(res.value, BuiltinConcepts.CANNOT_RESOLVE_CONCEPT)
|
||||||
|
assert res.value.body == ("key", "one")
|
||||||
|
|
||||||
@pytest.mark.parametrize("text", [
|
@pytest.mark.parametrize("text", [
|
||||||
'def concept "def concept x"',
|
'def concept "def concept x"',
|
||||||
'def concept "def concept x" as x',
|
'def concept "def concept x" as x',
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ class TestExactConceptParser(TestUsingMemoryBasedSheerka):
|
|||||||
# def test_i_can_detect_concept_from_tokens(self):
|
# def test_i_can_detect_concept_from_tokens(self):
|
||||||
# context = self.get_context(self.get_sheerka(singleton=True))
|
# context = self.get_context(self.get_sheerka(singleton=True))
|
||||||
# concept = get_concept("hello world", [])
|
# concept = get_concept("hello world", [])
|
||||||
# context.sheerka.add_in_cache(concept)
|
# context.sheerka.test_only_add_in_cache(concept)
|
||||||
#
|
#
|
||||||
# source = "hello world"
|
# source = "hello world"
|
||||||
# results = ExactConceptParser().parse(context, list(Tokenizer(source)))
|
# results = ExactConceptParser().parse(context, list(Tokenizer(source)))
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class TestSyaNodeParser(TestUsingMemoryBasedSheerka):
|
|||||||
cmap["minus"],
|
cmap["minus"],
|
||||||
CONCEPT_COMPARISON_CONTEXT)
|
CONCEPT_COMPARISON_CONTEXT)
|
||||||
|
|
||||||
# TestSyaNodeParser.sheerka.force_sya_def(context, [
|
# TestSyaNodeParser.sheerka.test_only_force_sya_def(context, [
|
||||||
# (cmap["plus"].id, 5, SyaAssociativity.Right),
|
# (cmap["plus"].id, 5, SyaAssociativity.Right),
|
||||||
# (cmap["mult"].id, 10, SyaAssociativity.Right),
|
# (cmap["mult"].id, 10, SyaAssociativity.Right),
|
||||||
# (cmap["minus"].id, 5, SyaAssociativity.Right)])
|
# (cmap["minus"].id, 5, SyaAssociativity.Right)])
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class TestUnrecognizedNodeParser(TestUsingMemoryBasedSheerka):
|
|||||||
def setup_class(cls):
|
def setup_class(cls):
|
||||||
t = TestUnrecognizedNodeParser()
|
t = TestUnrecognizedNodeParser()
|
||||||
TestUnrecognizedNodeParser.sheerka, context, _ = t.init_parser(concepts_map, create_new=True)
|
TestUnrecognizedNodeParser.sheerka, context, _ = t.init_parser(concepts_map, create_new=True)
|
||||||
TestUnrecognizedNodeParser.sheerka.force_sya_def(context, [
|
TestUnrecognizedNodeParser.sheerka.test_only_force_sya_def(context, [
|
||||||
(concepts_map["mult"].id, 20, SyaAssociativity.Right),
|
(concepts_map["mult"].id, 20, SyaAssociativity.Right),
|
||||||
(concepts_map["plus"].id, 10, SyaAssociativity.Right),
|
(concepts_map["plus"].id, 10, SyaAssociativity.Right),
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class TestSheerkaPickler(TestUsingMemoryBasedSheerka):
|
|||||||
|
|
||||||
concept = Concept("foo").init_key()
|
concept = Concept("foo").init_key()
|
||||||
sheerka.set_id_if_needed(concept, False)
|
sheerka.set_id_if_needed(concept, False)
|
||||||
sheerka.add_in_cache(concept)
|
sheerka.test_only_add_in_cache(concept)
|
||||||
obj = {concept: "a"}
|
obj = {concept: "a"}
|
||||||
flatten = SheerkaPickler(sheerka).flatten(obj)
|
flatten = SheerkaPickler(sheerka).flatten(obj)
|
||||||
assert flatten == {'c:foo|1001:': 'a'}
|
assert flatten == {'c:foo|1001:': 'a'}
|
||||||
|
|||||||
Reference in New Issue
Block a user