1
0
Fork 0
mirror of https://github.com/yweber/lodel2.git synced 2026-08-03 19:08:37 +02:00

Updated comments (and deleting space between ## and @brief )

This commit is contained in:
Yann 2016-04-12 12:16:52 +02:00
commit c5971d9590
23 changed files with 322 additions and 239 deletions

View file

@ -3,9 +3,12 @@ dyncode_filename='lodel/leapi/dyncode.py'
all: tests doc dyncode all: tests doc dyncode
# generate doxygen documentation # generate doxygen documentation
doc: cleandoc doc: cleandoc doc_graphviz
doxygen doxygen
doc_graphviz:
cd doc/img/graphviz; make
# Test em update ( examples/em_test.pickle ) # Test em update ( examples/em_test.pickle )
em_test: em_test:
python3 em_test.py python3 em_test.py

View file

@ -142,7 +142,7 @@ text.new_field( 'title',
display_name = {'eng': 'Title', 'fre': 'Titre'}, display_name = {'eng': 'Title', 'fre': 'Titre'},
group = editorial_group, group = editorial_group,
data_handler = 'varchar', data_handler = 'varchar',
) nullable = True,)
text.new_field( 'subtitle', text.new_field( 'subtitle',
display_name = { display_name = {
'eng': 'Subtitle', 'eng': 'Subtitle',
@ -150,21 +150,65 @@ text.new_field( 'subtitle',
}, },
group = editorial_group, group = editorial_group,
data_handler = 'varchar', data_handler = 'varchar',
) nullable = True)
# Classe collection # Classe collection
collection = em.new_class( 'collection', collection = em.new_class( 'collection',
display_name = 'Collection', display_name = 'Collection',
group = editorial_group, group = editorial_group,
abstract = True, abstract = False,
parents = entitie, parents = entitie)
)
collection.new_field( 'title', collection.new_field( 'title',
display_name = 'Title', display_name = 'Title',
group = editorial_group, group = editorial_group,
abstract = True,
data_handler = 'varchar' data_handler = 'varchar'
) )
collection.new_field( 'publications',
display_name = 'Publications',
group = editorial_group,
data_handler = 'list',
back_reference = ('publication', 'collection'))
# Classe publication
pulication = em.new_class( 'publication',
display_name = 'Publication',
group = editorial_group,
abstract = False,
parents = entitie,)
publication.new_field( 'collection',
display_name = 'Collection',
group = editorial_group,
data_handler = 'link',
back_reference = ('collection', 'publications'))
#########################
# Texte definition #
#########################
section = em.new_class( 'section',
display_name = 'Section',
group = editorial_group,
abstract = False,
parents = text)
subsection = em.new_class( 'subsection',
display_name = 'Subsection',
group = editorial_group,
abstract = False,
parents = section)
section.new_field( 'childs',
display_name = 'Next section',
group = editorial_group,
data_hander = 'hierarch',
allowed_class = [subsection],
back_reference = ('subsection', 'parent'))
subsection.new_field( 'parent',
display_name = 'Parent',
group = editorial_group,
data_handler = 'link',
allowed_class = [section])
##################### #####################
# Persons & authors # # Persons & authors #

View file

@ -24,7 +24,7 @@ class MongoDbDataSource(object):
self.connection = MongoClient(connection_string) self.connection = MongoClient(connection_string)
self.database = self.connection[connection_args['dbname']] self.database = self.connection[connection_args['dbname']]
## @brief Inserts a list of records in a given collection ##@brief Inserts a list of records in a given collection
# #
# @param collection_name str : name of the MongoDB collection in which we will insert the records # @param collection_name str : name of the MongoDB collection in which we will insert the records
# @param datas list : list of dictionaries corresponding to the records # @param datas list : list of dictionaries corresponding to the records

View file

@ -9,12 +9,12 @@ from lodel.utils.mlstring import MlString
from lodel.editorial_model.exceptions import * from lodel.editorial_model.exceptions import *
## @brief Abstract class to represent editorial model components ##@brief Abstract class to represent editorial model components
# @see EmClass EmField # @see EmClass EmField
# @todo forbid '.' in uid # @todo forbid '.' in uid
class EmComponent(object): class EmComponent(object):
## @brief Instanciate an EmComponent ##@brief Instanciate an EmComponent
# @param uid str : uniq identifier # @param uid str : uniq identifier
# @param display_name MlString|str|dict : component display_name # @param display_name MlString|str|dict : component display_name
# @param help_text MlString|str|dict : help_text # @param help_text MlString|str|dict : help_text
@ -43,10 +43,10 @@ class EmComponent(object):
return int.from_bytes(m.digest(), byteorder='big') return int.from_bytes(m.digest(), byteorder='big')
## @brief Handles editorial model objects classes ##@brief Handles editorial model objects classes
class EmClass(EmComponent): class EmClass(EmComponent):
## @brief Instanciate a new EmClass ##@brief Instanciate a new EmClass
# @param uid str : uniq identifier # @param uid str : uniq identifier
# @param display_name MlString|str|dict : component display_name # @param display_name MlString|str|dict : component display_name
# @param abstract bool : set the class as asbtract if True # @param abstract bool : set the class as asbtract if True
@ -68,10 +68,10 @@ class EmClass(EmComponent):
else: else:
parents = list() parents = list()
self.parents = parents self.parents = parents
## @brief Stores EmFields instances indexed by field uid ##@brief Stores EmFields instances indexed by field uid
self.__fields = dict() self.__fields = dict()
## @brief Property that represent a dict of all fields (the EmField defined in this class and all its parents) ##@brief Property that represent a dict of all fields (the EmField defined in this class and all its parents)
@property @property
def __all_fields(self): def __all_fields(self):
res = dict() res = dict()
@ -80,7 +80,7 @@ class EmClass(EmComponent):
res.update(self.__fields) res.update(self.__fields)
return res return res
## @brief Return the list of all dependencies ##@brief Return the list of all dependencies
# #
# Reccursive parents listing # Reccursive parents listing
@property @property
@ -93,7 +93,7 @@ class EmClass(EmComponent):
res |= parent.parents_recc res |= parent.parents_recc
return res return res
## @brief EmField getter ##@brief EmField getter
# @param uid None | str : If None returns an iterator on EmField instances else return an EmField instance # @param uid None | str : If None returns an iterator on EmField instances else return an EmField instance
# @param no_parents bool : If True returns only fields defined is this class and not the one defined in parents classes # @param no_parents bool : If True returns only fields defined is this class and not the one defined in parents classes
# @return A list on EmFields instances (if uid is None) else return an EmField instance # @return A list on EmFields instances (if uid is None) else return an EmField instance
@ -104,7 +104,7 @@ class EmClass(EmComponent):
except KeyError: except KeyError:
raise EditorialModelError("No such EmField '%s'" % uid) raise EditorialModelError("No such EmField '%s'" % uid)
## @brief Add a field to the EmClass ##@brief Add a field to the EmClass
# @param emfield EmField : an EmField instance # @param emfield EmField : an EmField instance
# @warning do not add an EmField allready in another class ! # @warning do not add an EmField allready in another class !
# @throw EditorialModelException if an EmField with same uid allready in this EmClass (overwritting allowed from parents) # @throw EditorialModelException if an EmField with same uid allready in this EmClass (overwritting allowed from parents)
@ -121,7 +121,7 @@ class EmClass(EmComponent):
emfield._emclass = self emfield._emclass = self
return emfield return emfield
## @brief Create a new EmField and add it to the EmClass ##@brief Create a new EmField and add it to the EmClass
# @param data_handler str : A DataHandler name # @param data_handler str : A DataHandler name
# @param uid str : the EmField uniq id # @param uid str : the EmField uniq id
# @param **field_kwargs : EmField constructor parameters ( see @ref EmField.__init__() ) # @param **field_kwargs : EmField constructor parameters ( see @ref EmField.__init__() )
@ -152,10 +152,10 @@ class EmClass(EmComponent):
return "<class %s EmClass uid=%s>" % (abstract, repr(self.uid) ) return "<class %s EmClass uid=%s>" % (abstract, repr(self.uid) )
## @brief Handles editorial model classes fields ##@brief Handles editorial model classes fields
class EmField(EmComponent): class EmField(EmComponent):
## @brief Instanciate a new EmField ##@brief Instanciate a new EmField
# @param uid str : uniq identifier # @param uid str : uniq identifier
# @param display_name MlString|str|dict : field display_name # @param display_name MlString|str|dict : field display_name
# @param data_handler str : A DataHandler name # @param data_handler str : A DataHandler name
@ -165,22 +165,22 @@ class EmField(EmComponent):
def __init__(self, uid, data_handler, display_name = None, help_text = None, group = None, **handler_kwargs): def __init__(self, uid, data_handler, display_name = None, help_text = None, group = None, **handler_kwargs):
from lodel.leapi.datahandlers.base_classes import DataHandler from lodel.leapi.datahandlers.base_classes import DataHandler
super().__init__(uid, display_name, help_text, group) super().__init__(uid, display_name, help_text, group)
## @brief The data handler name ##@brief The data handler name
self.data_handler_name = data_handler self.data_handler_name = data_handler
## @brief The data handler class ##@brief The data handler class
self.data_handler_cls = DataHandler.from_name(data_handler) self.data_handler_cls = DataHandler.from_name(data_handler)
## @brief The data handler instance associated with this EmField ##@brief The data handler instance associated with this EmField
self.data_handler_instance = self.data_handler_cls(**handler_kwargs) self.data_handler_instance = self.data_handler_cls(**handler_kwargs)
## @brief Stores data handler instanciation options ##@brief Stores data handler instanciation options
self.data_handler_options = handler_kwargs self.data_handler_options = handler_kwargs
## @brief Stores the emclass that contains this field (set by EmClass.add_field() method) ##@brief Stores the emclass that contains this field (set by EmClass.add_field() method)
self._emclass = None self._emclass = None
## @brief Returns data_handler_name attribute ##@brief Returns data_handler_name attribute
def get_data_handler_name(self): def get_data_handler_name(self):
return copy.copy(self.data_handler_name) return copy.copy(self.data_handler_name)
## @brief Returns data_handler_cls attribute ##@brief Returns data_handler_cls attribute
def get_data_handler_cls(self): def get_data_handler_cls(self):
return copy.copy(selfdata_handler_cls) return copy.copy(selfdata_handler_cls)
@ -195,10 +195,10 @@ class EmField(EmComponent):
'utf-8') 'utf-8')
).digest(), byteorder='big') ).digest(), byteorder='big')
## @brief Handles functionnal group of EmComponents ##@brief Handles functionnal group of EmComponents
class EmGroup(object): class EmGroup(object):
## @brief Create a new EmGroup ##@brief Create a new EmGroup
# @note you should NEVER call the constructor yourself. Use Model.add_group instead # @note you should NEVER call the constructor yourself. Use Model.add_group instead
# @param uid str : Uniq identifier # @param uid str : Uniq identifier
# @param depends list : A list of EmGroup dependencies # @param depends list : A list of EmGroup dependencies
@ -206,11 +206,11 @@ class EmGroup(object):
# @param help_text MlString|str : # @param help_text MlString|str :
def __init__(self, uid, depends = None, display_name = None, help_text = None): def __init__(self, uid, depends = None, display_name = None, help_text = None):
self.uid = uid self.uid = uid
## @brief Stores the list of groups that depends on this EmGroup indexed by uid ##@brief Stores the list of groups that depends on this EmGroup indexed by uid
self.required_by = dict() self.required_by = dict()
## @brief Stores the list of dependencies (EmGroup) indexed by uid ##@brief Stores the list of dependencies (EmGroup) indexed by uid
self.require = dict() self.require = dict()
## @brief Stores the list of EmComponent instances contained in this group ##@brief Stores the list of EmComponent instances contained in this group
self.__components = set() self.__components = set()
self.display_name = None if display_name is None else MlString(display_name) self.display_name = None if display_name is None else MlString(display_name)
@ -221,7 +221,7 @@ class EmGroup(object):
raise ValueError("EmGroup expected in depends argument but %s found" % grp) raise ValueError("EmGroup expected in depends argument but %s found" % grp)
self.add_dependencie(grp) self.add_dependencie(grp)
## @brief Returns EmGroup dependencie ##@brief Returns EmGroup dependencie
# @param recursive bool : if True return all dependencies and their dependencies # @param recursive bool : if True return all dependencies and their dependencies
# @return a dict of EmGroup identified by uid # @return a dict of EmGroup identified by uid
def dependencies(self, recursive = False): def dependencies(self, recursive = False):
@ -237,7 +237,7 @@ class EmGroup(object):
res[new_dep.uid] = new_dep res[new_dep.uid] = new_dep
return res return res
## @brief Returns EmGroup applicants ##@brief Returns EmGroup applicants
# @param recursive bool : if True return all dependencies and their dependencies # @param recursive bool : if True return all dependencies and their dependencies
# @returns a dict of EmGroup identified by uid # @returns a dict of EmGroup identified by uid
def applicants(self, recursive = False): def applicants(self, recursive = False):
@ -253,12 +253,12 @@ class EmGroup(object):
res[new_app.uid] = new_app res[new_app.uid] = new_app
return res return res
## @brief Returns EmGroup components ##@brief Returns EmGroup components
# @returns a copy of the set of components # @returns a copy of the set of components
def components(self): def components(self):
return (self.__components).copy() return (self.__components).copy()
## @brief Returns EmGroup display_name ##@brief Returns EmGroup display_name
# @param lang str | None : If None return default lang translation # @param lang str | None : If None return default lang translation
# @returns None if display_name is None, a str for display_name else # @returns None if display_name is None, a str for display_name else
def get_display_name(self, lang=None): def get_display_name(self, lang=None):
@ -266,7 +266,7 @@ class EmGroup(object):
if name is None : return None if name is None : return None
return name.get(lang); return name.get(lang);
## @brief Returns EmGroup help_text ##@brief Returns EmGroup help_text
# @param lang str | None : If None return default lang translation # @param lang str | None : If None return default lang translation
# @returns None if display_name is None, a str for display_name else # @returns None if display_name is None, a str for display_name else
def get_help_text(self, lang=None): def get_help_text(self, lang=None):
@ -274,7 +274,7 @@ class EmGroup(object):
if help is None : return None if help is None : return None
return help.get(lang); return help.get(lang);
## @brief Add components in a group ##@brief Add components in a group
# @param components list : EmComponent instances list # @param components list : EmComponent instances list
def add_components(self, components): def add_components(self, components):
for component in components: for component in components:
@ -285,7 +285,7 @@ class EmGroup(object):
raise EditorialModelError("Expecting components to be a list of EmComponent, but %s found in the list" % type(component)) raise EditorialModelError("Expecting components to be a list of EmComponent, but %s found in the list" % type(component))
self.__components |= set(components) self.__components |= set(components)
## @brief Add a dependencie ##@brief Add a dependencie
# @param em_group EmGroup|iterable : an EmGroup instance or list of instance # @param em_group EmGroup|iterable : an EmGroup instance or list of instance
def add_dependencie(self, grp): def add_dependencie(self, grp):
try: try:
@ -301,7 +301,7 @@ class EmGroup(object):
self.require[grp.uid] = grp self.require[grp.uid] = grp
grp.required_by[self.uid] = self grp.required_by[self.uid] = self
## @brief Add a applicant ##@brief Add a applicant
# @param em_group EmGroup|iterable : an EmGroup instance or list of instance # @param em_group EmGroup|iterable : an EmGroup instance or list of instance
def add_applicant(self, grp): def add_applicant(self, grp):
try: try:
@ -317,17 +317,17 @@ class EmGroup(object):
self.required_by[grp.uid] = grp self.required_by[grp.uid] = grp
grp.require[self.uid] = self grp.require[self.uid] = self
## @brief Search for circular dependencie ##@brief Search for circular dependencie
# @return True if circular dep found else False # @return True if circular dep found else False
def __circular_dependencie(self, new_dep): def __circular_dependencie(self, new_dep):
return self.uid in new_dep.dependencies(True) return self.uid in new_dep.dependencies(True)
## @brief Search for circular applicant ##@brief Search for circular applicant
# @return True if circular app found else False # @return True if circular app found else False
def __circular_applicant(self, new_app): def __circular_applicant(self, new_app):
return self.uid in new_app.applicants(True) return self.uid in new_app.applicants(True)
## @brief Fancy string representation of an EmGroup ##@brief Fancy string representation of an EmGroup
# @return a string # @return a string
def __str__(self): def __str__(self):
if self.display_name is None: if self.display_name is None:
@ -353,7 +353,7 @@ class EmGroup(object):
byteorder = 'big' byteorder = 'big'
) )
## @brief Complete string representation of an EmGroup ##@brief Complete string representation of an EmGroup
# @return a string # @return a string
def __repr__(self): def __repr__(self):
return "<class EmGroup '%s' depends : [%s]>" % (self.uid, ', '.join([duid for duid in self.dependencies(False)]) ) return "<class EmGroup '%s' depends : [%s]>" % (self.uid, ', '.join([duid for duid in self.dependencies(False)]) )

View file

@ -8,21 +8,21 @@ from lodel.utils.mlstring import MlString
from lodel.editorial_model.exceptions import * from lodel.editorial_model.exceptions import *
from lodel.editorial_model.components import EmClass, EmField, EmGroup from lodel.editorial_model.components import EmClass, EmField, EmGroup
## @brief Describe an editorial model ##@brief Describe an editorial model
class EditorialModel(object): class EditorialModel(object):
## @brief Create a new editorial model ##@brief Create a new editorial model
# @param name MlString|str|dict : the editorial model name # @param name MlString|str|dict : the editorial model name
# @param description MlString|str|dict : the editorial model description # @param description MlString|str|dict : the editorial model description
def __init__(self, name, description = None): def __init__(self, name, description = None):
self.name = MlString(name) self.name = MlString(name)
self.description = MlString(description) self.description = MlString(description)
## @brief Stores all groups indexed by id ##@brief Stores all groups indexed by id
self.__groups = dict() self.__groups = dict()
## @brief Stores all classes indexed by id ##@brief Stores all classes indexed by id
self.__classes = dict() self.__classes = dict()
## @brief EmClass accessor ##@brief EmClass accessor
# @param uid None | str : give this argument to get a specific EmClass # @param uid None | str : give this argument to get a specific EmClass
# @return if uid is given returns an EmClass else returns an EmClass iterator # @return if uid is given returns an EmClass else returns an EmClass iterator
def classes(self, uid = None): def classes(self, uid = None):
@ -31,7 +31,7 @@ class EditorialModel(object):
except KeyError: except KeyError:
raise EditorialModelException("EmClass not found : '%s'" % uid) raise EditorialModelException("EmClass not found : '%s'" % uid)
## @brief EmGroup getter ##@brief EmGroup getter
# @param uid None | str : give this argument to get a specific EmGroup # @param uid None | str : give this argument to get a specific EmGroup
# @return if uid is given returns an EmGroup else returns an EmGroup iterator # @return if uid is given returns an EmGroup else returns an EmGroup iterator
def groups(self, uid = None): def groups(self, uid = None):
@ -40,7 +40,7 @@ class EditorialModel(object):
except KeyError: except KeyError:
raise EditorialModelException("EmGroup not found : '%s'" % uid) raise EditorialModelException("EmGroup not found : '%s'" % uid)
## @brief EmField getter ##@brief EmField getter
# @param uid str : An EmField uid represented by "CLASSUID.FIELDUID" # @param uid str : An EmField uid represented by "CLASSUID.FIELDUID"
# @return Fals or an EmField instance # @return Fals or an EmField instance
# #
@ -61,7 +61,7 @@ class EditorialModel(object):
pass pass
return False return False
## @brief Add a class to the editorial model ##@brief Add a class to the editorial model
# @param emclass EmClass : the EmClass instance to add # @param emclass EmClass : the EmClass instance to add
# @return emclass # @return emclass
def add_class(self, emclass): def add_class(self, emclass):
@ -72,7 +72,7 @@ class EditorialModel(object):
self.__classes[emclass.uid] = emclass self.__classes[emclass.uid] = emclass
return emclass return emclass
## @brief Add a group to the editorial model ##@brief Add a group to the editorial model
# @param emgroup EmGroup : the EmGroup instance to add # @param emgroup EmGroup : the EmGroup instance to add
# @return emgroup # @return emgroup
def add_group(self, emgroup): def add_group(self, emgroup):
@ -83,13 +83,13 @@ class EditorialModel(object):
self.__groups[emgroup.uid] = emgroup self.__groups[emgroup.uid] = emgroup
return emgroup return emgroup
## @brief Add a new EmClass to the editorial model ##@brief Add a new EmClass to the editorial model
# @param uid str : EmClass uid # @param uid str : EmClass uid
# @param **kwargs : EmClass constructor options ( see @ref lodel.editorial_model.component.EmClass.__init__() ) # @param **kwargs : EmClass constructor options ( see @ref lodel.editorial_model.component.EmClass.__init__() )
def new_class(self, uid, **kwargs): def new_class(self, uid, **kwargs):
return self.add_class(EmClass(uid, **kwargs)) return self.add_class(EmClass(uid, **kwargs))
## @brief Add a new EmGroup to the editorial model ##@brief Add a new EmGroup to the editorial model
# @param uid str : EmGroup uid # @param uid str : EmGroup uid
# @param *kwargs : EmGroup constructor keywords arguments (see @ref lodel.editorial_model.component.EmGroup.__init__() ) # @param *kwargs : EmGroup constructor keywords arguments (see @ref lodel.editorial_model.component.EmGroup.__init__() )
def new_group(self, uid, **kwargs): def new_group(self, uid, **kwargs):
@ -103,7 +103,7 @@ class EditorialModel(object):
translator = self.translator_from_name(translator) translator = self.translator_from_name(translator)
return translator.save(self, **translator_kwargs) return translator.save(self, **translator_kwargs)
## @brief Load a model ##@brief Load a model
# @param translator module : The translator module to use # @param translator module : The translator module to use
# @param **translator_args # @param **translator_args
@classmethod @classmethod
@ -112,7 +112,7 @@ class EditorialModel(object):
translator = cls.translator_from_name(translator) translator = cls.translator_from_name(translator)
return translator.load(**translator_kwargs) return translator.load(**translator_kwargs)
## @brief Return a translator module given a translator name ##@brief Return a translator module given a translator name
# @param translator_name str : The translator name # @param translator_name str : The translator name
# @return the translator python module # @return the translator python module
# @throw NameError if the translator does not exists # @throw NameError if the translator does not exists
@ -126,12 +126,12 @@ class EditorialModel(object):
return mod return mod
## @brief Private getter for __groups or __classes ##@brief Private getter for __groups or __classes
# @see classes() groups() # @see classes() groups()
def __elt_getter(self, elts, uid): def __elt_getter(self, elts, uid):
return list(elts.values()) if uid is None else elts[uid] return list(elts.values()) if uid is None else elts[uid]
## @brief Lodel hash ##@brief Lodel hash
def d_hash(self): def d_hash(self):
payload = "%s%s" % ( payload = "%s%s" % (
self.name, self.name,

View file

@ -3,7 +3,7 @@
import pickle import pickle
from pickle import Pickler from pickle import Pickler
## @brief Save a model in a file ##@brief Save a model in a file
# @param model EditorialModel : the model to save # @param model EditorialModel : the model to save
# @param filename str|None : if None return the model as pickle bytes # @param filename str|None : if None return the model as pickle bytes
# @return None if filename is a string, else returns bytes representation of model # @return None if filename is a string, else returns bytes representation of model
@ -12,7 +12,7 @@ def save(model, filename = None):
pickle.dump(model, ffd) pickle.dump(model, ffd)
return filename return filename
## @brief Load a model from a file ##@brief Load a model from a file
# @param filename str : the filename to use to load the model # @param filename str : the filename to use to load the model
def load(filename): def load(filename):
with open(filename, 'rb') as ffd: with open(filename, 'rb') as ffd:

View file

@ -13,22 +13,22 @@ from lodel import logger
class FieldValidationError(Exception): class FieldValidationError(Exception):
pass pass
## @brief Base class for all data handlers ##@brief Base class for all data handlers
class DataHandler(object): class DataHandler(object):
__HANDLERS_MODULES = ('datas_base', 'datas', 'references') __HANDLERS_MODULES = ('datas_base', 'datas', 'references')
## @brief Stores the DataHandler childs classes indexed by name ##@brief Stores the DataHandler childs classes indexed by name
__base_handlers = None __base_handlers = None
## @brief Stores custom datahandlers classes indexed by name ##@brief Stores custom datahandlers classes indexed by name
# @todo do it ! (like plugins, register handlers... blablabla) # @todo do it ! (like plugins, register handlers... blablabla)
__custom_handlers = dict() __custom_handlers = dict()
help_text = 'Generic Field Data Handler' help_text = 'Generic Field Data Handler'
## @brief List fields that will be exposed to the construct_data_method ##@brief List fields that will be exposed to the construct_data_method
_construct_datas_deps = [] _construct_datas_deps = []
## @brief constructor ##@brief constructor
# @param internal False | str : define whether or not a field is internal # @param internal False | str : define whether or not a field is internal
# @param immutable bool : indicates if the fieldtype has to be defined in child classes of LeObject or if it is # @param immutable bool : indicates if the fieldtype has to be defined in child classes of LeObject or if it is
# designed globally and immutable # designed globally and immutable
@ -65,12 +65,12 @@ class DataHandler(object):
def is_primary_key(self): def is_primary_key(self):
return self.primary_key return self.primary_key
## @brief checks if a fieldtype is internal ##@brief checks if a fieldtype is internal
# @return bool # @return bool
def is_internal(self): def is_internal(self):
return self.internal is not False return self.internal is not False
## @brief calls the data_field defined _check_data_value() method ##@brief calls the data_field defined _check_data_value() method
# @return tuple (value, error|None) # @return tuple (value, error|None)
def check_data_value(self, value): def check_data_value(self, value):
if value is None: if value is None:
@ -80,7 +80,7 @@ class DataHandler(object):
return None, None return None, None
return self._check_data_value(value) return self._check_data_value(value)
## @brief checks if this class can override the given data handler ##@brief checks if this class can override the given data handler
# @param data_handler DataHandler # @param data_handler DataHandler
# @return bool # @return bool
def can_override(self, data_handler): def can_override(self, data_handler):
@ -88,7 +88,7 @@ class DataHandler(object):
return False return False
return True return True
## @brief Build field value ##@brief Build field value
# @param emcomponent EmComponent : An EmComponent child class instance # @param emcomponent EmComponent : An EmComponent child class instance
# @param fname str : The field name # @param fname str : The field name
# @param datas dict : dict storing fields values (from the component) # @param datas dict : dict storing fields values (from the component)
@ -110,7 +110,7 @@ class DataHandler(object):
return RuntimeError("Unable to construct data for field %s", fname) return RuntimeError("Unable to construct data for field %s", fname)
## @brief Check datas consistency ##@brief Check datas consistency
# @param emcomponent EmComponent : An EmComponent child class instance # @param emcomponent EmComponent : An EmComponent child class instance
# @param fname : the field name # @param fname : the field name
# @param datas dict : dict storing fields values # @param datas dict : dict storing fields values
@ -119,7 +119,7 @@ class DataHandler(object):
def check_data_consistency(self, emcomponent, fname, datas): def check_data_consistency(self, emcomponent, fname, datas):
return True return True
## @brief This method is use by plugins to register new data handlers ##@brief This method is use by plugins to register new data handlers
@classmethod @classmethod
def register_new_handler(cls, name, data_handler): def register_new_handler(cls, name, data_handler):
if not inspect.isclass(data_handler): if not inspect.isclass(data_handler):
@ -140,7 +140,7 @@ class DataHandler(object):
cls.__base_handlers[name.lower()] = obj cls.__base_handlers[name.lower()] = obj
return copy.copy(cls.__base_handlers) return copy.copy(cls.__base_handlers)
## @brief given a field type name, returns the associated python class ##@brief given a field type name, returns the associated python class
# @param fieldtype_name str : A field type name (not case sensitive) # @param fieldtype_name str : A field type name (not case sensitive)
# @return DataField child class # @return DataField child class
# @todo implements custom handlers fetch # @todo implements custom handlers fetch
@ -152,7 +152,7 @@ class DataHandler(object):
raise NameError("No data handlers named '%s'" % (name,)) raise NameError("No data handlers named '%s'" % (name,))
return cls.__base_handlers[name] return cls.__base_handlers[name]
## @brief Return the module name to import in order to use the datahandler ##@brief Return the module name to import in order to use the datahandler
# @param data_handler_name str : Data handler name # @param data_handler_name str : Data handler name
# @return a str # @return a str
@classmethod @classmethod
@ -164,24 +164,24 @@ class DataHandler(object):
class_name = handler_class.__name__ class_name = handler_class.__name__
) )
## @brief __hash__ implementation for fieldtypes ##@brief __hash__ implementation for fieldtypes
def __hash__(self): def __hash__(self):
hash_dats = [self.__class__.__module__] hash_dats = [self.__class__.__module__]
for kdic in sorted([k for k in self.__dict__.keys() if not k.startswith('_')]): for kdic in sorted([k for k in self.__dict__.keys() if not k.startswith('_')]):
hash_dats.append((kdic, getattr(self, kdic))) hash_dats.append((kdic, getattr(self, kdic)))
return hash(tuple(hash_dats)) return hash(tuple(hash_dats))
## @brief Base class for datas data handler (by opposition with references) ##@brief Base class for datas data handler (by opposition with references)
class DataField(DataHandler): class DataField(DataHandler):
pass pass
## @brief Abstract class for all references ##@brief Abstract class for all references
# #
# References are fields that stores a reference to another # References are fields that stores a reference to another
# editorial object # editorial object
class Reference(DataHandler): class Reference(DataHandler):
## @brief Instanciation ##@brief Instanciation
# @param allowed_classes list | None : list of allowed em classes if None no restriction # @param allowed_classes list | None : list of allowed em classes if None no restriction
# @param back_reference tuple | None : tuple containing (LeObject child class, fieldname) # @param back_reference tuple | None : tuple containing (LeObject child class, fieldname)
# @param internal bool : if False, the field is not internal # @param internal bool : if False, the field is not internal
@ -200,12 +200,12 @@ class Reference(DataHandler):
def back_reference(self): def back_reference(self):
return copy.copy(self.__back_reference) return copy.copy(self.__back_reference)
## @brief Set the back reference for this field. ##@brief Set the back reference for this field.
def _set_back_reference(self, back_reference): def _set_back_reference(self, back_reference):
self.__back_reference = back_reference self.__back_reference = back_reference
## @brief Check value ##@brief Check value
# @param value * # @param value *
# @return tuple(value, exception) # @return tuple(value, exception)
# @todo implement the check when we have LeObject to check value # @todo implement the check when we have LeObject to check value
@ -222,7 +222,7 @@ class Reference(DataHandler):
return value return value
## @brief This class represent a data_handler for single reference to another object ##@brief This class represent a data_handler for single reference to another object
# #
# The fields using this data handlers are like "foreign key" on another object # The fields using this data handlers are like "foreign key" on another object
class SingleRef(Reference): class SingleRef(Reference):
@ -238,7 +238,7 @@ class SingleRef(Reference):
return val, expt return val, expt
## @brief This class represent a data_handler for multiple references to another object ##@brief This class represent a data_handler for multiple references to another object
# #
# The fields using this data handlers are like SingleRef but can store multiple references in one field # The fields using this data handlers are like SingleRef but can store multiple references in one field
# @note SQL implementation could be tricky # @note SQL implementation could be tricky

View file

@ -2,13 +2,13 @@
from lodel.leapi.datahandlers.datas_base import * from lodel.leapi.datahandlers.datas_base import *
## @brief Data field designed to handle formated strings ##@brief Data field designed to handle formated strings
class FormatString(Varchar): class FormatString(Varchar):
help = 'Automatic string field, designed to use the str % operator to build its content' help = 'Automatic string field, designed to use the str % operator to build its content'
base_type = 'char' base_type = 'char'
## @brief Build its content with a field list and a format string ##@brief Build its content with a field list and a format string
# @param format_string str # @param format_string str
# @param max_length int : the maximum length of the handled value # @param max_length int : the maximum length of the handled value
# @param field_list list : List of field to use # @param field_list list : List of field to use
@ -26,13 +26,13 @@ class FormatString(Varchar):
return False return False
return True return True
## @brief Varchar validated by a regex ##@brief Varchar validated by a regex
class Regex(Varchar): class Regex(Varchar):
help = 'String field validated with a regex. Takes two options : max_length and regex' help = 'String field validated with a regex. Takes two options : max_length and regex'
base_type = 'char' base_type = 'char'
## @brief A string field validated by a regex ##@brief A string field validated by a regex
# @param regex str : a regex string (passed as argument to re.compile()) # @param regex str : a regex string (passed as argument to re.compile())
# @param max_length int : the max length for this field (default : 10) # @param max_length int : the max length for this field (default : 10)
# @param **kwargs # @param **kwargs
@ -57,13 +57,13 @@ class Regex(Varchar):
return False return False
return True return True
## @brief Handles uniq ID ##@brief Handles uniq ID
class UniqID(Integer): class UniqID(Integer):
help = 'Fieldtype designed to handle editorial model UID' help = 'Fieldtype designed to handle editorial model UID'
base_type = 'int' base_type = 'int'
## @brief A uid field ##@brief A uid field
# @param **kwargs # @param **kwargs
def __init__(self, **kwargs): def __init__(self, **kwargs):
kwargs['internal'] = 'automatic' kwargs['internal'] = 'automatic'

View file

@ -3,13 +3,13 @@ import warnings
from lodel.leapi.datahandlers.base_classes import DataField from lodel.leapi.datahandlers.base_classes import DataField
## @brief Data field designed to handle boolean values ##@brief Data field designed to handle boolean values
class Boolean(DataField): class Boolean(DataField):
help = 'A basic boolean field' help = 'A basic boolean field'
base_type = 'bool' base_type = 'bool'
## @brief A boolean field ##@brief A boolean field
def __init__(self, **kwargs): def __init__(self, **kwargs):
if 'check_data_value' not in kwargs: if 'check_data_value' not in kwargs:
kwargs['check_data_value'] = self.check_value kwargs['check_data_value'] = self.check_value
@ -23,7 +23,7 @@ class Boolean(DataField):
error = TypeError("The value '%s' is not, and will never, be a boolean" % value) error = TypeError("The value '%s' is not, and will never, be a boolean" % value)
return value, error return value, error
## @brief Data field designed to handle integer values ##@brief Data field designed to handle integer values
class Integer(DataField): class Integer(DataField):
help = 'Basic integer field' help = 'Basic integer field'
@ -40,19 +40,19 @@ class Integer(DataField):
error = TypeError("The value '%s' is not, and will never, be an integer" % value) error = TypeError("The value '%s' is not, and will never, be an integer" % value)
return value, error return value, error
## @brief Data field designed to handle string ##@brief Data field designed to handle string
class Varchar(DataField): class Varchar(DataField):
help = 'Basic string (varchar) field. Default size is 64 characters' help = 'Basic string (varchar) field. Default size is 64 characters'
base_type = 'char' base_type = 'char'
## @brief A string field ##@brief A string field
# @brief max_length int: The maximum length of this field # @brief max_length int: The maximum length of this field
def __init__(self, max_length=64, **kwargs): def __init__(self, max_length=64, **kwargs):
self.max_length = int(max_length) self.max_length = int(max_length)
super().__init__(**kwargs) super().__init__(**kwargs)
## @brief checks if this class can override the given data handler ##@brief checks if this class can override the given data handler
# @param data_handler DataHandler # @param data_handler DataHandler
# @return bool # @return bool
def can_override(self, data_handler): def can_override(self, data_handler):
@ -62,13 +62,13 @@ class Varchar(DataField):
return False return False
return True return True
## @brief Data field designed to handle date & time ##@brief Data field designed to handle date & time
class DateTime(DataField): class DateTime(DataField):
help = 'A datetime field. Take two boolean options now_on_update and now_on_create' help = 'A datetime field. Take two boolean options now_on_update and now_on_create'
base_type = 'datetime' base_type = 'datetime'
## @brief A datetime field ##@brief A datetime field
# @param now_on_update bool : If true, the date is set to NOW on update # @param now_on_update bool : If true, the date is set to NOW on update
# @param now_on_create bool : If true, the date is set to NEW on creation # @param now_on_create bool : If true, the date is set to NEW on creation
# @param **kwargs # @param **kwargs
@ -77,7 +77,7 @@ class DateTime(DataField):
self.now_on_create = now_on_create self.now_on_create = now_on_create
super().__init__(**kwargs) super().__init__(**kwargs)
## @brief Data field designed to handle long string ##@brief Data field designed to handle long string
class Text(DataField): class Text(DataField):
help = 'A text field (big string)' help = 'A text field (big string)'
base_type = 'text' base_type = 'text'
@ -85,12 +85,12 @@ class Text(DataField):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(self.__class__, self).__init__(ftype='text', **kwargs) super(self.__class__, self).__init__(ftype='text', **kwargs)
## @brief Data field designed to handle Files ##@brief Data field designed to handle Files
class File(DataField): class File(DataField):
base_type = 'file' base_type = 'file'
## @brief a file field ##@brief a file field
# @param upload_path str : None by default # @param upload_path str : None by default
# @param **kwargs # @param **kwargs
def __init__(self, upload_path=None, **kwargs): def __init__(self, upload_path=None, **kwargs):

View file

@ -3,17 +3,17 @@ from lodel.leapi.datahandlers.base_classes import Reference, MultipleRef, Single
class Link(SingleRef): pass class Link(SingleRef): pass
## @brief Child class of MultipleRef where references are represented in the form of a python list ##@brief Child class of MultipleRef where references are represented in the form of a python list
class List(MultipleRef): class List(MultipleRef):
## @brief instanciates a list reference ##@brief instanciates a list reference
# @param allowed_classes list | None : list of allowed em classes if None no restriction # @param allowed_classes list | None : list of allowed em classes if None no restriction
# @param internal bool # @param internal bool
# @param kwargs # @param kwargs
def __init__(self, max_length = None, **kwargs): def __init__(self, max_length = None, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
## @brief Check value ##@brief Check value
# @param value * # @param value *
# @return tuple(value, exception) # @return tuple(value, exception)
def _check_data_value(self, value): def _check_data_value(self, value):
@ -24,17 +24,17 @@ class List(MultipleRef):
return val, expt return val, expt
## @brief Child class of MultipleRef where references are represented in the form of a python set ##@brief Child class of MultipleRef where references are represented in the form of a python set
class Set(MultipleRef): class Set(MultipleRef):
## @brief instanciates a set reference ##@brief instanciates a set reference
# @param allowed_classes list | None : list of allowed em classes if None no restriction # @param allowed_classes list | None : list of allowed em classes if None no restriction
# @param internal bool : if False, the field is not internal # @param internal bool : if False, the field is not internal
# @param kwargs : Other named arguments # @param kwargs : Other named arguments
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
## @brief Check value ##@brief Check value
# @param value * # @param value *
# @return tuple(value, exception) # @return tuple(value, exception)
def _check_data_value(self, value): def _check_data_value(self, value):
@ -45,17 +45,17 @@ class Set(MultipleRef):
return val, expt return val, expt
## @brief Child class of MultipleRef where references are represented in the form of a python dict ##@brief Child class of MultipleRef where references are represented in the form of a python dict
class Map(MultipleRef): class Map(MultipleRef):
## @brief instanciates a dict reference ##@brief instanciates a dict reference
# @param allowed_classes list | None : list of allowed em classes if None no restriction # @param allowed_classes list | None : list of allowed em classes if None no restriction
# @param internal bool : if False, the field is not internal # @param internal bool : if False, the field is not internal
# @param kwargs : Other named arguments # @param kwargs : Other named arguments
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
## @brief Check value ##@brief Check value
# @param value * # @param value *
# @return tuple(value, exception) # @return tuple(value, exception)
def _check_data_value(self, value): def _check_data_value(self, value):
@ -66,10 +66,10 @@ class Map(MultipleRef):
None if isinstance(expt, Exception) else value, None if isinstance(expt, Exception) else value,
expt) expt)
## @brief This Reference class is designed to handler hierarchy with some constraint ##@brief This Reference class is designed to handler hierarchy with some constraint
class Hierarch(MultipleRef): class Hierarch(MultipleRef):
## @brief Instanciate a data handler handling hierarchical relation with constraints ##@brief Instanciate a data handler handling hierarchical relation with constraints
# @param back_reference tuple : Here it is mandatory to have a back ref (like a parent field) # @param back_reference tuple : Here it is mandatory to have a back ref (like a parent field)
# @param max_depth int | None : limit of depth # @param max_depth int | None : limit of depth
# @param max_childs int | Nine : maximum number of childs by nodes # @param max_childs int | Nine : maximum number of childs by nodes

View file

@ -5,7 +5,7 @@ from lodel.editorial_model.components import *
from lodel.leapi.leobject import LeObject from lodel.leapi.leobject import LeObject
from lodel.leapi.datahandlers.base_classes import DataHandler from lodel.leapi.datahandlers.base_classes import DataHandler
## @brief Generate python module code from a given model ##@brief Generate python module code from a given model
# @param model lodel.editorial_model.model.EditorialModel # @param model lodel.editorial_model.model.EditorialModel
def dyncode_from_em(model): def dyncode_from_em(model):
@ -31,7 +31,7 @@ from lodel.leapi.datahandlers.base_classes import DataField
) )
return res_code return res_code
## @brief return A list of EmClass sorted by dependencies ##@brief return A list of EmClass sorted by dependencies
# #
# The first elts in the list depends on nothing, etc. # The first elts in the list depends on nothing, etc.
# @return a list of EmClass instances # @return a list of EmClass instances
@ -41,11 +41,11 @@ def emclass_sorted_by_deps(emclass_list):
ret = sorted(emclass_list, key = functools.cmp_to_key(emclass_deps_cmp)) ret = sorted(emclass_list, key = functools.cmp_to_key(emclass_deps_cmp))
return ret return ret
## @brief Returns a list of EmClass that will be represented as LeObject child classes ##@brief Returns a list of EmClass that will be represented as LeObject child classes
def get_classes(model): def get_classes(model):
return [ cls for cls in emclass_sorted_by_deps(model.classes()) if not cls.pure_abstract ] return [ cls for cls in emclass_sorted_by_deps(model.classes()) if not cls.pure_abstract ]
## @brief Given an EmField returns the data_handler constructor suitable for dynamic code ##@brief Given an EmField returns the data_handler constructor suitable for dynamic code
def data_handler_constructor(emfield): def data_handler_constructor(emfield):
#dh_module_name = DataHandler.module_name(emfield.data_handler_name)+'.DataHandler' #dh_module_name = DataHandler.module_name(emfield.data_handler_name)+'.DataHandler'
get_handler_class_instr = 'DataField.from_name(%s)' % repr(emfield.data_handler_name) get_handler_class_instr = 'DataField.from_name(%s)' % repr(emfield.data_handler_name)
@ -63,7 +63,7 @@ def data_handler_constructor(emfield):
handler_instr = get_handler_class_instr, handler_instr = get_handler_class_instr,
options = ', '.join(options)) options = ', '.join(options))
## @brief Return a python repr of option values ##@brief Return a python repr of option values
def forge_optval(optval): def forge_optval(optval):
if isinstance(optval, dict): if isinstance(optval, dict):
return '{' + (', '.join( [ '%s: %s' % (repr(name), forge_optval(val)) for name, val in optval.items()])) + '}' return '{' + (', '.join( [ '%s: %s' % (repr(name), forge_optval(val)) for name, val in optval.items()])) + '}'
@ -81,7 +81,7 @@ def forge_optval(optval):
else: else:
return repr(optval) return repr(optval)
## @brief Generate dyncode from an EmClass ##@brief Generate dyncode from an EmClass
# @param model EditorialModel : # @param model EditorialModel :
# @param emclass EmClass : EmClass instance # @param emclass EmClass : EmClass instance
# @return a tuple with emclass python code, a set containing modules name to import, and a list of python instruction to bootstrap dynamic code, in this order # @return a tuple with emclass python code, a set containing modules name to import, and a list of python instruction to bootstrap dynamic code, in this order

View file

@ -3,7 +3,7 @@
import importlib import importlib
class LeApiErrors(Exception): class LeApiErrors(Exception):
## @brief Instanciate a new exceptions handling multiple exceptions ##@brief Instanciate a new exceptions handling multiple exceptions
# @param msg str : Exception message # @param msg str : Exception message
# @param exceptions dict : A list of data check Exception with concerned field (or stuff) as key # @param exceptions dict : A list of data check Exception with concerned field (or stuff) as key
def __init__(self, msg = "Unknow error", exceptions = None): def __init__(self, msg = "Unknow error", exceptions = None):
@ -25,37 +25,37 @@ class LeApiErrors(Exception):
return msg return msg
## @brief When an error concern a query ##@brief When an error concern a query
class LeApiQueryError(LeApiErrors): class LeApiQueryError(LeApiErrors):
pass pass
## @brief When an error concerns a datas ##@brief When an error concerns a datas
class LeApiDataCheckError(LeApiErrors): class LeApiDataCheckError(LeApiErrors):
pass pass
## @brief Wrapper class for LeObject getter & setter ##@brief Wrapper class for LeObject getter & setter
# #
# This class intend to provide easy & friendly access to LeObject fields values # This class intend to provide easy & friendly access to LeObject fields values
# without name collision problems # without name collision problems
# @note Wrapped methods are : LeObject.data() & LeObject.set_data() # @note Wrapped methods are : LeObject.data() & LeObject.set_data()
class LeObjectValues(object): class LeObjectValues(object):
## @brief Construct a new LeObjectValues ##@brief Construct a new LeObjectValues
# @param set_callback method : The LeObject.set_datas() method of corresponding LeObject class # @param set_callback method : The LeObject.set_datas() method of corresponding LeObject class
# @param get_callback method : The LeObject.get_datas() method of corresponding LeObject class # @param get_callback method : The LeObject.get_datas() method of corresponding LeObject class
def __init__(self, fieldnames_callback, set_callback, get_callback): def __init__(self, fieldnames_callback, set_callback, get_callback):
self.__setter = set_callback self.__setter = set_callback
self.__getter = get_callback self.__getter = get_callback
## @brief Provide read access to datas values ##@brief Provide read access to datas values
# @note Read access should be provided for all fields # @note Read access should be provided for all fields
# @param fname str : Field name # @param fname str : Field name
def __getattribute__(self, fname): def __getattribute__(self, fname):
return self.__getter(fname) return self.__getter(fname)
## @brief Provide write access to datas values ##@brief Provide write access to datas values
# @note Write acces shouldn't be provided for internal or immutable fields # @note Write acces shouldn't be provided for internal or immutable fields
# @param fname str : Field name # @param fname str : Field name
# @param fval * : the field value # @param fval * : the field value
@ -65,23 +65,23 @@ class LeObjectValues(object):
class LeObject(object): class LeObject(object):
## @brief boolean that tells if an object is abtract or not ##@brief boolean that tells if an object is abtract or not
_abstract = None _abstract = None
## @brief A dict that stores DataHandler instances indexed by field name ##@brief A dict that stores DataHandler instances indexed by field name
_fields = None _fields = None
## @brief A tuple of fieldname (or a uniq fieldname) representing uid ##@brief A tuple of fieldname (or a uniq fieldname) representing uid
_uid = None _uid = None
## @brief Construct an object representing an Editorial component ##@brief Construct an object representing an Editorial component
# @note Can be considered as EmClass instance # @note Can be considered as EmClass instance
def __init__(self, **kwargs): def __init__(self, **kwargs):
if self._abstract: if self._abstract:
raise NotImplementedError("%s is abstract, you cannot instanciate it." % self.__class__.__name__ ) raise NotImplementedError("%s is abstract, you cannot instanciate it." % self.__class__.__name__ )
## @brief A dict that stores fieldvalues indexed by fieldname ##@brief A dict that stores fieldvalues indexed by fieldname
self.__datas = { fname:None for fname in self._fields } self.__datas = { fname:None for fname in self._fields }
## @brief Store a list of initianilized fields when instanciation not complete else store True ##@brief Store a list of initianilized fields when instanciation not complete else store True
self.__initialized = list() self.__initialized = list()
## @brief Datas accessor. Instance of @ref LeObjectValues ##@brief Datas accessor. Instance of @ref LeObjectValues
self.d = LeObjectValues(self.fieldnames, self.set_data, self.data) self.d = LeObjectValues(self.fieldnames, self.set_data, self.data)
# Checks that uid is given # Checks that uid is given
@ -114,12 +114,12 @@ class LeObject(object):
# Fields datas handling methods # # Fields datas handling methods #
#-----------------------------------# #-----------------------------------#
## @brief @property True if LeObject is initialized else False ##@brief @property True if LeObject is initialized else False
@property @property
def initialized(self): def initialized(self):
return not isinstance(self.__initialized, list) return not isinstance(self.__initialized, list)
## @brief Return a list of fieldnames ##@brief Return a list of fieldnames
# @param include_ro bool : if True include read only field names # @param include_ro bool : if True include read only field names
# @return a list of str # @return a list of str
@classmethod @classmethod
@ -133,7 +133,7 @@ class LeObject(object):
def name2objname(cls, name): def name2objname(cls, name):
return name.title() return name.title()
## @brief Return the datahandler asssociated with a LeObject field ##@brief Return the datahandler asssociated with a LeObject field
# @param fieldname str : The fieldname # @param fieldname str : The fieldname
# @return A data handler instance # @return A data handler instance
@classmethod @classmethod
@ -142,7 +142,7 @@ class LeObject(object):
raise NameError("No field named '%s' in %s" % (fieldname, cls.__name__)) raise NameError("No field named '%s' in %s" % (fieldname, cls.__name__))
return cls._fields[fieldname] return cls._fields[fieldname]
## @brief Return a LeObject child class from a name ##@brief Return a LeObject child class from a name
# @warning This method has to be called from dynamically generated LeObjects # @warning This method has to be called from dynamically generated LeObjects
# @param leobject_name str : LeObject name # @param leobject_name str : LeObject name
# @return A LeObject child class # @return A LeObject child class
@ -161,7 +161,7 @@ class LeObject(object):
def is_abstract(cls): def is_abstract(cls):
return cls._abstract return cls._abstract
## @brief Read only access to all datas ##@brief Read only access to all datas
# @note for fancy data accessor use @ref LeObject.g attribute @ref LeObjectValues instance # @note for fancy data accessor use @ref LeObject.g attribute @ref LeObjectValues instance
# @param name str : field name # @param name str : field name
# @return the Value # @return the Value
@ -174,7 +174,7 @@ class LeObject(object):
raise RuntimeError("The field %s is not initialized yet (and have no value)" % name) raise RuntimeError("The field %s is not initialized yet (and have no value)" % name)
return self.__datas[name] return self.__datas[name]
## @brief Datas setter ##@brief Datas setter
# @note for fancy data accessor use @ref LeObject.g attribute @ref LeObjectValues instance # @note for fancy data accessor use @ref LeObject.g attribute @ref LeObjectValues instance
# @param fname str : field name # @param fname str : field name
# @param fval * : field value # @param fval * : field value
@ -211,7 +211,7 @@ class LeObject(object):
else: else:
self.__datas[fname] = val self.__datas[fname] = val
## @brief Update the __initialized attribute according to LeObject internal state ##@brief Update the __initialized attribute according to LeObject internal state
# #
# Check the list of initialized fields and set __initialized to True if all fields initialized # Check the list of initialized fields and set __initialized to True if all fields initialized
def __set_initialized(self): def __set_initialized(self):
@ -220,7 +220,7 @@ class LeObject(object):
if set(expected_fields) == set(self.__initialized): if set(expected_fields) == set(self.__initialized):
self.__initialized = True self.__initialized = True
## @brief Designed to be called when datas are modified ##@brief Designed to be called when datas are modified
# #
# Make different checks on the LeObject given it's state (fully initialized or not) # Make different checks on the LeObject given it's state (fully initialized or not)
# @return None if checks succeded else return an exception list # @return None if checks succeded else return an exception list
@ -267,7 +267,7 @@ class LeObject(object):
# Other methods # # Other methods #
#--------------------# #--------------------#
## @brief Temporary method to set private fields attribute at dynamic code generation ##@brief Temporary method to set private fields attribute at dynamic code generation
# #
# This method is used in the generated dynamic code to set the _fields attribute # This method is used in the generated dynamic code to set the _fields attribute
# at the end of the dyncode parse # at the end of the dyncode parse

View file

@ -9,13 +9,13 @@ class LeQueryError(Exception):
class LeQuery(object): class LeQuery(object):
## @brief The datasource object used for this query ##@brief The datasource object used for this query
datasource = None datasource = None
## @brief The available operators used in query definitions ##@brief The available operators used in query definitions
query_operators = ['=', '<=', '>=', '!=', '<', '>', ' in ', ' not in ', ' like ', ' not like '] query_operators = ['=', '<=', '>=', '!=', '<', '>', ' in ', ' not in ', ' like ', ' not like ']
## @brief Constructor ##@brief Constructor
# @param target_class EmClass : class of the object to query about # @param target_class EmClass : class of the object to query about
def __init__(self, target_class): def __init__(self, target_class):
if not issubclass(target_class, LeObject): if not issubclass(target_class, LeObject):
@ -23,17 +23,17 @@ class LeQuery(object):
self.target_class = target_class self.target_class = target_class
## @brief Class representing an Insert query ##@brief Class representing an Insert query
class LeInsertQuery(LeQuery): class LeInsertQuery(LeQuery):
## @brief Constructor ##@brief Constructor
# @param target_class EmClass: class corresponding to the inserted object # @param target_class EmClass: class corresponding to the inserted object
# @param datas dict : datas to insert # @param datas dict : datas to insert
def __init__(self, target_class, datas): def __init__(self, target_class, datas):
super().__init__(target_class) super().__init__(target_class)
self.datas = datas self.datas = datas
## @brief executes the insert query ##@brief executes the insert query
# @return bool # @return bool
# @TODO reactivate the LodelHooks call when this class is implemented # @TODO reactivate the LodelHooks call when this class is implemented
def execute(self): def execute(self):
@ -42,7 +42,7 @@ class LeInsertQuery(LeQuery):
# ret = LodelHook.call_hook('leapi_insert_post', self.target_class, ret) # ret = LodelHook.call_hook('leapi_insert_post', self.target_class, ret)
return ret return ret
## @brief calls the datasource to perform the insert command ##@brief calls the datasource to perform the insert command
# @param datas dict : formatted datas corresponding to the insert # @param datas dict : formatted datas corresponding to the insert
# @return str : the uid of the inserted object # @return str : the uid of the inserted object
def __insert(self, **datas): def __insert(self, **datas):
@ -51,15 +51,15 @@ class LeInsertQuery(LeQuery):
return res return res
## @brief Class representing an Abstract Filtered Query ##@brief Class representing an Abstract Filtered Query
class LeFilteredQuery(LeQuery): class LeFilteredQuery(LeQuery):
## @brief Constructor ##@brief Constructor
# @param target_class EmClass : Object of the query # @param target_class EmClass : Object of the query
def __init__(self, target_class): def __init__(self, target_class):
super().__init__(target_class) super().__init__(target_class)
## @brief Validates the query filters ##@brief Validates the query filters
# @param query_filters list # @param query_filters list
# @return bool # @return bool
# @raise LeQueryError if one of the filter is not valid # @raise LeQueryError if one of the filter is not valid
@ -70,7 +70,7 @@ class LeFilteredQuery(LeQuery):
raise LeQueryError("The operator %s is not valid." % query_filter[1]) raise LeQueryError("The operator %s is not valid." % query_filter[1])
return True return True
## @brief Checks if a field is relational ##@brief Checks if a field is relational
# @param field str : Name of the field # @param field str : Name of the field
# @return bool # @return bool
@classmethod @classmethod
@ -78,10 +78,10 @@ class LeFilteredQuery(LeQuery):
return field.startswith('superior.') or field.startswith('subordinate.') return field.startswith('superior.') or field.startswith('subordinate.')
## @brief Class representing a Get Query ##@brief Class representing a Get Query
class LeGetQuery(LeFilteredQuery): class LeGetQuery(LeFilteredQuery):
## @brief Constructor ##@brief Constructor
# @param target_class EmClass : main class # @param target_class EmClass : main class
# @param query_filters # @param query_filters
# @param field_list list # @param field_list list
@ -101,7 +101,7 @@ class LeGetQuery(LeFilteredQuery):
self.offset = offset self.offset = offset
self.instanciate = instanciate self.instanciate = instanciate
## @brief executes the query ##@brief executes the query
# @return list # @return list
# @TODO activate LodelHook calls # @TODO activate LodelHook calls
def execute(self): def execute(self):
@ -137,7 +137,7 @@ class LeGetQuery(LeFilteredQuery):
results = self._datasource.select() # TODO add the correct arguments for the datasource's method call results = self._datasource.select() # TODO add the correct arguments for the datasource's method call
return results return results
## @brief prepares the field list ##@brief prepares the field list
# @return list # @return list
# @raise LeApiDataCheckError # @raise LeApiDataCheckError
def __prepare_field_list(self): def __prepare_field_list(self):
@ -159,12 +159,12 @@ class LeGetQuery(LeFilteredQuery):
return ret_field_list return ret_field_list
## @brief prepares a relational field ##@brief prepares a relational field
def __prepare_relational_field(self, field): def __prepare_relational_field(self, field):
# TODO Implement the method # TODO Implement the method
return field return field
## @brief splits the filter string into a tuple (FIELD, OPERATOR, VALUE) ##@brief splits the filter string into a tuple (FIELD, OPERATOR, VALUE)
# @param filter str # @param filter str
# @return tuple # @return tuple
# @raise ValueError # @raise ValueError
@ -190,7 +190,7 @@ class LeGetQuery(LeFilteredQuery):
op_re_piece += ')' op_re_piece += ')'
self.query_re = re.compile('^\s*(?P<field>(((superior)|(subordinate))\.)?[a-z_][a-z0-9\-_]*)\s*'+op_re_piece+'\s*(?P<value>[^<>=!].*)\s*$', flags=re.IGNORECASE) self.query_re = re.compile('^\s*(?P<field>(((superior)|(subordinate))\.)?[a-z_][a-z0-9\-_]*)\s*'+op_re_piece+'\s*(?P<value>[^<>=!].*)\s*$', flags=re.IGNORECASE)
## @brief checks if a field is in the target class of the query ##@brief checks if a field is in the target class of the query
# @param field str # @param field str
# @return str # @return str
# @raise ValueError # @raise ValueError
@ -199,7 +199,7 @@ class LeGetQuery(LeFilteredQuery):
return ValueError("No such field '%s' in %s" % (field, self.target_class)) return ValueError("No such field '%s' in %s" % (field, self.target_class))
return field return field
## @brief Prepares the filters (relational and others) ##@brief Prepares the filters (relational and others)
# @return tuple # @return tuple
def __prepare_filters(self): def __prepare_filters(self):
filters = list() filters = list()
@ -234,7 +234,7 @@ class LeGetQuery(LeFilteredQuery):
datas['target_class'] = self.target_class datas['target_class'] = self.target_class
return datas return datas
## @brief prepares the "order" parameters ##@brief prepares the "order" parameters
# @return list # @return list
def __prepare_order(self): def __prepare_order(self):
errors = dict() errors = dict()
@ -269,7 +269,7 @@ class LeUpdateQuery(LeFilteredQuery):
# ret = LodelHook.call_hook('leapi_update_post', self.target_object, ret) # ret = LodelHook.call_hook('leapi_update_post', self.target_object, ret)
return ret return ret
## @brief calls the datasource's update method and the corresponding hooks ##@brief calls the datasource's update method and the corresponding hooks
# @return bool # @return bool
# @TODO change the behavior in case of error in the update process # @TODO change the behavior in case of error in the update process
def __update(self): def __update(self):
@ -280,7 +280,7 @@ class LeUpdateQuery(LeFilteredQuery):
else: else:
return False return False
## @brief prepares the query_filters to be used as argument for the datasource's update method ##@brief prepares the query_filters to be used as argument for the datasource's update method
def __prepare(self): def __prepare(self):
datas = dict() datas = dict()
if LeFilteredQuery.validate_query_filters(self.query_filters): if LeFilteredQuery.validate_query_filters(self.query_filters):
@ -304,7 +304,7 @@ class LeDeleteQuery(LeFilteredQuery):
# ret = LodelHook.call('leapi_delete_post', self.target_object, ret) # ret = LodelHook.call('leapi_delete_post', self.target_object, ret)
return ret return ret
## @brief calls the datasource's delete method ##@brief calls the datasource's delete method
# @return bool # @return bool
# @TODO change the behavior in case of error in the update process # @TODO change the behavior in case of error in the update process
def __delete(self): def __delete(self):

View file

@ -23,7 +23,7 @@ def __init_from_settings():
for name, logging_opt in Settings.logging.items(): for name, logging_opt in Settings.logging.items():
add_handler(name, logging_opt) add_handler(name, logging_opt)
## @brief Add an handler, identified by a name, to a given logger ##@brief Add an handler, identified by a name, to a given logger
# #
# logging_opt is a dict with logger option. Allowed keys are : # logging_opt is a dict with logger option. Allowed keys are :
# - filename : take a filepath as value and cause the use of a logging.handlers.RotatingFileHandler # - filename : take a filepath as value and cause the use of a logging.handlers.RotatingFileHandler
@ -67,14 +67,14 @@ def add_handler(name, logging_opt):
logger.addHandler(handler) logger.addHandler(handler)
## @brief Remove an handler generated from configuration (runtime logger configuration) ##@brief Remove an handler generated from configuration (runtime logger configuration)
# @param name str : handler name # @param name str : handler name
def remove_handler(name): def remove_handler(name):
if name in handlers: if name in handlers:
logger.removeHandler(handlers[name]) logger.removeHandler(handlers[name])
# else: can we do anything ? # else: can we do anything ?
## @brief Utility function that disable unconditionnaly handlers that implies console output ##@brief Utility function that disable unconditionnaly handlers that implies console output
# @note In fact, this function disables handlers generated from settings wich are instances of logging.StreamHandler # @note In fact, this function disables handlers generated from settings wich are instances of logging.StreamHandler
def remove_console_handlers(): def remove_console_handlers():
for name, handler in handlers.items(): for name, handler in handlers.items():
@ -84,7 +84,7 @@ def remove_console_handlers():
# Utility functions # Utility functions
## @brief Generic logging function ##@brief Generic logging function
# @param lvl int : Log severity # @param lvl int : Log severity
# @param msg str : log message # @param msg str : log message
# @param *args : additional positionnal arguments # @param *args : additional positionnal arguments

View file

@ -4,16 +4,16 @@ import os
import copy import copy
from importlib.machinery import SourceFileLoader from importlib.machinery import SourceFileLoader
## @brief Class designed to handle a hook's callback with a priority ##@brief Class designed to handle a hook's callback with a priority
class DecoratedWrapper(object): class DecoratedWrapper(object):
## @brief Constructor ##@brief Constructor
# @param hook function : the function to wrap # @param hook function : the function to wrap
# @param priority int : the callbacl priority # @param priority int : the callbacl priority
def __init__(self, hook, priority): def __init__(self, hook, priority):
self._priority = priority self._priority = priority
self._hook = hook self._hook = hook
## @brief Call the callback ##@brief Call the callback
# @param hook_name str : The name of the called hook # @param hook_name str : The name of the called hook
# @param caller * : The caller (depends on the hook) # @param caller * : The caller (depends on the hook)
# @param payload * : Datas that depends on the hook # @param payload * : Datas that depends on the hook
@ -21,7 +21,7 @@ class DecoratedWrapper(object):
def __call__(self, hook_name, caller, payload): def __call__(self, hook_name, caller, payload):
return self._hook(hook_name, caller, payload) return self._hook(hook_name, caller, payload)
## @brief Decorator designed to register hook's callbacks ##@brief Decorator designed to register hook's callbacks
# #
# @note Decorated functions are expected to take 3 arguments : # @note Decorated functions are expected to take 3 arguments :
#  - hook_name : the called hook name #  - hook_name : the called hook name
@ -29,17 +29,17 @@ class DecoratedWrapper(object):
# - payload : datas depending on the hook # - payload : datas depending on the hook
class LodelHook(object): class LodelHook(object):
## @brief Stores all hooks (DecoratedWrapper instances) ##@brief Stores all hooks (DecoratedWrapper instances)
_hooks = dict() _hooks = dict()
## @brief Decorator constructor ##@brief Decorator constructor
# @param hook_name str : the name of the hook to register to # @param hook_name str : the name of the hook to register to
# @param priority int : the hook priority # @param priority int : the hook priority
def __init__(self, hook_name, priority = None): def __init__(self, hook_name, priority = None):
self._hook_name = hook_name self._hook_name = hook_name
self._priority = 0xFFFF if priority is None else priority self._priority = 0xFFFF if priority is None else priority
## @brief called just after __init__ ##@brief called just after __init__
# @param hook function : the decorated function # @param hook function : the decorated function
# @return the hook argument # @return the hook argument
def __call__(self, hook): def __call__(self, hook):
@ -50,7 +50,7 @@ class LodelHook(object):
self._hooks[self._hook_name] = sorted(self._hooks[self._hook_name], key = lambda h: h._priority) self._hooks[self._hook_name] = sorted(self._hooks[self._hook_name], key = lambda h: h._priority)
return hook return hook
## @brief Call hooks ##@brief Call hooks
# @param hook_name str : the hook's name # @param hook_name str : the hook's name
# @param caller * : the hook caller (depends on the hook) # @param caller * : the hook caller (depends on the hook)
# @param payload * : datas for the hook # @param payload * : datas for the hook
@ -63,7 +63,7 @@ class LodelHook(object):
payload = hook(hook_name, caller, payload) payload = hook(hook_name, caller, payload)
return payload return payload
## @brief Fetch registered hooks ##@brief Fetch registered hooks
# @param names list | None : optionnal filter on name # @param names list | None : optionnal filter on name
# @param cls # @param cls
# @return a list of functions # @return a list of functions
@ -76,7 +76,7 @@ class LodelHook(object):
res = copy.copy(cls._hooks) res = copy.copy(cls._hooks)
return { name: [(hook._hook, hook._priority) for hook in hooks] for name, hooks in res.items() } return { name: [(hook._hook, hook._priority) for hook in hooks] for name, hooks in res.items() }
## @brief Unregister all hooks ##@brief Unregister all hooks
# @param cls # @param cls
# @warning REALLY NOT a good idea ! # @warning REALLY NOT a good idea !
# @note implemented for testing purpose # @note implemented for testing purpose

View file

@ -12,7 +12,7 @@ from importlib.machinery import SourceFileLoader, SourcelessFileLoader
# - main.py containing hooks registration etc # - main.py containing hooks registration etc
# - confspec.py containing a configuration specification dictionary named CONFSPEC # - confspec.py containing a configuration specification dictionary named CONFSPEC
## @brief The package in wich we will load plugins modules ##@brief The package in wich we will load plugins modules
VIRTUAL_PACKAGE_NAME = 'lodel.plugins_pkg' VIRTUAL_PACKAGE_NAME = 'lodel.plugins_pkg'
CONFSPEC_FILENAME = 'confspec.py' CONFSPEC_FILENAME = 'confspec.py'
MAIN_FILENAME = 'main.py' MAIN_FILENAME = 'main.py'
@ -23,15 +23,15 @@ class PluginError(Exception):
class Plugins(object): class Plugins(object):
## @brief Stores plugin directories paths ##@brief Stores plugin directories paths
_plugin_directories = None _plugin_directories = None
## @brief Optimisation cache storage for plugin paths ##@brief Optimisation cache storage for plugin paths
_plugin_paths = dict() _plugin_paths = dict()
def __init__(self): # may be useless def __init__(self): # may be useless
self.started() self.started()
## @brief Given a plugin name returns the plugin path ##@brief Given a plugin name returns the plugin path
# @param plugin_name str : The plugin name # @param plugin_name str : The plugin name
# @return the plugin directory path # @return the plugin directory path
@classmethod @classmethod
@ -50,7 +50,7 @@ class Plugins(object):
return plugin_path return plugin_path
raise NameError("No plugin named '%s'" % plugin_name) raise NameError("No plugin named '%s'" % plugin_name)
## @brief Fetch a confspec given a plugin_name ##@brief Fetch a confspec given a plugin_name
# @param plugin_name str : The plugin name # @param plugin_name str : The plugin name
# @return a dict of conf spec # @return a dict of conf spec
# @throw PluginError if plugin_name is not valid # @throw PluginError if plugin_name is not valid
@ -70,7 +70,7 @@ class Plugins(object):
raise PluginError("Failed to load plugin '%s'. It seems that the plugin name is not valid" % plugin_name) raise PluginError("Failed to load plugin '%s'. It seems that the plugin name is not valid" % plugin_name)
return getattr(confspec_module, CONFSPEC_VARNAME) return getattr(confspec_module, CONFSPEC_VARNAME)
## @brief Load a module to register plugin's hooks ##@brief Load a module to register plugin's hooks
# @param plugin_name str : The plugin name # @param plugin_name str : The plugin name
@classmethod @classmethod
def load_plugin(cls, plugin_name): def load_plugin(cls, plugin_name):
@ -86,7 +86,7 @@ class Plugins(object):
except ImportError: except ImportError:
raise PluginError("Failed to load plugin '%s'. It seems that the plugin name is not valid" % plugin_name) raise PluginError("Failed to load plugin '%s'. It seems that the plugin name is not valid" % plugin_name)
## @brief Bootstrap the Plugins class ##@brief Bootstrap the Plugins class
@classmethod @classmethod
def bootstrap(cls, plugins_directories): def bootstrap(cls, plugins_directories):
cls._plugin_directories = plugins_directories cls._plugin_directories = plugins_directories

View file

@ -1,6 +1,34 @@
#-*- coding: utf-8 -*- #-*- coding: utf-8 -*-
## @package lodel.settings Lodel2 settings package
# 
# @par Bootstrap/load/use in lodel instance
# To use Settings in production you have to write a loader that will bootstrap
# the Settings class allowing @ref lodel.settings.__init__.py to expose a copy
# of the lodel.settings.Settings representation of the
# @ref lodel.settings.settings.Settings.__confs . Here is an example of
# loader file :
# <pre>
# #-*- coding: utf-8 -*-
# from lodel.settings.settings import Settings
# Settings.bootstrap(
# conf_file = 'somepath/settings_local.ini',
# conf_dir = 'somepath/conf.d')
# </pre>
# Once this file is imported it allows to all lodel2 modules to use settings
# like this :
# <pre>
# from lodel.settings import Settings
# if Settings.debug:
# print("DEBUG MODE !")
# </pre>
#
from lodel.settings.settings import Settings as SettingsHandler from lodel.settings.settings import Settings as SettingsHandler
##@brief Bootstraped instance
settings = SettingsHandler.bootstrap() settings = SettingsHandler.bootstrap()
if settings is not None: if settings is not None:
##@brief Exposed variable that represents configurations values in a
# namedtuple tree
Settings = settings.confs Settings = settings.confs

View file

@ -12,18 +12,15 @@ from lodel.settings.utils import SettingsError, SettingsErrors
from lodel.settings.validator import SettingValidator, LODEL2_CONF_SPECS from lodel.settings.validator import SettingValidator, LODEL2_CONF_SPECS
from lodel.settings.settings_loader import SettingsLoader from lodel.settings.settings_loader import SettingsLoader
## @package lodel.settings Lodel2 settings package
#
# Contains all module that help handling settings
## @package lodel.settings.settings Lodel2 settings module ## @package lodel.settings.settings Lodel2 settings module
# #
# Handles configuration load/parse/check. # Handles configuration load/parse/check.
# #
# @subsection Configuration load process # @subsection Configuration load process
# #
# The configuration load process is not trivial. In fact loaded plugins are able to add their own options. # The configuration load process is not trivial. In fact loaded plugins are
# But the list of plugins to load and the plugins options are in the same file, the instance configuration file. # able to add their own options. But the list of plugins to load and the
# plugins options are in the same file, the instance configuration file.
# #
# @subsection Configuration specification # @subsection Configuration specification
# #
@ -32,14 +29,17 @@ from lodel.settings.settings_loader import SettingsLoader
# - value validation/cast (see @ref Lodel.settings.validator.ConfValidator ) # - value validation/cast (see @ref Lodel.settings.validator.ConfValidator )
#  # 
## @brief A default python system lib path ##@brief A default python system lib path
PYTHON_SYS_LIB_PATH = '/usr/local/lib/python{major}.{minor}/'.format( PYTHON_SYS_LIB_PATH = '/usr/local/lib/python{major}.{minor}/'.format(
major = sys.version_info.major, major = sys.version_info.major,
minor = sys.version_info.minor) minor = sys.version_info.minor)
## @brief Handles configuration load etc. ##@brief Handles configuration load etc.
# #
# @par Basic usage # To see howto bootstrap Settings and use it in lodel instance see
# @ref lodel.settings
#
# @par Basic instance usage
# For example if a file defines confs like : # For example if a file defines confs like :
# <pre> # <pre>
# [super_section] # [super_section]
@ -49,13 +49,16 @@ PYTHON_SYS_LIB_PATH = '/usr/local/lib/python{major}.{minor}/'.format(
# <pre> settings_instance.confs.super_section.super_conf </pre> # <pre> settings_instance.confs.super_section.super_conf </pre>
# #
# @par Init sequence # @par Init sequence
# The initialization sequence is a bit tricky. In fact, plugins adds allowed configuration # The initialization sequence is a bit tricky. In fact, plugins adds allowed
# sections/values, but the list of plugins to load in in... the settings. # configuration sections/values, but the list of plugins to load in in... the
# settings.
# Here is the conceptual presentation of Settings class initialization stages : # Here is the conceptual presentation of Settings class initialization stages :
# -# Preloading (sets values like lodel2 library path or the plugins path) # -# Preloading (sets values like lodel2 library path or the plugins path)
# -# Ask a @ref lodel.settings.setting_loader.SettingsLoader to load all configurations files # -# Ask a @ref lodel.settings.setting_loader.SettingsLoader to load all
#configurations files
# -# Fetch the list of plugins in the loaded settings # -# Fetch the list of plugins in the loaded settings
# -# Merge plugins settings specification with the global lodel settings specs ( see @ref lodel.plugin ) # -# Merge plugins settings specification with the global lodel settings
#specs ( see @ref lodel.plugin )
# -# Fetch all settings from the merged settings specs # -# Fetch all settings from the merged settings specs
# #
# @par Init sequence in practical # @par Init sequence in practical
@ -65,10 +68,11 @@ PYTHON_SYS_LIB_PATH = '/usr/local/lib/python{major}.{minor}/'.format(
# -# @ref Settings.__populate_from_specs() (step 5) # -# @ref Settings.__populate_from_specs() (step 5)
# -# And finally @ref Settings.__confs_to_namedtuple() # -# And finally @ref Settings.__confs_to_namedtuple()
# #
# @todo handles default sections for variable sections (sections ending with '.*') # @todo handles default sections for variable sections (sections ending with
# '.*')
class Settings(object): class Settings(object):
## @brief global conf specsification (default_value + validator) ##@brief global conf specsification (default_value + validator)
_conf_preload = { _conf_preload = {
'lib_path': ( PYTHON_SYS_LIB_PATH+'/lodel2/', 'lib_path': ( PYTHON_SYS_LIB_PATH+'/lodel2/',
SettingValidator('directory')), SettingValidator('directory')),
@ -77,7 +81,7 @@ class Settings(object):
} }
instance = None instance = None
## @brief Should be called only by the boostrap classmethod ##@brief Should be called only by the boostrap classmethod
def __init__(self, conf_file = '/etc/lodel2/lodel2.conf', conf_dir = 'conf.d'): def __init__(self, conf_file = '/etc/lodel2/lodel2.conf', conf_dir = 'conf.d'):
self.__confs = dict() self.__confs = dict()
self.__conf_dir = conf_dir self.__conf_dir = conf_dir
@ -86,7 +90,7 @@ class Settings(object):
# and self.__confs['lodel2']['lib_path'] set # and self.__confs['lodel2']['lib_path'] set
self.__bootstrap() self.__bootstrap()
## @brief Stores as class attribute a Settings instance ##@brief Stores as class attribute a Settings instance
@classmethod @classmethod
def bootstrap(cls, conf_file = None, conf_dir = None): def bootstrap(cls, conf_file = None, conf_dir = None):
if cls.instance is None: if cls.instance is None:
@ -96,13 +100,13 @@ class Settings(object):
cls.instance = cls(conf_file, conf_dir) cls.instance = cls(conf_file, conf_dir)
return cls.instance return cls.instance
## @brief Configuration keys accessor ##@brief Configuration keys accessor
# @return All confs organised into named tuples # @return All confs organised into named tuples
@property @property
def confs(self): def confs(self):
return copy.copy(self.__confs) return copy.copy(self.__confs)
## @brief This method handlers Settings instance bootstraping ##@brief This method handlers Settings instance bootstraping
def __bootstrap(self): def __bootstrap(self):
lodel2_specs = LODEL2_CONF_SPECS lodel2_specs = LODEL2_CONF_SPECS
plugins_opt_specs = lodel2_specs['lodel2']['plugins'] plugins_opt_specs = lodel2_specs['lodel2']['plugins']
@ -126,7 +130,7 @@ class Settings(object):
specs = self.__merge_specs(specs) specs = self.__merge_specs(specs)
self.__populate_from_specs(specs, loader) self.__populate_from_specs(specs, loader)
## @brief Produce a configuration specification dict by merging all specifications ##@brief Produce a configuration specification dict by merging all specifications
# #
# Merges global lodel2 conf spec from @ref lodel.settings.validator.LODEL2_CONF_SPECS # Merges global lodel2 conf spec from @ref lodel.settings.validator.LODEL2_CONF_SPECS
# and configuration specifications from loaded plugins # and configuration specifications from loaded plugins
@ -144,7 +148,7 @@ class Settings(object):
res[section][kname] = copy.copy(spec[section][kname]) res[section][kname] = copy.copy(spec[section][kname])
return res return res
## @brief Populate the Settings instance with options values fecthed with the loader from merged specs ##@brief Populate the Settings instance with options values fecthed with the loader from merged specs
# #
# Populate the __confs attribute # Populate the __confs attribute
# @param specs dict : Settings specification dictionnary as returned by __merge_specs # @param specs dict : Settings specification dictionnary as returned by __merge_specs
@ -170,7 +174,7 @@ class Settings(object):
self.__confs_to_namedtuple() self.__confs_to_namedtuple()
pass pass
## @brief Transform the __confs attribute into imbricated namedtuple ##@brief Transform the __confs attribute into imbricated namedtuple
# #
# For example an option named "foo" in a section named "hello.world" will # For example an option named "foo" in a section named "hello.world" will
# be acessible with self.__confs.hello.world.foo # be acessible with self.__confs.hello.world.foo
@ -225,14 +229,14 @@ class Settings(object):
path.append( (curname, cur) ) path.append( (curname, cur) )
nodename += '.'+curname.title() nodename += '.'+curname.title()
## @brief Forge a named tuple given a conftree node ##@brief Forge a named tuple given a conftree node
# @param conftree dict : A conftree node # @param conftree dict : A conftree node
# @return a named tuple with fieldnames corresponding to conftree keys # @return a named tuple with fieldnames corresponding to conftree keys
def __tree2namedtuple(self, conftree, name): def __tree2namedtuple(self, conftree, name):
ResNamedTuple = namedtuple(name, conftree.keys()) ResNamedTuple = namedtuple(name, conftree.keys())
return ResNamedTuple(**conftree) return ResNamedTuple(**conftree)
## @brief Load base global configurations keys ##@brief Load base global configurations keys
# #
# Base configurations keys are : # Base configurations keys are :
# - lodel2 lib path # - lodel2 lib path

View file

@ -7,16 +7,16 @@ import copy
from lodel.settings.utils import * from lodel.settings.utils import *
## @brief Merges and loads configuration files ##@brief Merges and loads configuration files
class SettingsLoader(object): class SettingsLoader(object):
## @brief Constructor ##@brief Constructor
# @param conf_path str : conf.d path # @param conf_path str : conf.d path
def __init__(self,conf_path): def __init__(self,conf_path):
self.__conf_path=conf_path self.__conf_path=conf_path
self.__conf_sv=set() self.__conf_sv=set()
self.__conf=self.__merge() self.__conf=self.__merge()
## @brief Lists and merges files in settings_loader.conf_path ##@brief Lists and merges files in settings_loader.conf_path
# #
# #
# @return dict() # @return dict()
@ -49,7 +49,7 @@ class SettingsLoader(object):
## @brief Returns option if exists default_value else and validates ##@brief Returns option if exists default_value else and validates
# @param section str : name of the section # @param section str : name of the section
# @param keyname str # @param keyname str
# @param validator callable : takes one argument value and raises validation fail # @param validator callable : takes one argument value and raises validation fail
@ -70,7 +70,7 @@ class SettingsLoader(object):
return default_value return default_value
## @brief Returns the section to be configured ##@brief Returns the section to be configured
# @param section_prefix str # @param section_prefix str
# @param default_section str # @param default_section str
# @return the section as dict() # @return the section as dict()
@ -82,8 +82,8 @@ class SettingsLoader(object):
return conf[default_section] return conf[default_section]
return []; return [];
## @brief Returns the sections which have not been configured ##@brief Returns the sections which have not been configured
# @return list of missing options # @return list of missing options
def getremains(self): def getremains(self):
return list(self.__conf_sv) return list(self.__conf_sv)

View file

@ -1,9 +1,13 @@
#-*- coding: utf-8 -*- #-*- coding: utf-8 -*-
## @brief Error class for settings errors ## @package lodel.settings.utils Lodel 2 settings utility
#
# For the moment defines exception classes
##@brief Error class for settings errors
class SettingsError(Exception): class SettingsError(Exception):
## @brief Instanciate a new SettingsError ##@brief Instanciate a new SettingsError
# @param msg str : Error message # @param msg str : Error message
# @param key_id str : The key concerned by the error # @param key_id str : The key concerned by the error
def __init__(self, msg = "Unknown error", key_id = None, filename = None): def __init__(self, msg = "Unknown error", key_id = None, filename = None):
@ -23,10 +27,10 @@ class SettingsError(Exception):
res += ": %s" % (self.__msg) res += ": %s" % (self.__msg)
return res return res
## @brief Designed to handles mutliple SettingsError ##@brief Designed to handles mutliple SettingsError
class SettingsErrors(Exception): class SettingsErrors(Exception):
## @brief Instanciate an SettingsErrors ##@brief Instanciate an SettingsErrors
# @param exceptions list : list of SettingsError instance # @param exceptions list : list of SettingsError instance
def __init__(self, exceptions): def __init__(self, exceptions):
for expt in exceptions: for expt in exceptions:

View file

@ -13,7 +13,7 @@ import copy
class SettingsValidationError(Exception): class SettingsValidationError(Exception):
pass pass
## @brief Handles settings validators ##@brief Handles settings validators
# #
# Class instance are callable objects that takes a value argument (the value to validate). It raises # Class instance are callable objects that takes a value argument (the value to validate). It raises
# a SettingsValidationError if validation fails, else it returns a properly # a SettingsValidationError if validation fails, else it returns a properly
@ -23,13 +23,13 @@ class SettingValidator(object):
_validators = dict() _validators = dict()
_description = dict() _description = dict()
## @brief Instanciate a validator ##@brief Instanciate a validator
def __init__(self, name, none_is_valid = False): def __init__(self, name, none_is_valid = False):
if name is not None and name not in self._validators: if name is not None and name not in self._validators:
raise NameError("No validator named '%s'" % name) raise NameError("No validator named '%s'" % name)
self.__name = name self.__name = name
## @brief Call the validator ##@brief Call the validator
# @param value * # @param value *
# @return properly casted value # @return properly casted value
# @throw SettingsValidationError # @throw SettingsValidationError
@ -41,7 +41,7 @@ class SettingValidator(object):
except Exception as e: except Exception as e:
raise SettingsValidationError(e) raise SettingsValidationError(e)
## @brief Register a new validator ##@brief Register a new validator
# @param name str : validator name # @param name str : validator name
# @param callback callable : the function that will validate a value # @param callback callable : the function that will validate a value
@classmethod @classmethod
@ -54,12 +54,12 @@ class SettingValidator(object):
cls._validators[name] = callback cls._validators[name] = callback
cls._description[name] = description cls._description[name] = description
## @brief Get the validator list associated with description ##@brief Get the validator list associated with description
@classmethod @classmethod
def validators_list(cls): def validators_list(cls):
return copy.copy(cls._description) return copy.copy(cls._description)
## @brief Create and register a list validator ##@brief Create and register a list validator
# @param elt_validator callable : The validator that will be used for validate each elt value # @param elt_validator callable : The validator that will be used for validate each elt value
# @param validator_name str # @param validator_name str
# @param description None | str # @param description None | str
@ -80,7 +80,7 @@ class SettingValidator(object):
description) description)
return cls(validator_name) return cls(validator_name)
## @brief Create and register a regular expression validator ##@brief Create and register a regular expression validator
# @param pattern str : regex pattern # @param pattern str : regex pattern
# @param validator_name str : The validator name # @param validator_name str : The validator name
# @param description str : Validator description # @param description str : Validator description
@ -109,11 +109,11 @@ class SettingValidator(object):
result += "\n" result += "\n"
return result return result
## @brief Integer value validator callback ##@brief Integer value validator callback
def int_val(value): def int_val(value):
return int(value) return int(value)
## @brief Output file validator callback ##@brief Output file validator callback
# @return A file object (if filename is '-' return sys.stderr) # @return A file object (if filename is '-' return sys.stderr)
def file_err_output(value): def file_err_output(value):
if not isinstance(value, str): if not isinstance(value, str):
@ -122,7 +122,7 @@ def file_err_output(value):
return sys.stderr return sys.stderr
return value return value
## @brief Boolean value validator callback ##@brief Boolean value validator callback
def boolean_val(value): def boolean_val(value):
if not (value is True) and not (value is False): if not (value is True) and not (value is False):
raise SettingsValidationError("A boolean was expected but got '%s' " % value) raise SettingsValidationError("A boolean was expected but got '%s' " % value)
@ -194,7 +194,7 @@ SettingValidator.create_re_validator(
# Lodel 2 configuration specification # Lodel 2 configuration specification
# #
## @brief Global specifications for lodel2 settings ##@brief Global specifications for lodel2 settings
LODEL2_CONF_SPECS = { LODEL2_CONF_SPECS = {
'lodel2': { 'lodel2': {
'debug': ( True, 'debug': ( True,

View file

@ -5,7 +5,7 @@ import hashlib
import json import json
## @brief Stores multilangage string ##@brief Stores multilangage string
class MlString(object): class MlString(object):
__default_lang = 'eng' __default_lang = 'eng'
@ -17,7 +17,7 @@ class MlString(object):
'esp', 'esp',
] ]
## @brief Create a new MlString instance ##@brief Create a new MlString instance
# @param arg str | dict : Can be a json string, a string or a dict # @param arg str | dict : Can be a json string, a string or a dict
def __init__(self, arg): def __init__(self, arg):
self.values = dict() self.values = dict()
@ -33,7 +33,7 @@ class MlString(object):
else: else:
raise ValueError('<class str>, <class dict> or <class MlString> expected, but %s found' % type(arg)) raise ValueError('<class str>, <class dict> or <class MlString> expected, but %s found' % type(arg))
## @brief Return a translation given a lang ##@brief Return a translation given a lang
# @param lang str | None : If None return default lang translation # @param lang str | None : If None return default lang translation
def get(self, lang = None): def get(self, lang = None):
lang = self.__default_lang if lang is None else lang lang = self.__default_lang if lang is None else lang
@ -44,7 +44,7 @@ class MlString(object):
else: else:
return str(self) return str(self)
## @brief Set a translation ##@brief Set a translation
# @param lang str : the lang # @param lang str : the lang
# @param val str | None: the translation if None delete the translation # @param val str | None: the translation if None delete the translation
def set(self, lang, val): def set(self, lang, val):
@ -57,7 +57,7 @@ class MlString(object):
else: else:
self.values[lang] = val self.values[lang] = val
## @brief Checks that given lang is valid ##@brief Checks that given lang is valid
# @param lang str : the lang # @param lang str : the lang
@classmethod @classmethod
def lang_is_valid(cls, lang): def lang_is_valid(cls, lang):
@ -65,7 +65,7 @@ class MlString(object):
raise ValueError('Invalid value for lang. Str expected but %s found' % type(lang)) raise ValueError('Invalid value for lang. Str expected but %s found' % type(lang))
return lang in cls.langs return lang in cls.langs
## @brief Get or set the default lang ##@brief Get or set the default lang
@classmethod @classmethod
def default_lang(cls, lang = None): def default_lang(cls, lang = None):
if lang is None: if lang is None:
@ -74,7 +74,7 @@ class MlString(object):
raise ValueError('lang "%s" is not valid"' % lang) raise ValueError('lang "%s" is not valid"' % lang)
cls.__default_lang = lang cls.__default_lang = lang
## @brief Return a mlstring loaded from a json string ##@brief Return a mlstring loaded from a json string
# @param json_str str : Json string # @param json_str str : Json string
@classmethod @classmethod
def from_json(cls, json_str): def from_json(cls, json_str):

View file

@ -2,7 +2,7 @@
from lodel.plugin import LodelHook from lodel.plugin import LodelHook
## @brief Hook's callback example ##@brief Hook's callback example
@LodelHook('leapi_get_pre') @LodelHook('leapi_get_pre')
@LodelHook('leapi_get_post') @LodelHook('leapi_get_post')
@LodelHook('leapi_update_pre') @LodelHook('leapi_update_pre')