1
0
Fork 0
mirror of https://github.com/yweber/lodel2.git synced 2026-09-15 22:20:29 +02:00

Some adjustments and corresions

This commit is contained in:
prieto 2016-10-06 08:59:55 +02:00
commit 2d8a9811e6
7 changed files with 193 additions and 142 deletions

View file

@ -1,4 +1,4 @@
#-*- co:ding: utf-8 -*-
#-*- coding: utf-8 -*-
## @package lodel.leapi.datahandlers.base_classes Define all base/abstract class for data handlers
#
@ -15,7 +15,7 @@ from lodel import logger
##@brief Base class for all data handlers
#@ingroup lodel2_datahandlers
class DataHandler(object):
base_type = "type"
_HANDLERS_MODULES = ('datas_base', 'datas', 'references')
##@brief Stores the DataHandler childs classes indexed by name
_base_handlers = None
@ -27,7 +27,7 @@ class DataHandler(object):
##@brief List fields that will be exposed to the construct_data_method
_construct_datas_deps = []
directly_editable = True
##@brief constructor
# @param internal False | str : define whether or not a field is internal
@ -38,9 +38,7 @@ class DataHandler(object):
def __init__(self, **kwargs):
if self.__class__ == DataHandler:
raise NotImplementedError("Abstract class")
self.__arguments = kwargs
self.nullable = True
self.uniq = False
self.immutable = False
@ -62,7 +60,7 @@ class DataHandler(object):
@classmethod
def is_reference(cls):
return issubclass(cls, Reference)
@classmethod
def is_singlereference(cls):
return issubclass(cls, SingleRef)
@ -70,7 +68,6 @@ class DataHandler(object):
def is_primary_key(self):
return self.primary_key
##@brief checks if a fieldtype is internal
# @return bool
def is_internal(self):
@ -78,7 +75,7 @@ class DataHandler(object):
##brief check if a value can be nullable
#@param value *
#@throw DataNoneValid if value is None and nullable. LodelExceptions if not nullable
#@throw DataNoneValid if value is None and nullable. LodelExceptions if not nullable
#@return value (if not None)
# @return value
def _check_data_value(self, value):
@ -88,7 +85,6 @@ class DataHandler(object):
raise DataNoneValid("None with a nullable. This exeption is allowed")
return value
##@brief calls the data_field (defined in derived class) _check_data_value() method
#@param value *
#@return tuple (value|None, None|error) value can be cast if NoneError
@ -125,7 +121,6 @@ class DataHandler(object):
data_handler = None
if fname in emcomponent_fields:
data_handler = emcomponent_fields[fname]
new_val = cur_value
if fname in datas.keys():
pass
@ -134,7 +129,7 @@ class DataHandler(object):
elif data_handler is not None and data_handler.nullable:
new_val = None
return self._construct_data(emcomponent, fname, datas, new_val)
##@brief Designed to be reimplemented by child classes
#@param emcomponent EmComponent : An EmComponent child class instance
#@param fname str : The field name
@ -144,7 +139,6 @@ class DataHandler(object):
#@see construct_data() lodel2_dh_check_impl
def _construct_data(self, empcomponent, fname, datas, cur_value):
return cur_value
##@brief Check datas consistency
#@ingroup lodel2_dh_checks
@ -160,7 +154,7 @@ class DataHandler(object):
#@todo A implémenter
def check_data_consistency(self, emcomponent, fname, datas):
return self._check_data_consistency(emcomponent, fname, datas)
##@brief Designed to be reimplemented by child classes
#@param emcomponent EmComponent : An EmComponent child class instance
#@param fname : the field name
@ -175,10 +169,10 @@ class DataHandler(object):
# @param fname : the field name
# @param datas dict : dict storing fields values
# @return an Exception instance if fails else True
# @todo A implémenter
# @todo A implémenter
def make_consistency(self, emcomponent, fname, datas):
pass
##@brief This method is use by plugins to register new data handlers
@classmethod
def register_new_handler(cls, name, data_handler):
@ -187,7 +181,7 @@ class DataHandler(object):
if not issubclass(data_handler, DataHandler):
raise ValueError("A data handler HAS TO be a child class of DataHandler")
cls.__custom_handlers[name] = data_handler
##@brief Load all datahandlers
@classmethod
def load_base_handlers(cls):
@ -213,7 +207,7 @@ class DataHandler(object):
if name not in all_handlers:
raise NameError("No data handlers named '%s'" % (name,))
return all_handlers[name]
##@brief Return the module name to import in order to use the datahandler
# @param data_handler_name str : Data handler name
# @return a str
@ -222,10 +216,10 @@ class DataHandler(object):
name = name.lower()
handler_class = cls.from_name(name)
return '{module_name}.{class_name}'.format(
module_name = handler_class.__module__,
class_name = handler_class.__name__
module_name=handler_class.__module__,
class_name=handler_class.__name__
)
##@brief __hash__ implementation for fieldtypes
def __hash__(self):
hash_dats = [self.__class__.__module__]
@ -248,17 +242,16 @@ class DataField(DataHandler):
#@todo Check data consistency implementation : check that LeObject instance
#is from an allowed class
class Reference(DataHandler):
base_type="ref"
base_type = "ref"
##@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
# @param **kwargs : other arguments
def __init__(self, allowed_classes = None, back_reference = None, internal=False, **kwargs):
def __init__(self, allowed_classes=None, back_reference=None, internal=False, **kwargs):
self.__allowed_classes = set() if allowed_classes is None else set(allowed_classes)
self.allowed_classes = list() if allowed_classes is None else allowed_classes
if back_reference is not None:
if len(back_reference) != 2:
raise ValueError("A tuple (classname, fieldname) expected but got '%s'" % back_reference)
@ -266,8 +259,8 @@ class Reference(DataHandler):
# raise TypeError("Back reference was expected to be a tuple(<class LeObject>, str) but got : (%s, %s)" % (back_reference[0], back_reference[1]))
self.__back_reference = back_reference
super().__init__(internal=internal, **kwargs)
##@brief Method designed to return an empty value for this kind of
##@brief Method designed to return an empty value for this kind of
#multipleref
@classmethod
def empty(cls):
@ -277,8 +270,8 @@ class Reference(DataHandler):
@property
def back_reference(self):
return copy.copy(self.__back_reference)
##@brief Property that takes value of datahandler of the backreference or
##@brief Property that takes value of datahandler of the backreference or
#None
@property
def back_ref_datahandler(self):
@ -296,7 +289,7 @@ class Reference(DataHandler):
##@brief Check and cast value in appropriate type
#@param value *
#@throw FieldValidationError if value is an appropriate type
#@throw FieldValidationError if value is an appropriate type
#@return value
#@todo implement the check when we have LeObject uid check value
def _check_data_value(self, value):
@ -328,34 +321,29 @@ class Reference(DataHandler):
return rep
if self.back_reference is None:
return True
# !! Reimplement instance fetching in construct data !!
dh = emcomponent.field(fname)
uid = datas[emcomponent.uid_fieldname()[0]] #multi uid broken here
target_class = self.back_reference[0]
target_field = self.back_reference[1]
target_uidfield = target_class.uid_fieldname()[0] #multi uid broken here
value = datas[fname]
obj = target_class.get([(target_uidfield , '=', value)])
obj = target_class.get([(target_uidfield, '=', value)])
if len(obj) == 0:
logger.warning('Object referenced does not exist')
return False
return True
##@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):
def __init__(self, allowed_classes = None, **kwargs):
super().__init__(allowed_classes = allowed_classes, **kwargs)
def __init__(self, allowed_classes=None, **kwargs):
super().__init__(allowed_classes=allowed_classes)
##@brief Check and cast value in appropriate type
#@param value: *
#@throw FieldValidationError if value is unappropriate or can not be cast
#@throw FieldValidationError if value is unappropriate or can not be cast
#@return value
def _check_data_value(self, value):
value = super()._check_data_value(value)
@ -364,20 +352,22 @@ class SingleRef(Reference):
# raise FieldValidationError("List or string expected for a set field")
return value
##@brief This class represent a data_handler for multiple references to another object
#@ingroup lodel2_datahandlers
#
# The fields using this data handlers are like SingleRef but can store multiple references in one field
# @note for the moment split on ',' chars
class MultipleRef(Reference):
##
# @param max_item int | None : indicate the maximum number of item referenced by this field, None mean no limit
def __init__(self, max_item = None, **kwargs):
def __init__(self, max_item=None, **kwargs):
self.max_item = max_item
super().__init__(**kwargs)
##@brief Method designed to return an empty value for this kind of
##@brief Method designed to return an empty value for this kind of
#multipleref
@classmethod
def empty(cls):
@ -385,11 +375,11 @@ class MultipleRef(Reference):
##@brief Check and cast value in appropriate type
#@param value *
#@throw FieldValidationError if value is unappropriate or can not be cast
#@throw FieldValidationError if value is unappropriate or can not be cast
#@return value
#@TODO Writing test error for errors when stored multiple references in one field
def _check_data_value(self, value):
value = DataHandler._check_data_value(self,value)
value = DataHandler._check_data_value(self, value)
if not hasattr(value, '__iter__'):
raise FieldValidationError("MultipleRef has to be an iterable or a string, '%s' found" % value)
if self.max_item is not None:
@ -397,29 +387,93 @@ class MultipleRef(Reference):
raise FieldValidationError("Too many items")
new_val = list()
error_list = list()
for i,v in enumerate(value):
for i, v in enumerate(value):
try:
v = super()._check_data_value(v)
new_val.append(v)
except (FieldValidationError) as f:
except (FieldValidationError):
error_list.append(repr(v))
if len(error_list) > 0:
raise FieldValidationError("MultipleRef have for invalid values [%s] :" % (",".join(error_list)))
return new_val
##@brief Construct a multiple ref data
def construct_data(self, emcomponent, fname, datas, cur_value):
cur_value = super().construct_data(emcomponent, fname, datas, cur_value)
if cur_value is not None:
if self.back_reference is not None:
br_class = self.back_reference[0]
for br_id in cur_value:
query_filters = list()
query_filters.append((br_class.uid_fieldname()[0], '=', br_id))
br_obj = br_class.get(query_filters)
if len(br_obj) != 0:
br_list = br_obj[0].data(self.back_reference[1])
if br_list is None:
br_list = list()
if br_id not in br_list:
br_list.append(br_id)
return cur_value
## @brief Checks the backreference, updates it if it is not complete
# @param emcomponent EmComponent : An EmComponent child class instance
# @param fname : the field name
# @param datas dict : dict storing fields values
# @note Not done in case of delete
def make_consistency(self, emcomponent, fname, datas, type_query):
dh = emcomponent.field(fname)
logger.info('Warning : multiple uid capabilities are broken here')
uid = datas[emcomponent.uid_fieldname()[0]]
if self.back_reference is not None:
target_class = self.back_reference[0]
target_field = self.back_reference[1]
target_uidfield = target_class.uid_fieldname()[0]
l_value = datas[fname]
if l_value is not None:
for value in l_value:
query_filters = list()
query_filters.append((target_uidfield, '=', value))
obj = target_class.get(query_filters)
if len(obj) == 0:
logger.warning('Object referenced does not exist')
return False
l_uids_ref = obj[0].data(target_field)
if l_uids_ref is None:
l_uids_ref = list()
if uid not in l_uids_ref:
l_uids_ref.append(uid)
obj[0].set_data(target_field, l_uids_ref)
obj[0].update()
if type_query == 'update':
query_filters = list()
query_filters.append((uid, ' in ', target_field))
objects = target_class.get(query_filters)
if l_value is None:
l_value = list()
if len(objects) != len(l_value):
for obj in objects:
l_uids_ref = obj.data(target_field)
if obj.data(target_uidfield) not in l_value:
l_uids_ref.remove(uid)
obj.set_data(target_field, l_uids_ref)
obj.update()
## @brief Class designed to handle datas access will fieldtypes are constructing datas
#@ingroup lodel2_datahandlers
#
# This class is designed to allow automatic scheduling of construct_data calls.
# This class is designed to allow automatic scheduling of construct_data calls.
#
# In theory it's able to detect circular dependencies
# @todo test circular deps detection
# @todo test circulat deps false positiv
class DatasConstructor(object):
## @brief Init a DatasConstructor
# @param lec LeCrud : @ref LeObject child class
# @param lec LeCrud : @ref LeObject child class
# @param datas dict : dict with field name as key and field values as value
# @param fields_handler dict : dict with field name as key and data handler instance as value
def __init__(self, leobject, datas, fields_handler):
@ -433,11 +487,11 @@ class DatasConstructor(object):
self._constructed = []
## Stores construct calls list
self._construct_calls = []
## @brief Implements the dict.keys() method on instance
def keys(self):
return self._datas.keys()
## @brief Allows to access the instance like a dict
def __getitem__(self, fname):
if fname not in self._constructed:
@ -447,10 +501,10 @@ class DatasConstructor(object):
self._datas[fname] = self._fields_handler[fname].construct_data(self._leobject, fname, self, cur_value)
self._constructed.append(fname)
return self._datas[fname]
## @brief Allows to set instance values like a dict
# @warning Should not append in theory
def __setitem__(self, fname, value):
self._datas[fname] = value
warnings.warn("Setting value of an DatasConstructor instance")

View file

@ -1,5 +1,5 @@
#-
#- THE CONTENT OF THIS FILE IS DESIGNED TO BE INCLUDED IN DYNAMICALLY
#- THE CONTENT OF THIS FILE IS DESIGNED TO BE INCLUDED IN DYNAMICALLY
#- GENERATED CODE
#-
#- All lines that begins with #- will be deleted from dynamically generated

View file

@ -63,6 +63,8 @@ class LeObject(object):
_rw_datasource = None
##@brief Store the list of child classes
_child_classes = None
##@brief Name of the datasource plugin
_datasource_name = None
def __new__(cls, **kwargs):
@ -367,13 +369,13 @@ class LeObject(object):
for fname in self.fieldnames(include_ro = True):
try:
field = self._fields[fname]
self.__datas[fname] = fields.construct_data( self,
self.__datas[fname] = field.construct_data( self,
fname,
self.__datas,
self.__datas[fname]
)
except Exception as e:
err_list[fname] = e
except Exception as exp:
err_list[fname] = exp
# Datas consistency check
if len(err_list) == 0:
for fname in self.fieldnames(include_ro = True):

View file

@ -16,7 +16,7 @@ class LeQuery(object):
##@brief Hookname prefix
_hook_prefix = None
##@brief arguments for the LeObject.check_data_value()
_data_check_args = { 'complete': False, 'allow_internal': False }
_data_check_args = {'complete': False, 'allow_internal': False}
##@brief Abstract constructor
# @param target_class LeObject : class of object the query is about
@ -30,7 +30,7 @@ class LeQuery(object):
self._target_class = target_class
self._ro_datasource = target_class._ro_datasource
self._rw_datasource = target_class._rw_datasource
##@brief Execute a query and return the result
#@param **datas
#@return the query result
@ -44,11 +44,11 @@ class LeQuery(object):
self._target_class.prepare_datas(datas) #not yet implemented
if self._hook_prefix is None:
raise NotImplementedError("Abstract method")
LodelHook.call_hook( self._hook_prefix+'_pre',
LodelHook.call_hook(self._hook_prefix+'_pre',
self._target_class,
datas)
ret = self._query(datas = datas)
ret = LodelHook.call_hook( self._hook_prefix+'_post',
ret = self._query(datas=datas)
ret = LodelHook.call_hook(self._hook_prefix+'_post',
self._target_class,
ret)
return ret
@ -71,7 +71,6 @@ class LeQuery(object):
##@brief Abstract class handling query with filters
class LeFilteredQuery(LeQuery):
##@brief The available operators used in query definitions
_query_operators = [
' = ',
@ -84,16 +83,16 @@ class LeFilteredQuery(LeQuery):
' not in ',
' like ',
' not like ']
##@brief Regular expression to process filters
_query_re = None
##@brief Abtract constructor for queries with filter
#@param target_class LeObject : class of object the query is about
#@param query_filters list : with a tuple (only one filter) or a list of
#@param query_filters list : with a tuple (only one filter) or a list of
# tuple or a dict: {OP,list(filters)} with OP = 'OR' or 'AND for tuple
# (FIELD,OPERATOR,VALUE)
def __init__(self, target_class, query_filters = None):
def __init__(self, target_class, query_filters=None):
super().__init__(target_class)
##@brief The query filter tuple(std_filter, relational_filters)
self._query_filter = None
@ -108,7 +107,7 @@ class LeFilteredQuery(LeQuery):
##@brief Abstract FilteredQuery execution method
#
# This method takes care to execute subqueries before calling super execute
def execute(self, datas = None):
def execute(self, datas=None):
#copy originals filters
orig_filters = copy.copy(self._query_filter)
std_filters, rel_filters = self._query_filter
@ -143,7 +142,7 @@ class LeFilteredQuery(LeQuery):
if isinstance(query_filter, str):
query_filter = [query_filter]
#Query filter prepration
filters_orig , rel_filters = self._prepare_filters(query_filter)
filters_orig, rel_filters = self._prepare_filters(query_filter)
# Here we now that each relational filter concern only one datasource
# thank's to _prepare_relational_fields
@ -165,16 +164,16 @@ class LeFilteredQuery(LeQuery):
# The line below brake multi UID support
#
if tfield == tclass.uid_fieldname()[0]:
#This relational filter can be simplified as
#This relational filter can be simplified as
# ref_field, op, value
# Note : we will have to dedup filters_orig
filters_orig.append((rfield, op, value))
del(ref_dict[tclass])
if len(ref_dict) == 0:
continue
#Determine what to do with other relational filters given
#Determine what to do with other relational filters given
# referenced class datasource
#Remember : each class in a relational filter has the same
#Remember : each class in a relational filter has the same
# datasource
tclass = list(ref_dict.keys())[0]
cur_ds = tclass._datasource_name
@ -191,7 +190,7 @@ class LeFilteredQuery(LeQuery):
filters_cp = set()
if not isinstance(filters_orig, set):
for i, cfilt in enumerate(filters_orig):
a,b,c = cfilt
a, b, c = cfilt
if isinstance(c, list): #list are not hashable
newc = tuple(c)
else:
@ -210,12 +209,12 @@ class LeFilteredQuery(LeQuery):
(rfield, ref_dict), op, value = rfilter
for tclass, tfield in ref_dict.items():
query = LeGetQuery(
target_class = tclass,
query_filters = [(tfield, op, value)],
field_list = [tfield])
target_class=tclass,
query_filters=[(tfield, op, value)],
field_list=[tfield])
subq.append((rfield, query))
self.subqueries = subq
##@return informations
def dump_infos(self):
ret = super().dump_infos()
@ -227,17 +226,17 @@ class LeFilteredQuery(LeQuery):
res = "<{classname} target={target_class} query_filter={query_filter}"
res = res.format(
classname=self.__class__.__name__,
query_filter = self._query_filter,
target_class = self._target_class)
query_filter=self._query_filter,
target_class=self._target_class)
if len(self.subqueries) > 0:
for n,subq in enumerate(self.subqueries):
for n, subq in enumerate(self.subqueries):
res += "\n\tSubquerie %d : %s"
res %= (n, subq)
res += '>'
return res
## @brief Prepare filters for datasource
#
#
#A filter can be a string or a tuple with len = 3.
#
#This method divide filters in two categories :
@ -248,13 +247,13 @@ class LeFilteredQuery(LeQuery):
#the content, etc.) They are composed of three elements : FIELDNAME OP
# VALUE . Where :
#- FIELDNAME is the name of the field
#- OP is one of the authorized comparison operands ( see
#- OP is one of the authorized comparison operands (see
#@ref LeFilteredQuery.query_operators )
#- VALUE is... a value
#
#@par Relational filters
#
#Those filters concerns on reference fields ( see the corresponding
#Those filters concerns on reference fields (see the corresponding
#abstract datahandler @ref lodel.leapi.datahandlers.base_classes.Reference)
#The filter as quite the same composition than simple filters :
# FIELDNAME[.REF_FIELD] OP VALUE . Where :
@ -269,12 +268,12 @@ class LeFilteredQuery(LeQuery):
#@todo move this doc in another place (a dedicated page ?)
#@warning Does not supports multiple UID for an EmClass
def _prepare_filters(self, filters_l):
filters = list()
filters=list()
res_filters = list()
rel_filters = list()
err_l = dict()
#Splitting in tuple if necessary
for i,fil in enumerate(filters_l):
for i, fil in enumerate(filters_l):
if len(fil) == 3 and not isinstance(fil, str):
filters.append(tuple(fil))
else:
@ -292,8 +291,8 @@ class LeFilteredQuery(LeQuery):
elif len(field_spl) == 1:
ref_field = None
else:
err_l[field] = NameError( "'%s' is not a valid relational \
field name" % fieldname)
err_l[field] = NameError("'%s' is not a valid relational \
field name" % field)
continue
# Checking field against target_class
ret = self._check_field(self._target_class, field)
@ -302,13 +301,13 @@ field name" % fieldname)
continue
field_datahandler = self._target_class.field(field)
if isinstance(field_datahandler, Exception):
err_l[field] = error
err_l[field] = field_datahandler
continue
if ref_field is not None and not field_datahandler.is_reference():
# inconsistency
err_l[field] = NameError( "The field '%s' in %s is not \
err_l[field] = NameError("The field '%s' in %s is not \
a relational field, but %s.%s was present in the filter"
% ( field,
% (field,
self._target_class.__name__,
field,
ref_field))
@ -321,7 +320,7 @@ a relational field, but %s.%s was present in the filter"
# This piece of code does not supports multiple UID for an
# emclass
#
ref_uid = [
ref_uid = [
lc._uid[0] for lc in field_datahandler.linked_classes]
if len(set(ref_uid)) == 1:
@ -410,7 +409,7 @@ field to use for the relational filter"
#Relational filters are composed of a tuple like the simple filters
#but the first element of this tuple is a tuple to :
#
#<code>( (FIELDNAME, {REF_CLASS: REF_FIELD}), OP, VALUE)</code>
#<code>((FIELDNAME, {REF_CLASS: REF_FIELD}), OP, VALUE)</code>
# Where :
#- FIELDNAME is the field name is the target class
#- the second element is a dict with :
@ -429,7 +428,7 @@ field to use for the relational filter"
# {
# auteur: 'lodel_id',
# traducteur: 'lodel_id'
# }
# }
# ),
# ' IN ',
# [ 1,2,3,5 ])</pre>
@ -439,7 +438,7 @@ field to use for the relational filter"
#@param ref_field str|None : The referenced field name (if None use
#uniq identifiers as referenced field
#@return a well formed relational filter tuple or an Exception instance
def _prepare_relational_fields(self, fieldname, ref_field = None):
def _prepare_relational_fields(self, fieldname, ref_field=None):
datahandler = self._target_class.field(fieldname)
# now we are going to fetch the referenced class to see if the
# reference field is valid
@ -464,29 +463,28 @@ the relational filter %s"
msg %= (ref_class.__name__, ref_field)
logger.debug(msg)
if len(ref_dict) == 0:
return NameError( "No field named '%s' in referenced objects [%s]"
return NameError("No field named '%s' in referenced objects [%s]"
% (ref_field,
','.join([rc.__name__ for rc in ref_classes])))
return (fieldname, ref_dict)
##@brief A query to insert a new object
class LeInsertQuery(LeQuery):
_hook_prefix = 'leapi_insert_'
_data_check_args = { 'complete': True, 'allow_internal': False }
_data_check_args = {'complete': True, 'allow_internal': False}
def __init__(self, target_class):
if target_class.is_abstract():
raise LeApiQueryError("Trying to create an insert query on an \
abstract LeObject : %s" % target_class )
abstract LeObject : %s" % target_class)
super().__init__(target_class)
## @brief Implements an insert query operation, with only one insertion
# @param new_datas : datas to be inserted
def _query(self, datas):
datas = self._target_class.prepare_datas(datas, True, False)
id_inserted = self._rw_datasource.insert(self._target_class,datas)
id_inserted = self._rw_datasource.insert(self._target_class, datas)
return id_inserted
"""
## @brief Implements an insert query operation, with multiple insertions
@ -501,7 +499,7 @@ abstract LeObject : %s" % target_class )
## @brief Execute the insert query
def execute(self, datas):
return super().execute(datas = datas)
return super().execute(datas=datas)
##@brief A query to update datas for a given object
@ -509,10 +507,9 @@ abstract LeObject : %s" % target_class )
#@todo Change behavior, Huge optimization problem when updating using filters
#and not instance. We have to run a GET and then 1 update by fecthed object...
class LeUpdateQuery(LeFilteredQuery):
_hook_prefix = 'leapi_update_'
_data_check_args = { 'complete': False, 'allow_internal': False }
_data_check_args = {'complete': False, 'allow_internal': False}
##@brief Instanciate an update query
#
#If a class and not an instance is given, no query_filters are expected
@ -523,12 +520,12 @@ class LeUpdateQuery(LeFilteredQuery):
#@param query_filters list|None
#@todo change strategy with instance update. We have to accept datas for
#the execute method
def __init__(self, target, query_filters = None):
def __init__(self, target, query_filters=None):
##@brief This attr is set only if the target argument is an
#instance of a LeObject subclass
self.__leobject_instance_datas = None
target_class = target
if not inspect.isclass(target):
if query_filters is not None:
msg = "No query_filters accepted when an instance is given as \
@ -539,7 +536,7 @@ target to LeUpdateQuery constructor"
self.__leobject_instance_datas = target.datas(True)
else:
query_filters = [(target._uid[0], '=', target.uid())]
super().__init__(target_class, query_filters)
##@brief Implements an update query
@ -547,7 +544,7 @@ target to LeUpdateQuery constructor"
#@param rel_filters list : see @ref LeFilteredQuery
#@param datas dict : datas to update
#@returns the number of updated items
#@todo change stategy for instance update. Datas should be allowed
#@todo change stategy for instance update. Datas should be allowed
#for execute method (and query)
def _query(self, datas):
uid_name = self._target_class._uid[0]
@ -578,48 +575,47 @@ target to LeUpdateQuery constructor"
self._target_class, filters, [],
res_datas)
return res
## @brief Execute the update query
def execute(self, datas = None):
def execute(self, datas=None):
if self.__leobject_instance_datas is not None and datas is not None:
raise LeApiQueryError("No datas expected when running an update \
query on an instance")
if self.__leobject_instance_datas is None and datas is None:
raise LeApiQueryError("Datas are mandatory when running an update \
query on a class with filters")
return super().execute(datas = datas)
return super().execute(datas=datas)
##@brief A query to delete an object
class LeDeleteQuery(LeFilteredQuery):
_hook_prefix = 'leapi_delete_'
def __init__(self, target_class, query_filter):
super().__init__(target_class, query_filter)
## @brief Execute the delete query
def execute(self, datas = None):
def execute(self, datas=None):
return super().execute()
##@brief Implements delete query operations
#@param filters list : see @ref LeFilteredQuery
#@param rel_filters list : see @ref LeFilteredQuery
#@returns the number of deleted items
def _query(self, datas = None):
def _query(self, datas=None):
filters, rel_filters = self._query_filter
nb_deleted = self._rw_datasource.delete(
self._target_class, filters, rel_filters)
return nb_deleted
class LeGetQuery(LeFilteredQuery):
_hook_prefix = 'leapi_get_'
##@brief Instanciate a new get query
#@param target_class LeObject : class of object the query is about
#@param query_filters dict : {OP, list of query filters }
#@param query_filters dict : {OP, list of query filters}
# or tuple (FIELD, OPERATOR, VALUE) )
#@param field_list list|None : list of string representing fields see
#@param field_list list|None : list of string representing fields see
# @ref leobject_filters
#@param order list : A list of field names or tuple (FIELDNAME,[ASC | DESC])
#@param group list : A list of field names or tuple (FIELDNAME,[ASC | DESC])
@ -627,7 +623,6 @@ class LeGetQuery(LeFilteredQuery):
#@param offset int : offset
def __init__(self, target_class, query_filters, **kwargs):
super().__init__(target_class, query_filters)
##@brief The fields to get
self._field_list = None
##@brief An equivalent to the SQL ORDER BY
@ -638,7 +633,7 @@ class LeGetQuery(LeFilteredQuery):
self._limit = None
##@brief An equivalent to the SQL LIMIT x, OFFSET
self._offset = 0
# Checking kwargs and assigning default values if there is some
for argname in kwargs:
if argname not in (
@ -672,7 +667,7 @@ class LeGetQuery(LeFilteredQuery):
except ValueError:
msg = "offset argument expected to be an integer >= 0"
raise ValueError(msg)
##@brief Set the field list
# @param field_list list | None : If None use all fields
# @return None
@ -691,36 +686,36 @@ class LeGetQuery(LeFilteredQuery):
msg = "Error while setting field_list in a get query"
raise LeApiQueryErrors(msg = msg, exceptions = err_l)
self._field_list = list(set(field_list))
##@brief Execute the get query
def execute(self, datas = None):
def execute(self, datas=None):
return super().execute()
##@brief Implements select query operations
# @returns a list containing the item(s)
def _query(self, datas = None):
def _query(self, datas=None):
# select datas corresponding to query_filter
fl = list(self._field_list) if self._field_list is not None else None
l_datas=self._ro_datasource.select(
l_datas=self._ro_datasource.select(
target = self._target_class,
field_list = fl,
filters = self._query_filter[0],
relational_filters = self._query_filter[1],
order = self._order,
group = self._group,
limit = self._limit,
filters = self._query_filter[0],
relational_filters = self._query_filter[1],
order = self._order,
group = self._group,
limit = self._limit,
offset = self._offset)
return l_datas
##@return a dict with query infos
def dump_infos(self):
ret = super().dump_infos()
ret.update( { 'field_list' : self._field_list,
'order' : self._order,
'group' : self._group,
'limit' : self._limit,
'offset': self._offset,
})
ret.update({ 'field_list' : self._field_list,
'order' : self._order,
'group' : self._group,
'limit' : self._limit,
'offset': self._offset,
})
return ret
def __repr__(self):

View file

@ -201,7 +201,7 @@ DS_PLUGIN_NAME.DS_INSTANCE_NAME. But got %s" % ds_identifier)
from lodel.settings import Settings
if ds_plugin_name not in Settings.datasource._fields:
msg = "Unknown or unconfigured datasource plugin %s"
msg %= ds_plugin
msg %= ds_plugin_name
raise DatasourcePluginError(msg)
ds_conf = getattr(Settings.datasource, ds_plugin_name)
if ds_identifier not in ds_conf._fields:

View file

@ -110,7 +110,7 @@ class Settings(object, metaclass=MetaSettings):
# allready instanciated, else not
# @throw RuntimeError
@classmethod
def singleton_assert(cls, expect_instanciated = False):
def singleton_assert(cls, expect_instanciated=False):
if expect_instanciated:
if not cls.started():
raise RuntimeError("The Settings class is not started yet")

View file

@ -231,7 +231,7 @@ def host_val(value):
try:
socket.getaddrinfo(value, 80)
return value
except (TypeError,socket.gaierrror):
except (TypeError,socket.gaierror):
msg = "The value '%s' is not a valid host"
raise SettingsValidationError(msg % value)