Merge lp:~vds/desktopcouch/refactor_class_factory into lp:desktopcouch

Proposed by Vincenzo Di Somma
Status: Merged
Approved by: Vincenzo Di Somma
Approved revision: 191
Merged at revision: 186
Proposed branch: lp:~vds/desktopcouch/refactor_class_factory
Merge into: lp:desktopcouch
Diff against target: 431 lines (+141/-170)
7 files modified
desktopcouch/contacts/record.py (+32/-42)
desktopcouch/contacts/tests/test_record.py (+23/-18)
desktopcouch/notes/record.py (+18/-47)
desktopcouch/notes/tests/test_record.py (+27/-22)
desktopcouch/records/record.py (+22/-0)
desktopcouch/tasks/record.py (+11/-30)
desktopcouch/tasks/tests/test_record.py (+8/-11)
To merge this branch: bzr merge lp:~vds/desktopcouch/refactor_class_factory
Reviewer Review Type Date Requested Status
Manuel de la Peña (community) Approve
Eric Casteleijn (community) Approve
Review via email: mp+39761@code.launchpad.net

Commit message

The class factories are not making the code look nice, are just making more confusion, plus all the tests weren't actually testing nothing.

Description of the change

The class factories are not making the code look nice, are just making more confusion, plus all the tests weren't actually testing nothing.

To post a comment you must log in.
Revision history for this message
Eric Casteleijn (thisfred) wrote :

Big improvement, tests pass, yay!

review: Approve
Revision history for this message
Manuel de la Peña (mandel) wrote :

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'desktopcouch/contacts/record.py'
2--- desktopcouch/contacts/record.py 2010-05-27 18:45:07 +0000
3+++ desktopcouch/contacts/record.py 2010-11-01 17:09:45 +0000
4@@ -17,51 +17,41 @@
5 # Authors: Eric Casteleijn <eric.casteleijn@canonical.com>
6 # Nicola Larosa <nicola.larosa@canonical.com>
7 # Mark G. Saye <mark.saye@canonical.com>
8+# Vincenzo Di Somma <vincenzo.di.somma@canonical.com>
9
10 """A dictionary based contact record representation."""
11
12-from desktopcouch.records.record import Record
13-
14-CONTACT_RECORD_TYPE = (
15- 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/contact')
16-# keep in sync with the above contacts record type
17-SINGLE_FIELDS = frozenset((
18- 'first_name', 'middle_name', 'last_name', 'title', 'suffix', 'birth_date',
19- 'nick_name', 'spouse_name', 'wedding_date', 'company', 'department',
20- 'job_title', 'manager_name', 'assistant_name', 'office',
21-))
22-LIST_FIELDS = frozenset((
23- 'addresses', 'phone_numbers', 'email_addresses', 'urls', 'im_addresses',
24-))
25-ALL_FIELDS = SINGLE_FIELDS | LIST_FIELDS
26-
27-
28-class ContactBase(Record):
29- """
30- A base for Contact records.
31-
32- Use make_contact_class to create the Contact class with the required fields.
33- """
34+from desktopcouch.records.record import Record, RecordField
35+
36+CONTACT_RECORD_TYPE = \
37+ 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/contact'
38+
39+
40+class Contact(Record):
41+ """Contact records."""
42+
43+ first_name = RecordField('first_name')
44+ middle_name = RecordField('middle_name')
45+ last_name = RecordField('last_name')
46+ title = RecordField('title')
47+ suffix = RecordField('suffix')
48+ birth_date = RecordField('birth_date')
49+ nick_name = RecordField('nick_name')
50+ spouse_name = RecordField('spouse_name')
51+ wedding_date = RecordField('wedding_date')
52+ company = RecordField('company')
53+ department = RecordField('department')
54+ job_title = RecordField('job_title')
55+ manager_name = RecordField('manager_name')
56+ assistant_name = RecordField('assistant_name')
57+ office = RecordField('office')
58+ addresses = RecordField('addresses')
59+ phone_numbers = RecordField('phone_numbers')
60+ email_addresses = RecordField('email_addresses')
61+ urls = RecordField('urls')
62+ im_addresses = RecordField('im_addresses')
63
64 def __init__(self, data=None, record_id=None):
65- super(ContactBase, self).__init__(
66+ super(Contact, self).__init__(
67 record_id=record_id, data=data, record_type=CONTACT_RECORD_TYPE)
68-
69-
70-def make_contact_class(field_names):
71- """Contact class factory function. field_names is a strings iterable."""
72- ContactClass = type('Contact', (ContactBase,), {})
73- for field_name in field_names:
74-
75- # without the _field_name param, only the last one gets used
76- def fget(self, _field_name=field_name):
77- return self.get(_field_name)
78-
79- def fset(self, value, _field_name=field_name):
80- self[_field_name] = value
81-
82- setattr(ContactClass, field_name, property(fget, fset))
83- return ContactClass
84-
85-
86-Contact = make_contact_class(ALL_FIELDS)
87+
88
89=== modified file 'desktopcouch/contacts/tests/test_record.py'
90--- desktopcouch/contacts/tests/test_record.py 2010-05-27 18:45:07 +0000
91+++ desktopcouch/contacts/tests/test_record.py 2010-11-01 17:09:45 +0000
92@@ -1,4 +1,4 @@
93-# Copyright 2009 Canonical Ltd.
94+# Copyright 2009-2010 Canonical Ltd.
95 #
96 # This file is part of desktopcouch-contacts.
97 #
98@@ -15,32 +15,37 @@
99 # along with desktopcouch. If not, see <http://www.gnu.org/licenses/>.
100 #
101 # Authors: Nicola Larosa <nicola.larosa@canonical.com>
102+# Vincenzo Di Somma <vincenzo.di.somma@canonical.com>
103
104 """Tests for the ContactDocument class"""
105
106 import testtools
107
108-from desktopcouch.contacts import record as contact_mod
109+from desktopcouch.contacts.record import Contact
110
111+SINGLE_FIELDS = frozenset((
112+ 'first_name', 'middle_name', 'last_name', 'title', 'suffix', 'birth_date',
113+ 'nick_name', 'spouse_name', 'wedding_date', 'company', 'department',
114+ 'job_title', 'manager_name', 'assistant_name', 'office'))
115+LIST_FIELDS = frozenset((
116+ 'addresses', 'phone_numbers', 'email_addresses', 'urls', 'im_addresses'))
117+ALL_FIELDS = SINGLE_FIELDS | LIST_FIELDS
118
119 class TestContactRecord(testtools.TestCase):
120 """Test the Contact Record object."""
121
122 def test_contact_record(self):
123 """Test that we get the correct record type."""
124- contact = contact_mod.Contact()
125- self.assertEqual(contact.record_type, contact_mod.CONTACT_RECORD_TYPE)
126- for field_name in contact_mod.SINGLE_FIELDS:
127- setattr(contact, field_name, field_name)
128- self.assertEqual(getattr(contact, field_name), field_name)
129- # direct access to internal representation
130- self.assertEqual(contact._data[field_name], field_name)
131- for field_name in contact_mod.LIST_FIELDS:
132- setattr(contact, field_name, [field_name])
133- self.assertEqual(getattr(contact, field_name), [field_name])
134- # direct access to internal representation
135- self.assert_(field_name in contact._data[field_name].values())
136- # transversal check
137- all_keys = set(contact_mod.ALL_FIELDS)
138- all_keys.add('record_type')
139- self.assertEqual(set(contact.keys()), all_keys)
140+ contact = Contact()
141+ for field_name in SINGLE_FIELDS:
142+ self.assert_(hasattr(contact, field_name))
143+ # direct access to internal representation
144+ for field_name in LIST_FIELDS:
145+ self.assert_(hasattr(contact, field_name))
146+ # direct access to internal representation
147+ first_name = 'manuel'
148+ contact.first_name = first_name
149+ self.assertEqual(first_name, contact.first_name)
150+ self.assertEqual(set(['record_type', 'first_name']),
151+ set(contact.keys()))
152+
153
154=== modified file 'desktopcouch/notes/record.py'
155--- desktopcouch/notes/record.py 2010-05-28 08:30:50 +0000
156+++ desktopcouch/notes/record.py 2010-11-01 17:09:45 +0000
157@@ -15,53 +15,24 @@
158 # along with desktopcouch. If not, see <http://www.gnu.org/licenses/>.
159 #
160 # Authors: Rodrigo Moya <rodrigo.moya@canonical.com>
161-
162-"""A dictionary based note record representation."""
163-
164-from time import strptime
165-from desktopcouch.records.record import Record
166-
167-NOTE_RECORD_TYPE = 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/note'
168-# keep in sync with the above notes record type
169-FIELDS = {
170- # String fields
171- 'note_format': 'string',
172- 'title': 'string',
173- 'content': 'string',
174- # Date fields
175- 'last_change_date': 'date',
176- 'create_date': 'date'
177-}
178-
179-class NoteBase(Record):
180- """
181- A base for Note records.
182-
183- Use make_note_class to create the Note class with the required fields.
184- """
185+# Vincenzo Di Somma <vincenzo.di.somma@canonical.com>
186+
187+"""Note record representation."""
188+
189+from desktopcouch.records.record import Record, RecordField, DateRecordField
190+
191+NOTE_RECORD_TYPE = \
192+ 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/note'
193+
194+class Note(Record):
195+ """Note record """
196+
197+ note_format = RecordField('note_format')
198+ title = RecordField('title')
199+ content = RecordField('content')
200+ last_change_date = DateRecordField('last_change_date')
201+ create_date = DateRecordField('create_date')
202
203 def __init__(self, data=None, record_id=None):
204- super(NoteBase, self).__init__(
205+ super(Note, self).__init__(
206 record_id=record_id, data=data, record_type=NOTE_RECORD_TYPE)
207-
208-def make_note_class(fields):
209- """Note class factory function. field_names is a list of strings."""
210- NoteClass = type('Note', (NoteBase,), {})
211- for field_name in fields:
212-
213- def fget(self, _field_name=field_name):
214- return self.get(_field_name)
215-
216- def fset(self, value, _field_name=field_name):
217- field_type = fields[_field_name]
218- if field_type == 'date':
219- # Check that it is a date with the correct format
220- date_value = strptime(value, "%Y-%m-%dT%H:%M:%S")
221- if date_value is None:
222- return
223- self[_field_name] = value
224-
225- setattr(NoteClass, field_name, property(fget, fset))
226- return NoteClass
227-
228-Note = make_note_class(FIELDS)
229
230=== modified file 'desktopcouch/notes/tests/test_record.py'
231--- desktopcouch/notes/tests/test_record.py 2010-05-28 09:51:46 +0000
232+++ desktopcouch/notes/tests/test_record.py 2010-11-01 17:09:45 +0000
233@@ -16,35 +16,40 @@
234 #
235 # Authors: Nicola Larosa <nicola.larosa@canonical.com>
236 # Rodrigo Moya <rodrigo.moya@canonical.com>
237+# Vincenzo Di Somma <vincenzo.di.somma@canonical.com>
238
239 """Tests for the NoteDocument class"""
240
241 import testtools
242-from time import (strftime, gmtime)
243-from desktopcouch.notes import record as note_mod
244+from time import strftime, gmtime
245+from desktopcouch.notes.record import Note, NOTE_RECORD_TYPE
246+
247+FIELDS = {
248+ # String fields
249+ 'note_format': 'string',
250+ 'title': 'string',
251+ 'content': 'string',
252+ # Date fields
253+ 'last_change_date': 'date',
254+ 'create_date': 'date'
255+}
256
257 class TestNoteRecord(testtools.TestCase):
258 """Test the Note Record object."""
259
260 def test_note_record(self):
261 """Test that we get the correct record type."""
262- note = note_mod.Note()
263- self.assertEqual(note_mod.NOTE_RECORD_TYPE, note.record_type)
264- for field_name in note_mod.FIELDS:
265- field_type = note_mod.FIELDS[field_name]
266- if field_type == 'string':
267- setattr(note, field_name, 'value')
268- self.assertEqual('value', note._data[field_name])
269- self.assertEqual(getattr(note, field_name), 'value')
270- elif field_type == 'date':
271- current_time = strftime("%Y-%m-%dT%H:%M:%S", gmtime())
272- setattr(note, field_name, current_time)
273- self.assertEqual(current_time, note._data[field_name])
274- self.assertEqual(getattr(note, field_name), current_time)
275- else:
276- self.fail('Unknown field type: %s' % field_type)
277-
278- # Check all keys
279- all_keys = set(note_mod.FIELDS)
280- all_keys.add('record_type')
281- self.assertEqual(set(note.keys()), all_keys)
282+ note = Note()
283+ self.assertEqual(NOTE_RECORD_TYPE, note.record_type)
284+ for field_name in FIELDS:
285+ self.assert_(hasattr(note, field_name))
286+ now = gmtime()
287+ now_str = strftime("%Y-%m-%dT%H:%M:%S", now)
288+ note.last_change_date = now_str
289+ # For some reason that I ignore strptime and strftime return
290+ # different timezones so we remove the timezone value
291+ # before asserting equal
292+ self.assertEqual(now[0:-1], note.last_change_date[0:-1])
293+
294+
295+
296
297=== modified file 'desktopcouch/records/record.py'
298--- desktopcouch/records/record.py 2010-10-31 15:52:12 +0000
299+++ desktopcouch/records/record.py 2010-11-01 17:09:45 +0000
300@@ -23,6 +23,7 @@
301
302 import re
303 import uuid
304+from time import strptime
305
306 RX = re.compile('[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
307
308@@ -76,6 +77,27 @@
309 for value in data.values():
310 validate(value)
311
312+
313+class RecordField(object):
314+ """Descriptor to manage record fields"""
315+
316+ def __init__(self, field_name):
317+ self.field_name = field_name
318+
319+ def __get__(self, obj, type=None):
320+ return obj.get(self.field_name)
321+
322+ def __set__(self, obj, value):
323+ obj[self.field_name] = value
324+
325+
326+class DateRecordField(RecordField):
327+ """Descriptor to manage data record fields"""
328+
329+ def __set__(self, obj, value):
330+ obj[self.field_name] = strptime(value, "%Y-%m-%dT%H:%M:%S")
331+
332+
333 class IllegalKeyException(Exception):
334 """Exception when attempting to set a key we don't allow."""
335 pass
336
337=== modified file 'desktopcouch/tasks/record.py'
338--- desktopcouch/tasks/record.py 2010-05-28 08:30:50 +0000
339+++ desktopcouch/tasks/record.py 2010-11-01 17:09:45 +0000
340@@ -15,41 +15,22 @@
341 # along with desktopcouch. If not, see <http://www.gnu.org/licenses/>.
342 #
343 # Authors: Rodrigo Moya <rodrigo.moya@canonical.com>
344+# Vincenzo Di Somma <vincenzo.di.somma@canonical.com>
345
346
347 """A dictionary based task record representation."""
348
349-from desktopcouch.records.record import Record
350-
351-TASK_RECORD_TYPE = 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/task'
352-# keep in sync with the above tasks record type
353-FIELD_NAMES = (
354- 'summary'
355-)
356-
357-class TaskBase(Record):
358- """
359- A base for Task records.
360-
361- Use make_task_class to create the Note class with the required fields.
362- """
363+from desktopcouch.records.record import Record, RecordField
364+
365+TASK_RECORD_TYPE = \
366+ 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/task'
367+
368+class Task(Record):
369+ """ Task records."""
370+
371+ summary = RecordField('summary')
372
373 def __init__(self, data=None, record_id=None):
374- super(TaskBase, self).__init__(
375+ super(Task, self).__init__(
376 record_id=record_id, data=data, record_type=TASK_RECORD_TYPE)
377
378-def make_task_class(field_names):
379- """Task class factory function. field_names is a list of strings."""
380- TaskClass = type('Task', (TaskBase,), {})
381- for field_name in field_names:
382-
383- def fget(self, _field_name=field_name):
384- return self.get(_field_name)
385-
386- def fset(self, value, _field_name=field_name):
387- self[_field_name] = value
388-
389- setattr(TaskClass, field_name, property(fget, fset))
390- return TaskClass
391-
392-Task = make_task_class(FIELD_NAMES)
393
394=== modified file 'desktopcouch/tasks/tests/test_record.py'
395--- desktopcouch/tasks/tests/test_record.py 2010-05-28 09:51:46 +0000
396+++ desktopcouch/tasks/tests/test_record.py 2010-11-01 17:09:45 +0000
397@@ -15,26 +15,23 @@
398 # along with desktopcouch. If not, see <http://www.gnu.org/licenses/>.
399 #
400 # Authors: Rodrigo Moya <rodrigo.moya@canonical.com>
401+# Vincenzo Di Somma <vincenzo.di.somma@canonical.com>
402
403 """Tests for the Tasks record classes"""
404
405 import testtools
406
407-from desktopcouch.tasks import record as task_mod
408+from desktopcouch.tasks.record import Task, TASK_RECORD_TYPE
409
410 class TestTaskRecord(testtools.TestCase):
411 """Test the Task Record object."""
412
413 def test_task_record(self):
414 """Test that we get the correct record type."""
415- task = task_mod.Task()
416- self.assertEqual(task_mod.TASK_RECORD_TYPE, task.record_type)
417- for field_name in task_mod.FIELD_NAMES:
418- setattr(task, field_name, 'value')
419- self.assertEqual('value', task._data[field_name])
420- self.assertEqual(getattr(task, field_name), 'value')
421+ task = Task()
422+ self.assertEqual(TASK_RECORD_TYPE, task.record_type)
423+ self.assert_(hasattr(task, 'summary'))
424+ summary = "manuel"
425+ task.summary = summary
426+ self.assertEqual(summary, task.summary)
427
428- # Check all keys
429- all_keys = set(task_mod.FIELD_NAMES)
430- all_keys.add('record_type')
431- self.assertEqual(set(task.keys()), all_keys)

Subscribers

People subscribed via source and target branches