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.
|
||||
# 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
|
||||
# scope will be included in the documentation.
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
""" Manipulate Classes of the Editorial Model
|
||||
Create classes of object
|
||||
@see EmClass, EmType, EmFieldGroup, EmField
|
||||
"""
|
||||
## @file classes.py
|
||||
# @see EditorialModel::classes::EmClass
|
||||
|
||||
import logging as logger
|
||||
|
||||
|
|
@ -14,18 +12,24 @@ import sqlalchemy as sql
|
|||
import EditorialModel.fieldtypes as ftypes
|
||||
import EditorialModel
|
||||
|
||||
## @brief Manipulate Classes of the Editorial Model
|
||||
# Create classes of object.
|
||||
#@see EmClass, EmType, EmFieldGroup, EmField
|
||||
class EmClass(EmComponent):
|
||||
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):
|
||||
self.table = EmClass.table
|
||||
self._fields = [('classtype', ftypes.EmField_char()), ('icon', ftypes.EmField_integer()), ('sortcolumn', ftypes.EmField_char())]
|
||||
super(EmClass, self).__init__(id_or_name)
|
||||
|
||||
""" create a new class
|
||||
@param name str: name of the new class
|
||||
@param class_type EmClasstype: type of the class
|
||||
"""
|
||||
## Create a new class
|
||||
# @param name str: name of the new class
|
||||
# @param class_type EmClasstype: type of the class
|
||||
# @return An EmClass instance
|
||||
@classmethod
|
||||
def create(c, name, class_type):
|
||||
try:
|
||||
|
|
@ -38,8 +42,9 @@ class EmClass(EmComponent):
|
|||
return res
|
||||
|
||||
@classmethod
|
||||
## Isolate SQL for create
|
||||
## Isolate SQL for EmClass::create
|
||||
# @todo Remove hardcoded default value for icon
|
||||
# @return An instance of EmClass
|
||||
def _createDb(c, name, class_type):
|
||||
""" Do the db querys for EmClass::create() """
|
||||
|
||||
|
|
@ -62,15 +67,16 @@ class EmClass(EmComponent):
|
|||
return resclass
|
||||
|
||||
|
||||
""" retrieve list of the field_groups of this class
|
||||
@return field_groups [EmFieldGroup]:
|
||||
"""
|
||||
## Retrieve list of the field_groups of this class
|
||||
# @return field_groups [EmFieldGroup]:
|
||||
def fieldgroups(self):
|
||||
records = self._fieldgroupsDb()
|
||||
fieldgroups = [ EditorialModel.fieldgroups.EmFieldGroup(int(record.uid)) for record in records ]
|
||||
|
||||
return fieldgroups
|
||||
|
||||
## Isolate SQL for EmClass::fieldgroups
|
||||
# @return An array of dict (sqlalchemy fetchall)
|
||||
def _fieldgroupsDb(self):
|
||||
dbe = self.__class__.getDbE()
|
||||
emfg = sql.Table(EditorialModel.fieldgroups.EmFieldGroup.table, sqlutils.meta(dbe))
|
||||
|
|
@ -81,21 +87,21 @@ class EmClass(EmComponent):
|
|||
return res.fetchall()
|
||||
|
||||
|
||||
""" retrieve list of fields
|
||||
@return fields [EmField]:
|
||||
"""
|
||||
## Retrieve list of fields
|
||||
# @return fields [EmField]:
|
||||
def fields(self):
|
||||
pass
|
||||
|
||||
""" retrieve list of type of this class
|
||||
@return types [EmType]:
|
||||
"""
|
||||
## Retrieve list of type of this class
|
||||
# @return types [EmType]:
|
||||
def types(self):
|
||||
records = self._typesDb()
|
||||
types = [ EditorialModel.types.EmType(int(record.uid)) for record in records ]
|
||||
|
||||
return types
|
||||
|
||||
## Isolate SQL for EmCLass::types
|
||||
# @return An array of dict (sqlalchemy fetchall)
|
||||
def _typesDb(self):
|
||||
dbe = self.__class__.getDbE()
|
||||
emtype = sql.Table(EditorialModel.types.EmType.table, sqlutils.meta(dbe))
|
||||
|
|
@ -104,15 +110,13 @@ class EmClass(EmComponent):
|
|||
res = conn.execute(req)
|
||||
return res.fetchall()
|
||||
|
||||
""" add a new EmType that can ben linked to this class
|
||||
@param t EmType: type to link
|
||||
@return success bool: done or not
|
||||
"""
|
||||
## Add a new EmType that can ben linked to this class
|
||||
# @param t EmType: type to link
|
||||
# @return success bool: done or not
|
||||
def link_type(self, t):
|
||||
pass
|
||||
|
||||
""" retrieve list of EmType that are linked to this class
|
||||
@return types [EmType]:
|
||||
"""
|
||||
## Retrieve list of EmType that are linked to this class
|
||||
# @return types [EmType]:
|
||||
def linked_types(self):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -30,8 +30,24 @@ class EmComponent(object):
|
|||
## Used by EmComponent::modify_rank
|
||||
ranked_in = None
|
||||
|
||||
##Read only properties
|
||||
_ro_properties = [ 'date_update', 'date_create', 'uid', 'rank']
|
||||
## Read only properties
|
||||
_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
|
||||
# @param id_or_name int|str: name or id of the object
|
||||
|
|
@ -42,8 +58,11 @@ class EmComponent(object):
|
|||
if type(self) is EmComponent:
|
||||
raise NotImplementedError('Abstract class')
|
||||
|
||||
# data fields of the object
|
||||
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)
|
||||
## @brief An OrderedDict storing fields name and values
|
||||
# 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
|
||||
if isinstance(id_or_name, int):
|
||||
|
|
@ -52,6 +71,7 @@ class EmComponent(object):
|
|||
self.name = id_or_name
|
||||
else:
|
||||
raise TypeError('Bad argument: expecting <int> or <str> but got : '+str(type(id_or_name)))
|
||||
self.table = self.__class__.table
|
||||
self.populate()
|
||||
|
||||
## Access values of data fields from the object properties
|
||||
|
|
@ -60,8 +80,17 @@ class EmComponent(object):
|
|||
def __getattr__(self, name):
|
||||
if name != '_fields' and name in self._fields:
|
||||
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
|
||||
# @param name str: The propertie name
|
||||
|
|
@ -85,6 +114,8 @@ class EmComponent(object):
|
|||
if keys in record:
|
||||
self._fields[keys].from_string(record[keys])
|
||||
|
||||
super(EmComponent, self).__setattr__('deleted', False)
|
||||
|
||||
@classmethod
|
||||
## Shortcut that return the sqlAlchemy engine
|
||||
def getDbE(c):
|
||||
|
|
@ -108,7 +139,7 @@ class EmComponent(object):
|
|||
c.close()
|
||||
|
||||
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
|
||||
|
||||
|
|
@ -198,6 +229,8 @@ class EmComponent(object):
|
|||
c.close
|
||||
if not res:
|
||||
raise RuntimeError("Unable to delete the component in the database")
|
||||
|
||||
super(EmComponent, self).__setattr__('deleted', True)
|
||||
#</SQL>
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -19,17 +19,13 @@ class EmFieldGroup(EmComponent):
|
|||
table = 'em_fieldgroup'
|
||||
## List of fields
|
||||
# @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
|
||||
# @param id_or_name str|int: Identify the EmFieldGroup by name or by global_id
|
||||
# @throw TypeError
|
||||
# @see EditorialModel::components::EmComponent::__init__()
|
||||
# @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
|
||||
## Create a new EmFieldGroup
|
||||
|
|
|
|||
|
|
@ -115,10 +115,7 @@ def tearDownModule():
|
|||
class EmTestComp(EmComponent):
|
||||
table = 'ttest'
|
||||
ranked_in = 'rank_fam'
|
||||
def __init__(self, ion):
|
||||
self._fields = [('rank_fam', ftypes.EmField_char())]
|
||||
super(EmTestComp, self).__init__(ion)
|
||||
pass
|
||||
_fields = [('rank_fam', ftypes.EmField_char)]
|
||||
|
||||
# The parent class of all other test cases for component
|
||||
# It defines a SetUp function and some utility functions for EmComponent tests
|
||||
|
|
@ -431,6 +428,9 @@ class TestCreate(ComponentTestCase):
|
|||
|
||||
pass
|
||||
|
||||
#====================#
|
||||
# EmComponent.delete #
|
||||
#====================#
|
||||
class TestDelete(ComponentTestCase):
|
||||
|
||||
def test_delete(self):
|
||||
|
|
@ -466,7 +466,7 @@ class TestDelete(ComponentTestCase):
|
|||
|
||||
for j in range(i+1,len(vals)):
|
||||
try:
|
||||
tc = EmTestComp(tcv['name'])
|
||||
tc = EmTestComp(vals[j]['name'])
|
||||
except EmComponentNotExistError:
|
||||
self.fail('EmComponent should not be deleted')
|
||||
pass
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue