Refactord Concept class to regroup all builtins properties into a ConceptMetadata class
This commit is contained in:
+48
-51
@@ -1,6 +1,6 @@
|
||||
from dataclasses import dataclass
|
||||
from core.builtin_concepts import BuiltinConcepts, ErrorConcept, ReturnValueConcept
|
||||
from core.concept import Concept, ConceptParts
|
||||
from core.concept import Concept, ConceptParts, PROPERTIES_FOR_DIGEST
|
||||
from evaluators.BaseEvaluator import OneReturnValueEvaluator
|
||||
from parsers.BaseParser import BaseParser
|
||||
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event, SheerkaDataProviderDuplicateKeyError
|
||||
@@ -55,7 +55,7 @@ class Sheerka(Concept):
|
||||
self.debug = debug
|
||||
self.skip_builtins_in_db = skip_builtins_in_db
|
||||
|
||||
def initialize(self, root_folder=None):
|
||||
def initialize(self, root_folder: str = None):
|
||||
"""
|
||||
Starting Sheerka
|
||||
Loads the current configuration
|
||||
@@ -80,18 +80,6 @@ class Sheerka(Concept):
|
||||
|
||||
return ReturnValueConcept(self, True, self)
|
||||
|
||||
def set_id_if_needed(self, obj, is_builtin):
|
||||
"""
|
||||
Set the key for the concept if needed
|
||||
:param obj:
|
||||
:param is_builtin:
|
||||
:return:
|
||||
"""
|
||||
if obj.id is not None:
|
||||
return
|
||||
obj.id = self.sdp.get_next_key(self.BUILTIN_CONCEPTS_KEYS if is_builtin else self.USER_CONCEPTS_KEYS)
|
||||
log.debug(f"Setting id '{obj.id}' to concept '{obj.name}'.")
|
||||
|
||||
def initialize_builtin_concepts(self):
|
||||
"""
|
||||
Initializes the builtin concepts
|
||||
@@ -107,11 +95,11 @@ class Sheerka(Concept):
|
||||
else builtins_classes[str(key)]() if str(key) in builtins_classes \
|
||||
else Concept(key, True, False, key)
|
||||
|
||||
if not concept.is_unique and str(key) in builtins_classes:
|
||||
if not concept.metadata.is_unique and str(key) in builtins_classes:
|
||||
self.builtin_cache[key] = builtins_classes[str(key)]
|
||||
|
||||
if not self.skip_builtins_in_db:
|
||||
from_db = self.sdp.get_safe(self.CONCEPTS_ENTRY, concept.key)
|
||||
from_db = self.sdp.get_safe(self.CONCEPTS_ENTRY, concept.metadata.key)
|
||||
if from_db is None:
|
||||
log.debug(f"'{concept.name}' concept is not found in db. Adding.")
|
||||
self.set_id_if_needed(concept, True)
|
||||
@@ -158,7 +146,7 @@ class Sheerka(Concept):
|
||||
|
||||
logging.basicConfig(format=log_format, level=log_level)
|
||||
|
||||
def eval(self, text):
|
||||
def eval(self, text: str):
|
||||
"""
|
||||
Note to KSI: If you try to add execution context to this function,
|
||||
You may end in an infinite loop
|
||||
@@ -294,7 +282,19 @@ class Sheerka(Concept):
|
||||
|
||||
return return_values
|
||||
|
||||
def create_new_concept(self, context, concept):
|
||||
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
|
||||
obj.metadata.id = self.sdp.get_next_key(self.BUILTIN_CONCEPTS_KEYS if is_builtin else self.USER_CONCEPTS_KEYS)
|
||||
log.debug(f"Setting id '{obj.metadata.id}' to concept '{obj.metadata.name}'.")
|
||||
|
||||
def create_new_concept(self, context, concept: Concept):
|
||||
"""
|
||||
Adds a new concept to the system
|
||||
:param context:
|
||||
@@ -325,7 +325,7 @@ class Sheerka(Concept):
|
||||
ret = self.ret(self.create_new_concept.__name__, True, self.new(BuiltinConcepts.NEW_CONCEPT, body=concept))
|
||||
return ret
|
||||
|
||||
def add_codes_to_concept(self, context, concept):
|
||||
def initialize_concept_asts(self, context, concept: Concept):
|
||||
"""
|
||||
Updates the codes of the newly created concept
|
||||
Basically, it runs the parsers on all parts
|
||||
@@ -334,16 +334,16 @@ class Sheerka(Concept):
|
||||
:return:
|
||||
"""
|
||||
for part_key in ConceptParts:
|
||||
source = getattr(concept, part_key.value)
|
||||
source = getattr(concept.metadata, part_key.value)
|
||||
if source is None or not isinstance(source, str) or source == "":
|
||||
# the only sources that I am sure to parse are strings
|
||||
# I refuse empty strings for performance, I don't want to handle useless NOPConcepts
|
||||
continue
|
||||
else:
|
||||
concept.codes[part_key] = self.parse(context, source)
|
||||
concept.cached_asts[part_key] = self.parse(context, source)
|
||||
|
||||
for prop in concept.props:
|
||||
concept.codes[prop] = self.parse(context, concept.props[prop].value)
|
||||
concept.cached_asts[prop] = self.parse(context, concept.props[prop].value)
|
||||
|
||||
# updates the code of the reference when possible
|
||||
if concept.key in self.concepts_cache:
|
||||
@@ -352,11 +352,20 @@ class Sheerka(Concept):
|
||||
# TODO : manage when there are multiple entries
|
||||
pass
|
||||
else:
|
||||
self.concepts_cache[concept.key].codes = concept.codes
|
||||
self.concepts_cache[concept.key].cached_asts = concept.cached_asts
|
||||
|
||||
def eval_concept(self, context, concept, properties_to_eval=None):
|
||||
if len(concept.codes) == 0:
|
||||
self.add_codes_to_concept(context, concept)
|
||||
def eval_concept(self, context, concept: Concept, properties_to_eval=None):
|
||||
"""
|
||||
Evaluation a concept
|
||||
It means that if the where clause is True, will evaluate the body
|
||||
Also chc
|
||||
:param context:
|
||||
:param concept:
|
||||
:param properties_to_eval:
|
||||
:return:
|
||||
"""
|
||||
if len(concept.cached_asts) == 0:
|
||||
self.initialize_concept_asts(context, concept)
|
||||
|
||||
if properties_to_eval is None:
|
||||
properties_to_eval = ["where", "pre", "post", "body", "props"]
|
||||
@@ -366,13 +375,13 @@ class Sheerka(Concept):
|
||||
pass
|
||||
else:
|
||||
part_key = ConceptParts(prop)
|
||||
if concept.codes[part_key] is None:
|
||||
if concept.cached_asts[part_key] is None:
|
||||
continue
|
||||
res = self.chain_process(context, concept.codes[part_key], concept_evaluation_steps)
|
||||
res = self.chain_process(context, concept.cached_asts[part_key], concept_evaluation_steps)
|
||||
res = core.builtin_helpers.expect_one(context, res)
|
||||
setattr(concept, prop, res.value)
|
||||
setattr(concept.metadata, prop, res.value)
|
||||
|
||||
def add_in_cache(self, concept):
|
||||
def add_in_cache(self, concept: Concept):
|
||||
"""
|
||||
Adds a concept template in cache.
|
||||
The cache is used as a proxy before looking at sdp
|
||||
@@ -416,7 +425,7 @@ class Sheerka(Concept):
|
||||
unknown_concept = Concept()
|
||||
template = self.concepts_cache[str(BuiltinConcepts.UNKNOWN_CONCEPT)]
|
||||
unknown_concept.update_from(template)
|
||||
unknown_concept.body = concept_key
|
||||
unknown_concept.metadata.body = concept_key
|
||||
return unknown_concept
|
||||
|
||||
def new(self, concept_key, **kwargs):
|
||||
@@ -431,7 +440,7 @@ class Sheerka(Concept):
|
||||
|
||||
def new_from_template(t, k, **kwargs_):
|
||||
# manage singleton
|
||||
if t.is_unique:
|
||||
if t.metadata.is_unique:
|
||||
return t
|
||||
|
||||
# otherwise, create another instance
|
||||
@@ -442,6 +451,8 @@ class Sheerka(Concept):
|
||||
for k, v in kwargs_.items():
|
||||
if k in concept.props:
|
||||
concept.set_prop(k, v)
|
||||
elif k in PROPERTIES_FOR_DIGEST:
|
||||
setattr(concept.metadata, k, v)
|
||||
elif hasattr(concept, k):
|
||||
setattr(concept, k, v)
|
||||
else:
|
||||
@@ -462,7 +473,7 @@ class Sheerka(Concept):
|
||||
concepts = [new_from_template(t, concept_key, **kwargs) for t in template]
|
||||
return self.new(BuiltinConcepts.ENUMERATION, body=concepts)
|
||||
|
||||
def ret(self, who, status, value, message=None, parents=None):
|
||||
def ret(self, who: str, status: bool, value, message=None, parents=None):
|
||||
"""
|
||||
Creates and returns a ReturnValue concept
|
||||
:param who:
|
||||
@@ -569,32 +580,18 @@ class Sheerka(Concept):
|
||||
|
||||
return sorted(res, key=lambda i: int(i.id))
|
||||
|
||||
def test(self):
|
||||
return f"I have access to Sheerka !"
|
||||
|
||||
@staticmethod
|
||||
def get_builtins_classes_as_dict():
|
||||
res = {}
|
||||
for c in core.utils.get_classes("core.builtin_concepts"):
|
||||
if issubclass(c, Concept) and c != Concept:
|
||||
res[c().key] = c
|
||||
res[c().metadata.key] = c
|
||||
|
||||
return res
|
||||
|
||||
@staticmethod
|
||||
def get_builtin_parsers():
|
||||
res = []
|
||||
# modules = core.utils.get_module("parsers")
|
||||
# for m in modules:
|
||||
base_class = core.utils.get_class("parsers.BaseParser.BaseParser")
|
||||
|
||||
for c in core.utils.get_classes_recursive("parsers"):
|
||||
# if issubclass(c, base_class) and c != base_class:
|
||||
res.append(c)
|
||||
|
||||
return res
|
||||
|
||||
@staticmethod
|
||||
def test():
|
||||
return "I have access to Sheerka !"
|
||||
|
||||
|
||||
@dataclass
|
||||
class ExecutionContext:
|
||||
|
||||
Reference in New Issue
Block a user