Merge lp:~thisfred/desktopcouch/i_believe_you_have_my_couchdb into lp:desktopcouch
- i_believe_you_have_my_couchdb
- Merge into trunk
Proposed by
Eric Casteleijn
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~thisfred/desktopcouch/i_believe_you_have_my_couchdb |
Merge into: | lp:desktopcouch |
Diff against target: | None lines |
To merge this branch: | bzr merge lp:~thisfred/desktopcouch/i_believe_you_have_my_couchdb |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu One hackers | Pending | ||
Review via email:
|
Commit message
Makes the tests no longer use the user's desktopcouch couchdb.
Description of the change
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Eric Casteleijn (thisfred) wrote : | # |
- 47. By Eric Casteleijn
-
one forgotten checkin
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'desktopcouch/__init__.py' |
2 | --- desktopcouch/__init__.py 2009-08-19 16:00:01 +0000 |
3 | +++ desktopcouch/__init__.py 2009-08-21 21:57:37 +0000 |
4 | @@ -16,7 +16,7 @@ |
5 | "Desktop Couch helper files" |
6 | |
7 | from __future__ import with_statement |
8 | -import os, re, errno, time, fcntl |
9 | +import os, re, time |
10 | |
11 | |
12 | def find_pid(start_if_not_running=True): |
13 | @@ -88,7 +88,7 @@ |
14 | # which was shorter but less reliable) |
15 | |
16 | proc_dir = "/proc/%s" % (pid,) |
17 | - |
18 | + |
19 | # enumerate the process' file descriptors |
20 | fd_dir = os.path.join(proc_dir, 'fd') |
21 | try: |
22 | @@ -96,7 +96,7 @@ |
23 | for fd in os.listdir(fd_dir)] |
24 | except OSError: |
25 | raise RuntimeError("Unable to find file descriptors in /proc") |
26 | - |
27 | + |
28 | |
29 | # identify socket fds |
30 | socket_matches = [re.match('socket:\\[([0-9]+)\\]', p) for p in fd_paths] |
31 | @@ -140,11 +140,11 @@ |
32 | os_name = platform.system() |
33 | try: |
34 | process_is_couchdb = { |
35 | - "Linux":process_is_couchdb__linux |
36 | + "Linux": process_is_couchdb__linux |
37 | } [os_name] |
38 | |
39 | find_port = { |
40 | - "Linux":find_port__linux |
41 | + "Linux": find_port__linux |
42 | } [os_name] |
43 | except KeyError: |
44 | raise NotImplementedError("os %r is not yet supported" % (os_name,)) |
45 | |
46 | === modified file 'desktopcouch/contacts/contactspicker.py' |
47 | --- desktopcouch/contacts/contactspicker.py 2009-08-18 23:00:26 +0000 |
48 | +++ desktopcouch/contacts/contactspicker.py 2009-08-20 22:14:02 +0000 |
49 | @@ -28,18 +28,13 @@ |
50 | class ContactsPicker(gtk.VBox): |
51 | __gtype_name__ = "ContactsPicker" |
52 | |
53 | - def __init__(self, server_ip = 'http://127.0.0.1:5984/'): |
54 | + def __init__(self): |
55 | """Create a new ContactsPicker widget |
56 | - optional arguments: |
57 | - server_ip - specify and ip and port for the server location. |
58 | - Defaults to http://127.0.0.1:5984 |
59 | |
60 | """ |
61 | |
62 | gtk.VBox.__init__(self) |
63 | |
64 | - self.server_ip = server_ip |
65 | - |
66 | # Create search entry and button |
67 | hbox = gtk.HBox() |
68 | self.pack_start(hbox, False, False, 3) |
69 | @@ -51,11 +46,17 @@ |
70 | hbox.pack_start(self.search_button, False, False, 3) |
71 | |
72 | # Create CouchWidget to contain list of contacts |
73 | - self.contacts_list = CouchWidget(self.server_ip) |
74 | - self.contacts_list.database = 'contacts' |
75 | + self.contacts_list = CouchWidget('contacts') |
76 | self.contacts_list.editable = False |
77 | self.contacts_list.headings = [ "first_name", "last_name" ] |
78 | self.contacts_list.record_type = CONTACT_RECORD_TYPE |
79 | + |
80 | + #Pimp out the columns with some nicer titles |
81 | + #TODO: this should be set up for translatability |
82 | + columns = self.contacts_list.get_columns() |
83 | + columns[0].set_title("First Name") |
84 | + columns[1].set_title("Last Name") |
85 | + |
86 | self.contacts_list.show() |
87 | self.pack_start(self.contacts_list, True, True, 3) |
88 | |
89 | |
90 | === modified file 'desktopcouch/local_files.py' |
91 | --- desktopcouch/local_files.py 2009-08-05 11:18:46 +0000 |
92 | +++ desktopcouch/local_files.py 2009-08-21 22:45:24 +0000 |
93 | @@ -16,6 +16,8 @@ |
94 | # along with desktopcouch. If not, see <http://www.gnu.org/licenses/>. |
95 | # |
96 | # Author: Stuart Langridge <stuart.langridge@canonical.com> |
97 | +# Eric Casteleijn <eric.casteleijn@canonical.com> |
98 | + |
99 | """Specify location of files relevant to desktop CouchDB. |
100 | |
101 | Checks to see whether we're running out of the source tree or not. |
102 | @@ -30,48 +32,18 @@ |
103 | "Remove .. from paths" |
104 | return os.path.realpath(os.path.join(rootdir, path)) |
105 | |
106 | -def u1_is_in_source_tree(): |
107 | - """If the parent dir of the module directory is "lib", and there is |
108 | - a "tmp" dir and a "README" file, then the u1 code is in a source tree.""" |
109 | - try: |
110 | - import ubuntuone |
111 | - except ImportError: |
112 | - return False |
113 | - u1mod_dir, u1mod_file = os.path.split(ubuntuone.__file__) |
114 | - if u1mod_dir.split(os.sep)[-2] != "lib": |
115 | - return False |
116 | - |
117 | - proj_root = os.path.join(u1mod_dir, os.pardir, os.pardir) |
118 | - if not os.path.isdir(os.path.join(proj_root, "tmp")): |
119 | - return False |
120 | - |
121 | - if not os.path.isfile(os.path.join(proj_root, "README")): |
122 | - return False |
123 | - |
124 | - return True |
125 | - |
126 | - |
127 | -if u1_is_in_source_tree(): |
128 | - import ubuntuone |
129 | - rootdir = os.path.join(os.path.split(ubuntuone.__file__)[0], "..", "..", "tmp") |
130 | - FILE_INI = mkpath(rootdir, "desktop-couchdb.ini") |
131 | - DIR_DB = mkpath(rootdir, "desktop-couch-files") |
132 | - if not os.path.isdir(DIR_DB): |
133 | - os.makedirs(DIR_DB) |
134 | -else: |
135 | - rootdir = os.path.join(xdg.BaseDirectory.xdg_cache_home, "desktop-couch") |
136 | - if not os.path.isdir(rootdir): |
137 | - os.makedirs(rootdir) |
138 | - config_dir = xdg.BaseDirectory.save_config_path("desktop-couch") |
139 | - FILE_INI = os.path.join(config_dir, "desktop-couchdb.ini") |
140 | - DIR_DB = xdg.BaseDirectory.save_data_path("desktop-couch") |
141 | - |
142 | +rootdir = os.path.join(xdg.BaseDirectory.xdg_cache_home, "desktop-couch") |
143 | +if not os.path.isdir(rootdir): |
144 | + os.mkdir(rootdir) |
145 | +config_dir = xdg.BaseDirectory.save_config_path("desktop-couch") |
146 | +FILE_INI = os.path.join(config_dir, "desktop-couchdb.ini") |
147 | +DIR_DB = xdg.BaseDirectory.save_data_path("desktop-couch") |
148 | + |
149 | FILE_PID = mkpath(rootdir, "desktop-couchdb.pid") |
150 | FILE_LOG = mkpath(rootdir, "desktop-couchdb.log") |
151 | FILE_STDOUT = mkpath(rootdir, "desktop-couchdb.stdout") |
152 | FILE_STDERR = mkpath(rootdir, "desktop-couchdb.stderr") |
153 | |
154 | - |
155 | COUCH_EXE = os.environ.get('COUCHDB') |
156 | if not COUCH_EXE: |
157 | for x in os.environ['PATH'].split(':'): |
158 | @@ -92,7 +64,6 @@ |
159 | |
160 | return chain |
161 | |
162 | - |
163 | # You will need to add -b or -k on the end of this |
164 | COUCH_EXEC_COMMAND = [COUCH_EXE, couch_chain_flag(), FILE_INI, '-p', FILE_PID, |
165 | '-o', FILE_STDOUT, '-e', FILE_STDERR] |
166 | |
167 | === modified file 'desktopcouch/pair/tests/test_network_io.py' |
168 | --- desktopcouch/pair/tests/test_network_io.py 2009-07-10 22:13:01 +0000 |
169 | +++ desktopcouch/pair/tests/test_network_io.py 2009-08-21 21:57:37 +0000 |
170 | @@ -17,21 +17,14 @@ |
171 | |
172 | import pygtk |
173 | pygtk.require('2.0') |
174 | -import gtk |
175 | |
176 | from twisted.internet import gtk2reactor |
177 | gtk2reactor.install() |
178 | from twisted.internet import reactor, task |
179 | |
180 | - |
181 | -if __name__ == "__main__": |
182 | - import sys, os |
183 | - sys.path.append(os.pardir) |
184 | - from couchdb_pairing.network_io import start_send_invitation, ListenForInvitations |
185 | - from couchdb_pairing.dbus_io import get_local_hostname |
186 | -else: |
187 | - from ..couchdb_pairing.network_io import start_send_invitation, ListenForInvitations |
188 | - from ..couchdb_pairing.dbus_io import get_local_hostname |
189 | +from desktopcouch.pair.couchdb_pairing.network_io import ( |
190 | + start_send_invitation, ListenForInvitations) |
191 | +from desktopcouch.pair.couchdb_pairing.dbus_io import get_local_hostname |
192 | |
193 | import unittest |
194 | |
195 | @@ -49,7 +42,7 @@ |
196 | def test_successful_lifespan(self): |
197 | |
198 | secret = "sekrit" |
199 | - |
200 | + |
201 | def listener_get_secret_from_user(sender, f, send_secret): |
202 | """Get secret from user. Try several first.""" |
203 | self.assertFalse(f("sek")) |
204 | @@ -106,7 +99,7 @@ |
205 | def disabled__test_inviter_quits(self): |
206 | |
207 | secret = "sekrit" |
208 | - |
209 | + |
210 | def listener_get_secret_from_user(sender, f, send_secret): |
211 | """Get secret from user. Try several first.""" |
212 | self.assertFalse(f("sek")) |
213 | @@ -152,7 +145,7 @@ |
214 | def disabled__test_listener_quits(self): |
215 | |
216 | secret = "sekrit" |
217 | - |
218 | + |
219 | def listener_get_secret_from_user(sender, f, send_secret): |
220 | """Get secret from user. Try several first.""" |
221 | self.assertFalse(f("sek")) |
222 | @@ -193,9 +186,3 @@ |
223 | |
224 | self.assertEqual(self._listener_socket_state, "closed") |
225 | self.assertEqual(self._inviter_socket_state, "closed") |
226 | - |
227 | - |
228 | -if __name__ == "__main__": |
229 | - import logging |
230 | - logging.basicConfig(level=logging.ERROR) |
231 | - unittest.main() |
232 | |
233 | === modified file 'desktopcouch/records/couchwidget.py' |
234 | --- desktopcouch/records/couchwidget.py 2009-08-19 23:01:09 +0000 |
235 | +++ desktopcouch/records/couchwidget.py 2009-08-21 23:46:57 +0000 |
236 | @@ -26,24 +26,48 @@ |
237 | class CouchWidget(gtk.TreeView): |
238 | __gtype_name__ = "CouchWidget" |
239 | |
240 | - def __init__(self, server_ip = 'http://127.0.0.1:5984/'): |
241 | + def __init__( |
242 | + self, database_name, record_type=None, headings=None, uri=None): |
243 | """Create a new Couchwidget |
244 | + arguments: |
245 | + database_name - specify the name of the database in the desktop |
246 | + couchdb to use. If the specified database does not exist, it |
247 | + will be created. |
248 | + |
249 | optional arguments: |
250 | - server_ip - specify and ip and port for the server location. |
251 | - Defaults to http://127.0.0.1:5984 |
252 | - |
253 | + record_type - a string to specify the record_type to use in |
254 | + retrieving and creating records. Note that if no records are |
255 | + set the headings argument must also be used or a RuntimeError |
256 | + will result. |
257 | + |
258 | + headings - a list of strings specifying headings to use in |
259 | + the columns of the CouchWidget. |
260 | + |
261 | + Note that the CouchWidget uses headings for keys, and visa versa. |
262 | + If a record does not contain a value for a specified value |
263 | + the CouchWidget will simply display an empty string for the |
264 | + value. If the widget is set to editable, the user will be able |
265 | + to add values to the database. |
266 | + |
267 | """ |
268 | |
269 | gtk.TreeView.__init__(self) |
270 | |
271 | - #assume a local server |
272 | - self.server_ip = server_ip |
273 | - |
274 | #set up the default values |
275 | - self.__db = None |
276 | + if type(database_name) is not type(str()): |
277 | + raise TypeError("database_name is required and must be a string") |
278 | + |
279 | + #set up default values |
280 | self.__record_type = None |
281 | - self.__headings = None |
282 | + self.__headings = headings |
283 | self.__editable = False |
284 | + self.uri = uri |
285 | + |
286 | + #set the datatabase |
287 | + self.database = database_name |
288 | + if record_type is not None: |
289 | + self.record_type = record_type |
290 | + |
291 | self.get_selection().set_mode(gtk.SELECTION_MULTIPLE) |
292 | |
293 | @property |
294 | @@ -57,7 +81,7 @@ |
295 | value. If the widget is set to editable, the user will be able |
296 | to add values to the database. |
297 | |
298 | - Setting this property will cause the widget to reload. |
299 | + Setting this property will cause the widget to reload. |
300 | |
301 | """ |
302 | |
303 | @@ -84,20 +108,22 @@ |
304 | |
305 | #refresh the treeview if possible |
306 | if self.record_type != None: |
307 | - self.__populate_treeview()(self.record_type) |
308 | + self.__populate_treeview() |
309 | |
310 | @property |
311 | def database(self): |
312 | """database - gets an instance to the CouchDB. |
313 | Set to a string to change the database. |
314 | |
315 | - """ |
316 | + """ |
317 | return self.__db |
318 | |
319 | @database.setter |
320 | def database(self, db_name): |
321 | - self.__db = CouchDatabase(db_name, uri=self.server_ip, create=True) |
322 | - |
323 | + if self.uri: |
324 | + self.__db = CouchDatabase(db_name, create=True, uri=self.uri) |
325 | + else: |
326 | + self.__db = CouchDatabase(db_name, create=True) |
327 | if self.record_type != None: |
328 | self.__populate_treeview()(self.record_type) |
329 | |
330 | @@ -119,30 +145,52 @@ |
331 | |
332 | def __populate_treeview(self): |
333 | #if the database is not set up, just return |
334 | - if self.__db == None or self.__headings == None: |
335 | + if self.__db == None: |
336 | return |
337 | |
338 | - #refresh the model structure |
339 | - self.__reset_model() |
340 | + #the cases with headings are complex and hacky |
341 | + #there are the following cases: |
342 | + #1. headings have not been set and cannot be inferred |
343 | + #2. headings have been previously set |
344 | + #3. headings should be inferred from results |
345 | + |
346 | |
347 | #retrieve the docs for the record_type, if any |
348 | - results = self.__db.get_records(record_type=self.__record_type,create_view=True) |
349 | + results = self.__db.get_records( |
350 | + record_type=self.__record_type,create_view=True) |
351 | + |
352 | + #test for headings case 1 and raise an exception |
353 | + if len(results) < 1 and self.headings == None: |
354 | + raise RuntimeError("""Cannot infer columns for CouchWidget. |
355 | + Ensure that records exist, or define columns using |
356 | + CouchWidget.headings property. |
357 | + """) |
358 | + |
359 | + #test for case 2, and set up the model |
360 | + if self.headings is not None: |
361 | + self.__reset_model() |
362 | |
363 | #if headings are already assigned, set up headings and columns |
364 | + #for headings case 2 with or without results |
365 | if self.headings != None: |
366 | self.__make_headings() |
367 | |
368 | first_row = True |
369 | for r in results: |
370 | - #if headings are not set up, infer them from |
371 | - #the first stored record |
372 | + #handle headings case 3 |
373 | + #if headings are not set up, infer them from |
374 | if self.headings == None and first_row: |
375 | self.headings = [] |
376 | for k in r.value.keys(): |
377 | if not k.startswith("_") and k != "record_type": |
378 | self.headings.append(k) |
379 | #now set up the columns and headers |
380 | - self.__make_headings() |
381 | + self.__make_headings() |
382 | + |
383 | + #in headings case 3 the model has not been set yet |
384 | + #so do that now |
385 | + self.__reset_model() |
386 | + |
387 | first_row = False |
388 | |
389 | #lists have to match the list_store columns in length |
390 | @@ -152,19 +200,19 @@ |
391 | row = ["" for i in xrange(col_count)] |
392 | |
393 | #replace the values in the row with the values in the |
394 | - #retrieved rows. If the the key is not in the doc, |
395 | + #retrieved rows. If the the key is not in the doc, |
396 | #just continue with an empty string |
397 | for i, h in enumerate(self.headings): |
398 | try: |
399 | row[i] = r.value[h] |
400 | except: |
401 | pass |
402 | - |
403 | + |
404 | #set the last value as the document_id, and append |
405 | row[-1] = r.key |
406 | self.list_store.append(row) |
407 | |
408 | - #apply the model tot he Treeview |
409 | + #apply the model tot he Treeview |
410 | self.set_model(self.list_store) |
411 | |
412 | def append_row(self, new_row, auto_save = True): |
413 | @@ -176,45 +224,48 @@ |
414 | to specify all values to include in the new row, as |
415 | append_row will copy all the values starting at position 0 |
416 | and will fill in the remaining values with empty strings. |
417 | - |
418 | + |
419 | auto_save - if True will immediately commit the row |
420 | to the database. Otherwise, the row won't be saved until |
421 | a cell is edited. Typically should be False if adding an |
422 | - empty row. An empty list will not be autosaved, even if |
423 | + empty row. An empty list will not be autosaved, even if |
424 | auto_save is set to True. |
425 | |
426 | Defaults to True. |
427 | |
428 | """ |
429 | |
430 | + #TODO: add gaurd conditions |
431 | + #throw if no database is set |
432 | + |
433 | #lists have to match the list_store columns in length |
434 | #note that the last value is reserved for the doc_id |
435 | col_count = len(self.headings) + 1 |
436 | row = ["" for i in xrange(col_count)] |
437 | - |
438 | + |
439 | #create a document for autosaving |
440 | - doc = {"record_type":self.record_type} |
441 | - |
442 | + doc = {"record_type":self.record_type} |
443 | + |
444 | #copy the values into the row |
445 | #add to the document in case it needs to be auto saved |
446 | for i, v in enumerate(new_row): |
447 | row[i] = new_row[i] |
448 | doc[self.headings[i]] = new_row[i] |
449 | - |
450 | + |
451 | rec = Record(doc) |
452 | |
453 | #auto save non-empty rows |
454 | if auto_save and len(new_row) > 0: |
455 | doc_id = self.__db.put_record(rec) |
456 | row[len(self.headings)] = doc_id #store the id |
457 | - |
458 | + |
459 | #add it to the list store |
460 | self.list_store.append(row) |
461 | |
462 | @property |
463 | def selected_rows(self): |
464 | - """ selected_rows - returns a list of dictionaries |
465 | - for each row selected. Note that the values are not |
466 | + """ selected_rows - returns a list of dictionaries |
467 | + for each row selected. Note that the values are not |
468 | necessarily the complete dictionary for the records, but rather |
469 | are determined by the headings used for the CouchWidget. |
470 | |
471 | @@ -236,7 +287,7 @@ |
472 | #get the value for each heading and add it to the row |
473 | for i, h in enumerate(self.headings): |
474 | row[h] = model.get_value(iter,i) |
475 | - |
476 | + |
477 | #add the row to the list |
478 | rows.append(row) |
479 | return rows |
480 | @@ -244,7 +295,7 @@ |
481 | @property |
482 | def selected_record_ids(self): |
483 | """ selected_record_ids - a list of document ids that are |
484 | - selected in the CouchWidget. Throws an IndexError if |
485 | + selected in the CouchWidget. Throws an IndexError if |
486 | a specified id is not found in the list when setting |
487 | this property. |
488 | |
489 | @@ -269,7 +320,7 @@ |
490 | @selected_record_ids.setter |
491 | def selected_record_ids(self, indexes): |
492 | rows = [] #a list of rows to select |
493 | - for id in indexes: |
494 | + for id in indexes: |
495 | id_found = False #track if the id was found |
496 | |
497 | for i,r in enumerate(self.list_store): |
498 | @@ -286,7 +337,7 @@ |
499 | selection.unselect_all() |
500 | for r in rows: |
501 | selection.select_path(r) |
502 | - |
503 | + |
504 | @property |
505 | def selected_records(self): |
506 | """ selected_records - returns a list of Record objects |
507 | @@ -296,7 +347,7 @@ |
508 | |
509 | """ |
510 | recs = [] #a list of records to return |
511 | - for id in self.selected_record_ids: |
512 | + for id in self.selected_record_ids: |
513 | #retrieve a record for each id |
514 | recs.append(Record(record_id = id, record_type = self.record_type)) |
515 | return recs |
516 | @@ -314,12 +365,12 @@ |
517 | |
518 | #make a new ListStore |
519 | col_count = len(self.headings) + 1 |
520 | - self.list_store = gtk.ListStore(*[gobject.TYPE_STRING for i in xrange(col_count)]) |
521 | - |
522 | + self.list_store = gtk.ListStore( |
523 | + *[gobject.TYPE_STRING for i in xrange(col_count)]) |
524 | |
525 | def __make_headings(self): |
526 | """ __make_headings - internal funciton do not call direclty |
527 | - Sets up the headings and columnss for the TreeView. |
528 | + Sets up the headings and columns for the TreeView. |
529 | |
530 | """ |
531 | |
532 | @@ -334,12 +385,12 @@ |
533 | #create a column and add to the TreeView |
534 | col = gtk.TreeViewColumn(h, rend, text=i) |
535 | self.append_column(col) |
536 | - |
537 | + |
538 | def __edited(self, cellrenderertext, path, new_text, col): |
539 | """ __edited - internal signal handler. |
540 | Updates the database if a cell in the Treeview |
541 | has been edited. |
542 | - |
543 | + |
544 | """ |
545 | |
546 | #get an iterator that points to the edited row |
547 | @@ -356,10 +407,10 @@ |
548 | if id == "": #the row has not been stored |
549 | #create a document |
550 | doc = {"record_type":self.record_type} |
551 | - |
552 | + |
553 | for i, h in enumerate(self.headings): |
554 | #copy the all the values into the doc |
555 | - doc[h] = self.list_store.get_value(iter,i) |
556 | + doc[h] = self.list_store.get_value(iter,i) |
557 | |
558 | rec = Record(doc) |
559 | #save the document and store the id |
560 | @@ -383,7 +434,7 @@ |
561 | disp += "\n\nRecords:\n" |
562 | for r in cw.selected_records: |
563 | disp += str(r) + "\n" |
564 | - |
565 | + |
566 | tv.get_buffer().set_text(disp) |
567 | |
568 | def __select_ids(widget, widgets): |
569 | @@ -391,7 +442,7 @@ |
570 | try: |
571 | cw.selected_record_ids = entry.get_text().split(",") |
572 | except Exception, inst: |
573 | - lbl.set_text(str(inst)) |
574 | + lbl.set_text(str(inst)) |
575 | |
576 | if __name__ == "__main__": |
577 | """creates a test CouchWidget if called directly""" |
578 | @@ -408,19 +459,12 @@ |
579 | win.add(vbox) |
580 | |
581 | #create a test widget with test database values |
582 | - cw = CouchWidget() |
583 | - cw.database = "couch_widget_test" |
584 | + cw = CouchWidget("couch_widget_test", record_type="test_record_type", |
585 | + headings=["Key1", "Key2", "Key3", "Key4"]) |
586 | |
587 | #allow editing |
588 | cw.editable = True |
589 | |
590 | - #create headers/keys |
591 | - cw.headings = ["Key1","Key2","Key3","Key4"] |
592 | - |
593 | - #set the record_type for the TreeView |
594 | - #it will not populate without this value being set |
595 | - cw.record_type = "test_record_type" |
596 | - |
597 | #create a row with all four columns set |
598 | cw.append_row(["val1","val2","val3","val4"]) |
599 | |
600 | @@ -442,12 +486,10 @@ |
601 | tv.show() |
602 | cw.connect("cursor-changed",__show_selected, (tv,cw)) |
603 | |
604 | - |
605 | #create ui for testing selection |
606 | id_vbox = gtk.VBox(False, 5) |
607 | id_vbox.show() |
608 | |
609 | - |
610 | fb_lbl = gtk.Label("paste ids into the edit box to select them") |
611 | fb_lbl.show() |
612 | |
613 | |
614 | === modified file 'desktopcouch/records/server.py' |
615 | --- desktopcouch/records/server.py 2009-08-10 21:32:52 +0000 |
616 | +++ desktopcouch/records/server.py 2009-08-21 22:45:24 +0000 |
617 | @@ -21,7 +21,6 @@ |
618 | |
619 | """The Desktop Couch Records API.""" |
620 | |
621 | -import urllib |
622 | from couchdb import Server |
623 | from couchdb.client import ResourceNotFound, ResourceConflict |
624 | from couchdb.design import ViewDefinition |
625 | @@ -155,7 +154,7 @@ |
626 | |
627 | # sync_many does nothing if we pass an empty list. It even gets |
628 | # its design-document from the ViewDefinition items, and if there |
629 | - # are no items, then it has no idea of a design document to |
630 | + # are no items, then it has no idea of a design document to |
631 | # update. This is a serious flaw. Thus, the "else" to follow. |
632 | ViewDefinition.sync_many(self.db, views, remove_missing=True) |
633 | else: |
634 | @@ -219,16 +218,16 @@ |
635 | special value, None, is analogous to O_EXCL|O_CREAT . |
636 | |
637 | Set record_type to a string to retrieve records of only that |
638 | - specified type. Otherwise, usse the view to return *all* records. |
639 | - If there is no view to use or we insist on creating a new view |
640 | + specified type. Otherwise, usse the view to return *all* records. |
641 | + If there is no view to use or we insist on creating a new view |
642 | and cannot, raise KeyError . |
643 | |
644 | - You can use index notation on the result to get rows with a |
645 | + You can use index notation on the result to get rows with a |
646 | particular record type. |
647 | =>> results = get_records() |
648 | =>> for foo_document in results["foo"]: |
649 | ... print foo_document |
650 | - |
651 | + |
652 | Use slice notation to apply start-key and end-key options to the view. |
653 | =>> results = get_records() |
654 | =>> people = results[['Person']:['Person','ZZZZ']] |
655 | @@ -250,7 +249,7 @@ |
656 | |
657 | if not exists: |
658 | self.add_view(view_name, view_map_js, None, design_doc) |
659 | - |
660 | + |
661 | viewdata = self.execute_view(view_name, design_doc) |
662 | if record_type is None: |
663 | return viewdata |
664 | |
665 | === modified file 'desktopcouch/records/tests/__init__.py' |
666 | --- desktopcouch/records/tests/__init__.py 2009-07-08 17:48:11 +0000 |
667 | +++ desktopcouch/records/tests/__init__.py 2009-08-21 22:47:25 +0000 |
668 | @@ -14,3 +14,27 @@ |
669 | # You should have received a copy of the GNU Lesser General Public License |
670 | # along with desktopcouch. If not, see <http://www.gnu.org/licenses/>. |
671 | """Tests for Documents API""" |
672 | + |
673 | +import os, tempfile |
674 | +from desktopcouch.local_files import COUCH_EXE, couch_chain_flag |
675 | +from desktopcouch.start_local_couchdb import create_ini_file, run_couchdb |
676 | + |
677 | +directory = tempfile.mkdtemp() |
678 | +ini_path = os.path.join(directory, "test_couchdb.ini") |
679 | +log_path = os.path.join(directory, "test_couchdb.log") |
680 | +pid_path = os.path.join(directory, "test_couchdb.pid") |
681 | +stdout_path = os.path.join(directory, "test_couchdb.stdout") |
682 | +stderr_path = os.path.join(directory, "test_couchdb.stderr") |
683 | + |
684 | +db_dir = os.path.join(directory, "test_couchdb") |
685 | +os.mkdir(db_dir) |
686 | + |
687 | +port = "21224" |
688 | +create_ini_file( |
689 | + ini_path=ini_path, db_dir=db_dir, log_path=log_path, port=port) |
690 | +exec_command = [ |
691 | + COUCH_EXE, couch_chain_flag(), ini_path, '-p', pid_path, '-o', stdout_path, |
692 | + '-e', stderr_path] |
693 | +exec_command[2] = ini_path |
694 | +run_couchdb(exec_command=exec_command) |
695 | +URI = "htpp://localhost:%s" % port |
696 | |
697 | === modified file 'desktopcouch/records/tests/test_couchwidget.py' |
698 | --- desktopcouch/records/tests/test_couchwidget.py 2009-08-19 23:01:09 +0000 |
699 | +++ desktopcouch/records/tests/test_couchwidget.py 2009-08-21 23:46:57 +0000 |
700 | @@ -19,76 +19,182 @@ |
701 | """Tests for the couchwidget object""" |
702 | |
703 | from testtools import TestCase |
704 | +from desktopcouch.records.record import Record |
705 | from desktopcouch.records.server import CouchDatabase |
706 | from desktopcouch.records.couchwidget import CouchWidget |
707 | +from desktopcouch.records.tests import URI |
708 | + |
709 | |
710 | class TestCouchWidget(TestCase): |
711 | """Test the CouchWidget functionality""" |
712 | + |
713 | def setUp(self): |
714 | - self.dbname = "couch_widget_test" |
715 | + self.dbname = self._testMethodName |
716 | + self.db = CouchDatabase(self.dbname, create=True, uri=URI) |
717 | self.record_type = "test_record_type" |
718 | |
719 | - def test_headings_first(self): |
720 | - #create a test widget with test database values |
721 | - cw = CouchWidget() |
722 | - cw.database = self.dbname |
723 | - |
724 | - #allow editing |
725 | - cw.editable = True |
726 | - |
727 | - #create headers/keys |
728 | - cw.headings = ["Key1","Key2","Key3","Key4"] |
729 | - |
730 | - #set the record_type for the TreeView |
731 | - #it will not populate without this value being set |
732 | - cw.record_type = self.record_type |
733 | - |
734 | - #create a row with all four columns set |
735 | - cw.append_row(["val1","val2","val3","val4"]) |
736 | - |
737 | - #create a row with only the second column set |
738 | - cw.append_row(["","val2"]) |
739 | - |
740 | - #create an empty row (which will not be saved until the user edits it) |
741 | - cw.append_row([]) |
742 | - |
743 | - self.assertEqual(cw.record_type, self.record_type) |
744 | - self.__delete_db() |
745 | - |
746 | - def test_record_type_first(self): |
747 | - #create a test widget with test database values |
748 | - cw = CouchWidget() |
749 | - cw.database = self.dbname |
750 | - |
751 | - #allow editing |
752 | - cw.editable = True |
753 | - |
754 | - #set the record_type for the TreeView |
755 | - #it will not populate without this value being set |
756 | - cw.record_type = self.record_type |
757 | - |
758 | - #create headers/keys |
759 | - cw.headings = ["Key1","Key2","Key3","Key4"] |
760 | - |
761 | - #create a row with all four columns set |
762 | - cw.append_row(["val1","val2","val3","val4"]) |
763 | - |
764 | - #create a row with only the second column set |
765 | - cw.append_row(["","val2"]) |
766 | - |
767 | - #create an empty row (which will not be saved until the user edits it) |
768 | - cw.append_row([]) |
769 | - |
770 | - self.assertEqual(cw.record_type, self.record_type) |
771 | - self.__delete_db() |
772 | - |
773 | def tearDown(self): |
774 | """tear down each test""" |
775 | - self.__delete_db() |
776 | #delete the database |
777 | - |
778 | - def __delete_db(self): |
779 | - db = CouchDatabase(self.dbname, create=True) |
780 | - del db._server[self.dbname] |
781 | - |
782 | - |
783 | + del self.db._server[self.dbname] |
784 | + |
785 | + def test_constructor_guarded(self): |
786 | + """Ensure that couchwidget cannot be constructed without a |
787 | + database name. |
788 | + """ |
789 | + try: |
790 | + cw = CouchWidget(None, uri=URI) |
791 | + except TypeError, inst: |
792 | + self.assertEqual( |
793 | + inst.args[0],"database_name is required and must be a string") |
794 | + |
795 | + def test_new_rows_with_headings(self): |
796 | + """Test a simple creating a couchwidget """ |
797 | + |
798 | + #create a test widget with test database values |
799 | + cw = CouchWidget(self.dbname, uri=URI) |
800 | + |
801 | + #allow editing |
802 | + cw.editable = True |
803 | + |
804 | + #create headers/keys |
805 | + cw.headings = ["Key1", "Key2", "Key3", "Key4"] |
806 | + |
807 | + #set the record_type for the TreeView |
808 | + #it will not populate without this value being set |
809 | + cw.record_type = self.record_type |
810 | + |
811 | + #create a row with all four columns set |
812 | + cw.append_row(["val1", "val2", "val3", "val4"]) |
813 | + |
814 | + #create a row with only the second column set |
815 | + cw.append_row(["", "val2"]) |
816 | + |
817 | + #create an empty row (which will not be saved until the user edits it) |
818 | + cw.append_row([]) |
819 | + |
820 | + #if this all worked, there should be three rows in the model |
821 | + model = cw.get_model() |
822 | + self.assertEqual(len(model), 3) |
823 | + |
824 | + def test_no_headings_or_stored_records(self): |
825 | + """test when there is no defined headings and no stored records |
826 | + to infer headings from. Should raise a proper exception. |
827 | + """ |
828 | + |
829 | + try: |
830 | + #create a test widget with test database values |
831 | + cw = CouchWidget(self.dbname, uri=URI) |
832 | + |
833 | + #set the record_type for the TreeView |
834 | + #it will not populate without this value being set |
835 | + cw.record_type = self.record_type |
836 | + |
837 | + #create a row with all four columns set |
838 | + cw.append_row(["val1", "val2", "val3", "val4"]) |
839 | + |
840 | + #create a row with only the second column set |
841 | + cw.append_row(["", "val2"]) |
842 | + |
843 | + #create an empty row (which will not be saved until the |
844 | + #user edits it) |
845 | + cw.append_row([]) |
846 | + |
847 | + #if this all worked, there should be three rows in the model |
848 | + model = cw.get_model() |
849 | + |
850 | + #should be catching the following exception |
851 | + except RuntimeError, inst: |
852 | + self.assertEquals( |
853 | + inst.args[0].find("Cannot infer columns for CouchWidget"),0) |
854 | + |
855 | + def test_all_from_database(self): |
856 | + #create some records |
857 | + db = CouchDatabase(self.dbname, create=True, uri=URI) |
858 | + db.put_record(Record({ |
859 | + "key1_1": "val1_1", "key1_2": "val1_2", "key1_3": "val1_3", |
860 | + "record_type": self.record_type})) |
861 | + db.put_record(Record({ |
862 | + "key2_1": "val2_1", "key2_2": "val2_2", "key2_3": "val2_3", |
863 | + "record_type": self.record_type})) |
864 | + |
865 | + #build the couchwidget |
866 | + cw = CouchWidget(self.dbname, uri=URI) |
867 | + cw.record_type = self.record_type |
868 | + #make sure there are three columns and two rows |
869 | + self.assertEqual(cw.get_model().get_n_columns(),4) |
870 | + self.assertEqual(len(cw.get_model()),2) |
871 | + |
872 | + def test_single_col_from_database(self): |
873 | + #create some records |
874 | + self.db.put_record(Record({ |
875 | + "key1_1": "val1_1", "key1_2": "val1_2", "key1_3": "val1_3", |
876 | + "record_type": self.record_type})) |
877 | + self.db.put_record(Record({ |
878 | + "key1_1": "val2_1", "key1_2": "val2_2", "key1_3": "val2_3", |
879 | + "record_type": self.record_type})) |
880 | + #build the couchwidget |
881 | + cw = CouchWidget(self.dbname, uri=URI) |
882 | + cw.headings = ["key1_1"] |
883 | + cw.record_type = self.record_type |
884 | + #make sure there are three columns and two rows |
885 | + self.assertEqual(cw.get_model().get_n_columns(),2) |
886 | + self.assertEqual(len(cw.get_model()),2) |
887 | + |
888 | + def test_optional_record_type_arg(self): |
889 | + """Test a simple creating a couchwidget """ |
890 | + #create some records |
891 | + self.db.put_record(Record({ |
892 | + "key1_1": "val1_1", "key1_2": "val1_2", "key1_3": "val1_3", |
893 | + "record_type": self.record_type})) |
894 | + self.db.put_record(Record({ |
895 | + "key2_1": "val2_1", "key2_2": "val2_2", "key2_3": "val2_3", |
896 | + "record_type": self.record_type})) |
897 | + |
898 | + #create a test widget with test database values |
899 | + cw = CouchWidget(self.dbname, record_type=self.record_type, uri=URI) |
900 | + |
901 | + #make sure there are three columns and two rows |
902 | + self.assertEqual(cw.get_model().get_n_columns(),4) |
903 | + self.assertEqual(len(cw.get_model()),2) |
904 | + |
905 | + def test_optional_args_no_stored_records(self): |
906 | + """Test a simple creating a couchwidget """ |
907 | + |
908 | + #create a test widget with test database values |
909 | + cw = CouchWidget( |
910 | + self.dbname, record_type=self.record_type, |
911 | + headings=["Key1", "Key2", "Key3", "Key4"], uri=URI) |
912 | + |
913 | + #create a row with all four columns set |
914 | + cw.append_row(["val1", "val2", "val3", "val4"]) |
915 | + |
916 | + #create a row with only the second column set |
917 | + cw.append_row(["", "val2"]) |
918 | + |
919 | + #create an empty row (which will not be saved until the user edits it) |
920 | + cw.append_row([]) |
921 | + |
922 | + #if this all worked, there should be three rows in the model |
923 | + model = cw.get_model() |
924 | + self.assertEqual(len(model), 3) |
925 | + |
926 | + def test_programatically_add_row(self): |
927 | + """test appending different sized rows programatically""" |
928 | + #create some records |
929 | + self.db.put_record(Record({ |
930 | + "key1_1": "val1_1", "key1_2": "val1_2", "key1_3": "val1_3", |
931 | + "record_type": self.record_type})) |
932 | + self.db.put_record(Record({ |
933 | + "key2_1": "val2_1", "key2_2": "val2_2", "key2_3": "val2_3", |
934 | + "record_type": self.record_type})) |
935 | + |
936 | + #create a test widget with test database values |
937 | + cw = CouchWidget(self.dbname, record_type=self.record_type, uri=URI) |
938 | + |
939 | + #allow editing |
940 | + cw.append_row(["boo", "ray"]) |
941 | + |
942 | + #make sure there are three columns and two rows |
943 | + self.assertEqual(cw.get_model().get_n_columns(),4) |
944 | + self.assertEqual(len(cw.get_model()),3) |
945 | |
946 | === modified file 'desktopcouch/records/tests/test_server.py' |
947 | --- desktopcouch/records/tests/test_server.py 2009-08-12 14:26:40 +0000 |
948 | +++ desktopcouch/records/tests/test_server.py 2009-08-21 22:45:24 +0000 |
949 | @@ -17,12 +17,10 @@ |
950 | # Authors: Eric Casteleijn <eric.casteleijn@canonical.com> |
951 | |
952 | """testing database/contact.py module""" |
953 | - |
954 | import testtools |
955 | -import random |
956 | -from desktopcouch.stop_local_couchdb import stop_couchdb |
957 | from desktopcouch.records.server import CouchDatabase |
958 | from desktopcouch.records.record import Record |
959 | +from desktopcouch.records.tests import URI |
960 | |
961 | FAKE_RECORD_TYPE = "http://example.org/test" |
962 | |
963 | @@ -33,33 +31,38 @@ |
964 | } |
965 | }""" % FAKE_RECORD_TYPE |
966 | |
967 | + |
968 | class TestCouchDatabase(testtools.TestCase): |
969 | """tests specific for CouchDatabase""" |
970 | |
971 | + |
972 | def setUp(self): |
973 | """setup each test""" |
974 | # Connect to CouchDB server |
975 | self.dbname = self._testMethodName |
976 | - self.database = CouchDatabase(self.dbname, create=True) |
977 | - |
978 | + self.database = CouchDatabase( |
979 | + self.dbname, create=True, uri=URI) |
980 | #create some records to pull out and test |
981 | - self.database.put_record(Record({"key1_1":"val1_1","key1_2":"val1_2","key1_3":"val1_3","record_type":"test.com"})) |
982 | - self.database.put_record(Record({"key2_1":"val2_1","key2_2":"val2_2","key2_3":"val2_3","record_type":"test.com"})) |
983 | - self.database.put_record(Record({"key13_1":"va31_1","key3_2":"val3_2","key3_3":"val3_3","record_type":"test.com"})) |
984 | + self.database.put_record(Record({ |
985 | + "key1_1": "val1_1", "key1_2": "val1_2", "key1_3": "val1_3", |
986 | + "record_type": "test.com"})) |
987 | + self.database.put_record(Record({ |
988 | + "key2_1": "val2_1", "key2_2": "val2_2", "key2_3": "val2_3", |
989 | + "record_type": "test.com"})) |
990 | + self.database.put_record(Record({ |
991 | + "key13_1": "va31_1", "key3_2": "val3_2", "key3_3": "val3_3", |
992 | + "record_type": "test.com"})) |
993 | |
994 | def tearDown(self): |
995 | """tear down each test""" |
996 | del self.database._server[self.dbname] |
997 | - if random.choice([1,2,3,4]) == 3: # don't harass it unnecessarily |
998 | - print u"\u2620", # death |
999 | - stop_couchdb() |
1000 | |
1001 | def test_get_records_by_record_type_save_view(self): |
1002 | """Test getting mutliple records by type""" |
1003 | - records = self.database.get_records(record_type="test.com",create_view=True) |
1004 | + records = self.database.get_records( |
1005 | + record_type="test.com",create_view=True) |
1006 | self.assertEqual(3,len(records)) |
1007 | |
1008 | - |
1009 | def test_get_record(self): |
1010 | """Test getting a record.""" |
1011 | record = Record({'record_number': 0}, record_type="http://example.com/") |
1012 | @@ -122,14 +125,18 @@ |
1013 | }""" |
1014 | |
1015 | # add two and delete two. |
1016 | - self.assertRaises(KeyError, self.database.delete_view, view1_name, design_doc) |
1017 | - self.assertRaises(KeyError, self.database.delete_view, view2_name, design_doc) |
1018 | + self.assertRaises( |
1019 | + KeyError, self.database.delete_view, view1_name, design_doc) |
1020 | + self.assertRaises( |
1021 | + KeyError, self.database.delete_view, view2_name, design_doc) |
1022 | self.database.add_view(view1_name, map_js, reduce_js, design_doc) |
1023 | self.database.add_view(view2_name, map_js, reduce_js, design_doc) |
1024 | self.database.delete_view(view1_name, design_doc) |
1025 | - self.assertRaises(KeyError, self.database.delete_view, view1_name, design_doc) |
1026 | + self.assertRaises( |
1027 | + KeyError, self.database.delete_view, view1_name, design_doc) |
1028 | self.database.delete_view(view2_name, design_doc) |
1029 | - self.assertRaises(KeyError, self.database.delete_view, view2_name, design_doc) |
1030 | + self.assertRaises( |
1031 | + KeyError, self.database.delete_view, view2_name, design_doc) |
1032 | |
1033 | def test_func_get_records(self): |
1034 | record_ids_we_care_about = set() |
1035 | |
1036 | === modified file 'desktopcouch/start_local_couchdb.py' |
1037 | --- desktopcouch/start_local_couchdb.py 2009-08-19 16:00:01 +0000 |
1038 | +++ desktopcouch/start_local_couchdb.py 2009-08-21 22:45:24 +0000 |
1039 | @@ -16,6 +16,8 @@ |
1040 | # along with desktopcouch. If not, see <http://www.gnu.org/licenses/>. |
1041 | # |
1042 | # Author: Stuart Langridge <stuart.langridge@canonical.com> |
1043 | +# Eric Casteleijn <eric.casteleijn@canonical.com> |
1044 | + |
1045 | """ |
1046 | Start local CouchDB server. |
1047 | Steps: |
1048 | @@ -54,40 +56,31 @@ |
1049 | fd.write("\n") |
1050 | fd.close() |
1051 | |
1052 | -def create_ini_file(): |
1053 | +def create_ini_file( |
1054 | + ini_path=local_files.FILE_INI, db_dir=local_files.DIR_DB, |
1055 | + log_path=local_files.FILE_LOG, port="0"): |
1056 | """Write CouchDB ini file if not already present""" |
1057 | - # FIXME add update trigger folder |
1058 | - #update_trigger_dir = [ |
1059 | - # 'lib', 'canonical', 'ubuntuone', 'cloud_server', 'update_triggers'] |
1060 | - # |
1061 | - #timestamp_trigger = os.path.join( |
1062 | - # *update_trigger_dir + ['timestamp_trigger.py']) |
1063 | - #update_trigger = os.path.join( |
1064 | - # *update_trigger_dir + ['update_trigger.py']) |
1065 | - |
1066 | - if os.path.exists(local_files.FILE_INI): |
1067 | + if os.path.exists(ini_path): |
1068 | return |
1069 | - |
1070 | - local = { |
1071 | + ini = { |
1072 | 'couchdb': { |
1073 | - 'database_dir': local_files.DIR_DB, |
1074 | - 'view_index_dir': local_files.DIR_DB, |
1075 | + 'database_dir': db_dir, |
1076 | + 'view_index_dir': db_dir, |
1077 | }, |
1078 | 'httpd': { |
1079 | 'bind_address': '127.0.0.1', |
1080 | - 'port': "0", |
1081 | + 'port': port, |
1082 | }, |
1083 | 'log': { |
1084 | - 'file': local_files.FILE_LOG, |
1085 | + 'file': log_path, |
1086 | 'level': 'info', |
1087 | }, |
1088 | } |
1089 | - |
1090 | - dump_ini(local, local_files.FILE_INI) |
1091 | - |
1092 | -def run_couchdb(): |
1093 | + dump_ini(ini, ini_path) |
1094 | + |
1095 | +def run_couchdb(exec_command=local_files.COUCH_EXEC_COMMAND): |
1096 | """Actually start the CouchDB process""" |
1097 | - local_exec = local_files.COUCH_EXEC_COMMAND + ['-b'] |
1098 | + local_exec = exec_command + ['-b'] |
1099 | try: |
1100 | # subprocess is buggy. Chad patched, but that takes time to propagate. |
1101 | proc = subprocess.Popen(local_exec) |
1102 | @@ -109,39 +102,42 @@ |
1103 | |
1104 | def update_design_documents(): |
1105 | """Check system design documents and update any that need updating |
1106 | - |
1107 | - A database should be created if |
1108 | + |
1109 | + A database should be created if |
1110 | $XDG_DATA_DIRs/desktop-couch/databases/dbname/database.cfg exists |
1111 | Design docs are defined by the existence of |
1112 | - $XDG_DATA_DIRs/desktop-couch/databases/dbname/_design/designdocname/views/viewname/map.js |
1113 | + $XDG_DATA_DIRs/desktop-couch/databases/dbname/_design/designdocname/views/viewname/map.js |
1114 | reduce.js may also exist in the same folder. |
1115 | """ |
1116 | for base in xdg.BaseDirectory.xdg_data_dirs: |
1117 | - db_spec = os.path.join(base, "desktop-couch", "databases", "*", "database.cfg") |
1118 | + db_spec = os.path.join( |
1119 | + base, "desktop-couch", "databases", "*", "database.cfg") |
1120 | for database_path in glob.glob(db_spec): |
1121 | database_root = os.path.split(database_path)[0] |
1122 | database_name = os.path.split(database_root)[1] |
1123 | # Just the presence of database.cfg is enough to create the database |
1124 | db = CouchDatabase(database_name, create=True) |
1125 | # look for design documents |
1126 | - dd_spec = os.path.join(database_root, "_design", "*", "views", "*", "map.js") |
1127 | + dd_spec = os.path.join( |
1128 | + database_root, "_design", "*", "views", "*", "map.js") |
1129 | for dd_path in glob.glob(dd_spec): |
1130 | view_root = os.path.split(dd_path)[0] |
1131 | view_name = os.path.split(view_root)[1] |
1132 | dd_root = os.path.split(os.path.split(view_root)[0])[0] |
1133 | dd_name = os.path.split(dd_root)[1] |
1134 | - |
1135 | + |
1136 | def load_js_file(filename_no_extension): |
1137 | - fn = os.path.join(view_root, "%s.js" % (filename_no_extension)) |
1138 | + fn = os.path.join( |
1139 | + view_root, "%s.js" % (filename_no_extension)) |
1140 | if not os.path.isfile(fn): return None |
1141 | fp = open(fn) |
1142 | data = fp.read() |
1143 | fp.close() |
1144 | return data |
1145 | - |
1146 | + |
1147 | mapjs = load_js_file("map") |
1148 | reducejs = load_js_file("reduce") |
1149 | - |
1150 | + |
1151 | # XXX check whether this already exists or not, rather |
1152 | # than inefficiently just overwriting it regardless |
1153 | db.add_view(view_name, mapjs, reducejs, dd_name) |
1154 | @@ -150,13 +146,16 @@ |
1155 | """Write out an HTML document that the user can bookmark to find their DB""" |
1156 | bookmark_file = os.path.join(local_files.DIR_DB, "couchdb.html") |
1157 | |
1158 | - if os.path.exists(os.path.join(os.path.split(__file__)[0], "../data/couchdb.tmpl")): |
1159 | - bookmark_template = os.path.join(os.path.split(__file__)[0], "../data/couchdb.tmpl") |
1160 | + if os.path.exists( |
1161 | + os.path.join(os.path.split(__file__)[0], "../data/couchdb.tmpl")): |
1162 | + bookmark_template = os.path.join( |
1163 | + os.path.split(__file__)[0], "../data/couchdb.tmpl") |
1164 | else: |
1165 | for base in xdg.BaseDirectory.xdg_data_dirs: |
1166 | template_path = os.path.join(base, "desktopcouch", "couchdb.tmpl") |
1167 | if os.path.exists(template_path): |
1168 | - bookmark_template = os.path.join(os.path.split(__file__)[0], template_path) |
1169 | + bookmark_template = os.path.join( |
1170 | + os.path.split(__file__)[0], template_path) |
1171 | |
1172 | fp = open(bookmark_template) |
1173 | html = fp.read() |
1174 | @@ -175,7 +174,8 @@ |
1175 | continue |
1176 | |
1177 | if port is None: |
1178 | - print "We couldn't find desktop-CouchDB's network port. Bookmark file not written." |
1179 | + print ("We couldn't find desktop-CouchDB's network port. Bookmark " |
1180 | + "file not written.") |
1181 | try: |
1182 | os.remove(bookmark_file) |
1183 | except OSError: |
1184 | |
1185 | === modified file 'desktopcouch/tests/test_local_files.py' |
1186 | --- desktopcouch/tests/test_local_files.py 2009-08-04 12:31:15 +0000 |
1187 | +++ desktopcouch/tests/test_local_files.py 2009-08-21 21:57:37 +0000 |
1188 | @@ -1,28 +1,15 @@ |
1189 | """testing desktopcouch/local_files.py module""" |
1190 | |
1191 | import testtools |
1192 | -import os |
1193 | |
1194 | class TestLocalFiles(testtools.TestCase): |
1195 | """Testing that local files returns the right things""" |
1196 | def test_all_files_returned(self): |
1197 | "Does local_files list all the files that it needs to?" |
1198 | import desktopcouch.local_files |
1199 | - for required in ["FILE_LOG", "FILE_INI", "FILE_PID", "FILE_STDOUT", |
1200 | - "FILE_STDERR", "DIR_DB", "COUCH_EXE", "COUCH_EXEC_COMMAND"]: |
1201 | + for required in [ |
1202 | + "FILE_LOG", "FILE_INI", "FILE_PID", "FILE_STDOUT", |
1203 | + "FILE_STDERR", "DIR_DB", "COUCH_EXE", "COUCH_EXEC_COMMAND"]: |
1204 | self.assertTrue(required in dir(desktopcouch.local_files)) |
1205 | |
1206 | - def DISABLED_test_file_locations(self): |
1207 | - """This stopped working when we split desktopcouch into its own |
1208 | - top-level package.""" |
1209 | |
1210 | - "Are the files in local_files actually correct?" |
1211 | - # Only test one file; if one's right the others should be too |
1212 | - import desktopcouch.local_files |
1213 | - thisfolder = os.path.split(__file__)[0] |
1214 | - tmpfolder = os.path.join(thisfolder, "..", "..", "..", "..", "tmp") |
1215 | - pidfile = os.path.join(tmpfolder, "desktop-couchdb.pid") |
1216 | - flatpidfile = os.path.realpath(pidfile) |
1217 | - self.assertEqual(flatpidfile, desktopcouch.local_files.FILE_PID) |
1218 | - |
1219 | - |
1220 | |
1221 | === modified file 'desktopcouch/tests/test_start_local_couchdb.py' |
1222 | --- desktopcouch/tests/test_start_local_couchdb.py 2009-08-20 18:20:18 +0000 |
1223 | +++ desktopcouch/tests/test_start_local_couchdb.py 2009-08-21 21:57:37 +0000 |
1224 | @@ -3,7 +3,8 @@ |
1225 | import testtools |
1226 | import os, tempfile, sys |
1227 | import desktopcouch |
1228 | -sys.path.append(os.path.join(os.path.split(desktopcouch.__file__)[0], "..", "contrib")) |
1229 | +sys.path.append( |
1230 | + os.path.join(os.path.split(desktopcouch.__file__)[0], "..", "contrib")) |
1231 | from mocker import Mocker |
1232 | |
1233 | class TestUpdateDesignDocuments(testtools.TestCase): |
1234 | @@ -16,37 +17,37 @@ |
1235 | self.tmpdir = tempfile.mkdtemp(dir=branch_root) |
1236 | self.basedir = os.path.join(self.tmpdir, "desktop-couch") |
1237 | os.mkdir(self.basedir) |
1238 | - DIRS = [ |
1239 | - "databases", |
1240 | - "databases/nocfg", |
1241 | - "databases/cfg", |
1242 | - "databases/cfg_and_empty_design", |
1243 | - "databases/cfg_and_empty_design/_design", |
1244 | + DIRS = [ |
1245 | + "databases", |
1246 | + "databases/nocfg", |
1247 | + "databases/cfg", |
1248 | + "databases/cfg_and_empty_design", |
1249 | + "databases/cfg_and_empty_design/_design", |
1250 | "databases/cfg_and_design_no_views", |
1251 | - "databases/cfg_and_design_no_views/_design", |
1252 | - "databases/cfg_and_design_no_views/_design/doc1", |
1253 | - "databases/cfg_and_design_no_views/_design/doc1/views", |
1254 | + "databases/cfg_and_design_no_views/_design", |
1255 | + "databases/cfg_and_design_no_views/_design/doc1", |
1256 | + "databases/cfg_and_design_no_views/_design/doc1/views", |
1257 | "databases/cfg_and_design_one_view_no_map", |
1258 | - "databases/cfg_and_design_one_view_no_map/_design", |
1259 | - "databases/cfg_and_design_one_view_no_map/_design/doc1", |
1260 | - "databases/cfg_and_design_one_view_no_map/_design/doc1/views", |
1261 | - "databases/cfg_and_design_one_view_no_map/_design/doc1/views/view1", |
1262 | + "databases/cfg_and_design_one_view_no_map/_design", |
1263 | + "databases/cfg_and_design_one_view_no_map/_design/doc1", |
1264 | + "databases/cfg_and_design_one_view_no_map/_design/doc1/views", |
1265 | + "databases/cfg_and_design_one_view_no_map/_design/doc1/views/view1", |
1266 | "databases/cfg_and_design_one_view_map_no_reduce", |
1267 | - "databases/cfg_and_design_one_view_map_no_reduce/_design", |
1268 | - "databases/cfg_and_design_one_view_map_no_reduce/_design/doc1", |
1269 | - "databases/cfg_and_design_one_view_map_no_reduce/_design/doc1/views", |
1270 | - "databases/cfg_and_design_one_view_map_no_reduce/_design/doc1/views/view1", |
1271 | + "databases/cfg_and_design_one_view_map_no_reduce/_design", |
1272 | + "databases/cfg_and_design_one_view_map_no_reduce/_design/doc1", |
1273 | + "databases/cfg_and_design_one_view_map_no_reduce/_design/doc1/views", |
1274 | + "databases/cfg_and_design_one_view_map_no_reduce/_design/doc1/views/view1", |
1275 | "databases/cfg_and_design_one_view_map_reduce", |
1276 | - "databases/cfg_and_design_one_view_map_reduce/_design", |
1277 | - "databases/cfg_and_design_one_view_map_reduce/_design/doc1", |
1278 | - "databases/cfg_and_design_one_view_map_reduce/_design/doc1/views", |
1279 | - "databases/cfg_and_design_one_view_map_reduce/_design/doc1/views/view1", |
1280 | + "databases/cfg_and_design_one_view_map_reduce/_design", |
1281 | + "databases/cfg_and_design_one_view_map_reduce/_design/doc1", |
1282 | + "databases/cfg_and_design_one_view_map_reduce/_design/doc1/views", |
1283 | + "databases/cfg_and_design_one_view_map_reduce/_design/doc1/views/view1", |
1284 | "databases/cfg_and_design_two_views_map_reduce", |
1285 | - "databases/cfg_and_design_two_views_map_reduce/_design", |
1286 | - "databases/cfg_and_design_two_views_map_reduce/_design/doc1", |
1287 | - "databases/cfg_and_design_two_views_map_reduce/_design/doc1/views", |
1288 | - "databases/cfg_and_design_two_views_map_reduce/_design/doc1/views/view1", |
1289 | - "databases/cfg_and_design_two_views_map_reduce/_design/doc1/views/view2", |
1290 | + "databases/cfg_and_design_two_views_map_reduce/_design", |
1291 | + "databases/cfg_and_design_two_views_map_reduce/_design/doc1", |
1292 | + "databases/cfg_and_design_two_views_map_reduce/_design/doc1/views", |
1293 | + "databases/cfg_and_design_two_views_map_reduce/_design/doc1/views/view1", |
1294 | + "databases/cfg_and_design_two_views_map_reduce/_design/doc1/views/view2", |
1295 | ] |
1296 | FILES = { |
1297 | "databases/cfg/database.cfg": "", |
1298 | @@ -78,7 +79,7 @@ |
1299 | fp = open(os.path.join(self.basedir, f), "w") |
1300 | fp.write(data) |
1301 | fp.close() |
1302 | - |
1303 | + |
1304 | def tearDown(self): |
1305 | # delete temp folder |
1306 | for root, dirs, files in os.walk(self.tmpdir, topdown=False): |
1307 | @@ -86,10 +87,10 @@ |
1308 | os.remove(os.path.join(root, name)) |
1309 | for name in dirs: |
1310 | os.rmdir(os.path.join(root, name)) |
1311 | - os.rmdir(self.tmpdir) |
1312 | + os.rmdir(self.tmpdir) |
1313 | |
1314 | def test_create_databases_and_design_docs(self): |
1315 | - """Are databases and design documents correctly |
1316 | + """Are databases and design documents correctly |
1317 | created from the filesystem?""" |
1318 | # poke local_files so that it returns our temp folder |
1319 | os.environ['XDG_DATA_HOME'] = self.tmpdir |
1320 | @@ -101,11 +102,11 @@ |
1321 | import xdg.BaseDirectory |
1322 | reload(xdg.BaseDirectory) |
1323 | |
1324 | - |
1325 | + |
1326 | # Mock CouchDatabase |
1327 | mocker = Mocker() |
1328 | couchdb = mocker.replace("desktopcouch.records.server.CouchDatabase") |
1329 | - |
1330 | + |
1331 | # databases that should be created |
1332 | couchdb("cfg", create=True) |
1333 | couchdb("cfg_and_empty_design", create=True) |
1334 | @@ -114,28 +115,28 @@ |
1335 | couchdb("cfg_and_design_one_view_map_no_reduce", create=True) |
1336 | dbmock1 = mocker.mock() |
1337 | mocker.result(dbmock1) |
1338 | - dbmock1.add_view("view1", "cfg_and_design_one_view_map_no_reduce:map", |
1339 | + dbmock1.add_view("view1", "cfg_and_design_one_view_map_no_reduce:map", |
1340 | None, "doc1") |
1341 | couchdb("cfg_and_design_one_view_map_reduce", create=True) |
1342 | dbmock2 = mocker.mock() |
1343 | mocker.result(dbmock2) |
1344 | - dbmock2.add_view("view1", "cfg_and_design_one_view_map_reduce:map", |
1345 | + dbmock2.add_view("view1", "cfg_and_design_one_view_map_reduce:map", |
1346 | "cfg_and_design_one_view_map_reduce:reduce", "doc1") |
1347 | couchdb("cfg_and_design_two_views_map_reduce", create=True) |
1348 | dbmock3 = mocker.mock() |
1349 | mocker.result(dbmock3) |
1350 | - dbmock3.add_view("view1", "cfg_and_design_two_views_map_reduce:map1", |
1351 | + dbmock3.add_view("view1", "cfg_and_design_two_views_map_reduce:map1", |
1352 | "cfg_and_design_two_views_map_reduce:reduce1", "doc1") |
1353 | - dbmock3.add_view("view2", "cfg_and_design_two_views_map_reduce:map2", |
1354 | + dbmock3.add_view("view2", "cfg_and_design_two_views_map_reduce:map2", |
1355 | "cfg_and_design_two_views_map_reduce:reduce2", "doc1") |
1356 | - |
1357 | + |
1358 | # actually call update_design_documents to confirm that it creates |
1359 | # all the right things |
1360 | mocker.replay() |
1361 | from desktopcouch.start_local_couchdb import update_design_documents |
1362 | update_design_documents() |
1363 | - |
1364 | + |
1365 | mocker.restore() |
1366 | mocker.verify() |
1367 | - |
1368 | + |
1369 |
No longer uses the user's desktopcouch couchdb, which was super ungood. Now creating everything in /tmp and running against that. And leaving it around, and running after the tests... which is only normal ungood. Any pointers on how to execute some code (to stop couch and remove the tempdir) after all the tests have run (or even at the end of each testcase) welcome. I believe Zope testcases have support for this, but my brain is fried for the week.
This has the branch lp:~rick-rickspencer3/desktopcouch/CouchWidget-tests-and-robustness merged in, and any conflicts removed.