mirror of
https://github.com/yweber/lodel2.git
synced 2026-06-13 22:20:47 +02:00
New way to specify _fields and table in EmComponent's child classes
Now _fields and table MUST be class attribute. Its important to note that _fields now consist in a list of (name, ftype) tuples and that ftype is a EmFieldType class and NOT an EmFieldType instance
This commit is contained in:
parent
007a04ca2a
commit
00614d90e9
5 changed files with 80 additions and 47 deletions
2
Doxyfile
2
Doxyfile
|
|
@ -425,7 +425,7 @@ EXTRACT_ALL = YES
|
||||||
# be included in the documentation.
|
# be included in the documentation.
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
|
|
||||||
EXTRACT_PRIVATE = NO
|
EXTRACT_PRIVATE = YES
|
||||||
|
|
||||||
# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
|
# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
|
||||||
# scope will be included in the documentation.
|
# scope will be included in the documentation.
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
""" Manipulate Classes of the Editorial Model
|
## @file classes.py
|
||||||
Create classes of object
|
# @see EditorialModel::classes::EmClass
|
||||||
@see EmClass, EmType, EmFieldGroup, EmField
|
|
||||||
"""
|
|
||||||
|
|
||||||
import logging as logger
|
import logging as logger
|
||||||
|
|
||||||
|
|
@ -14,18 +12,24 @@ import sqlalchemy as sql
|
||||||
import EditorialModel.fieldtypes as ftypes
|
import EditorialModel.fieldtypes as ftypes
|
||||||
import EditorialModel
|
import EditorialModel
|
||||||
|
|
||||||
|
## @brief Manipulate Classes of the Editorial Model
|
||||||
|
# Create classes of object.
|
||||||
|
#@see EmClass, EmType, EmFieldGroup, EmField
|
||||||
class EmClass(EmComponent):
|
class EmClass(EmComponent):
|
||||||
table = 'em_class'
|
table = 'em_class'
|
||||||
|
|
||||||
|
## @brief Specific EmClass fields
|
||||||
|
# @see EditorialModel::components::EmComponent::_fields
|
||||||
|
_fields = [
|
||||||
|
('classtype', ftypes.EmField_char),
|
||||||
|
('icon', ftypes.EmField_integer),
|
||||||
|
('sortcolumn', ftypes.EmField_char)
|
||||||
|
]
|
||||||
|
|
||||||
def __init__(self, id_or_name):
|
## Create a new class
|
||||||
self.table = EmClass.table
|
# @param name str: name of the new class
|
||||||
self._fields = [('classtype', ftypes.EmField_char()), ('icon', ftypes.EmField_integer()), ('sortcolumn', ftypes.EmField_char())]
|
# @param class_type EmClasstype: type of the class
|
||||||
super(EmClass, self).__init__(id_or_name)
|
# @return An EmClass instance
|
||||||
|
|
||||||
""" create a new class
|
|
||||||
@param name str: name of the new class
|
|
||||||
@param class_type EmClasstype: type of the class
|
|
||||||
"""
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(c, name, class_type):
|
def create(c, name, class_type):
|
||||||
try:
|
try:
|
||||||
|
|
@ -38,8 +42,9 @@ class EmClass(EmComponent):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
## Isolate SQL for create
|
## Isolate SQL for EmClass::create
|
||||||
# @todo Remove hardcoded default value for icon
|
# @todo Remove hardcoded default value for icon
|
||||||
|
# @return An instance of EmClass
|
||||||
def _createDb(c, name, class_type):
|
def _createDb(c, name, class_type):
|
||||||
""" Do the db querys for EmClass::create() """
|
""" Do the db querys for EmClass::create() """
|
||||||
|
|
||||||
|
|
@ -62,15 +67,16 @@ class EmClass(EmComponent):
|
||||||
return resclass
|
return resclass
|
||||||
|
|
||||||
|
|
||||||
""" retrieve list of the field_groups of this class
|
## Retrieve list of the field_groups of this class
|
||||||
@return field_groups [EmFieldGroup]:
|
# @return field_groups [EmFieldGroup]:
|
||||||
"""
|
|
||||||
def fieldgroups(self):
|
def fieldgroups(self):
|
||||||
records = self._fieldgroupsDb()
|
records = self._fieldgroupsDb()
|
||||||
fieldgroups = [ EditorialModel.fieldgroups.EmFieldGroup(int(record.uid)) for record in records ]
|
fieldgroups = [ EditorialModel.fieldgroups.EmFieldGroup(int(record.uid)) for record in records ]
|
||||||
|
|
||||||
return fieldgroups
|
return fieldgroups
|
||||||
|
|
||||||
|
## Isolate SQL for EmClass::fieldgroups
|
||||||
|
# @return An array of dict (sqlalchemy fetchall)
|
||||||
def _fieldgroupsDb(self):
|
def _fieldgroupsDb(self):
|
||||||
dbe = self.__class__.getDbE()
|
dbe = self.__class__.getDbE()
|
||||||
emfg = sql.Table(EditorialModel.fieldgroups.EmFieldGroup.table, sqlutils.meta(dbe))
|
emfg = sql.Table(EditorialModel.fieldgroups.EmFieldGroup.table, sqlutils.meta(dbe))
|
||||||
|
|
@ -81,21 +87,21 @@ class EmClass(EmComponent):
|
||||||
return res.fetchall()
|
return res.fetchall()
|
||||||
|
|
||||||
|
|
||||||
""" retrieve list of fields
|
## Retrieve list of fields
|
||||||
@return fields [EmField]:
|
# @return fields [EmField]:
|
||||||
"""
|
|
||||||
def fields(self):
|
def fields(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
""" retrieve list of type of this class
|
## Retrieve list of type of this class
|
||||||
@return types [EmType]:
|
# @return types [EmType]:
|
||||||
"""
|
|
||||||
def types(self):
|
def types(self):
|
||||||
records = self._typesDb()
|
records = self._typesDb()
|
||||||
types = [ EditorialModel.types.EmType(int(record.uid)) for record in records ]
|
types = [ EditorialModel.types.EmType(int(record.uid)) for record in records ]
|
||||||
|
|
||||||
return types
|
return types
|
||||||
|
|
||||||
|
## Isolate SQL for EmCLass::types
|
||||||
|
# @return An array of dict (sqlalchemy fetchall)
|
||||||
def _typesDb(self):
|
def _typesDb(self):
|
||||||
dbe = self.__class__.getDbE()
|
dbe = self.__class__.getDbE()
|
||||||
emtype = sql.Table(EditorialModel.types.EmType.table, sqlutils.meta(dbe))
|
emtype = sql.Table(EditorialModel.types.EmType.table, sqlutils.meta(dbe))
|
||||||
|
|
@ -104,15 +110,13 @@ class EmClass(EmComponent):
|
||||||
res = conn.execute(req)
|
res = conn.execute(req)
|
||||||
return res.fetchall()
|
return res.fetchall()
|
||||||
|
|
||||||
""" add a new EmType that can ben linked to this class
|
## Add a new EmType that can ben linked to this class
|
||||||
@param t EmType: type to link
|
# @param t EmType: type to link
|
||||||
@return success bool: done or not
|
# @return success bool: done or not
|
||||||
"""
|
|
||||||
def link_type(self, t):
|
def link_type(self, t):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
""" retrieve list of EmType that are linked to this class
|
## Retrieve list of EmType that are linked to this class
|
||||||
@return types [EmType]:
|
# @return types [EmType]:
|
||||||
"""
|
|
||||||
def linked_types(self):
|
def linked_types(self):
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,24 @@ class EmComponent(object):
|
||||||
## Used by EmComponent::modify_rank
|
## Used by EmComponent::modify_rank
|
||||||
ranked_in = None
|
ranked_in = None
|
||||||
|
|
||||||
##Read only properties
|
## Read only properties
|
||||||
_ro_properties = [ 'date_update', 'date_create', 'uid', 'rank']
|
_ro_properties = [ 'date_update', 'date_create', 'uid', 'rank', 'deleted']
|
||||||
|
|
||||||
|
## @brief List fields name and fieldtype
|
||||||
|
#
|
||||||
|
# This is a list that describe database fields common for each EmComponent child classes.
|
||||||
|
# A database field is defined here by a tuple(name, type) with name a string and type an EditorialModel.fieldtypes.EmFieldType
|
||||||
|
# @warning The EmFieldType in second position in the tuples must be a class type and not a class instance !!!
|
||||||
|
# @see EditorialModel::classes::EmClass::_fields EditorialModel::fieldgroups::EmFieldGroup::_fields EditorialModel::types::EmType::_fields EditorialModel::fields::EmField::_fields
|
||||||
|
_fields = [
|
||||||
|
('uid', ftypes.EmField_integer),
|
||||||
|
('name', ftypes.EmField_char),
|
||||||
|
('rank', ftypes.EmField_integer),
|
||||||
|
('date_update', ftypes.EmField_date),
|
||||||
|
('date_create', ftypes.EmField_date),
|
||||||
|
('string', ftypes.EmField_mlstring),
|
||||||
|
('help', ftypes.EmField_mlstring)
|
||||||
|
]
|
||||||
|
|
||||||
## Instaciate an EmComponent
|
## Instaciate an EmComponent
|
||||||
# @param id_or_name int|str: name or id of the object
|
# @param id_or_name int|str: name or id of the object
|
||||||
|
|
@ -42,8 +58,11 @@ class EmComponent(object):
|
||||||
if type(self) is EmComponent:
|
if type(self) is EmComponent:
|
||||||
raise NotImplementedError('Abstract class')
|
raise NotImplementedError('Abstract class')
|
||||||
|
|
||||||
# data fields of the object
|
## @brief An OrderedDict storing fields name and values
|
||||||
self._fields = OrderedDict([('uid', ftypes.EmField_integer()), ('name', ftypes.EmField_char()), ('rank', ftypes.EmField_integer()), ('date_update', ftypes.EmField_date()), ('date_create', ftypes.EmField_date()), ('string', ftypes.EmField_mlstring()), ('help', ftypes.EmField_mlstring())] + self._fields)
|
# Values are handled by EditorialModel::fieldtypes::EmFieldType
|
||||||
|
# @warning \ref _fields instance property is not the same than EmComponent::_fields class property. In the instance property the EditorialModel::fieldtypes::EmFieldType are instanciated to be able to handle datas
|
||||||
|
# @see EmComponent::_fields EditorialModel::fieldtypes::EmFieldType
|
||||||
|
self._fields = OrderedDict([ (name, ftype()) for (name,ftype) in (EmComponent._fields + self.__class__._fields) ] )
|
||||||
|
|
||||||
# populate
|
# populate
|
||||||
if isinstance(id_or_name, int):
|
if isinstance(id_or_name, int):
|
||||||
|
|
@ -52,6 +71,7 @@ class EmComponent(object):
|
||||||
self.name = id_or_name
|
self.name = id_or_name
|
||||||
else:
|
else:
|
||||||
raise TypeError('Bad argument: expecting <int> or <str> but got : '+str(type(id_or_name)))
|
raise TypeError('Bad argument: expecting <int> or <str> but got : '+str(type(id_or_name)))
|
||||||
|
self.table = self.__class__.table
|
||||||
self.populate()
|
self.populate()
|
||||||
|
|
||||||
## Access values of data fields from the object properties
|
## Access values of data fields from the object properties
|
||||||
|
|
@ -60,8 +80,17 @@ class EmComponent(object):
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
if name != '_fields' and name in self._fields:
|
if name != '_fields' and name in self._fields:
|
||||||
return self._fields[name].value
|
return self._fields[name].value
|
||||||
|
else:
|
||||||
|
return super(EmComponent, self).__getattribute__(name)
|
||||||
|
|
||||||
raise AttributeError('Error unknown attribute : '+name)
|
#raise AttributeError('Error unknown attribute : '+name)
|
||||||
|
|
||||||
|
def __getattribute__(self, name):
|
||||||
|
if super(EmComponent, self).__getattribute__('deleted'):
|
||||||
|
#raise EmComponentNotExistError("This component has been deleted")
|
||||||
|
raise EmComponentNotExistError("This "+super(EmComponent, self).__getattribute__('__class__').__name__+" has been deleted")
|
||||||
|
res = super(EmComponent, self).__getattribute(name)
|
||||||
|
return res
|
||||||
|
|
||||||
## Set values of data fields from the object properties
|
## Set values of data fields from the object properties
|
||||||
# @param name str: The propertie name
|
# @param name str: The propertie name
|
||||||
|
|
@ -85,6 +114,8 @@ class EmComponent(object):
|
||||||
if keys in record:
|
if keys in record:
|
||||||
self._fields[keys].from_string(record[keys])
|
self._fields[keys].from_string(record[keys])
|
||||||
|
|
||||||
|
super(EmComponent, self).__setattr__('deleted', False)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
## Shortcut that return the sqlAlchemy engine
|
## Shortcut that return the sqlAlchemy engine
|
||||||
def getDbE(c):
|
def getDbE(c):
|
||||||
|
|
@ -108,7 +139,7 @@ class EmComponent(object):
|
||||||
c.close()
|
c.close()
|
||||||
|
|
||||||
if not res or len(res) == 0:
|
if not res or len(res) == 0:
|
||||||
raise EmComponentNotExistError("No component found with "+('name ' + self.name if self.uid == None else 'uid ' + str(self.uid) ))
|
raise EmComponentNotExistError("No "+self.__class__.__name__+" found with "+('name ' + self.name if self.uid == None else 'uid ' + str(self.uid) ))
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
@ -198,6 +229,8 @@ class EmComponent(object):
|
||||||
c.close
|
c.close
|
||||||
if not res:
|
if not res:
|
||||||
raise RuntimeError("Unable to delete the component in the database")
|
raise RuntimeError("Unable to delete the component in the database")
|
||||||
|
|
||||||
|
super(EmComponent, self).__setattr__('deleted', True)
|
||||||
#</SQL>
|
#</SQL>
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,17 +19,13 @@ class EmFieldGroup(EmComponent):
|
||||||
table = 'em_fieldgroup'
|
table = 'em_fieldgroup'
|
||||||
## List of fields
|
## List of fields
|
||||||
# @todo Bad storage, here we want an ordereddict not a tuple list
|
# @todo Bad storage, here we want an ordereddict not a tuple list
|
||||||
_fields = [('class_id', ftypes.EmField_integer())]
|
_fields = [('class_id', ftypes.EmField_integer)]
|
||||||
|
|
||||||
## Instanciate an EmFieldGroup with data fetched from db
|
## Instanciate an EmFieldGroup with data fetched from db
|
||||||
# @param id_or_name str|int: Identify the EmFieldGroup by name or by global_id
|
# @param id_or_name str|int: Identify the EmFieldGroup by name or by global_id
|
||||||
# @throw TypeError
|
# @throw TypeError
|
||||||
# @see EditorialModel::components::EmComponent::__init__()
|
# @see EditorialModel::components::EmComponent::__init__()
|
||||||
# @throw EditorialModel::components::EmComponentNotExistError
|
# @throw EditorialModel::components::EmComponentNotExistError
|
||||||
def __init__(self, id_or_name):
|
|
||||||
self.table = EmFieldGroup.table
|
|
||||||
self._fields = self.__class__._fields
|
|
||||||
super(EmFieldGroup, self).__init__(id_or_name)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
## Create a new EmFieldGroup
|
## Create a new EmFieldGroup
|
||||||
|
|
|
||||||
|
|
@ -115,10 +115,7 @@ def tearDownModule():
|
||||||
class EmTestComp(EmComponent):
|
class EmTestComp(EmComponent):
|
||||||
table = 'ttest'
|
table = 'ttest'
|
||||||
ranked_in = 'rank_fam'
|
ranked_in = 'rank_fam'
|
||||||
def __init__(self, ion):
|
_fields = [('rank_fam', ftypes.EmField_char)]
|
||||||
self._fields = [('rank_fam', ftypes.EmField_char())]
|
|
||||||
super(EmTestComp, self).__init__(ion)
|
|
||||||
pass
|
|
||||||
|
|
||||||
# The parent class of all other test cases for component
|
# The parent class of all other test cases for component
|
||||||
# It defines a SetUp function and some utility functions for EmComponent tests
|
# It defines a SetUp function and some utility functions for EmComponent tests
|
||||||
|
|
@ -431,6 +428,9 @@ class TestCreate(ComponentTestCase):
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
#====================#
|
||||||
|
# EmComponent.delete #
|
||||||
|
#====================#
|
||||||
class TestDelete(ComponentTestCase):
|
class TestDelete(ComponentTestCase):
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
|
|
@ -466,7 +466,7 @@ class TestDelete(ComponentTestCase):
|
||||||
|
|
||||||
for j in range(i+1,len(vals)):
|
for j in range(i+1,len(vals)):
|
||||||
try:
|
try:
|
||||||
tc = EmTestComp(tcv['name'])
|
tc = EmTestComp(vals[j]['name'])
|
||||||
except EmComponentNotExistError:
|
except EmComponentNotExistError:
|
||||||
self.fail('EmComponent should not be deleted')
|
self.fail('EmComponent should not be deleted')
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue