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,15 +81,16 @@ def meta(engine):
81 81
 
82 82
 ## Return an sqlalchemy table given an EmComponent child class
83 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 85
 # @return An sqlalchemy table
86 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 88
     from EditorialModel.components import EmComponent #dirty circula inclusion hack
89 89
     if not issubclass(cls, EmComponent) or cls.table == None:
90 90
         raise TypeError("Excepting an EmComponent child class not an "+str(cls))
91 91
     engine = cls.db_engine()
92 92
     return sqla.Table(cls.table, meta(engine))
93
+def getTable(cls): return get_table(cls)
93 94
 
94 95
 ## This function is intended to execute ddl defined in sqlalter
95 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,6 +106,16 @@ class EmComponent(object):
106 106
             self._fields[name].from_python(value)
107 107
         else:
108 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 120
     ## Lookup in the database properties of the object to populate the properties
111 121
     # @throw EmComponentNotExistError if the instance is not anymore stored in database

+ 0
- 105
EditorialModel/fields_types.py View File

@@ -1,105 +0,0 @@
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,7 +12,6 @@ from EditorialModel.classes import EmClass
12 12
 from EditorialModel.classtypes import EmClassType
13 13
 from EditorialModel.types import EmType
14 14
 from EditorialModel.fieldgroups import EmFieldGroup
15
-from EditorialModel.fields_types import Em_Field_Type
16 15
 from EditorialModel.test.utils import *
17 16
 from EditorialModel.fieldtypes import *
18 17
 

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

@@ -12,7 +12,6 @@ from EditorialModel.classtypes import EmClassType, EmNature
12 12
 from EditorialModel.components import EmComponent, EmComponentNotExistError
13 13
 from EditorialModel.fieldgroups import EmFieldGroup
14 14
 from EditorialModel.fieldtypes import *
15
-from EditorialModel.fields_types import Em_Field_Type
16 15
 from EditorialModel.fields import EmField
17 16
 from EditorialModel.test.utils import *
18 17
 from Database import sqlutils
@@ -44,8 +43,11 @@ def setUpModule():
44 43
     EmType.create(name='type7', em_class=emclass4)
45 44
 
46 45
     emfieldgroup = EmFieldGroup.create(name='fieldgroup1', em_class=emclass1)
46
+    emfieldgroup2 = EmFieldGroup.create(name='fieldgroup2', em_class=emclass2)
47 47
     emfieldtype = get_field_type('integer')
48 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 52
     saveDbState(TEST_TYPE_DBNAME)
51 53
 
@@ -69,18 +71,34 @@ class TypeTestCase(TestCase):
69 71
         self.emfieldgroup = EmFieldGroup('fieldgroup1')
70 72
         self.emfieldtype = get_field_type('integer')
71 73
         self.emfield = EmField('field1')
74
+        self.emfield2 = EmField('field2')
75
+        self.emfield3 = EmField('field3')
76
+        pass
77
+
72 78
 
73 79
 
74 80
 class TestSelectField(TypeTestCase):
75 81
     def testSelectField(self):
76 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 88
     def testUnselectField(self):
81 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 103
 class TestLinkedTypes(TypeTestCase):
86 104
     @unittest.skip("Not yet implemented")

+ 60
- 15
EditorialModel/types.py View File

@@ -1,9 +1,9 @@
1 1
 #-*- coding: utf-8 -*-
2 2
 
3
-from EditorialModel.fields_types import Em_Field_Type
4 3
 from Database import sqlutils
5 4
 import sqlalchemy as sql
6 5
 
6
+import EditorialModel
7 7
 from EditorialModel.components import EmComponent, EmComponentNotExistError
8 8
 from EditorialModel.fieldgroups import EmFieldGroup
9 9
 from EditorialModel.classtypes import EmNature, EmClassType
@@ -68,37 +68,82 @@ class EmType(EmComponent):
68 68
 
69 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 72
     # @return A list of EmField instance
73
-    # @todo handle optionnal fields
74
-    def fields(self):
73
+    def all_fields(self):
75 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 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 100
     ## Select_field (Function)
82 101
     #
83 102
     # Indicates that an optional field is used
84 103
     #
85 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 107
     # @todo change exception type and define return value and raise condition
88 108
     def select_field(self, field):
89
-        Em_Field_Type.create(self, field)
90
-
109
+        return self._opt_field_act(field, True)
110
+        
91 111
     ## Unselect_field (Function)
92 112
     #
93 113
     # Indicates that an optional field will not be used
94 114
     #
95 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 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 148
     ## Get the list of associated hooks
104 149
     # @note Not conceptualized yet

Loading…
Cancel
Save