Improved PyhtonEvaluator in order to use methods that need context

This commit is contained in:
2020-05-18 22:35:59 +02:00
parent c822ff6a7f
commit 95dc147bbd
14 changed files with 187 additions and 74 deletions
+64 -47
View File
@@ -1,3 +1,4 @@
import inspect
import logging
import core.builtin_helpers
@@ -76,6 +77,12 @@ class Sheerka(Concept):
self.save_execution_context = True
self.methods_with_context = {"test_using_context"}
self.sheerka_methods = {
"test": self.test,
"test_using_context": self.test_using_context
}
@property
def resolved_concepts_by_first_keyword(self):
"""
@@ -96,18 +103,21 @@ class Sheerka(Concept):
def concepts_grammars(self):
return self.cache_manager.caches[self.CONCEPTS_GRAMMARS_ENTRY].cache
def bind_service_method(self, instance, method, as_name=None):
def bind_service_method(self, bound_method, as_name=None):
"""
Bind service method to sheerka instance for ease to use
:param instance:
:param method:
Bind service method to sheerka instance for ease of use ?
:param bound_method:
:param as_name:
:return:
"""
if as_name is None:
as_name = method.__name__
as_name = bound_method.__name__
signature = inspect.signature(bound_method)
if len(signature.parameters) > 0 and list(signature.parameters.keys())[0] == "context":
self.methods_with_context.add(as_name)
self.sheerka_methods[as_name] = bound_method
bound_method = method.__get__(instance, instance.__class__)
setattr(self, as_name, bound_method)
def initialize(self, root_folder: str = None, save_execution_context=True):
@@ -198,11 +208,6 @@ class Sheerka(Concept):
cache = Cache()
self.cache_manager.register_cache(self.CONCEPTS_GRAMMARS_ENTRY, cache, persist=False)
def first_time_initialisation(self, context):
self.cache_manager.put(self.CONCEPTS_KEYS_ENTRY, self.USER_CONCEPTS_KEYS, 1000)
self.record(context, self.name, "save_execution_context", True)
def initialize_services(self):
"""
Introspect to find services and bind them
@@ -218,6 +223,11 @@ class Sheerka(Concept):
instance.initialize()
self.services[service.NAME] = instance
def first_time_initialisation(self, context):
self.cache_manager.put(self.CONCEPTS_KEYS_ENTRY, self.USER_CONCEPTS_KEYS, 1000)
self.record(context, self.name, "save_execution_context", True)
def initialize_builtin_concepts(self):
"""
Initializes the builtin concepts
@@ -653,42 +663,6 @@ class Sheerka(Concept):
raise NotImplementedError()
def is_success(self, obj):
if isinstance(obj, bool): # quick win
return obj
if isinstance(obj, ReturnValueConcept):
return obj.status
if isinstance(obj, Concept) and obj.metadata.is_builtin and obj.key in BuiltinErrors:
return False
return obj
def is_known(self, obj):
if not isinstance(obj, Concept):
return True
return obj.key != str(BuiltinConcepts.UNKNOWN_CONCEPT)
def isinstance(self, a, b):
"""
return true if the concept a is an instance of the concept b
:param a:
:param b:
:return:
"""
if isinstance(a, BuiltinConcepts): # common KSI error ;-)
raise SyntaxError("Remember that the first parameter of isinstance MUST be a concept")
if not isinstance(a, Concept):
return False
b_key = b.key if isinstance(b, Concept) else str(b)
return a.key == b_key
def get_evaluator_name(self, name):
if self.evaluators_prefix is None:
base_evaluator_class = core.utils.get_class("evaluators.BaseEvaluator.BaseEvaluator")
@@ -741,9 +715,52 @@ class Sheerka(Concept):
def test(self):
return f"I have access to Sheerka !"
def test_using_context(self, context, param1, param2):
event = context.event.get_digest()
return f"I have access to Sheerka ! {param1=}, {param2=}, {event=}."
def test_error(self):
raise Exception("I can raise an error")
@staticmethod
def is_success(obj):
if isinstance(obj, bool): # quick win
return obj
if isinstance(obj, ReturnValueConcept):
return obj.status
if isinstance(obj, Concept) and obj.metadata.is_builtin and obj.key in BuiltinErrors:
return False
return obj
@staticmethod
def is_known(obj):
if not isinstance(obj, Concept):
return True
return obj.key != str(BuiltinConcepts.UNKNOWN_CONCEPT)
@staticmethod
def isinstance(a, b):
"""
return true if the concept a is an instance of the concept b
:param a:
:param b:
:return:
"""
if isinstance(a, BuiltinConcepts): # common KSI error ;-)
raise SyntaxError("Remember that the first parameter of isinstance MUST be a concept")
if not isinstance(a, Concept):
return False
b_key = b.key if isinstance(b, Concept) else str(b)
return a.key == b_key
@staticmethod
def _get_unknown(metadata):
"""
@@ -89,10 +89,10 @@ class SheerkaComparisonManager(BaseService):
cache = Cache()
self.sheerka.cache_manager.register_cache(self.RESOLVED_COMPARISON_ENTRY, cache, persist=False)
self.sheerka.bind_service_method(self, SheerkaComparisonManager.is_greater_than)
self.sheerka.bind_service_method(self, SheerkaComparisonManager.is_less_than)
self.sheerka.bind_service_method(self, SheerkaComparisonManager.get_partition)
self.sheerka.bind_service_method(self, SheerkaComparisonManager.get_concepts_weights)
self.sheerka.bind_service_method(self.is_greater_than)
self.sheerka.bind_service_method(self.is_less_than)
self.sheerka.bind_service_method(self.get_partition)
self.sheerka.bind_service_method(self.get_concepts_weights)
def is_greater_than(self, context, prop_name, concept_a, concept_b, comparison_context="#"):
"""
@@ -20,7 +20,7 @@ class SheerkaCreateNewConcept(BaseService):
self.bnp = core.utils.get_class(BASE_NODE_PARSER_CLASS) # BaseNodeParser
def initialize(self):
self.sheerka.bind_service_method(self, SheerkaCreateNewConcept.create_new_concept)
self.sheerka.bind_service_method(self.create_new_concept)
def create_new_concept(self, context, concept: Concept):
"""
+3 -3
View File
@@ -22,9 +22,9 @@ class SheerkaDump(BaseService):
super().__init__(sheerka)
def initialize(self):
self.sheerka.bind_service_method(self, SheerkaDump.dump_concepts, "concepts")
self.sheerka.bind_service_method(self, SheerkaDump.dump_desc, "desc")
self.sheerka.bind_service_method(self, SheerkaDump.dump_state, "state")
self.sheerka.bind_service_method(self.dump_concepts, "concepts")
self.sheerka.bind_service_method(self.dump_desc, "desc")
self.sheerka.bind_service_method(self.dump_state, "state")
def dump_concepts(self):
lst = self.sheerka.sdp.list(self.sheerka.CONCEPTS_BY_ID_ENTRY)
@@ -16,7 +16,7 @@ class SheerkaEvaluateConcept(BaseService):
super().__init__(sheerka)
def initialize(self):
self.sheerka.bind_service_method(self, SheerkaEvaluateConcept.evaluate_concept)
self.sheerka.bind_service_method(self.evaluate_concept)
@staticmethod
def infinite_recursion_detected(context, concept):
+1 -1
View File
@@ -16,7 +16,7 @@ class SheerkaExecute(BaseService):
super().__init__(sheerka)
def initialize(self):
self.sheerka.bind_service_method(self, SheerkaExecute.execute)
self.sheerka.bind_service_method(self.execute)
def call_parsers(self, context, return_values):
@@ -50,7 +50,7 @@ class SheerkaHistoryManager(BaseService):
super().__init__(sheerka)
def initialize(self):
self.sheerka.bind_service_method(self, SheerkaHistoryManager.history)
self.sheerka.bind_service_method(self.history)
def history(self, depth=10, start=0):
"""
@@ -9,7 +9,7 @@ class SheerkaModifyConcept(BaseService):
super().__init__(sheerka)
def initialize(self):
self.sheerka.bind_service_method(self, SheerkaModifyConcept.modify_concept)
self.sheerka.bind_service_method(self.modify_concept)
def modify_concept(self, context, concept):
old_version = self.sheerka.get_by_id(concept.id)
@@ -16,12 +16,12 @@ class SheerkaSetsManager(BaseService):
super().__init__(sheerka)
def initialize(self):
self.sheerka.bind_service_method(self, SheerkaSetsManager.set_isa)
self.sheerka.bind_service_method(self, SheerkaSetsManager.get_set_elements)
self.sheerka.bind_service_method(self, SheerkaSetsManager.add_concept_to_set)
self.sheerka.bind_service_method(self, SheerkaSetsManager.isinset)
self.sheerka.bind_service_method(self, SheerkaSetsManager.isa)
self.sheerka.bind_service_method(self, SheerkaSetsManager.isaset)
self.sheerka.bind_service_method(self.set_isa)
self.sheerka.bind_service_method(self.get_set_elements)
self.sheerka.bind_service_method(self.add_concept_to_set)
self.sheerka.bind_service_method(self.isinset)
self.sheerka.bind_service_method(self.isa)
self.sheerka.bind_service_method(self.isaset)
cache = SetCache(default=lambda k: self.sheerka.sdp.get(self.CONCEPTS_GROUPS_ENTRY, k))
self.sheerka.cache_manager.register_cache(self.CONCEPTS_GROUPS_ENTRY, cache)
@@ -27,9 +27,9 @@ class SheerkaVariableManager(BaseService):
super().__init__(sheerka)
def initialize(self):
self.sheerka.bind_service_method(self, SheerkaVariableManager.record)
self.sheerka.bind_service_method(self, SheerkaVariableManager.load)
self.sheerka.bind_service_method(self, SheerkaVariableManager.delete)
self.sheerka.bind_service_method(self.record)
self.sheerka.bind_service_method(self.load)
self.sheerka.bind_service_method(self.delete)
cache = Cache(default=lambda k: self.sheerka.sdp.get(self.VARIABLES_ENTRY, k))
self.sheerka.cache_manager.register_cache(self.VARIABLES_ENTRY, cache, True, True)
+43 -5
View File
@@ -11,6 +11,28 @@ from evaluators.BaseEvaluator import OneReturnValueEvaluator
from parsers.PythonParser import PythonNode
def inject_context(context):
"""
function Decorator used to inject the context in methods that needed
:param context:
:return:
"""
def wrapped(func):
def inner(*args, **kwargs):
return func(context, *args, **kwargs)
return inner
return wrapped
class Expando:
def __init__(self, bag):
for k, v in bag.items():
setattr(self, k, v)
class PythonEvaluator(OneReturnValueEvaluator):
NAME = "Python"
@@ -65,14 +87,12 @@ class PythonEvaluator(OneReturnValueEvaluator):
def get_globals(self, context, node):
my_locals = {
"sheerka": context.sheerka,
# "desc": context.sheerka.dump_handler.dump_desc,
# "concepts": context.sheerka.dump_handler.dump_concepts,
# "history": context.sheerka.dump_handler.dump_history,
# "state": context.sheerka.dump_handler.dump_state,
"Concept": core.concept.Concept,
"BuiltinConcepts": core.builtin_concepts.BuiltinConcepts,
}
method_from_sheerka = self.update_globals_with_sheerka_methods(my_locals, context)
if context.obj:
context.log(f"Concept '{context.obj}' is in context. Adding it and its properties to locals.", self.name)
@@ -123,8 +143,26 @@ class PythonEvaluator(OneReturnValueEvaluator):
if self.locals: # when exta values are given. Add them
my_locals.update(self.locals)
my_locals["sheerka"] = Expando(method_from_sheerka) # it's the last, so I cannot be overridden
return my_locals
@staticmethod
def update_globals_with_sheerka_methods(my_locals, context):
methods_from_sheerka = {}
# Make sure that methods that need the concept are correctly wrapped
for method_name, method in context.sheerka.sheerka_methods.items():
if method_name in context.sheerka.methods_with_context:
methods_from_sheerka[method_name] = inject_context(context)(method)
else:
methods_from_sheerka[method_name] = method
# Add all the methods as a direct access
for method_name, method in methods_from_sheerka.items():
my_locals[method_name] = method
return methods_from_sheerka # to allow access using prefix "sheerka."
@staticmethod
def resolve_name(to_resolve):
"""