mirror of
				https://github.com/yweber/lodel2.git
				synced 2025-10-31 03:29:03 +01:00 
			
		
		
		
	Documentation on the lodel.plugin.datasource_plugin et lodel.plugin.exceptions modules
This commit is contained in:
		
					parent
					
						
							
								0ad3cc59bf
							
						
					
				
			
			
				commit
				
					
						72316b0f0a
					
				
			
		
					 2 changed files with 108 additions and 98 deletions
				
			
		|  | @ -1,3 +1,8 @@ | ||||||
|  | ## @package lodel.plugin.datasource_plugin Datasource plugins management module | ||||||
|  | # | ||||||
|  | # It contains the base classes for all the datasource plugins that could be added to Lodel | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| from lodel.context import LodelContext | from lodel.context import LodelContext | ||||||
| LodelContext.expose_modules(globals(), { | LodelContext.expose_modules(globals(), { | ||||||
|     'lodel.plugin.plugins': ['Plugin'], |     'lodel.plugin.plugins': ['Plugin'], | ||||||
|  | @ -7,58 +12,61 @@ LodelContext.expose_modules(globals(), { | ||||||
|     'lodel.exceptions': ['LodelException', 'LodelExceptions', |     'lodel.exceptions': ['LodelException', 'LodelExceptions', | ||||||
|         'LodelFatalError', 'DataNoneValid', 'FieldValidationError']}) |         'LodelFatalError', 'DataNoneValid', 'FieldValidationError']}) | ||||||
| 
 | 
 | ||||||
|  | ## @brief The plugin type that is used in the global settings of Lodel | ||||||
| _glob_typename = 'datasource' | _glob_typename = 'datasource' | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ##@brief Datasource class in plugins HAVE TO inherit from this abstract class | ## @brief Main abstract class from which the plugins' datasource classes must inherit. | ||||||
| class AbstractDatasource(object): | class AbstractDatasource(object): | ||||||
|      |      | ||||||
|     ##@brief Trigger LodelFatalError when abtract method called |     ## @brief Trigger LodelFatalError when abtract method called | ||||||
|  |     # @throw LodelFatalError if there is an attempt to instanciate an object from this class | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def _abs_err(): |     def _abs_err(): | ||||||
|         raise LodelFatalError("This method is abstract and HAVE TO be \ |         raise LodelFatalError("This method is abstract and HAVE TO be \ | ||||||
| reimplemented by plugin datasource child class") | reimplemented by plugin datasource child class") | ||||||
|      |      | ||||||
|     ##@brief The constructor |     ## | ||||||
|  |     # @param *conn_args | ||||||
|  |     # @param **conn_kwargs | ||||||
|     def __init__(self, *conn_args, **conn_kwargs): |     def __init__(self, *conn_args, **conn_kwargs): | ||||||
|         self._abs_err() |         self._abs_err() | ||||||
| 
 | 
 | ||||||
|     ##@brief Provide a new uniq numeric ID |     ## @brief Provides a new uniq numeric ID | ||||||
|     #@param emcomp LeObject subclass (not instance) : To know on wich things we |     # @param emcomp LeObject subclass (not instance) : defines against which objects type the id should be unique | ||||||
|     #have to be uniq |     # @return int | ||||||
|     #@return an integer |  | ||||||
|     def new_numeric_id(self, emcomp): |     def new_numeric_id(self, emcomp): | ||||||
|         self._abs_err() |         self._abs_err() | ||||||
| 
 | 
 | ||||||
|     ##@brief returns a selection of documents from the datasource |     ## @brief Returns a selection of documents from the datasource | ||||||
|     #@param target Emclass |     # @param target Emclass : class of the documents | ||||||
|     #@param field_list list |     # @param field_list list : fields to get from the datasource | ||||||
|     #@param filters list : List of filters |     # @param filters list : List of filters | ||||||
|     #@param rel_filters list : List of relational filters |     # @param rel_filters list : List of relational filters (default value : None) | ||||||
|     #@param order list : List of column to order. ex: order = [('title', 'ASC'),] |     # @param order list : List of column to order. ex: order = [('title', 'ASC'),] (default value : None) | ||||||
|     #@param group list : List of tupple representing the column to group together. ex: group = [('title', 'ASC'),] |     # @param group list : List of tupple representing the column to group together. ex: group = [('title', 'ASC'),] (default value : None) | ||||||
|     #@param limit int : Number of records to be returned |     # @param limit int : Number of records to be returned (default value None) | ||||||
|     #@param offset int: used with limit to choose the start record |     # @param offset int: used with limit to choose the start record (default value : 0) | ||||||
|     #@param instanciate bool : If true, the records are returned as instances, else they are returned as dict |     # @param instanciate bool : If true, the records are returned as instances, else they are returned as dict (default value : True) | ||||||
|     #@return list |     # @return list | ||||||
|     def select(self, target, field_list, filters, rel_filters=None, order=None, group=None, limit=None, offset=0, |     def select(self, target, field_list, filters, rel_filters=None, order=None, group=None, limit=None, offset=0, | ||||||
|                instanciate=True): |                instanciate=True): | ||||||
|         self._abs_err() |         self._abs_err() | ||||||
| 
 | 
 | ||||||
|     ##@brief Deletes records according to given filters |     ## @brief Deletes records according to given filters | ||||||
|     #@param target Emclass : class of the record to delete |     # @param target Emclass : class of the record to delete | ||||||
|     #@param filters list : List of filters |     # @param filters list : List of filters | ||||||
|     #@param relational_filters list : List of relational filters |     # @param relational_filters list : List of relational filters | ||||||
|     #@return int : number of deleted records |     # @return int : number of deleted records | ||||||
|     def delete(self, target, filters, relational_filters): |     def delete(self, target, filters, relational_filters): | ||||||
|         self._abs_err() |         self._abs_err() | ||||||
| 
 | 
 | ||||||
|     ## @brief updates records according to given filters |     ## @brief updates records according to given filters | ||||||
|     #@param target Emclass : class of the object to insert |     # @param target Emclass : class of the object to insert | ||||||
|     #@param filters list : List of filters |     # @param filters list : List of filters | ||||||
|     #@param relational_filters list : List of relational filters |     # @param relational_filters list : List of relational filters | ||||||
|     #@param upd_datas dict : datas to update (new values) |     # @param upd_datas dict : datas to update (new values) | ||||||
|     #@return int : Number of updated records |     # @return int : Number of updated records | ||||||
|     def update(self, target, filters, relational_filters, upd_datas): |     def update(self, target, filters, relational_filters, upd_datas): | ||||||
|         self._abs_err() |         self._abs_err() | ||||||
| 
 | 
 | ||||||
|  | @ -77,22 +85,21 @@ reimplemented by plugin datasource child class") | ||||||
|         self._abs_err() |         self._abs_err() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ##@brief Designed to handles datasources plugins | ## @brief Represents a Datasource plugin | ||||||
| # | # | ||||||
| #A datasource provide data access to LeAPI typically a connector on a DB | # It will provide an access to a data collection to LeAPI (i.e. database connector, API ...). | ||||||
| #or an API |  | ||||||
| # | # | ||||||
| #Provide methods to initialize datasource attribute in LeAPI LeObject child | # It provides the methods needed to initialize the datasource attribute in LeAPI LeObject child | ||||||
| #classes (see @ref leapi.leobject.LeObject._init_datasources() ) | # classes (see @ref leapi.leobject.LeObject._init_datasources() ) | ||||||
| # | # | ||||||
| #@note For the moment implementation is done with a retro-compatibilities | # @note For the moment implementation is done with a retro-compatibilities priority and not with a convenience priority. | ||||||
| #priority and not with a convenience priority. | # @todo Refactor and rewrite lodel2 datasource handling | ||||||
| #@todo Refactor and rewrite lodel2 datasource handling | # @todo Write abstract classes for Datasource and MigrationHandler !!! | ||||||
| #@todo Write abstract classes for Datasource and MigrationHandler !!! |  | ||||||
| class DatasourcePlugin(Plugin): | class DatasourcePlugin(Plugin): | ||||||
|      |      | ||||||
|     _type_conf_name = _glob_typename |     _type_conf_name = _glob_typename | ||||||
|     ##@brief Stores confspecs indicating where DatasourcePlugin list is stored |    | ||||||
|  |     ## @brief Stores confspecs indicating where DatasourcePlugin list is stored | ||||||
|     _plist_confspecs = { |     _plist_confspecs = { | ||||||
|         'section': 'lodel2', |         'section': 'lodel2', | ||||||
|         'key': 'datasource_connectors', |         'key': 'datasource_connectors', | ||||||
|  | @ -104,15 +111,17 @@ class DatasourcePlugin(Plugin): | ||||||
|                 'none_is_valid': False}) |                 'none_is_valid': False}) | ||||||
|         } |         } | ||||||
|   |   | ||||||
|     ##@brief Construct a DatasourcePlugin  |     ## | ||||||
|     #@param name str : plugin name |     # @param name str : plugin's name | ||||||
|     #@see plugins.Plugin |     # @see plugins.Plugin | ||||||
|     def __init__(self, name): |     def __init__(self, name): | ||||||
|         super().__init__(name) |         super().__init__(name) | ||||||
|         self.__datasource_cls = None |         self.__datasource_cls = None | ||||||
|      |      | ||||||
|     ##@brief Accessor to the datasource class |     ## @brief Returns an accessor to the datasource class | ||||||
|     #@return A python datasource class |     # @return A python datasource class | ||||||
|  |     # @throw DatasourcePluginError if the plugin's datasource class is not a child of  | ||||||
|  |     # @ref lodel.plugin.datasource_plugin.AbstractDatasource | ||||||
|     def datasource_cls(self): |     def datasource_cls(self): | ||||||
|         if self.__datasource_cls is None: |         if self.__datasource_cls is None: | ||||||
|             self.__datasource_cls = self.loader_module().Datasource |             self.__datasource_cls = self.loader_module().Datasource | ||||||
|  | @ -122,17 +131,15 @@ class DatasourcePlugin(Plugin): | ||||||
| lodel.plugin.datasource_plugin.AbstractDatasource" % (self.name)) | lodel.plugin.datasource_plugin.AbstractDatasource" % (self.name)) | ||||||
|         return self.__datasource_cls |         return self.__datasource_cls | ||||||
|      |      | ||||||
|     ##@brief Accessor to migration handler class |     ## @brief Returns an accessor to migration handler class | ||||||
|     #@return A python migration handler class |     # @return A python migration handler class | ||||||
|     def migration_handler_cls(self): |     def migration_handler_cls(self): | ||||||
|         return self.loader_module().migration_handler_class() |         return self.loader_module().migration_handler_class() | ||||||
| 
 | 
 | ||||||
|     ##@brief Return an initialized Datasource instance |     ## @brief Returns an initialized Datasource instance | ||||||
|     #@param ds_name str : The name of the datasource to instanciate |     # @param ds_name str : The name of the datasource to instanciate | ||||||
|     #@param ro bool |     # @param ro bool : indicates if it will be in read only mode, else it will be in write only mode | ||||||
|     #@return A properly initialized Datasource instance |     # @return A properly initialized Datasource instance | ||||||
|     #@throw SettingsError if an error occurs in settings |  | ||||||
|     #@throw DatasourcePluginError for various errors |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def init_datasource(cls, ds_name, ro): |     def init_datasource(cls, ds_name, ro): | ||||||
|         plugin_name, ds_identifier = cls.plugin_name(ds_name, ro) |         plugin_name, ds_identifier = cls.plugin_name(ds_name, ro) | ||||||
|  | @ -140,9 +147,10 @@ lodel.plugin.datasource_plugin.AbstractDatasource" % (self.name)) | ||||||
|         ds_cls = cls.get_datasource(plugin_name) |         ds_cls = cls.get_datasource(plugin_name) | ||||||
|         return ds_cls(**ds_conf) |         return ds_cls(**ds_conf) | ||||||
|      |      | ||||||
|     ##@brief Return an initialized MigrationHandler instance |     ## @brief Returns an initialized MigrationHandler instance | ||||||
|     #@param ds_name str : The datasource name |     # @param ds_name str : The datasource name | ||||||
|     #@return A properly initialized MigrationHandler instance |     # @return A properly initialized MigrationHandler instance | ||||||
|  |     # @throw PluginError if a read only datasource instance was given to the migration handler.  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def init_migration_handler(cls, ds_name): |     def init_migration_handler(cls, ds_name): | ||||||
|         plugin_name, ds_identifier = cls.plugin_name(ds_name, False) |         plugin_name, ds_identifier = cls.plugin_name(ds_name, False) | ||||||
|  | @ -156,13 +164,12 @@ migration handler !!!") | ||||||
|         return mh_cls(**ds_conf) |         return mh_cls(**ds_conf) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     ##@brief Given a datasource name returns a DatasourcePlugin name |     ## @brief Given a datasource name returns a DatasourcePlugin name | ||||||
|     #@param ds_name str : datasource name |     # @param ds_name str : datasource name | ||||||
|     #@param ro bool : if true consider the datasource as readonly |     # @param ro bool : if true consider the datasource as readonly | ||||||
|     #@return a DatasourcePlugin name |     # @return a DatasourcePlugin name | ||||||
|     #@throw PluginError if datasource name not found |     # @throw DatasourcePluginError if the given datasource is unknown or not configured, or if there is a conflict in its "read-only" property (between the instance and the settings). | ||||||
|     #@throw DatasourcePermError if datasource is read_only but ro flag arg is |     # @throw SettingsError if there are misconfigured datasource settings. | ||||||
|     #false |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def plugin_name(ds_name, ro): |     def plugin_name(ds_name, ro): | ||||||
|         LodelContext.expose_modules(globals(), { |         LodelContext.expose_modules(globals(), { | ||||||
|  | @ -195,11 +202,11 @@ True found in settings for datasource '%s'" % ds_name) | ||||||
| DS_PLUGIN_NAME.DS_INSTANCE_NAME. But got %s" % ds_identifier) | DS_PLUGIN_NAME.DS_INSTANCE_NAME. But got %s" % ds_identifier) | ||||||
|         return res |         return res | ||||||
| 
 | 
 | ||||||
|     ##@brief Try to fetch a datasource configuration |     ## @brief Returns a datasource's configuration | ||||||
|     #@param ds_identifier str : datasource name |     # @param ds_identifier str : datasource name | ||||||
|     #@param ds_plugin_name : datasource plugin name |     # @param ds_plugin_name : datasource plugin name | ||||||
|     #@return a dict containing datasource initialisation options |     # @return a dict containing datasource initialisation options | ||||||
|     #@throw NameError if a datasource plugin or instance cannot be found |     # @throw DatasourcePluginError if a datasource plugin or instance cannot be found | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def _get_ds_connection_conf(ds_identifier,ds_plugin_name): |     def _get_ds_connection_conf(ds_identifier,ds_plugin_name): | ||||||
|         LodelContext.expose_modules(globals(), { |         LodelContext.expose_modules(globals(), { | ||||||
|  | @ -216,56 +223,55 @@ DS_PLUGIN_NAME.DS_INSTANCE_NAME. But got %s" % ds_identifier) | ||||||
|         ds_conf = getattr(ds_conf, ds_identifier) |         ds_conf = getattr(ds_conf, ds_identifier) | ||||||
|         return {k: getattr(ds_conf,k) for k in ds_conf._fields } |         return {k: getattr(ds_conf,k) for k in ds_conf._fields } | ||||||
| 
 | 
 | ||||||
|     ##@brief DatasourcePlugin instance accessor |     ## @brief Returns a DatasourcePlugin instance from a plugin's name | ||||||
|     #@param ds_name str : plugin name |     # @param ds_name str : plugin name | ||||||
|     #@return a DatasourcePlugin instance |     # @return DatasourcePlugin | ||||||
|     #@throw PluginError if no plugin named ds_name found |     # @throw PluginError if no plugin named ds_name found (@see lodel.plugin.plugins.Plugin) | ||||||
|     #@throw PluginTypeError if ds_name ref to a plugin that is not a  |     # @throw PluginTypeError if ds_name ref to a plugin that is not a DatasourcePlugin | ||||||
|     #DatasourcePlugin |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def get(cls, ds_name): |     def get(cls, ds_name): | ||||||
|         pinstance = super().get(ds_name) #Will raise PluginError if bad name |         pinstance = super().get(ds_name)  # Will raise PluginError if bad name | ||||||
|         if not isinstance(pinstance, DatasourcePlugin): |         if not isinstance(pinstance, DatasourcePlugin): | ||||||
|            raise PluginTypeErrror("A name of a DatasourcePlugin was excepted \ |            raise PluginTypeErrror("A name of a DatasourcePlugin was excepted \ | ||||||
| but %s is a %s" % (ds_name, pinstance.__class__.__name__)) | but %s is a %s" % (ds_name, pinstance.__class__.__name__)) | ||||||
|         return pinstance |         return pinstance | ||||||
| 
 | 
 | ||||||
|     ##@brief Return a datasource class given a datasource name |     ## @brief Returns a datasource class given a datasource name | ||||||
|     #@param ds_plugin_name str : datasource plugin name |     # @param ds_plugin_name str : datasource plugin name | ||||||
|     #@throw PluginError if ds_name is not an existing plugin name |     # @return Datasource class | ||||||
|     #@throw PluginTypeError if ds_name is not the name of a DatasourcePlugin |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def get_datasource(cls, ds_plugin_name): |     def get_datasource(cls, ds_plugin_name): | ||||||
|         return cls.get(ds_plugin_name).datasource_cls() |         return cls.get(ds_plugin_name).datasource_cls() | ||||||
|      |      | ||||||
|     ##@brief Given a plugin name returns a migration handler class |     ## @brief Returns a migration handler class, given a plugin name | ||||||
|     #@param ds_plugin_name str : a datasource plugin name |     # @param ds_plugin_name str : a datasource plugin name | ||||||
|  |     # @return MigrationHandler class | ||||||
|     @classmethod |     @classmethod | ||||||
|     def get_migration_handler(cls, ds_plugin_name): |     def get_migration_handler(cls, ds_plugin_name): | ||||||
|         return cls.get(ds_plugin_name).migration_handler_cls() |         return cls.get(ds_plugin_name).migration_handler_cls() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ##@page lodel2_datasources Lodel2 datasources | ## @page lodel2_datasources Lodel2 datasources | ||||||
| # | # | ||||||
| #@par lodel2_datasources_intro Intro | # @par lodel2_datasources_intro Introduction | ||||||
| # A single lodel2 website can interact with multiple datasources. This page | # A single lodel2 website can interact with multiple datasources. This page | ||||||
| # aims to describe configuration & organisation of datasources in lodel2. | # aims to describe configuration and organisation of datasources in lodel2. | ||||||
| # Each object is attached to a datasource. This association is done in the | # Each object is attached to a datasource. This association is done in the | ||||||
| # editorial model, the datasource is identified by a name. | # editorial model, in which the datasource is identified by its name. | ||||||
| # | # | ||||||
| #@par Datasources declaration | # @par Datasources declaration | ||||||
| # To define a datasource you have to write something like this in confs file : | # To define a datasource you have to write something like this in configuration file : | ||||||
| #<pre> | # <pre> | ||||||
| #[lodel2.datasources.DATASOURCE_NAME] | # [lodel2.datasources.DATASOURCE_NAME] | ||||||
| #identifier = DATASOURCE_FAMILY.SOURCE_NAME | # identifier = DATASOURCE_FAMILY.SOURCE_NAME | ||||||
| #</pre> | # </pre> | ||||||
| # See below for DATASOURCE_FAMILY & SOURCE_NAME | #  See below for DATASOURCE_FAMILY & SOURCE_NAME | ||||||
| # | # | ||||||
| #@par Datasources plugins | # @par Datasources plugins | ||||||
| # Each datasource family is a plugin (  | # Each datasource family is a plugin ( @ref plugin_doc "More informations on plugins" ).  | ||||||
| #@ref plugin_doc "More informations on plugins" ). For example mysql or a  | # For example mysql or a mongodb plugins. \n | ||||||
| #mongodb plugins. Here is the CONFSPEC variable templates for datasources  | # | ||||||
| #plugin | # Here is the CONFSPEC variable templates for datasources plugin | ||||||
| #<pre> | #<pre> | ||||||
| #CONFSPEC = { | #CONFSPEC = { | ||||||
| #                'lodel2.datasource.example.*' : { | #                'lodel2.datasource.example.*' : { | ||||||
|  | @ -275,7 +281,8 @@ but %s is a %s" % (ds_name, pinstance.__class__.__name__)) | ||||||
| #                } | #                } | ||||||
| #} | #} | ||||||
| #</pre> | #</pre> | ||||||
| #MySQL example | #  | ||||||
|  | #MySQL example \n | ||||||
| #<pre> | #<pre> | ||||||
| #CONFSPEC = { | #CONFSPEC = { | ||||||
| #                'lodel2.datasource.mysql.*' : { | #                'lodel2.datasource.mysql.*' : { | ||||||
|  | @ -291,8 +298,8 @@ but %s is a %s" % (ds_name, pinstance.__class__.__name__)) | ||||||
| #} | #} | ||||||
| #</pre> | #</pre> | ||||||
| # | # | ||||||
| #@par Configuration example | # @par Configuration example | ||||||
| #<pre> | # <pre> | ||||||
| # [lodel2.datasources.main] | # [lodel2.datasources.main] | ||||||
| # identifier = mysql.Core | # identifier = mysql.Core | ||||||
| # [lodel2.datasources.revues_write] | # [lodel2.datasources.revues_write] | ||||||
|  |  | ||||||
|  | @ -1,3 +1,6 @@ | ||||||
|  | ## @package lodel.plugin.exceptions Plugin management specific exceptions | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class PluginError(Exception): | class PluginError(Exception): | ||||||
|     pass |     pass | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Roland Haroutiounian
				Roland Haroutiounian