1
0
Fork 0
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:
Yann 2015-06-19 12:26:46 +02:00
commit 00614d90e9
5 changed files with 80 additions and 47 deletions

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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