From 9a82936fbfc85da91b652edeaa6d8a84abf849d3 Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 10 Jun 2016 14:04:06 +0200 Subject: [PATCH] Datasources plugins enhancement and loading bugfixes - now we have a LodelHook to trigger migration handlers loading - datasources initialization in dyncode is now trigger by a hook (lodel2_plugin_loaded) - datasources loading by dyncode is better --- lodel/leapi/lefactory.py | 19 ++++++--- lodel/leapi/leobject.py | 3 +- lodel/plugin/plugins.py | 18 +++++++-- plugins/dummy_datasource/__init__.py | 2 +- plugins/dummy_datasource/main.py | 54 +++----------------------- plugins/mongodb_datasource/__init__.py | 12 +----- plugins/mongodb_datasource/main.py | 7 +--- 7 files changed, 40 insertions(+), 75 deletions(-) diff --git a/lodel/leapi/lefactory.py b/lodel/leapi/lefactory.py index 5a477ea..413297f 100644 --- a/lodel/leapi/lefactory.py +++ b/lodel/leapi/lefactory.py @@ -15,6 +15,7 @@ def dyncode_from_em(model): # Header imports = """from lodel.leapi.leobject import LeObject from lodel.leapi.datahandlers.base_classes import DataField +from lodel.plugin.hooks import LodelHook """ for module in modules: imports += "import %s\n" % module @@ -27,14 +28,27 @@ from lodel.leapi.datahandlers.base_classes import DataField {classes} {bootstrap_instr} dynclasses = {class_list} +{init_hook} """.format( imports = imports, classes = cls_code, bootstrap_instr = bootstrap_instr, class_list = '[' + (', '.join([cls for cls in class_list]))+']', + init_hook = datasource_init_hook(), ) return res_code +##@brief Produce the source code of the LodelHook that initialize datasources +#in dyncode +#@return str +def datasource_init_hook(): + return """ +@LodelHook("lodel2_plugins_loaded") +def lodel2_dyncode_datasources_init(self, caller, payload): + for cls in dynclasses: + cls._init_datasources() +""" + ##@brief return A list of EmClass sorted by dependencies # # The first elts in the list depends on nothing, etc. @@ -134,10 +148,5 @@ class {clsname}({parents}): fields = '{' + (', '.join(['\n\t%s: %s' % (repr(emfield.uid),data_handler_constructor(emfield)) for emfield in em_class.fields()])) + '}', ) bootstrap += "\n" - for em_class in get_classes(model): - # Dyncode datasource bootstrap instructions - bootstrap += """{classname}._init_datasources() -""".format( - classname = LeObject.name2objname(em_class.uid)) return res, set(imports), bootstrap diff --git a/lodel/leapi/leobject.py b/lodel/leapi/leobject.py index 8e031b7..9eac6ac 100644 --- a/lodel/leapi/leobject.py +++ b/lodel/leapi/leobject.py @@ -229,11 +229,10 @@ a read only as a read&write datasource" ds_conf = getattr(ds_conf, ds_name) #Checks that the datasource plugin exists - ds_plugin_module = Plugin.get(ds_plugin).module + ds_plugin_module = Plugin.get(ds_plugin).loader_module() try: datasource_class = getattr(ds_plugin_module, "Datasource") except AttributeError as e: - raise e expt_msg += "The datasource plugin %s seems to be invalid. Error \ raised when trying to import Datasource" expt_msg %= ds_identifier diff --git a/lodel/plugin/plugins.py b/lodel/plugin/plugins.py index 9155226..d355e01 100644 --- a/lodel/plugin/plugins.py +++ b/lodel/plugin/plugins.py @@ -60,8 +60,11 @@ class Plugin(object): self.started() self.name = plugin_name self.path = self.plugin_path(plugin_name) - + + ##@brief Stores the plugin module self.module = None + ##@breif Stores the plugin loader module + self.__loader_module = None self.__confspecs = dict() self.loaded = False @@ -110,6 +113,7 @@ class Plugin(object): ##@brief Try to import a file from a variable in __init__.py #@param varname str : The variable name + #@return loaded module #@throw AttributeError if varname not found #@throw ImportError if the file fails to be imported #@throw PluginError if the filename was not valid @@ -208,7 +212,7 @@ class Plugin(object): #Loading the plugin try: - self._import_from_init_var(LOADER_FILENAME_VARNAME) + self.__loader_module = self._import_from_init_var(LOADER_FILENAME_VARNAME) except AttributeError: msg = "Malformed plugin {plugin}. No {varname} found in __init__.py" msg = msg.format( @@ -223,7 +227,12 @@ class Plugin(object): raise PluginError(msg) logger.debug("Plugin '%s' loaded" % self.name) self.loaded = True - + + def loader_module(self): + if not self.loaded: + raise RuntimeError("Plugin %s not loaded yet."%self.name) + return self.__loader_module + ##@brief Call load method on every pre-loaded plugins # # Called by loader to trigger hooks registration. @@ -245,6 +254,9 @@ class Plugin(object): msg += "\n\t%20s : %s" % (name,e) msg += "\n" raise PluginError(msg) + from lodel.plugin.hooks import LodelHook + LodelHook.call_hook( + "lodel2_plugins_loaded", cls, cls._plugin_instances) ##@return a copy of __confspecs attr @property diff --git a/plugins/dummy_datasource/__init__.py b/plugins/dummy_datasource/__init__.py index fdd6868..9ac28d4 100644 --- a/plugins/dummy_datasource/__init__.py +++ b/plugins/dummy_datasource/__init__.py @@ -1,5 +1,5 @@ from lodel.settings.validator import SettingValidator -from .main import DummyDatasource as Datasource +from .datasource import DummyDatasource as Datasource __loader__ = 'main.py' __plugin_deps__ = [] diff --git a/plugins/dummy_datasource/main.py b/plugins/dummy_datasource/main.py index cb45b11..6e34448 100644 --- a/plugins/dummy_datasource/main.py +++ b/plugins/dummy_datasource/main.py @@ -1,53 +1,9 @@ #-*- coding:utf-8 -*- -class DummyDatasource(object): - - def __init__(self, *conn_args, **conn_kwargs): - self.conn_args = conn_args - self.conn_kwargs = conn_kwargs +from lodel.plugin import LodelHook +from .datasource import DummyDatasource as Datasource - ## @brief returns a selection of documents from the datasource - # @param target_cls Emclass - # @param field_list list - # @param filters list : List of filters - # @param rel_filters list : List of relational filters - # @param order list : List of column to order. ex: order = [('title', 'ASC'),] - # @param group list : List of tupple representing the column to group together. ex: group = [('title', 'ASC'),] - # @param limit int : Number of records to be returned - # @param offset int: used with limit to choose the start record - # @param instanciate bool : If true, the records are returned as instances, else they are returned as dict - # @return list - def select(self, target_cls, field_list, filters, rel_filters=None, order=None, group=None, limit=None, offset=0, - instanciate=True): - pass +@LodelHook('datasources_migration_init') +def dummy_migration_handler_init(): + from .migration_handler import DummyMigrationHandler as migration_handler - ##@brief Deletes records according to given filters - #@param target Emclass : class of the record to delete - #@param filters list : List of filters - #@param relational_filters list : List of relational filters - #@return int : number of deleted records - def delete(self, target, filters, relational_filters): - pass - - ## @brief updates records according to given filters - #@param target Emclass : class of the object to insert - #@param filters list : List of filters - #@param rel_filters list : List of relational filters - #@param upd_datas dict : datas to update (new values) - #@return int : Number of updated records - def update(self, target, filters, relational_filters, upd_datas): - pass - - ## @brief Inserts a record in a given collection - # @param target Emclass : class of the object to insert - # @param new_datas dict : datas to insert - # @return the inserted uid - def insert(self, target, new_datas): - pass - - ## @brief Inserts a list of records in a given collection - # @param target Emclass : class of the objects inserted - # @param datas_list list : list of dict - # @return list : list of the inserted records' ids - def insert_multi(self, target, datas_list): - pass diff --git a/plugins/mongodb_datasource/__init__.py b/plugins/mongodb_datasource/__init__.py index cf2457c..2ac622a 100644 --- a/plugins/mongodb_datasource/__init__.py +++ b/plugins/mongodb_datasource/__init__.py @@ -1,3 +1,4 @@ +#-*- coding: utf-8 -*- from .utils import connect, get_connection_args __loader__ = "main.py" @@ -12,13 +13,4 @@ __fullname__ = "MongoDB plugin" # # @return bool|str : True if all the checks are OK, an error message if not def _activate(): - default_connection_args = get_connection_args() - connection_check = connect( - default_connection_args['host'], - default_connection_args['port'], - default_connection_args['db_name'], - default_connection_args['username'], - default_connection_args['password']) - if not connection_check: - return False - return True \ No newline at end of file + return True diff --git a/plugins/mongodb_datasource/main.py b/plugins/mongodb_datasource/main.py index 431da57..9a5ed90 100644 --- a/plugins/mongodb_datasource/main.py +++ b/plugins/mongodb_datasource/main.py @@ -1,11 +1,8 @@ from lodel.plugin import LodelHook +from .datasource import MongoDbDatasource as Datasource -@LodelHook('mongodb_mh_init') +@LodelHook('datasources_migration_init') def mongodb_migration_handler_init(): import plugins.mongodb_datasource.migration_handler as migration_handler - -@LodelHook('mongodb_ds_init') -def mongodb_datasource_init(): - import plugins.mongodb_datasource.datasource as datasource \ No newline at end of file