Browse Source

Code factorization on EmType select and unselect fields. Added comparison capabilities to EmComponent (and childs)

Implemented __hash__ and __eq__ for EmComponent (based on class name and uid) to test equality betwenn two instance. Allows to use "instance in instance_list" syntax
Yann Weber 9 years ago
parent
commit
6af0b45f3f

+ 3
- 2
Database/sqlutils.py View File

81
 
81
 
82
 ## Return an sqlalchemy table given an EmComponent child class
82
 ## Return an sqlalchemy table given an EmComponent child class
83
 # @warning Except a class type not an instance
83
 # @warning Except a class type not an instance
84
-# @param em_class : An EmComponent child class
84
+# @param cls : An EmComponent child class
85
 # @return An sqlalchemy table
85
 # @return An sqlalchemy table
86
 # @throw TypeError if em_instance is an EmComponent  or not an EmComponent child class (or an instance)
86
 # @throw TypeError if em_instance is an EmComponent  or not an EmComponent child class (or an instance)
87
-def getTable(cls):
87
+def get_table(cls):
88
     from EditorialModel.components import EmComponent #dirty circula inclusion hack
88
     from EditorialModel.components import EmComponent #dirty circula inclusion hack
89
     if not issubclass(cls, EmComponent) or cls.table == None:
89
     if not issubclass(cls, EmComponent) or cls.table == None:
90
         raise TypeError("Excepting an EmComponent child class not an "+str(cls))
90
         raise TypeError("Excepting an EmComponent child class not an "+str(cls))
91
     engine = cls.db_engine()
91
     engine = cls.db_engine()
92
     return sqla.Table(cls.table, meta(engine))
92
     return sqla.Table(cls.table, meta(engine))
93
+def getTable(cls): return get_table(cls)
93
 
94
 
94
 ## This function is intended to execute ddl defined in sqlalter
95
 ## This function is intended to execute ddl defined in sqlalter
95
 # @warning There is a dirty workaround here, DDL should returns only one query, but DropColumn for sqlite has to return 4 queries (rename, create, insert, drop). There is a split on the compiled SQL to extract and execute one query at a time
96
 # @warning There is a dirty workaround here, DDL should returns only one query, but DropColumn for sqlite has to return 4 queries (rename, create, insert, drop). There is a split on the compiled SQL to extract and execute one query at a time

+ 10
- 0
EditorialModel/components.py View File

106
             self._fields[name].from_python(value)
106
             self._fields[name].from_python(value)
107
         else:
107
         else:
108
             object.__setattr__(self, name, value)
108
             object.__setattr__(self, name, value)
109
+    
110
+    ## @brief Hash function that allows to compare two EmComponent
111
+    # @return EmComponent+ClassName+uid
112
+    def __hash__(self):
113
+        return "EmComponent"+self.__class__.__name__+str(self.uid)
114
+
115
+    ## @brief Test if two EmComponent are "equals"
116
+    # @return True or False
117
+    def __eq__(self, other):
118
+        return self.__class__ == other.__class__ and self.uid == other.uid
109
 
119
 
110
     ## Lookup in the database properties of the object to populate the properties
120
     ## Lookup in the database properties of the object to populate the properties
111
     # @throw EmComponentNotExistError if the instance is not anymore stored in database
121
     # @throw EmComponentNotExistError if the instance is not anymore stored in database

+ 0
- 105
EditorialModel/fields_types.py View File

1
-#-*- coding: utf-8 -*-
2
-
3
-from EditorialModel.fieldtypes import EmField_integer
4
-from EditorialModel.components import EmComponent
5
-
6
-from Database import sqlutils
7
-import sqlalchemy as sqla
8
-
9
-import logging
10
-
11
-logger = logging.getLogger('Lodel2.EditorialModel')
12
-
13
-
14
-## Em_Field_Type (Class)
15
-#
16
-# Represents an association between a field and a type
17
-class Em_Field_Type(object):
18
-
19
-    table = 'em_field_type'
20
-    _fields = [('type_id', EmField_integer), ('field_id', EmField_integer)]
21
-
22
-    ## __init__ (Function)
23
-    #
24
-    # Instanciates an Em_Field_Type object with data fetched from the database
25
-    #
26
-    # @param type_id integer: Identifier of the type
27
-    # @param field_id integer: Identifier of the field
28
-    def __init__(self, type_id, field_id):
29
-        self.table = Em_Field_Type.table
30
-        self._fields = self.__class__._fields
31
-        self.type_id = type_id
32
-        self.field_id = field_id
33
-
34
-    ## Create (Function)
35
-    #
36
-    # Creates a relation between a field and a type
37
-    #
38
-    # @static
39
-    #
40
-    # @param emType EmType: Object representing the Type
41
-    # @param emField EmField: Object representing the Field
42
-    # @return Em_Field_Type object
43
-    @classmethod
44
-    def create(cls, em_type, em_field):
45
-        values = {
46
-            'type_id': em_type.uid,
47
-            'field_id': em_field.uid
48
-        }
49
-
50
-        created_relation = Em_Field_Type._create_db(**values)
51
-        return created_relation
52
-
53
-    @classmethod
54
-    def _create_db(cls, **kwargs):
55
-        dbe = EmComponent.db_engine()
56
-        conn = dbe.connect()
57
-        table = sqla.Table(cls.table, sqlutils.meta(dbe))
58
-        req = table.insert(kwargs)
59
-        res = conn.execute(req)
60
-        conn.close()
61
-        return Em_Field_Type(kwargs['type_id'], kwargs['field_id'])
62
-
63
-    ## Delete (Function)
64
-    #
65
-    # Deletes a relation between a field and a type
66
-    #
67
-    # @return Boolean
68
-    def delete(self):
69
-        return self._delete_db()
70
-
71
-    def _delete_db(self):
72
-        dbe = EmComponent.db_engine()
73
-        table = sqla.Table(self.table, sqlutils.meta(dbe))
74
-        req = table.delete().where(table.c.type_id == self.type_id).where(table.c.field_id == self.field_id)
75
-        conn = dbe.connect()
76
-        try:
77
-            conn.execute(req)
78
-            res = True
79
-        except:
80
-            res = False
81
-        conn.close()
82
-
83
-        return res
84
-
85
-    ## Exists (Function)
86
-    #
87
-    # Checks if a the relation exists in the database
88
-    #
89
-    # @return True if success, False if failure
90
-    def exists(self):
91
-        return self._exists_db()
92
-
93
-    ## _ExistsDb (Function)
94
-    #
95
-    # Queries the database to see if a relation exists or not
96
-    #
97
-    # @return True if success, False if failure
98
-    def _exists_db(self):
99
-        dbe = EmComponent.db_engine()
100
-        table = sqla.Table(self.table, sqlutils.meta(dbe))
101
-        req = table.select().where(table.c.type_id == self.type_id).where(table.c.field_id == self.field_id)
102
-        conn = dbe.connect()
103
-        res = conn.execute(req).fetchall()
104
-        conn.close()
105
-        return len(res) > 0

+ 0
- 1
EditorialModel/test/test_field.py View File

12
 from EditorialModel.classtypes import EmClassType
12
 from EditorialModel.classtypes import EmClassType
13
 from EditorialModel.types import EmType
13
 from EditorialModel.types import EmType
14
 from EditorialModel.fieldgroups import EmFieldGroup
14
 from EditorialModel.fieldgroups import EmFieldGroup
15
-from EditorialModel.fields_types import Em_Field_Type
16
 from EditorialModel.test.utils import *
15
 from EditorialModel.test.utils import *
17
 from EditorialModel.fieldtypes import *
16
 from EditorialModel.fieldtypes import *
18
 
17
 

+ 23
- 5
EditorialModel/test/test_types.py View File

12
 from EditorialModel.components import EmComponent, EmComponentNotExistError
12
 from EditorialModel.components import EmComponent, EmComponentNotExistError
13
 from EditorialModel.fieldgroups import EmFieldGroup
13
 from EditorialModel.fieldgroups import EmFieldGroup
14
 from EditorialModel.fieldtypes import *
14
 from EditorialModel.fieldtypes import *
15
-from EditorialModel.fields_types import Em_Field_Type
16
 from EditorialModel.fields import EmField
15
 from EditorialModel.fields import EmField
17
 from EditorialModel.test.utils import *
16
 from EditorialModel.test.utils import *
18
 from Database import sqlutils
17
 from Database import sqlutils
44
     EmType.create(name='type7', em_class=emclass4)
43
     EmType.create(name='type7', em_class=emclass4)
45
 
44
 
46
     emfieldgroup = EmFieldGroup.create(name='fieldgroup1', em_class=emclass1)
45
     emfieldgroup = EmFieldGroup.create(name='fieldgroup1', em_class=emclass1)
46
+    emfieldgroup2 = EmFieldGroup.create(name='fieldgroup2', em_class=emclass2)
47
     emfieldtype = get_field_type('integer')
47
     emfieldtype = get_field_type('integer')
48
     EmField.create(name='field1', fieldgroup=emfieldgroup, fieldtype=emfieldtype, rel_to_type_id=emtype.uid)
48
     EmField.create(name='field1', fieldgroup=emfieldgroup, fieldtype=emfieldtype, rel_to_type_id=emtype.uid)
49
+    EmField.create(name='field2', fieldgroup=emfieldgroup2, fieldtype=emfieldtype, optional=True)
50
+    EmField.create(name='field3', fieldgroup=emfieldgroup2, fieldtype=emfieldtype, optional=False)
49
 
51
 
50
     saveDbState(TEST_TYPE_DBNAME)
52
     saveDbState(TEST_TYPE_DBNAME)
51
 
53
 
69
         self.emfieldgroup = EmFieldGroup('fieldgroup1')
71
         self.emfieldgroup = EmFieldGroup('fieldgroup1')
70
         self.emfieldtype = get_field_type('integer')
72
         self.emfieldtype = get_field_type('integer')
71
         self.emfield = EmField('field1')
73
         self.emfield = EmField('field1')
74
+        self.emfield2 = EmField('field2')
75
+        self.emfield3 = EmField('field3')
76
+        pass
77
+
72
 
78
 
73
 
79
 
74
 class TestSelectField(TypeTestCase):
80
 class TestSelectField(TypeTestCase):
75
     def testSelectField(self):
81
     def testSelectField(self):
76
         """ Testing optionnal field selection """
82
         """ Testing optionnal field selection """
77
-        self.emtype.select_field(self.emfield)
78
-        self.assertIsNotNone(Em_Field_Type(self.emtype.uid, self.emfield.uid))
83
+        self.emtype.select_field(self.emfield2)
84
+        #a bit queick and dirty
85
+        self.assertIn(self.emfield2, self.emtype.selected_fields()) 
86
+        pass
79
 
87
 
80
     def testUnselectField(self):
88
     def testUnselectField(self):
81
         """ Testing optionnal field unselection """
89
         """ Testing optionnal field unselection """
82
-        self.emtype.unselect_field(self.emfield)
83
-        self.assertFalse(Em_Field_Type(self.emtype.uid, self.emfield.uid).exists())
90
+        self.emtype.select_field(self.emfield2)
91
+        self.emtype.unselect_field(self.emfield2)
92
+        self.assertNotIn(self.emfield2, self.emtype.selected_fields())
93
+        pass
94
+
95
+    def testSelectFieldInvalid(self):
96
+        """ Testing optionnal field selection with invalid fields """
97
+        with self.assertRaises(ValueError, msg="But the field was not optionnal"):
98
+            self.emtype.select_field(self.emfield3)
99
+        with self.assertRaises(ValueError, msg="But the field was not part of this type"):
100
+            self.emtype.select_field(self.emfield)
101
+        pass
84
 
102
 
85
 class TestLinkedTypes(TypeTestCase):
103
 class TestLinkedTypes(TypeTestCase):
86
     @unittest.skip("Not yet implemented")
104
     @unittest.skip("Not yet implemented")

+ 60
- 15
EditorialModel/types.py View File

1
 #-*- coding: utf-8 -*-
1
 #-*- coding: utf-8 -*-
2
 
2
 
3
-from EditorialModel.fields_types import Em_Field_Type
4
 from Database import sqlutils
3
 from Database import sqlutils
5
 import sqlalchemy as sql
4
 import sqlalchemy as sql
6
 
5
 
6
+import EditorialModel
7
 from EditorialModel.components import EmComponent, EmComponentNotExistError
7
 from EditorialModel.components import EmComponent, EmComponentNotExistError
8
 from EditorialModel.fieldgroups import EmFieldGroup
8
 from EditorialModel.fieldgroups import EmFieldGroup
9
 from EditorialModel.classtypes import EmNature, EmClassType
9
 from EditorialModel.classtypes import EmNature, EmClassType
68
 
68
 
69
         return [ EmFieldGroup(row['uid']) for row in rows ]
69
         return [ EmFieldGroup(row['uid']) for row in rows ]
70
 
70
 
71
-    ## Get the list of associated fields
71
+    ## Get the list of all Emfield possibly associated with this type
72
     # @return A list of EmField instance
72
     # @return A list of EmField instance
73
-    # @todo handle optionnal fields
74
-    def fields(self):
73
+    def all_fields(self):
75
         res = []
74
         res = []
76
-        for fguid in self.field_groups():
77
-            res += EmFieldGroup(fguid).fields()
75
+        for fieldgroup in self.field_groups():
76
+            res += fieldgroup.fields()
78
         return res
77
         return res
79
-        pass
78
+
79
+    ## Return selected optional field
80
+    # @return A list of EmField instance
81
+    def selected_fields(self):
82
+        dbe = self.db_engine()
83
+        meta = sqlutils.meta(dbe)
84
+        conn = dbe.connect()
85
+
86
+        table = sql.Table('em_field_type', meta)
87
+        res = conn.execute(table.select().where(table.c.type_id == self.uid))
88
+
89
+        return [ EditorialModel.fields.EmField(row['field_id']) for row in res.fetchall()]
90
+    
91
+    ## Return the list of associated fields
92
+    # @return A list of EmField instance
93
+    def fields(self):
94
+        result = list()
95
+        for field in self.all_fields():
96
+            if not field.optional:
97
+                result.append(field)
98
+        return result+selected_fields
80
 
99
 
81
     ## Select_field (Function)
100
     ## Select_field (Function)
82
     #
101
     #
83
     # Indicates that an optional field is used
102
     # Indicates that an optional field is used
84
     #
103
     #
85
     # @param field EmField: The optional field to select
104
     # @param field EmField: The optional field to select
86
-    # @throw ValueError, TypeError
105
+    # @return True if success False if failed
106
+    # @throw TypeError
87
     # @todo change exception type and define return value and raise condition
107
     # @todo change exception type and define return value and raise condition
88
     def select_field(self, field):
108
     def select_field(self, field):
89
-        Em_Field_Type.create(self, field)
90
-
109
+        return self._opt_field_act(field, True)
110
+        
91
     ## Unselect_field (Function)
111
     ## Unselect_field (Function)
92
     #
112
     #
93
     # Indicates that an optional field will not be used
113
     # Indicates that an optional field will not be used
94
     #
114
     #
95
     # @param field EmField: The optional field to unselect
115
     # @param field EmField: The optional field to unselect
96
-    # @throw ValueError, TypeError
97
-    # @todo change exception type and define return value and raise condition
116
+    # @return True if success False if fails
117
+    # @throw TypeError
98
     def unselect_field(self, field):
118
     def unselect_field(self, field):
99
-        emFieldType = Em_Field_Type(self.uid, field.uid)
100
-        emFieldType.delete()
101
-        del emFieldType
119
+        return self._opt_field_act(field, False)
120
+
121
+    
122
+    ## @brief Select or unselect an optional field
123
+    # @param field EmField: The EmField to select or unselect
124
+    # @param select bool: If True select field, else unselect it
125
+    # @return True if success False if fails
126
+    # @throw TypeError if field is not an EmField instance
127
+    # @throw ValueError if field is not optional or is not associated with this type
128
+    def _opt_field_act(self, field, select=True):
129
+        if not field in self.all_fields():
130
+            raise ValueError("This field is not part of this type")
131
+        if not field.optional:
132
+            raise ValueError("This field is not optional")
133
+
134
+        dbe = self.db_engine()
135
+        meta = sqlutils.meta(dbe)
136
+        conn = dbe.connect()
137
+
138
+        table = sql.Table('em_field_type', meta)
139
+        if select:
140
+            req = table.insert({'type_id': self.uid, 'field_id': field.uid})
141
+        else:
142
+            req = table.delete().where(table.c.type_id == self.uid and table.c.field_id == field.uid)
143
+
144
+        res = conn.execute(req)
145
+        conn.close()
146
+        return bool(res)
102
 
147
 
103
     ## Get the list of associated hooks
148
     ## Get the list of associated hooks
104
     # @note Not conceptualized yet
149
     # @note Not conceptualized yet

Loading…
Cancel
Save