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
# generate doxygen documentation
doc: cleandoc
doc: cleandoc doc_graphviz
doxygen
doc_graphviz:
cd doc/img/graphviz; make
# Test em update ( examples/em_test.pickle )
em_test:
python3 em_test.py

View file

@ -142,7 +142,7 @@ text.new_field( 'title',
display_name = {'eng': 'Title', 'fre': 'Titre'},
group = editorial_group,
data_handler = 'varchar',
)
nullable = True,)
text.new_field( 'subtitle',
display_name = {
'eng': 'Subtitle',
@ -150,21 +150,65 @@ text.new_field( 'subtitle',
},
group = editorial_group,
data_handler = 'varchar',
)
nullable = True)
# Classe collection
collection = em.new_class( 'collection',
display_name = 'Collection',
group = editorial_group,
abstract = True,
parents = entitie,
)
abstract = False,
parents = entitie)
collection.new_field( 'title',
display_name = 'Title',
group = editorial_group,
abstract = True,
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 #

View file

@ -24,7 +24,7 @@ class MongoDbDataSource(object):
self.connection = MongoClient(connection_string)
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 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 *
## @brief Abstract class to represent editorial model components
##@brief Abstract class to represent editorial model components
# @see EmClass EmField
# @todo forbid '.' in uid
class EmComponent(object):
## @brief Instanciate an EmComponent
##@brief Instanciate an EmComponent
# @param uid str : uniq identifier
# @param display_name MlString|str|dict : component display_name
# @param help_text MlString|str|dict : help_text
@ -43,10 +43,10 @@ class EmComponent(object):
return int.from_bytes(m.digest(), byteorder='big')
## @brief Handles editorial model objects classes
##@brief Handles editorial model objects classes
class EmClass(EmComponent):
## @brief Instanciate a new EmClass
##@brief Instanciate a new EmClass
# @param uid str : uniq identifier
# @param display_name MlString|str|dict : component display_name
# @param abstract bool : set the class as asbtract if True
@ -68,10 +68,10 @@ class EmClass(EmComponent):
else:
parents = list()
self.parents = parents
## @brief Stores EmFields instances indexed by field uid
##@brief Stores EmFields instances indexed by field uid
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
def __all_fields(self):
res = dict()
@ -80,7 +80,7 @@ class EmClass(EmComponent):
res.update(self.__fields)
return res
## @brief Return the list of all dependencies
##@brief Return the list of all dependencies
#
# Reccursive parents listing
@property
@ -93,7 +93,7 @@ class EmClass(EmComponent):
res |= parent.parents_recc
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 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
@ -104,7 +104,7 @@ class EmClass(EmComponent):
except KeyError:
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
# @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)
@ -121,7 +121,7 @@ class EmClass(EmComponent):
emfield._emclass = self
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 uid str : the EmField uniq id
# @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) )
## @brief Handles editorial model classes fields
##@brief Handles editorial model classes fields
class EmField(EmComponent):
## @brief Instanciate a new EmField
##@brief Instanciate a new EmField
# @param uid str : uniq identifier
# @param display_name MlString|str|dict : field display_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):
from lodel.leapi.datahandlers.base_classes import DataHandler
super().__init__(uid, display_name, help_text, group)
## @brief The data handler name
##@brief The data handler name
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)
## @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)
## @brief Stores data handler instanciation options
##@brief Stores data handler instanciation options
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
## @brief Returns data_handler_name attribute
##@brief Returns data_handler_name attribute
def get_data_handler_name(self):
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):
return copy.copy(selfdata_handler_cls)
@ -195,10 +195,10 @@ class EmField(EmComponent):
'utf-8')
).digest(), byteorder='big')
## @brief Handles functionnal group of EmComponents
##@brief Handles functionnal group of EmComponents
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
# @param uid str : Uniq identifier
# @param depends list : A list of EmGroup dependencies
@ -206,11 +206,11 @@ class EmGroup(object):
# @param help_text MlString|str :
def __init__(self, uid, depends = None, display_name = None, help_text = None):
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()
## @brief Stores the list of dependencies (EmGroup) indexed by uid
##@brief Stores the list of dependencies (EmGroup) indexed by uid
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.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)
self.add_dependencie(grp)
## @brief Returns EmGroup dependencie
##@brief Returns EmGroup dependencie
# @param recursive bool : if True return all dependencies and their dependencies
# @return a dict of EmGroup identified by uid
def dependencies(self, recursive = False):
@ -237,7 +237,7 @@ class EmGroup(object):
res[new_dep.uid] = new_dep
return res
## @brief Returns EmGroup applicants
##@brief Returns EmGroup applicants
# @param recursive bool : if True return all dependencies and their dependencies
# @returns a dict of EmGroup identified by uid
def applicants(self, recursive = False):
@ -253,12 +253,12 @@ class EmGroup(object):
res[new_app.uid] = new_app
return res
## @brief Returns EmGroup components
##@brief Returns EmGroup components
# @returns a copy of the set of components
def components(self):
return (self.__components).copy()
## @brief Returns EmGroup display_name
##@brief Returns EmGroup display_name
# @param lang str | None : If None return default lang translation
# @returns None if display_name is None, a str for display_name else
def get_display_name(self, lang=None):
@ -266,7 +266,7 @@ class EmGroup(object):
if name is None : return None
return name.get(lang);
## @brief Returns EmGroup help_text
##@brief Returns EmGroup help_text
# @param lang str | None : If None return default lang translation
# @returns None if display_name is None, a str for display_name else
def get_help_text(self, lang=None):
@ -274,7 +274,7 @@ class EmGroup(object):
if help is None : return None
return help.get(lang);
## @brief Add components in a group
##@brief Add components in a group
# @param components list : EmComponent instances list
def add_components(self, 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))
self.__components |= set(components)
## @brief Add a dependencie
##@brief Add a dependencie
# @param em_group EmGroup|iterable : an EmGroup instance or list of instance
def add_dependencie(self, grp):
try:
@ -301,7 +301,7 @@ class EmGroup(object):
self.require[grp.uid] = grp
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
def add_applicant(self, grp):
try:
@ -317,17 +317,17 @@ class EmGroup(object):
self.required_by[grp.uid] = grp
grp.require[self.uid] = self
## @brief Search for circular dependencie
##@brief Search for circular dependencie
# @return True if circular dep found else False
def __circular_dependencie(self, new_dep):
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
def __circular_applicant(self, new_app):
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
def __str__(self):
if self.display_name is None:
@ -353,7 +353,7 @@ class EmGroup(object):
byteorder = 'big'
)
## @brief Complete string representation of an EmGroup
##@brief Complete string representation of an EmGroup
# @return a string
def __repr__(self):
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.components import EmClass, EmField, EmGroup
## @brief Describe an editorial model
##@brief Describe an editorial model
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 description MlString|str|dict : the editorial model description
def __init__(self, name, description = None):
self.name = MlString(name)
self.description = MlString(description)
## @brief Stores all groups indexed by id
##@brief Stores all groups indexed by id
self.__groups = dict()
## @brief Stores all classes indexed by id
##@brief Stores all classes indexed by id
self.__classes = dict()
## @brief EmClass accessor
##@brief EmClass accessor
# @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
def classes(self, uid = None):
@ -31,7 +31,7 @@ class EditorialModel(object):
except KeyError:
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
# @return if uid is given returns an EmGroup else returns an EmGroup iterator
def groups(self, uid = None):
@ -40,7 +40,7 @@ class EditorialModel(object):
except KeyError:
raise EditorialModelException("EmGroup not found : '%s'" % uid)
## @brief EmField getter
##@brief EmField getter
# @param uid str : An EmField uid represented by "CLASSUID.FIELDUID"
# @return Fals or an EmField instance
#
@ -61,7 +61,7 @@ class EditorialModel(object):
pass
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
# @return emclass
def add_class(self, emclass):
@ -72,7 +72,7 @@ class EditorialModel(object):
self.__classes[emclass.uid] = 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
# @return emgroup
def add_group(self, emgroup):
@ -83,13 +83,13 @@ class EditorialModel(object):
self.__groups[emgroup.uid] = 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 **kwargs : EmClass constructor options ( see @ref lodel.editorial_model.component.EmClass.__init__() )
def new_class(self, 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 *kwargs : EmGroup constructor keywords arguments (see @ref lodel.editorial_model.component.EmGroup.__init__() )
def new_group(self, uid, **kwargs):
@ -103,7 +103,7 @@ class EditorialModel(object):
translator = self.translator_from_name(translator)
return translator.save(self, **translator_kwargs)
## @brief Load a model
##@brief Load a model
# @param translator module : The translator module to use
# @param **translator_args
@classmethod
@ -112,7 +112,7 @@ class EditorialModel(object):
translator = cls.translator_from_name(translator)
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
# @return the translator python module
# @throw NameError if the translator does not exists
@ -126,12 +126,12 @@ class EditorialModel(object):
return mod
## @brief Private getter for __groups or __classes
##@brief Private getter for __groups or __classes
# @see classes() groups()
def __elt_getter(self, elts, uid):
return list(elts.values()) if uid is None else elts[uid]
## @brief Lodel hash
##@brief Lodel hash
def d_hash(self):
payload = "%s%s" % (
self.name,

View file

@ -3,7 +3,7 @@
import pickle
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 filename str|None : if None return the model as pickle bytes
# @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)
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
def load(filename):
with open(filename, 'rb') as ffd:

View file

@ -13,22 +13,22 @@ from lodel import logger
class FieldValidationError(Exception):
pass
## @brief Base class for all data handlers
##@brief Base class for all data handlers
class DataHandler(object):
__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
## @brief Stores custom datahandlers classes indexed by name
##@brief Stores custom datahandlers classes indexed by name
# @todo do it ! (like plugins, register handlers... blablabla)
__custom_handlers = dict()
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 = []
## @brief constructor
##@brief constructor
# @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
# designed globally and immutable
@ -65,12 +65,12 @@ class DataHandler(object):
def is_primary_key(self):
return self.primary_key
## @brief checks if a fieldtype is internal
##@brief checks if a fieldtype is internal
# @return bool
def is_internal(self):
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)
def check_data_value(self, value):
if value is None:
@ -80,7 +80,7 @@ class DataHandler(object):
return None, None
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
# @return bool
def can_override(self, data_handler):
@ -88,7 +88,7 @@ class DataHandler(object):
return False
return True
## @brief Build field value
##@brief Build field value
# @param emcomponent EmComponent : An EmComponent child class instance
# @param fname str : The field name
# @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)
## @brief Check datas consistency
##@brief Check datas consistency
# @param emcomponent EmComponent : An EmComponent child class instance
# @param fname : the field name
# @param datas dict : dict storing fields values
@ -119,7 +119,7 @@ class DataHandler(object):
def check_data_consistency(self, emcomponent, fname, datas):
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
def register_new_handler(cls, name, data_handler):
if not inspect.isclass(data_handler):
@ -140,7 +140,7 @@ class DataHandler(object):
cls.__base_handlers[name.lower()] = obj
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)
# @return DataField child class
# @todo implements custom handlers fetch
@ -152,7 +152,7 @@ class DataHandler(object):
raise NameError("No data handlers named '%s'" % (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
# @return a str
@classmethod
@ -164,24 +164,24 @@ class DataHandler(object):
class_name = handler_class.__name__
)
## @brief __hash__ implementation for fieldtypes
##@brief __hash__ implementation for fieldtypes
def __hash__(self):
hash_dats = [self.__class__.__module__]
for kdic in sorted([k for k in self.__dict__.keys() if not k.startswith('_')]):
hash_dats.append((kdic, getattr(self, kdic)))
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):
pass
## @brief Abstract class for all references
##@brief Abstract class for all references
#
# References are fields that stores a reference to another
# editorial object
class Reference(DataHandler):
## @brief Instanciation
##@brief Instanciation
# @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 internal bool : if False, the field is not internal
@ -200,12 +200,12 @@ class Reference(DataHandler):
def back_reference(self):
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):
self.__back_reference = back_reference
## @brief Check value
##@brief Check value
# @param value *
# @return tuple(value, exception)
# @todo implement the check when we have LeObject to check value
@ -222,7 +222,7 @@ class Reference(DataHandler):
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
class SingleRef(Reference):
@ -238,7 +238,7 @@ class SingleRef(Reference):
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
# @note SQL implementation could be tricky

View file

@ -2,13 +2,13 @@
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):
help = 'Automatic string field, designed to use the str % operator to build its content'
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 max_length int : the maximum length of the handled value
# @param field_list list : List of field to use
@ -26,13 +26,13 @@ class FormatString(Varchar):
return False
return True
## @brief Varchar validated by a regex
##@brief Varchar validated by a regex
class Regex(Varchar):
help = 'String field validated with a regex. Takes two options : max_length and regex'
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 max_length int : the max length for this field (default : 10)
# @param **kwargs
@ -57,13 +57,13 @@ class Regex(Varchar):
return False
return True
## @brief Handles uniq ID
##@brief Handles uniq ID
class UniqID(Integer):
help = 'Fieldtype designed to handle editorial model UID'
base_type = 'int'
## @brief A uid field
##@brief A uid field
# @param **kwargs
def __init__(self, **kwargs):
kwargs['internal'] = 'automatic'

View file

@ -3,13 +3,13 @@ import warnings
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):
help = 'A basic boolean field'
base_type = 'bool'
## @brief A boolean field
##@brief A boolean field
def __init__(self, **kwargs):
if 'check_data_value' not in kwargs:
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)
return value, error
## @brief Data field designed to handle integer values
##@brief Data field designed to handle integer values
class Integer(DataField):
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)
return value, error
## @brief Data field designed to handle string
##@brief Data field designed to handle string
class Varchar(DataField):
help = 'Basic string (varchar) field. Default size is 64 characters'
base_type = 'char'
## @brief A string field
##@brief A string field
# @brief max_length int: The maximum length of this field
def __init__(self, max_length=64, **kwargs):
self.max_length = int(max_length)
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
# @return bool
def can_override(self, data_handler):
@ -62,13 +62,13 @@ class Varchar(DataField):
return False
return True
## @brief Data field designed to handle date & time
##@brief Data field designed to handle date & time
class DateTime(DataField):
help = 'A datetime field. Take two boolean options now_on_update and now_on_create'
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_create bool : If true, the date is set to NEW on creation
# @param **kwargs
@ -77,7 +77,7 @@ class DateTime(DataField):
self.now_on_create = now_on_create
super().__init__(**kwargs)
## @brief Data field designed to handle long string
##@brief Data field designed to handle long string
class Text(DataField):
help = 'A text field (big string)'
base_type = 'text'
@ -85,12 +85,12 @@ class Text(DataField):
def __init__(self, **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):
base_type = 'file'
## @brief a file field
##@brief a file field
# @param upload_path str : None by default
# @param **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
## @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):
## @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 internal bool
# @param kwargs
def __init__(self, max_length = None, **kwargs):
super().__init__(**kwargs)
## @brief Check value
##@brief Check value
# @param value *
# @return tuple(value, exception)
def _check_data_value(self, value):
@ -24,17 +24,17 @@ class List(MultipleRef):
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):
## @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 internal bool : if False, the field is not internal
# @param kwargs : Other named arguments
def __init__(self, **kwargs):
super().__init__(**kwargs)
## @brief Check value
##@brief Check value
# @param value *
# @return tuple(value, exception)
def _check_data_value(self, value):
@ -45,17 +45,17 @@ class Set(MultipleRef):
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):
## @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 internal bool : if False, the field is not internal
# @param kwargs : Other named arguments
def __init__(self, **kwargs):
super().__init__(**kwargs)
## @brief Check value
##@brief Check value
# @param value *
# @return tuple(value, exception)
def _check_data_value(self, value):
@ -66,10 +66,10 @@ class Map(MultipleRef):
None if isinstance(expt, Exception) else value,
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):
## @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 max_depth int | None : limit of depth
# @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.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
def dyncode_from_em(model):
@ -31,7 +31,7 @@ from lodel.leapi.datahandlers.base_classes import DataField
)
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.
# @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))
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):
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):
#dh_module_name = DataHandler.module_name(emfield.data_handler_name)+'.DataHandler'
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,
options = ', '.join(options))
## @brief Return a python repr of option values
##@brief Return a python repr of option values
def forge_optval(optval):
if isinstance(optval, dict):
return '{' + (', '.join( [ '%s: %s' % (repr(name), forge_optval(val)) for name, val in optval.items()])) + '}'
@ -81,7 +81,7 @@ def forge_optval(optval):
else:
return repr(optval)
## @brief Generate dyncode from an EmClass
##@brief Generate dyncode from an EmClass
# @param model EditorialModel :
# @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

View file

@ -3,7 +3,7 @@
import importlib
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 exceptions dict : A list of data check Exception with concerned field (or stuff) as key
def __init__(self, msg = "Unknow error", exceptions = None):
@ -25,37 +25,37 @@ class LeApiErrors(Exception):
return msg
## @brief When an error concern a query
##@brief When an error concern a query
class LeApiQueryError(LeApiErrors):
pass
## @brief When an error concerns a datas
##@brief When an error concerns a datas
class LeApiDataCheckError(LeApiErrors):
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
# without name collision problems
# @note Wrapped methods are : LeObject.data() & LeObject.set_data()
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 get_callback method : The LeObject.get_datas() method of corresponding LeObject class
def __init__(self, fieldnames_callback, set_callback, get_callback):
self.__setter = set_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
# @param fname str : Field name
def __getattribute__(self, 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
# @param fname str : Field name
# @param fval * : the field value
@ -65,23 +65,23 @@ class LeObjectValues(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
## @brief A dict that stores DataHandler instances indexed by field name
##@brief A dict that stores DataHandler instances indexed by field name
_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
## @brief Construct an object representing an Editorial component
##@brief Construct an object representing an Editorial component
# @note Can be considered as EmClass instance
def __init__(self, **kwargs):
if self._abstract:
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 }
## @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()
## @brief Datas accessor. Instance of @ref LeObjectValues
##@brief Datas accessor. Instance of @ref LeObjectValues
self.d = LeObjectValues(self.fieldnames, self.set_data, self.data)
# Checks that uid is given
@ -114,12 +114,12 @@ class LeObject(object):
# Fields datas handling methods #
#-----------------------------------#
## @brief @property True if LeObject is initialized else False
##@brief @property True if LeObject is initialized else False
@property
def initialized(self):
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
# @return a list of str
@classmethod
@ -133,7 +133,7 @@ class LeObject(object):
def name2objname(cls, name):
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
# @return A data handler instance
@classmethod
@ -142,7 +142,7 @@ class LeObject(object):
raise NameError("No field named '%s' in %s" % (fieldname, cls.__name__))
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
# @param leobject_name str : LeObject name
# @return A LeObject child class
@ -161,7 +161,7 @@ class LeObject(object):
def is_abstract(cls):
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
# @param name str : field name
# @return the Value
@ -174,7 +174,7 @@ class LeObject(object):
raise RuntimeError("The field %s is not initialized yet (and have no value)" % name)
return self.__datas[name]
## @brief Datas setter
##@brief Datas setter
# @note for fancy data accessor use @ref LeObject.g attribute @ref LeObjectValues instance
# @param fname str : field name
# @param fval * : field value
@ -211,7 +211,7 @@ class LeObject(object):
else:
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
def __set_initialized(self):
@ -220,7 +220,7 @@ class LeObject(object):
if set(expected_fields) == set(self.__initialized):
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)
# @return None if checks succeded else return an exception list
@ -267,7 +267,7 @@ class LeObject(object):
# 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
# at the end of the dyncode parse

View file

@ -9,13 +9,13 @@ class LeQueryError(Exception):
class LeQuery(object):
## @brief The datasource object used for this query
##@brief The datasource object used for this query
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 ']
## @brief Constructor
##@brief Constructor
# @param target_class EmClass : class of the object to query about
def __init__(self, target_class):
if not issubclass(target_class, LeObject):
@ -23,17 +23,17 @@ class LeQuery(object):
self.target_class = target_class
## @brief Class representing an Insert query
##@brief Class representing an Insert query
class LeInsertQuery(LeQuery):
## @brief Constructor
##@brief Constructor
# @param target_class EmClass: class corresponding to the inserted object
# @param datas dict : datas to insert
def __init__(self, target_class, datas):
super().__init__(target_class)
self.datas = datas
## @brief executes the insert query
##@brief executes the insert query
# @return bool
# @TODO reactivate the LodelHooks call when this class is implemented
def execute(self):
@ -42,7 +42,7 @@ class LeInsertQuery(LeQuery):
# ret = LodelHook.call_hook('leapi_insert_post', self.target_class, 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
# @return str : the uid of the inserted object
def __insert(self, **datas):
@ -51,15 +51,15 @@ class LeInsertQuery(LeQuery):
return res
## @brief Class representing an Abstract Filtered Query
##@brief Class representing an Abstract Filtered Query
class LeFilteredQuery(LeQuery):
## @brief Constructor
##@brief Constructor
# @param target_class EmClass : Object of the query
def __init__(self, target_class):
super().__init__(target_class)
## @brief Validates the query filters
##@brief Validates the query filters
# @param query_filters list
# @return bool
# @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])
return True
## @brief Checks if a field is relational
##@brief Checks if a field is relational
# @param field str : Name of the field
# @return bool
@classmethod
@ -78,10 +78,10 @@ class LeFilteredQuery(LeQuery):
return field.startswith('superior.') or field.startswith('subordinate.')
## @brief Class representing a Get Query
##@brief Class representing a Get Query
class LeGetQuery(LeFilteredQuery):
## @brief Constructor
##@brief Constructor
# @param target_class EmClass : main class
# @param query_filters
# @param field_list list
@ -101,7 +101,7 @@ class LeGetQuery(LeFilteredQuery):
self.offset = offset
self.instanciate = instanciate
## @brief executes the query
##@brief executes the query
# @return list
# @TODO activate LodelHook calls
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
return results
## @brief prepares the field list
##@brief prepares the field list
# @return list
# @raise LeApiDataCheckError
def __prepare_field_list(self):
@ -159,12 +159,12 @@ class LeGetQuery(LeFilteredQuery):
return ret_field_list
## @brief prepares a relational field
##@brief prepares a relational field
def __prepare_relational_field(self, field):
# TODO Implement the method
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
# @return tuple
# @raise ValueError
@ -190,7 +190,7 @@ class LeGetQuery(LeFilteredQuery):
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)
## @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
# @return str
# @raise ValueError
@ -199,7 +199,7 @@ class LeGetQuery(LeFilteredQuery):
return ValueError("No such field '%s' in %s" % (field, self.target_class))
return field
## @brief Prepares the filters (relational and others)
##@brief Prepares the filters (relational and others)
# @return tuple
def __prepare_filters(self):
filters = list()
@ -234,7 +234,7 @@ class LeGetQuery(LeFilteredQuery):
datas['target_class'] = self.target_class
return datas
## @brief prepares the "order" parameters
##@brief prepares the "order" parameters
# @return list
def __prepare_order(self):
errors = dict()
@ -269,7 +269,7 @@ class LeUpdateQuery(LeFilteredQuery):
# ret = LodelHook.call_hook('leapi_update_post', self.target_object, 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
# @TODO change the behavior in case of error in the update process
def __update(self):
@ -280,7 +280,7 @@ class LeUpdateQuery(LeFilteredQuery):
else:
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):
datas = dict()
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)
return ret
## @brief calls the datasource's delete method
##@brief calls the datasource's delete method
# @return bool
# @TODO change the behavior in case of error in the update process
def __delete(self):

View file

@ -23,7 +23,7 @@ def __init_from_settings():
for name, logging_opt in Settings.logging.items():
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 :
# - 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)
## @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
def remove_handler(name):
if name in handlers:
logger.removeHandler(handlers[name])
# 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
def remove_console_handlers():
for name, handler in handlers.items():
@ -84,7 +84,7 @@ def remove_console_handlers():
# Utility functions
## @brief Generic logging function
##@brief Generic logging function
# @param lvl int : Log severity
# @param msg str : log message
# @param *args : additional positionnal arguments

View file

@ -4,16 +4,16 @@ import os
import copy
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):
## @brief Constructor
##@brief Constructor
# @param hook function : the function to wrap
# @param priority int : the callbacl priority
def __init__(self, hook, priority):
self._priority = priority
self._hook = hook
## @brief Call the callback
##@brief Call the callback
# @param hook_name str : The name of the called hook
# @param caller * : The caller (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):
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 :
#  - hook_name : the called hook name
@ -29,17 +29,17 @@ class DecoratedWrapper(object):
# - payload : datas depending on the hook
class LodelHook(object):
## @brief Stores all hooks (DecoratedWrapper instances)
##@brief Stores all hooks (DecoratedWrapper instances)
_hooks = dict()
## @brief Decorator constructor
##@brief Decorator constructor
# @param hook_name str : the name of the hook to register to
# @param priority int : the hook priority
def __init__(self, hook_name, priority = None):
self._hook_name = hook_name
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
# @return the hook argument
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)
return hook
## @brief Call hooks
##@brief Call hooks
# @param hook_name str : the hook's name
# @param caller * : the hook caller (depends on the hook)
# @param payload * : datas for the hook
@ -63,7 +63,7 @@ class LodelHook(object):
payload = hook(hook_name, caller, payload)
return payload
## @brief Fetch registered hooks
##@brief Fetch registered hooks
# @param names list | None : optionnal filter on name
# @param cls
# @return a list of functions
@ -76,7 +76,7 @@ class LodelHook(object):
res = copy.copy(cls._hooks)
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
# @warning REALLY NOT a good idea !
# @note implemented for testing purpose

View file

@ -12,7 +12,7 @@ from importlib.machinery import SourceFileLoader, SourcelessFileLoader
# - main.py containing hooks registration etc
# - 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'
CONFSPEC_FILENAME = 'confspec.py'
MAIN_FILENAME = 'main.py'
@ -23,15 +23,15 @@ class PluginError(Exception):
class Plugins(object):
## @brief Stores plugin directories paths
##@brief Stores plugin directories paths
_plugin_directories = None
## @brief Optimisation cache storage for plugin paths
##@brief Optimisation cache storage for plugin paths
_plugin_paths = dict()
def __init__(self): # may be useless
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
# @return the plugin directory path
@classmethod
@ -50,7 +50,7 @@ class Plugins(object):
return plugin_path
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
# @return a dict of conf spec
# @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)
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
@classmethod
def load_plugin(cls, plugin_name):
@ -86,7 +86,7 @@ class Plugins(object):
except ImportError:
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
def bootstrap(cls, plugins_directories):
cls._plugin_directories = plugins_directories

View file

@ -1,6 +1,34 @@
#-*- 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
##@brief Bootstraped instance
settings = SettingsHandler.bootstrap()
if settings is not None:
##@brief Exposed variable that represents configurations values in a
# namedtuple tree
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.settings_loader import SettingsLoader
## @package lodel.settings Lodel2 settings package
#
# Contains all module that help handling settings
## @package lodel.settings.settings Lodel2 settings module
#
# Handles configuration load/parse/check.
#
# @subsection Configuration load process
#
# The configuration load process is not trivial. In fact loaded plugins are 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.
# The configuration load process is not trivial. In fact loaded plugins are
# 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
#
@ -32,14 +29,17 @@ from lodel.settings.settings_loader import SettingsLoader
# - 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(
major = sys.version_info.major,
minor = sys.version_info.minor)
## @brief Handles configuration load etc.
major = sys.version_info.major,
minor = sys.version_info.minor)
##@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 :
# <pre>
# [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>
#
# @par Init sequence
# The initialization sequence is a bit tricky. In fact, plugins adds allowed configuration
# sections/values, but the list of plugins to load in in... the settings.
# The initialization sequence is a bit tricky. In fact, plugins adds allowed
# configuration sections/values, but the list of plugins to load in in... the
# settings.
# Here is the conceptual presentation of Settings class initialization stages :
# -# 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
# -# 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
#
# @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)
# -# 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):
## @brief global conf specsification (default_value + validator)
##@brief global conf specsification (default_value + validator)
_conf_preload = {
'lib_path': ( PYTHON_SYS_LIB_PATH+'/lodel2/',
SettingValidator('directory')),
@ -77,7 +81,7 @@ class Settings(object):
}
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'):
self.__confs = dict()
self.__conf_dir = conf_dir
@ -86,7 +90,7 @@ class Settings(object):
# and self.__confs['lodel2']['lib_path'] set
self.__bootstrap()
## @brief Stores as class attribute a Settings instance
##@brief Stores as class attribute a Settings instance
@classmethod
def bootstrap(cls, conf_file = None, conf_dir = None):
if cls.instance is None:
@ -96,13 +100,13 @@ class Settings(object):
cls.instance = cls(conf_file, conf_dir)
return cls.instance
## @brief Configuration keys accessor
##@brief Configuration keys accessor
# @return All confs organised into named tuples
@property
def confs(self):
return copy.copy(self.__confs)
## @brief This method handlers Settings instance bootstraping
##@brief This method handlers Settings instance bootstraping
def __bootstrap(self):
lodel2_specs = LODEL2_CONF_SPECS
plugins_opt_specs = lodel2_specs['lodel2']['plugins']
@ -126,7 +130,7 @@ class Settings(object):
specs = self.__merge_specs(specs)
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
# and configuration specifications from loaded plugins
@ -144,7 +148,7 @@ class Settings(object):
res[section][kname] = copy.copy(spec[section][kname])
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
# @param specs dict : Settings specification dictionnary as returned by __merge_specs
@ -170,7 +174,7 @@ class Settings(object):
self.__confs_to_namedtuple()
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
# be acessible with self.__confs.hello.world.foo
@ -225,14 +229,14 @@ class Settings(object):
path.append( (curname, cur) )
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
# @return a named tuple with fieldnames corresponding to conftree keys
def __tree2namedtuple(self, conftree, name):
ResNamedTuple = namedtuple(name, conftree.keys())
return ResNamedTuple(**conftree)
## @brief Load base global configurations keys
##@brief Load base global configurations keys
#
# Base configurations keys are :
# - lodel2 lib path

View file

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

View file

@ -1,9 +1,13 @@
#-*- 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):
## @brief Instanciate a new SettingsError
##@brief Instanciate a new SettingsError
# @param msg str : Error message
# @param key_id str : The key concerned by the error
def __init__(self, msg = "Unknown error", key_id = None, filename = None):
@ -23,10 +27,10 @@ class SettingsError(Exception):
res += ": %s" % (self.__msg)
return res
## @brief Designed to handles mutliple SettingsError
##@brief Designed to handles mutliple SettingsError
class SettingsErrors(Exception):
## @brief Instanciate an SettingsErrors
##@brief Instanciate an SettingsErrors
# @param exceptions list : list of SettingsError instance
def __init__(self, exceptions):
for expt in exceptions:

View file

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

View file

@ -5,7 +5,7 @@ import hashlib
import json
## @brief Stores multilangage string
##@brief Stores multilangage string
class MlString(object):
__default_lang = 'eng'
@ -17,7 +17,7 @@ class MlString(object):
'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
def __init__(self, arg):
self.values = dict()
@ -33,7 +33,7 @@ class MlString(object):
else:
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
def get(self, lang = None):
lang = self.__default_lang if lang is None else lang
@ -44,7 +44,7 @@ class MlString(object):
else:
return str(self)
## @brief Set a translation
##@brief Set a translation
# @param lang str : the lang
# @param val str | None: the translation if None delete the translation
def set(self, lang, val):
@ -57,7 +57,7 @@ class MlString(object):
else:
self.values[lang] = val
## @brief Checks that given lang is valid
##@brief Checks that given lang is valid
# @param lang str : the lang
@classmethod
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))
return lang in cls.langs
## @brief Get or set the default lang
##@brief Get or set the default lang
@classmethod
def default_lang(cls, lang = None):
if lang is None:
@ -74,7 +74,7 @@ class MlString(object):
raise ValueError('lang "%s" is not valid"' % 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
@classmethod
def from_json(cls, json_str):

View file

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