import os import time from os import path from core.builtin_concepts_ids import BuiltinConcepts, BuiltinContainers from core.builtin_helpers import ensure_concept_or_rule from core.concept import Concept from core.global_symbols import SHEERKA_BACKUP_FOLDER from core.sheerka.services.SheerkaExecute import SheerkaExecute from core.sheerka.services.SheerkaHistoryManager import SheerkaHistoryManager from core.sheerka.services.SheerkaMemory import SheerkaMemory from core.sheerka.services.sheerka_service import BaseService CONCEPTS_FILE_FULL = "full.sb" # .sb for sheerka backup CONCEPTS_FILE_TO_USE = CONCEPTS_FILE_FULL class SheerkaAdmin(BaseService): NAME = "Admin" def __init__(self, sheerka): super().__init__(sheerka) def initialize(self): self.sheerka.bind_service_method(self.NAME, self.caches_names, False) self.sheerka.bind_service_method(self.NAME, self.cache, False) self.sheerka.bind_service_method(self.NAME, self.restore, True) self.sheerka.bind_service_method(self.NAME, self.concepts, False) self.sheerka.bind_service_method(self.NAME, self.builtins, False) self.sheerka.bind_service_method(self.NAME, self.desc, False) self.sheerka.bind_service_method(self.NAME, self.desc_evaluators, False) self.sheerka.bind_service_method(self.NAME, self.desc_parsers, False) self.sheerka.bind_service_method(self.NAME, self.extended_isinstance, False) self.sheerka.bind_service_method(self.NAME, self.is_container, False) self.sheerka.bind_service_method(self.NAME, self.format_rules, False) self.sheerka.bind_service_method(self.NAME, self.exec_rules, False) self.sheerka.bind_service_method(self.NAME, self.admin_push_ontology, True, as_name="push_ontology") self.sheerka.bind_service_method(self.NAME, self.admin_pop_ontology, True, as_name="pop_ontology") self.sheerka.bind_service_method(self.NAME, self.ontologies, False) self.sheerka.bind_service_method(self.NAME, self.in_memory, False) self.sheerka.bind_service_method(self.NAME, self.admin_history, False, as_name="history") self.sheerka.bind_service_method(self.NAME, self.sdp, False) self.sheerka.bind_service_method(self.NAME, self.set_sheerka, True) def caches_names(self): """ Returns the name of all the caches :return: """ return self.sheerka.new(BuiltinConcepts.TO_LIST, body=self.sheerka.om.current_cache_manager().caches.keys()) def cache(self, name, *keys): """ Returns the content of a cache :param name: :param keys: look for a specific key. May ask to sdp if the key is not in cache :return: """ if name not in self.sheerka.om.current_cache_manager().caches: return self.sheerka.new(BuiltinConcepts.NOT_FOUND, body={"cache": name}) if not keys: return self.sheerka.om.current_cache_manager().caches[name].cache.copy() return {key: self.sheerka.om.get(name, key) for key in keys} def sdp(self, name=None): if name: for ontology in self.sheerka.om.ontologies: if ontology.name == name: return ontology.cache_manager.sdp return self.sheerka.err(self.sheerka.new(BuiltinConcepts.NOT_FOUND, {"sdp_name", name})) return self.sheerka.om.current_sdp() def restore(self, backup_file=CONCEPTS_FILE_TO_USE): """ Restore the state with all previous valid concept definitions :return: """ def restore_from_file(file_name): _nb_lines, _nb_instructions, _nb_lines_in_error = 0, 0, 0 _min_time, _max_time = None, None file_path = path.join(backup_folder, file_name) if not path.exists(file_path): print(f"\u001b[31mFile '{file_path}' is not found !\u001b[0m") return 0, 0, 1 with open(file_path, "r") as f: for line in f.readlines(): _nb_lines += 1 line = line.strip() if line.startswith("#import "): to_import = line[8:] + ".sb" print(f" ==== Importing {to_import} ==== ") res = restore_from_file(to_import) _nb_lines += res[0] _nb_instructions += res[1] _nb_lines_in_error += res[2] if _min_time is None or res[3] < _min_time: _min_time = res[3] if _max_time is None or res[4] > _max_time: _max_time = res[4] continue if line == "" or line.startswith("#"): continue print(line) _nb_instructions += 1 stop_watch = time.time_ns() res = self.sheerka.evaluate_user_input(line) user_input_elapsed = time.time_ns() - stop_watch if _min_time is None or user_input_elapsed < _min_time: _min_time = user_input_elapsed if _max_time is None or user_input_elapsed > _max_time: _max_time = user_input_elapsed if len(res) > 1 or not res[0].status: _nb_lines_in_error += 1 print("\u001b[31mError detected !\u001b[0m") return _nb_lines, _nb_instructions, _nb_lines_in_error, _min_time, _max_time backup_folder = os.getenv(SHEERKA_BACKUP_FOLDER) if backup_folder is None: return self.sheerka.ret(self.NAME, False, self.sheerka.err(SHEERKA_BACKUP_FOLDER + " is not defined")) if not backup_file.endswith(".sb"): backup_file = backup_file + ".sb" try: start = time.time_ns() self.sheerka.during_restore = True self.sheerka.save_execution_context = False enable_process_return_values_previous_value = self.sheerka.enable_process_return_values self.sheerka.enable_process_return_values = False self.sheerka.add_to_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED) nb_lines, nb_instructions, nb_lines_in_error, min_time, max_time = restore_from_file(backup_file) self.sheerka.remove_fom_context(BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED) self.sheerka.enable_process_return_values = enable_process_return_values_previous_value self.sheerka.save_execution_context = True self.sheerka.during_restore = False stop = time.time_ns() nano_sec = stop - start dt = nano_sec / 1e6 elapsed = f"{dt:.3f} ms" if dt < 1000 else f"{dt / 1000:.3f} s" min_str = f"{min_time / 1e6:.3f} ms" max_str = f"{max_time / 1e6:.3f} ms" mean_time = dt / nb_lines mean_str = f"{mean_time:.3f} ms" if mean_time < 1000 else f"{mean_time / 1000:.3f} s" print(f"Imported {nb_lines} line(s) in {elapsed}. min={min_str}, max={max_str}, mean={mean_str}") print(f"{nb_instructions} instruction(s).") if nb_lines_in_error > 0: print(f"\u001b[31m{nb_lines_in_error} errors(s) found.\u001b[0m") else: print(f"No error.") except IOError as e: raise e def concepts(self): concepts = sorted(self.sheerka.om.list(self.sheerka.CONCEPTS_BY_ID_ENTRY), key=lambda item: int(item.id)) return self.sheerka.new(BuiltinConcepts.TO_LIST, body=concepts) def builtins(self): builtins = sorted(self.sheerka.sheerka_methods.values(), key=lambda builtin_method: builtin_method.name) return self.sheerka.new(BuiltinConcepts.TO_LIST, body=builtins) def desc_evaluators(self): evaluators = {k: sorted(v[0].items(), reverse=True) for k, v in self.sheerka.services[SheerkaExecute.NAME].grouped_evaluators_cache.items()} return self.sheerka.new(BuiltinConcepts.TO_DICT, body=evaluators) def desc_parsers(self): res = {} for k, v in self.sheerka.services[SheerkaExecute.NAME].grouped_parsers_cache.items(): parsers = {k1: [p.__name__ for p in v1] for k1, v1 in v[0].items()} sorted_parsers = sorted(parsers.items(), reverse=True) res[k] = sorted_parsers return self.sheerka.new(BuiltinConcepts.TO_DICT, body=res) def desc(self, *items): if len(items) == 1 and isinstance(items[0], str): name = items[0].strip().lower() if name == "parsers": return self.desc_parsers() elif name == "evaluators": return self.desc_evaluators() ensure_concept_or_rule(*items) res = [] for item in items: if isinstance(item, Concept): bag = { "id": item.id, "name": item.name, "key": item.key, "definition": item.get_metadata().definition, "type": item.get_metadata().definition_type, "hash": item.get_definition_hash(), "body": item.get_metadata().body, "where": item.get_metadata().where, "pre": item.get_metadata().pre, "post": item.get_metadata().post, "ret": item.get_metadata().ret, "vars": item.get_metadata().variables, "props": item.get_metadata().props, } else: bag = { "id": item.id, "name": item.metadata.name, "type": item.metadata.action_type, "predicate": item.metadata.predicate, "action": item.metadata.action, "priority": item.priority, "compiled": item.metadata.is_compiled, "enabled": item.metadata.is_enabled, } res.append(self.sheerka.new(BuiltinConcepts.TO_DICT, body=bag)) return res[0] if len(res) == 1 else self.sheerka.new(BuiltinConcepts.TO_LIST, body=res) def format_rules(self): return self.sheerka.new(BuiltinConcepts.TO_LIST, items=self.sheerka.get_format_rules()) def exec_rules(self): return self.sheerka.new(BuiltinConcepts.TO_LIST, items=self.sheerka.get_exec_rules()) def extended_isinstance(self, a, b): """ switch between sheerka.isinstance and builtin.isinstance :param a: :param b: :return: """ if isinstance(b, (type, tuple)): return isinstance(a, b) return self.sheerka.isinstance(a, b) @staticmethod def is_container(obj): """ A container concept is a builtin concept that embed a result :param obj: :return: """ if not isinstance(obj, Concept): return False return obj.key in BuiltinContainers def admin_push_ontology(self, context, name): return self.sheerka.push_ontology(context, name, False) def admin_pop_ontology(self, context): return self.sheerka.pop_ontology(context) def ontologies(self): ontologies = self.sheerka.om.ontologies_names return self.sheerka.new(BuiltinConcepts.TO_LIST, body=ontologies) def in_memory(self): """ Returns the list of all obj in memory """ res = {} for k, obj in self.sheerka.om.get_all(SheerkaMemory.OBJECTS_ENTRY).items(): if isinstance(obj, list): obj = obj[-1] res[k] = obj.obj return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.TO_DICT, body=res)) def admin_history(self, depth=10, start=0): history = self.sheerka.services[SheerkaHistoryManager.NAME].history(depth, start) return self.sheerka.new(BuiltinConcepts.TO_LIST, body=history) def set_sheerka(self, context, key, value, service=None): """ @param context: @param key: @param value: @param service: @return: """ return self.sheerka.record_var(context, service or self.sheerka.name, key, value)