Initialized logging
This commit is contained in:
+93
-27
@@ -1,10 +1,14 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from core.concept import Concept, ErrorConcept
|
||||
from parsers.PythonParser import PythonParser
|
||||
from core.concept import Concept, ErrorConcept, Property
|
||||
from parsers.PythonParser import PythonParser, PythonGetNamesVisitor, PythonNode
|
||||
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event
|
||||
from parsers.DefaultParser import DefaultParser, DefConceptNode
|
||||
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Singleton(type):
|
||||
_instances = {}
|
||||
@@ -27,6 +31,14 @@ class ReturnValue:
|
||||
message: str = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class ExecutionContext:
|
||||
"""
|
||||
To keep track of the execution of a request
|
||||
"""
|
||||
event_digest: str
|
||||
|
||||
|
||||
class Sheerka(Concept, metaclass=Singleton):
|
||||
"""
|
||||
Main controller for the project
|
||||
@@ -37,11 +49,16 @@ class Sheerka(Concept, metaclass=Singleton):
|
||||
ERROR_CONCEPT_NAME = "Error"
|
||||
SUCCESS_CONCEPT_NAME = "Success"
|
||||
|
||||
CONCEPTS_ENTRY = "Concepts"
|
||||
BUILTIN_CONCEPTS_KEYS = "Builtins"
|
||||
USER_CONCEPTS_KEYS = "Concepts"
|
||||
|
||||
def __init__(self):
|
||||
log.debug("Starting Sheerka.")
|
||||
super().__init__(Sheerka.NAME)
|
||||
|
||||
# list of all concepts known be the system
|
||||
self.concepts = []
|
||||
# cache of the most used concepts
|
||||
self.concepts_cache = []
|
||||
|
||||
# a concept can be instantiated
|
||||
# ex: File is a concept, but File('foo.txt') is an instance
|
||||
@@ -52,20 +69,10 @@ class Sheerka(Concept, metaclass=Singleton):
|
||||
# ex: hello => say('hello')
|
||||
self.rules = []
|
||||
|
||||
self.create_builtin_concepts()
|
||||
|
||||
self.sdp = None
|
||||
self.parsers = []
|
||||
|
||||
def create_builtin_concepts(self):
|
||||
"""
|
||||
Initializes the builtin concepts
|
||||
:return: None
|
||||
"""
|
||||
self.concepts.append(self)
|
||||
self.concepts.append(Concept(Sheerka.UNKNOWN_CONCEPT_NAME))
|
||||
self.concepts.append(Concept(Sheerka.SUCCESS_CONCEPT_NAME))
|
||||
self.concepts.append(Concept(Sheerka.ERROR_CONCEPT_NAME))
|
||||
self.key = self.NAME
|
||||
|
||||
def initialize(self, root_folder=None):
|
||||
"""
|
||||
@@ -79,13 +86,54 @@ class Sheerka(Concept, metaclass=Singleton):
|
||||
try:
|
||||
self.sdp = SheerkaDataProvider(root_folder)
|
||||
self.parsers.append(lambda text: DefaultParser(text, PythonParser))
|
||||
except IOError as e:
|
||||
return ReturnValue(False, self.get_concept(Sheerka.ERROR_CONCEPT_NAME, True), e)
|
||||
|
||||
return ReturnValue(True, self.get_concept(Sheerka.SUCCESS_CONCEPT_NAME, True))
|
||||
if self.sdp.first_time:
|
||||
self.sdp.set_key(self.USER_CONCEPTS_KEYS, 1000)
|
||||
|
||||
self.create_builtin_concepts()
|
||||
except IOError as e:
|
||||
return ReturnValue(False, self.get_concept(Sheerka.ERROR_CONCEPT_NAME), e)
|
||||
|
||||
return ReturnValue(True, self.get_concept(Sheerka.SUCCESS_CONCEPT_NAME))
|
||||
|
||||
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 create_builtin_concepts(self):
|
||||
"""
|
||||
Initializes the builtin concepts
|
||||
:return: None
|
||||
"""
|
||||
log.debug("Initializing builtin concepts")
|
||||
builtins = [
|
||||
self,
|
||||
Concept(Sheerka.UNKNOWN_CONCEPT_NAME, key=Sheerka.UNKNOWN_CONCEPT_NAME),
|
||||
Concept(Sheerka.SUCCESS_CONCEPT_NAME, key=Sheerka.SUCCESS_CONCEPT_NAME),
|
||||
Concept(Sheerka.ERROR_CONCEPT_NAME, key=Sheerka.ERROR_CONCEPT_NAME),
|
||||
]
|
||||
|
||||
for concept in builtins:
|
||||
from_db = self.sdp.get_safe(self.CONCEPTS_ENTRY, concept.name)
|
||||
if from_db is None:
|
||||
log.debug(f"'{concept.name}' concept is not found. Adding.")
|
||||
self.set_id_if_needed(concept, True)
|
||||
self.sdp.add("init", self.CONCEPTS_ENTRY, concept, use_ref=True)
|
||||
else:
|
||||
log.debug(f"Found concept '{from_db}'. Updating.")
|
||||
concept.update_from(from_db)
|
||||
|
||||
def eval(self, text):
|
||||
# evt_digest = self.sdp.save_event(Event(text))
|
||||
evt_digest = self.sdp.save_event(Event(text))
|
||||
exec_context = ExecutionContext(evt_digest)
|
||||
result = self.try_parse(text)
|
||||
|
||||
return_values = []
|
||||
@@ -93,12 +141,13 @@ class Sheerka(Concept, metaclass=Singleton):
|
||||
if not status:
|
||||
return_values.append(ReturnValue(False, ErrorConcept(body=node)))
|
||||
elif status and isinstance(node, DefConceptNode):
|
||||
return_values.append(self.add_concept(node))
|
||||
return_values.append(self.add_concept(exec_context, node))
|
||||
|
||||
return return_values
|
||||
|
||||
def try_parse(self, text):
|
||||
result = []
|
||||
log.debug(f"Parsing '{text}'")
|
||||
for parser in self.parsers:
|
||||
p = parser(text)
|
||||
# try:
|
||||
@@ -110,32 +159,49 @@ class Sheerka(Concept, metaclass=Singleton):
|
||||
result.append((p.name, not p.has_error, p.error_sink if p.has_error else tree))
|
||||
return result
|
||||
|
||||
def get_concept(self, name, is_builtin=False):
|
||||
def get_concept(self, name):
|
||||
"""
|
||||
Given a concept name, tries to find it
|
||||
:param name: name of the concept to look for
|
||||
:param is_builtin: is it a builtin concept ?
|
||||
:return: concept if found, UNKNOWN_CONCEPT otherwise
|
||||
"""
|
||||
for concept in self.concepts:
|
||||
if concept.name == name and concept.is_builtin == is_builtin:
|
||||
for concept in self.concepts_cache:
|
||||
if concept.name == name:
|
||||
return concept
|
||||
return self.concepts[1]
|
||||
return ErrorConcept()
|
||||
|
||||
def add_concept(self, def_concept_node: DefConceptNode):
|
||||
def add_concept(self, exec_context, def_concept_node: DefConceptNode):
|
||||
"""
|
||||
Adds a new concept to the system
|
||||
:param exec_context:
|
||||
:param def_concept_node: DefConceptNode
|
||||
:return: digest of the new concept
|
||||
"""
|
||||
|
||||
# validate the node
|
||||
get_names_visitor = PythonGetNamesVisitor()
|
||||
|
||||
concept = Concept(def_concept_node.name)
|
||||
for prop in ("where", "pre", "post", "body"):
|
||||
# put back the sources
|
||||
concept_part_node = getattr(def_concept_node, prop)
|
||||
value = concept_part_node.source if hasattr(concept_part_node, "source") else ""
|
||||
setattr(concept, prop, value)
|
||||
if isinstance(concept_part_node, PythonNode):
|
||||
get_names_visitor.visit(concept_part_node.ast)
|
||||
source = concept_part_node.source if hasattr(concept_part_node, "source") else ""
|
||||
setattr(concept, prop, source)
|
||||
|
||||
# try to find variables (eg props)
|
||||
for token in def_concept_node.tokens["name"]:
|
||||
if token.value in get_names_visitor.names:
|
||||
concept.props.append(Property(token.value, None))
|
||||
|
||||
concept.key = DefaultParser.get_concept_name(def_concept_node.tokens["name"], [p.name for p in concept.props])
|
||||
concept.add_codes(def_concept_node.get_codes())
|
||||
self.set_id_if_needed(concept, False)
|
||||
|
||||
self.sdp.add(exec_context.event_digest, self.CONCEPTS_ENTRY, concept, use_ref=True)
|
||||
|
||||
return ReturnValue(True, concept)
|
||||
|
||||
@staticmethod
|
||||
|
||||
Reference in New Issue
Block a user