Merge lp:~allenap/launchpad/remove-xmlrpclib-marshalling-bug-254999 into lp:launchpad
- remove-xmlrpclib-marshalling-bug-254999
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Gavin Panella |
Approved revision: | not available |
Merged at revision: | not available |
Proposed branch: | lp:~allenap/launchpad/remove-xmlrpclib-marshalling-bug-254999 |
Merge into: | lp:launchpad |
Diff against target: |
894 lines (+102/-210) 7 files modified
lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt (+13/-17) lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt (+10/-10) lib/lp/bugs/externalbugtracker/bugzilla.py (+18/-71) lib/lp/bugs/externalbugtracker/xmlrpc.py (+2/-3) lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt (+26/-41) lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt (+22/-35) lib/lp/bugs/tests/externalbugtracker.py (+11/-33) |
To merge this branch: | bzr merge lp:~allenap/launchpad/remove-xmlrpclib-marshalling-bug-254999 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Brad Crittenden (community) | code | Approve | |
Review via email: mp+16436@code.launchpad.net |
Commit message
Remove xmlrpclib.DateTime conversion hacks from external bug tracker code. Python 2.5's xmlrpclib groks datetime.datetime.
Description of the change
Gavin Panella (allenap) wrote : | # |
Brad Crittenden (bac) wrote : | # |
Hi Gavin,
The changes you made look good but I don't think you got all of the spots that need to be fixed. What about these others?
bzr ls -VR --kind=file --null | xargs -0 grep -In 254999
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
Gavin Panella (allenap) wrote : | # |
Thanks for spotting that I'd missed those. The incremental diff is
pretty big, but a lot of it is just the same date format changes in
innumerable doctests.
1 | === modified file 'lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt' | |||
2 | --- lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt 2009-12-21 15:03:42 +0000 | |||
3 | +++ lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt 2009-12-23 10:18:19 +0000 | |||
4 | @@ -139,8 +139,8 @@ | |||
5 | 139 | >>> def print_bugs(bugs): | 139 | >>> def print_bugs(bugs): |
6 | 140 | ... for bug in sorted(bugs): | 140 | ... for bug in sorted(bugs): |
7 | 141 | ... print "Bug %s:" % bug | 141 | ... print "Bug %s:" % bug |
10 | 142 | ... for key in sorted(bugzilla._bugs[bug]): | 142 | ... for key in sorted(bugs[bug]): |
11 | 143 | ... print " %s: %s" % (key, bugzilla._bugs[bug][key]) | 143 | ... print " %s: %s" % (key, bugs[bug][key]) |
12 | 144 | ... print "\n" | 144 | ... print "\n" |
13 | 145 | 145 | ||
14 | 146 | >>> print_bugs(bugzilla._bugs) | 146 | >>> print_bugs(bugzilla._bugs) |
15 | @@ -148,11 +148,11 @@ | |||
16 | 148 | alias: | 148 | alias: |
17 | 149 | assigned_to: test@canonical.com | 149 | assigned_to: test@canonical.com |
18 | 150 | component: GPPSystems | 150 | component: GPPSystems |
20 | 151 | creation_time: 20080610T16:19:53 | 151 | creation_time: 2008-06-10 16:19:53 |
21 | 152 | id: 1 | 152 | id: 1 |
22 | 153 | internals:... | 153 | internals:... |
23 | 154 | is_open: True | 154 | is_open: True |
25 | 155 | last_change_time: 20080610T16:19:53 | 155 | last_change_time: 2008-06-10 16:19:53 |
26 | 156 | priority: P1 | 156 | priority: P1 |
27 | 157 | product: Marvin | 157 | product: Marvin |
28 | 158 | resolution: FIXED | 158 | resolution: FIXED |
29 | @@ -165,11 +165,11 @@ | |||
30 | 165 | alias: bug-two | 165 | alias: bug-two |
31 | 166 | assigned_to: marvin@heartofgold.ship | 166 | assigned_to: marvin@heartofgold.ship |
32 | 167 | component: Crew | 167 | component: Crew |
34 | 168 | creation_time: 20080611T09:23:12 | 168 | creation_time: 2008-06-11 09:23:12 |
35 | 169 | id: 2 | 169 | id: 2 |
36 | 170 | internals:... | 170 | internals:... |
37 | 171 | is_open: True | 171 | is_open: True |
39 | 172 | last_change_time: 20080611T09:24:29 | 172 | last_change_time: 2008-06-11 09:24:29 |
40 | 173 | priority: P1 | 173 | priority: P1 |
41 | 174 | product: HeartOfGold | 174 | product: HeartOfGold |
42 | 175 | resolution: | 175 | resolution: |
43 | @@ -194,20 +194,16 @@ | |||
44 | 194 | >>> bugzilla.initializeRemoteBugDB([2, 'bug-two']) | 194 | >>> bugzilla.initializeRemoteBugDB([2, 'bug-two']) |
45 | 195 | CALLED Bug.get({'ids': [2, 'bug-two'], 'permissive': True}) | 195 | CALLED Bug.get({'ids': [2, 'bug-two'], 'permissive': True}) |
46 | 196 | 196 | ||
52 | 197 | >>> for bug in sorted(bugzilla._bugs): | 197 | >>> print_bugs(bugzilla._bugs) |
48 | 198 | ... print "Bug %r:" % bug | ||
49 | 199 | ... for key in sorted(bugzilla._bugs[bug]): | ||
50 | 200 | ... print " %s: %s" % (key, bugzilla._bugs[bug][key]) | ||
51 | 201 | ... print "\n" | ||
53 | 202 | Bug 2: | 198 | Bug 2: |
54 | 203 | alias: bug-two | 199 | alias: bug-two |
55 | 204 | assigned_to: marvin@heartofgold.ship | 200 | assigned_to: marvin@heartofgold.ship |
56 | 205 | component: Crew | 201 | component: Crew |
58 | 206 | creation_time: 20080611T09:23:12 | 202 | creation_time: 2008-06-11 09:23:12 |
59 | 207 | id: 2 | 203 | id: 2 |
60 | 208 | internals:... | 204 | internals:... |
61 | 209 | is_open: True | 205 | is_open: True |
63 | 210 | last_change_time: 20080611T09:24:29 | 206 | last_change_time: 2008-06-11 09:24:29 |
64 | 211 | priority: P1 | 207 | priority: P1 |
65 | 212 | product: HeartOfGold | 208 | product: HeartOfGold |
66 | 213 | resolution: | 209 | resolution: |
67 | @@ -450,14 +446,14 @@ | |||
68 | 450 | id: 1 | 446 | id: 1 |
69 | 451 | is_private: False | 447 | is_private: False |
70 | 452 | text: I'd really appreciate it if Marvin would enjoy life a bit. | 448 | text: I'd really appreciate it if Marvin would enjoy life a bit. |
72 | 453 | time: 20080616T12:44:29 | 449 | time: 2008-06-16 12:44:29 |
73 | 454 | Comment 3: | 450 | Comment 3: |
74 | 455 | author: marvin | 451 | author: marvin |
75 | 456 | bug_id: 1 | 452 | bug_id: 1 |
76 | 457 | id: 3 | 453 | id: 3 |
77 | 458 | is_private: False | 454 | is_private: False |
78 | 459 | text: Life? Don't talk to me about life. | 455 | text: Life? Don't talk to me about life. |
80 | 460 | time: 20080616T13:22:29 | 456 | time: 2008-06-16 13:22:29 |
81 | 461 | 457 | ||
82 | 462 | If we try to fetch comments that don't belong to the current bug | 458 | If we try to fetch comments that don't belong to the current bug |
83 | 463 | fetchComments() will silently ignore them. | 459 | fetchComments() will silently ignore them. |
84 | @@ -477,7 +473,7 @@ | |||
85 | 477 | id: 1 | 473 | id: 1 |
86 | 478 | is_private: False | 474 | is_private: False |
87 | 479 | text: I'd really appreciate it if Marvin would enjoy life a bit. | 475 | text: I'd really appreciate it if Marvin would enjoy life a bit. |
89 | 480 | time: 20080616T12:44:29 | 476 | time: 2008-06-16 12:44:29 |
90 | 481 | 477 | ||
91 | 482 | 478 | ||
92 | 483 | getPosterForComment() | 479 | getPosterForComment() |
93 | @@ -521,7 +517,7 @@ | |||
94 | 521 | field on the imported comment. | 517 | field on the imported comment. |
95 | 522 | 518 | ||
96 | 523 | >>> print bugzilla._bugs[2]['comments'][2]['time'] | 519 | >>> print bugzilla._bugs[2]['comments'][2]['time'] |
98 | 524 | 20080616T13:08:08 | 520 | 2008-06-16 13:08:08 |
99 | 525 | 521 | ||
100 | 526 | >>> print message.datecreated | 522 | >>> print message.datecreated |
101 | 527 | 2008-06-16 13:08:08+00:00 | 523 | 2008-06-16 13:08:08+00:00 |
102 | 528 | 524 | ||
103 | === modified file 'lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt' | |||
104 | --- lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt 2009-12-21 15:03:42 +0000 | |||
105 | +++ lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt 2009-12-23 10:23:47 +0000 | |||
106 | @@ -204,8 +204,8 @@ | |||
107 | 204 | >>> def print_bugs(bugs): | 204 | >>> def print_bugs(bugs): |
108 | 205 | ... for bug in sorted(bugs): | 205 | ... for bug in sorted(bugs): |
109 | 206 | ... print "Bug %s:" % bug | 206 | ... print "Bug %s:" % bug |
112 | 207 | ... for key in sorted(bugzilla._bugs[bug]): | 207 | ... for key in sorted(bugs[bug]): |
113 | 208 | ... print " %s: %s" % (key, bugzilla._bugs[bug][key]) | 208 | ... print " %s: %s" % (key, bugs[bug][key]) |
114 | 209 | ... print "\n" | 209 | ... print "\n" |
115 | 210 | 210 | ||
116 | 211 | >>> print_bugs(bugzilla._bugs) | 211 | >>> print_bugs(bugzilla._bugs) |
117 | @@ -213,11 +213,11 @@ | |||
118 | 213 | alias: | 213 | alias: |
119 | 214 | assigned_to: test@canonical.com | 214 | assigned_to: test@canonical.com |
120 | 215 | component: GPPSystems | 215 | component: GPPSystems |
122 | 216 | creation_time: 20080610T16:19:53 | 216 | creation_time: 2008-06-10 16:19:53 |
123 | 217 | id: 1 | 217 | id: 1 |
124 | 218 | internals:... | 218 | internals:... |
125 | 219 | is_open: True | 219 | is_open: True |
127 | 220 | last_change_time: 20080610T16:19:53 | 220 | last_change_time: 2008-06-10 16:19:53 |
128 | 221 | priority: P1 | 221 | priority: P1 |
129 | 222 | product: Marvin | 222 | product: Marvin |
130 | 223 | resolution: FIXED | 223 | resolution: FIXED |
131 | @@ -230,11 +230,11 @@ | |||
132 | 230 | alias: bug-two | 230 | alias: bug-two |
133 | 231 | assigned_to: marvin@heartofgold.ship | 231 | assigned_to: marvin@heartofgold.ship |
134 | 232 | component: Crew | 232 | component: Crew |
136 | 233 | creation_time: 20080611T09:23:12 | 233 | creation_time: 2008-06-11 09:23:12 |
137 | 234 | id: 2 | 234 | id: 2 |
138 | 235 | internals:... | 235 | internals:... |
139 | 236 | is_open: True | 236 | is_open: True |
141 | 237 | last_change_time: 20080611T09:24:29 | 237 | last_change_time: 2008-06-11 09:24:29 |
142 | 238 | priority: P1 | 238 | priority: P1 |
143 | 239 | product: HeartOfGold | 239 | product: HeartOfGold |
144 | 240 | resolution: | 240 | resolution: |
145 | @@ -416,13 +416,13 @@ | |||
146 | 416 | id: 1 | 416 | id: 1 |
147 | 417 | number: 1 | 417 | number: 1 |
148 | 418 | text: I'd really appreciate it if Marvin would enjoy life a bit. | 418 | text: I'd really appreciate it if Marvin would enjoy life a bit. |
150 | 419 | time: 20080616T12:44:29 | 419 | time: 2008-06-16 12:44:29 |
151 | 420 | Comment 3: | 420 | Comment 3: |
152 | 421 | author: marvin | 421 | author: marvin |
153 | 422 | id: 3 | 422 | id: 3 |
154 | 423 | number: 2 | 423 | number: 2 |
155 | 424 | text: Life? Don't talk to me about life. | 424 | text: Life? Don't talk to me about life. |
157 | 425 | time: 20080616T13:22:29 | 425 | time: 2008-06-16 13:22:29 |
158 | 426 | 426 | ||
159 | 427 | 427 | ||
160 | 428 | Pushing comments to remote systems | 428 | Pushing comments to remote systems |
161 | @@ -560,11 +560,11 @@ | |||
162 | 560 | alias: bug-two | 560 | alias: bug-two |
163 | 561 | assigned_to: marvin@heartofgold.ship | 561 | assigned_to: marvin@heartofgold.ship |
164 | 562 | component: Crew | 562 | component: Crew |
166 | 563 | creation_time: 20080611T09:23:12 | 563 | creation_time: 2008-06-11 09:23:12 |
167 | 564 | id: 2 | 564 | id: 2 |
168 | 565 | internals:... | 565 | internals:... |
169 | 566 | is_open: True | 566 | is_open: True |
171 | 567 | last_change_time: 20080611T09:24:29 | 567 | last_change_time: 2008-06-11 09:24:29 |
172 | 568 | priority: P1 | 568 | priority: P1 |
173 | 569 | product: HeartOfGold | 569 | product: HeartOfGold |
174 | 570 | resolution: | 570 | resolution: |
175 | 571 | 571 | ||
176 | === modified file 'lib/lp/bugs/externalbugtracker/bugzilla.py' | |||
177 | --- lib/lp/bugs/externalbugtracker/bugzilla.py 2009-12-22 21:08:42 +0000 | |||
178 | +++ lib/lp/bugs/externalbugtracker/bugzilla.py 2009-12-23 10:21:32 +0000 | |||
179 | @@ -12,11 +12,9 @@ | |||
180 | 12 | ] | 12 | ] |
181 | 13 | 13 | ||
182 | 14 | import pytz | 14 | import pytz |
183 | 15 | import time | ||
184 | 16 | import xml.parsers.expat | 15 | import xml.parsers.expat |
185 | 17 | import xmlrpclib | 16 | import xmlrpclib |
186 | 18 | 17 | ||
187 | 19 | from datetime import datetime | ||
188 | 20 | from email.Utils import parseaddr | 18 | from email.Utils import parseaddr |
189 | 21 | from xml.dom import minidom | 19 | from xml.dom import minidom |
190 | 22 | 20 | ||
191 | @@ -505,28 +503,17 @@ | |||
192 | 505 | """See `IExternalBugTracker`.""" | 503 | """See `IExternalBugTracker`.""" |
193 | 506 | time_dict = self.xmlrpc_proxy.Bugzilla.time() | 504 | time_dict = self.xmlrpc_proxy.Bugzilla.time() |
194 | 507 | 505 | ||
195 | 508 | # Convert the XML-RPC DateTime we get back into a regular Python | ||
196 | 509 | # datetime. | ||
197 | 510 | server_db_timetuple = time.strptime( | ||
198 | 511 | str(time_dict['db_time']), '%Y%m%dT%H:%M:%S') | ||
199 | 512 | server_db_datetime = datetime(*server_db_timetuple[:6]) | ||
200 | 513 | |||
201 | 514 | # The server's DB time is the one that we want to use. However, | 506 | # The server's DB time is the one that we want to use. However, |
202 | 515 | # this may not be in UTC, so we need to convert it. Since we | 507 | # this may not be in UTC, so we need to convert it. Since we |
203 | 516 | # can't guarantee that the timezone data returned by the server | 508 | # can't guarantee that the timezone data returned by the server |
204 | 517 | # is sane, we work out the server's offset from UTC by looking | 509 | # is sane, we work out the server's offset from UTC by looking |
205 | 518 | # at the difference between the web_time and the web_time_utc | 510 | # at the difference between the web_time and the web_time_utc |
206 | 519 | # values. | 511 | # values. |
214 | 520 | server_web_time = time.strptime( | 512 | server_web_datetime = time_dict['web_time'] |
215 | 521 | str(time_dict['web_time']), '%Y%m%dT%H:%M:%S') | 513 | server_web_datetime_utc = time_dict['web_time_utc'] |
209 | 522 | server_web_datetime = datetime(*server_web_time[:6]) | ||
210 | 523 | server_web_time_utc = time.strptime( | ||
211 | 524 | str(time_dict['web_time_utc']), '%Y%m%dT%H:%M:%S') | ||
212 | 525 | server_web_datetime_utc = datetime(*server_web_time_utc[:6]) | ||
213 | 526 | |||
216 | 527 | server_utc_offset = server_web_datetime - server_web_datetime_utc | 514 | server_utc_offset = server_web_datetime - server_web_datetime_utc |
217 | 515 | server_db_datetime = time_dict['db_time'] | ||
218 | 528 | server_utc_datetime = server_db_datetime - server_utc_offset | 516 | server_utc_datetime = server_db_datetime - server_utc_offset |
219 | 529 | |||
220 | 530 | return server_utc_datetime.replace(tzinfo=pytz.timezone('UTC')) | 517 | return server_utc_datetime.replace(tzinfo=pytz.timezone('UTC')) |
221 | 531 | 518 | ||
222 | 532 | def _getActualBugId(self, bug_id): | 519 | def _getActualBugId(self, bug_id): |
223 | @@ -715,22 +702,9 @@ | |||
224 | 715 | # bug 248938). | 702 | # bug 248938). |
225 | 716 | comment_id = int(comment_id) | 703 | comment_id = int(comment_id) |
226 | 717 | comment = self._bugs[actual_bug_id]['comments'][comment_id] | 704 | comment = self._bugs[actual_bug_id]['comments'][comment_id] |
239 | 718 | 705 | return getUtility(IMessageSet).fromText( | |
228 | 719 | # Turn the time in the comment, which is an XML-RPC datetime | ||
229 | 720 | # into something more useful to us. | ||
230 | 721 | # XXX 2008-08-05 gmb (bug 254999): | ||
231 | 722 | # We can remove these lines once we upgrade to python 2.5. | ||
232 | 723 | comment_timestamp = time.mktime( | ||
233 | 724 | time.strptime(str(comment['time']), '%Y%m%dT%H:%M:%S')) | ||
234 | 725 | comment_datetime = datetime.fromtimestamp(comment_timestamp) | ||
235 | 726 | comment_datetime = comment_datetime.replace( | ||
236 | 727 | tzinfo=pytz.timezone('UTC')) | ||
237 | 728 | |||
238 | 729 | message = getUtility(IMessageSet).fromText( | ||
240 | 730 | owner=poster, subject='', content=comment['text'], | 706 | owner=poster, subject='', content=comment['text'], |
244 | 731 | datecreated=comment_datetime) | 707 | datecreated=comment['time'].replace(tzinfo=pytz.timezone('UTC'))) |
242 | 732 | |||
243 | 733 | return message | ||
245 | 734 | 708 | ||
246 | 735 | @needs_authentication | 709 | @needs_authentication |
247 | 736 | def addRemoteComment(self, remote_bug, comment_body, rfc822msgid): | 710 | def addRemoteComment(self, remote_bug, comment_body, rfc822msgid): |
248 | @@ -868,10 +842,7 @@ | |||
249 | 868 | 842 | ||
250 | 869 | # Return the UTC time sent by the server so that we don't have | 843 | # Return the UTC time sent by the server so that we don't have |
251 | 870 | # to care about timezones. | 844 | # to care about timezones. |
256 | 871 | server_timetuple = time.strptime( | 845 | server_utc_time = time_dict['utc_time'] |
253 | 872 | str(time_dict['utc_time']), '%Y%m%dT%H:%M:%S') | ||
254 | 873 | |||
255 | 874 | server_utc_time = datetime(*server_timetuple[:6]) | ||
257 | 875 | return server_utc_time.replace(tzinfo=pytz.timezone('UTC')) | 846 | return server_utc_time.replace(tzinfo=pytz.timezone('UTC')) |
258 | 876 | 847 | ||
259 | 877 | def getCommentIds(self, bug_watch): | 848 | def getCommentIds(self, bug_watch): |
260 | 878 | 849 | ||
261 | === modified file 'lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt' | |||
262 | --- lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt 2009-11-30 09:33:24 +0000 | |||
263 | +++ lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt 2009-12-23 10:53:40 +0000 | |||
264 | @@ -66,12 +66,12 @@ | |||
265 | 66 | >>> time_dict = server.Bugzilla.time() | 66 | >>> time_dict = server.Bugzilla.time() |
266 | 67 | >>> for key in sorted(time_dict): | 67 | >>> for key in sorted(time_dict): |
267 | 68 | ... print "%s: %s" % (key, time_dict[key]) | 68 | ... print "%s: %s" % (key, time_dict[key]) |
269 | 69 | db_time: 20080501T01:01:01 | 69 | db_time: 2008-05-01 01:01:01 |
270 | 70 | tz_name: UTC | 70 | tz_name: UTC |
271 | 71 | tz_offset: +0000 | 71 | tz_offset: +0000 |
272 | 72 | tz_short_name: UTC | 72 | tz_short_name: UTC |
275 | 73 | web_time: 20080501T01:01:01 | 73 | web_time: 2008-05-01 01:01:01 |
276 | 74 | web_time_utc: 20080501T01:01:01 | 74 | web_time_utc: 2008-05-01 01:01:01 |
277 | 75 | 75 | ||
278 | 76 | If the remote server is in a different timezone, the db_time and | 76 | If the remote server is in a different timezone, the db_time and |
279 | 77 | web_time items will be in the server's local timezone whilst | 77 | web_time items will be in the server's local timezone whilst |
280 | @@ -82,12 +82,12 @@ | |||
281 | 82 | >>> time_dict = server.Bugzilla.time() | 82 | >>> time_dict = server.Bugzilla.time() |
282 | 83 | >>> for key in sorted(time_dict): | 83 | >>> for key in sorted(time_dict): |
283 | 84 | ... print "%s: %s" % (key, time_dict[key]) | 84 | ... print "%s: %s" % (key, time_dict[key]) |
285 | 85 | db_time: 20080501T01:01:01 | 85 | db_time: 2008-05-01 01:01:01 |
286 | 86 | tz_name: CET | 86 | tz_name: CET |
287 | 87 | tz_offset: +0100 | 87 | tz_offset: +0100 |
288 | 88 | tz_short_name: CET | 88 | tz_short_name: CET |
291 | 89 | web_time: 20080501T01:01:01 | 89 | web_time: 2008-05-01 01:01:01 |
292 | 90 | web_time_utc: 20080501T00:01:01 | 90 | web_time_utc: 2008-05-01 00:01:01 |
293 | 91 | 91 | ||
294 | 92 | 92 | ||
295 | 93 | Getting bugs from the server | 93 | Getting bugs from the server |
296 | @@ -105,11 +105,11 @@ | |||
297 | 105 | alias: | 105 | alias: |
298 | 106 | assigned_to: test@canonical.com | 106 | assigned_to: test@canonical.com |
299 | 107 | component: GPPSystems | 107 | component: GPPSystems |
301 | 108 | creation_time: 20080610T16:19:53 | 108 | creation_time: 2008-06-10 16:19:53 |
302 | 109 | id: 1 | 109 | id: 1 |
303 | 110 | internals:... | 110 | internals:... |
304 | 111 | is_open: True | 111 | is_open: True |
306 | 112 | last_change_time: 20080610T16:19:53 | 112 | last_change_time: 2008-06-10 16:19:53 |
307 | 113 | priority: P1 | 113 | priority: P1 |
308 | 114 | product: Marvin | 114 | product: Marvin |
309 | 115 | resolution: FIXED | 115 | resolution: FIXED |
310 | @@ -135,16 +135,7 @@ | |||
311 | 135 | date / time. | 135 | date / time. |
312 | 136 | 136 | ||
313 | 137 | >>> from datetime import datetime | 137 | >>> from datetime import datetime |
314 | 138 | >>> from xmlrpclib import DateTime | ||
315 | 139 | >>> last_change_time = datetime(2008, 6, 11, 9, 0, 0) | 138 | >>> last_change_time = datetime(2008, 6, 11, 9, 0, 0) |
316 | 140 | |||
317 | 141 | # XXX 2009-08-21 gmb (bug 254999): | ||
318 | 142 | # We can remove this once we upgrade to python 2.5. We encode | ||
319 | 143 | # last_change_time into an XML-RPC DateTime manually. This is | ||
320 | 144 | # because xmlrpclib can't handle DateTime encoding within a | ||
321 | 145 | # dict. | ||
322 | 146 | >>> last_change_time = DateTime(last_change_time.timetuple()) | ||
323 | 147 | |||
324 | 148 | >>> return_value = server.Bug.search({ | 139 | >>> return_value = server.Bug.search({ |
325 | 149 | ... 'last_change_time': last_change_time, | 140 | ... 'last_change_time': last_change_time, |
326 | 150 | ... }) | 141 | ... }) |
327 | @@ -158,11 +149,11 @@ | |||
328 | 158 | alias: bug-two | 149 | alias: bug-two |
329 | 159 | assigned_to: marvin@heartofgold.ship | 150 | assigned_to: marvin@heartofgold.ship |
330 | 160 | component: Crew | 151 | component: Crew |
332 | 161 | creation_time: 20080611T09:23:12 | 152 | creation_time: 2008-06-11 09:23:12 |
333 | 162 | id: 2 | 153 | id: 2 |
334 | 163 | internals:... | 154 | internals:... |
335 | 164 | is_open: True | 155 | is_open: True |
337 | 165 | last_change_time: 20080611T09:24:29 | 156 | last_change_time: 2008-06-11 09:24:29 |
338 | 166 | priority: P1 | 157 | priority: P1 |
339 | 167 | product: HeartOfGold | 158 | product: HeartOfGold |
340 | 168 | resolution: | 159 | resolution: |
341 | @@ -175,7 +166,6 @@ | |||
342 | 175 | results to those IDs. | 166 | results to those IDs. |
343 | 176 | 167 | ||
344 | 177 | >>> last_change_time = datetime(2007, 6, 10, 1, 1, 1) | 168 | >>> last_change_time = datetime(2007, 6, 10, 1, 1, 1) |
345 | 178 | >>> last_change_time = DateTime(last_change_time.timetuple()) | ||
346 | 179 | >>> return_value = server.Bug.search({ | 169 | >>> return_value = server.Bug.search({ |
347 | 180 | ... 'id': [1], | 170 | ... 'id': [1], |
348 | 181 | ... 'last_change_time': last_change_time, | 171 | ... 'last_change_time': last_change_time, |
349 | @@ -188,11 +178,11 @@ | |||
350 | 188 | alias: | 178 | alias: |
351 | 189 | assigned_to: test@canonical.com | 179 | assigned_to: test@canonical.com |
352 | 190 | component: GPPSystems | 180 | component: GPPSystems |
354 | 191 | creation_time: 20080610T16:19:53 | 181 | creation_time: 2008-06-10 16:19:53 |
355 | 192 | id: 1 | 182 | id: 1 |
356 | 193 | internals:... | 183 | internals:... |
357 | 194 | is_open: True | 184 | is_open: True |
359 | 195 | last_change_time: 20080610T16:19:53 | 185 | last_change_time: 2008-06-10 16:19:53 |
360 | 196 | priority: P1 | 186 | priority: P1 |
361 | 197 | product: Marvin | 187 | product: Marvin |
362 | 198 | resolution: FIXED | 188 | resolution: FIXED |
363 | @@ -206,11 +196,6 @@ | |||
364 | 206 | 196 | ||
365 | 207 | >>> from datetime import timedelta | 197 | >>> from datetime import timedelta |
366 | 208 | >>> last_change_time = datetime.now() + timedelta(days=42) | 198 | >>> last_change_time = datetime.now() + timedelta(days=42) |
367 | 209 | |||
368 | 210 | >>> # XXX 2008-08-05 gmb (bug 254999): | ||
369 | 211 | >>> # We can remove this once we upgrade to python 2.5. | ||
370 | 212 | >>> last_change_time = DateTime(last_change_time.timetuple()) | ||
371 | 213 | |||
372 | 214 | >>> return_value = server.Bug.search({ | 199 | >>> return_value = server.Bug.search({ |
373 | 215 | ... 'last_change_time': last_change_time, | 200 | ... 'last_change_time': last_change_time, |
374 | 216 | ... }) | 201 | ... }) |
375 | @@ -232,11 +217,11 @@ | |||
376 | 232 | alias: bug-two | 217 | alias: bug-two |
377 | 233 | assigned_to: marvin@heartofgold.ship | 218 | assigned_to: marvin@heartofgold.ship |
378 | 234 | component: Crew | 219 | component: Crew |
380 | 235 | creation_time: 20080611T09:23:12 | 220 | creation_time: 2008-06-11 09:23:12 |
381 | 236 | id: 2 | 221 | id: 2 |
382 | 237 | internals:... | 222 | internals:... |
383 | 238 | is_open: True | 223 | is_open: True |
385 | 239 | last_change_time: 20080611T09:24:29 | 224 | last_change_time: 2008-06-11 09:24:29 |
386 | 240 | priority: P1 | 225 | priority: P1 |
387 | 241 | product: HeartOfGold | 226 | product: HeartOfGold |
388 | 242 | resolution: | 227 | resolution: |
389 | @@ -257,11 +242,11 @@ | |||
390 | 257 | alias: | 242 | alias: |
391 | 258 | assigned_to: test@canonical.com | 243 | assigned_to: test@canonical.com |
392 | 259 | component: GPPSystems | 244 | component: GPPSystems |
394 | 260 | creation_time: 20080610T16:19:53 | 245 | creation_time: 2008-06-10 16:19:53 |
395 | 261 | id: 1 | 246 | id: 1 |
396 | 262 | internals:... | 247 | internals:... |
397 | 263 | is_open: True | 248 | is_open: True |
399 | 264 | last_change_time: 20080610T16:19:53 | 249 | last_change_time: 2008-06-10 16:19:53 |
400 | 265 | priority: P1 | 250 | priority: P1 |
401 | 266 | product: Marvin | 251 | product: Marvin |
402 | 267 | resolution: FIXED | 252 | resolution: FIXED |
403 | @@ -272,11 +257,11 @@ | |||
404 | 272 | alias: bug-two | 257 | alias: bug-two |
405 | 273 | assigned_to: marvin@heartofgold.ship | 258 | assigned_to: marvin@heartofgold.ship |
406 | 274 | component: Crew | 259 | component: Crew |
408 | 275 | creation_time: 20080611T09:23:12 | 260 | creation_time: 2008-06-11 09:23:12 |
409 | 276 | id: 2 | 261 | id: 2 |
410 | 277 | internals:... | 262 | internals:... |
411 | 278 | is_open: True | 263 | is_open: True |
413 | 279 | last_change_time: 20080611T09:24:29 | 264 | last_change_time: 2008-06-11 09:24:29 |
414 | 280 | priority: P1 | 265 | priority: P1 |
415 | 281 | product: HeartOfGold | 266 | product: HeartOfGold |
416 | 282 | resolution: | 267 | resolution: |
417 | @@ -321,14 +306,14 @@ | |||
418 | 321 | id: 1 | 306 | id: 1 |
419 | 322 | is_private: False | 307 | is_private: False |
420 | 323 | text: I'd really appreciate it if Marvin would enjoy life a bit. | 308 | text: I'd really appreciate it if Marvin would enjoy life a bit. |
422 | 324 | time: 20080616T12:44:29 | 309 | time: 2008-06-16 12:44:29 |
423 | 325 | <BLANKLINE> | 310 | <BLANKLINE> |
424 | 326 | author: marvin | 311 | author: marvin |
425 | 327 | bug_id: 1 | 312 | bug_id: 1 |
426 | 328 | id: 3 | 313 | id: 3 |
427 | 329 | is_private: False | 314 | is_private: False |
428 | 330 | text: Life? Don't talk to me about life. | 315 | text: Life? Don't talk to me about life. |
430 | 331 | time: 20080616T13:22:29 | 316 | time: 2008-06-16 13:22:29 |
431 | 332 | <BLANKLINE> | 317 | <BLANKLINE> |
432 | 333 | <BLANKLINE> | 318 | <BLANKLINE> |
433 | 334 | Bug 2: | 319 | Bug 2: |
434 | @@ -337,14 +322,14 @@ | |||
435 | 337 | id: 2 | 322 | id: 2 |
436 | 338 | is_private: False | 323 | is_private: False |
437 | 339 | text: Bring the passengers to the bridge please Marvin. | 324 | text: Bring the passengers to the bridge please Marvin. |
439 | 340 | time: 20080616T13:08:08 | 325 | time: 2008-06-16 13:08:08 |
440 | 341 | <BLANKLINE> | 326 | <BLANKLINE> |
441 | 342 | author: Ford Prefect <ford.prefect@h2g2.com> | 327 | author: Ford Prefect <ford.prefect@h2g2.com> |
442 | 343 | bug_id: 2 | 328 | bug_id: 2 |
443 | 344 | id: 4 | 329 | id: 4 |
444 | 345 | is_private: False | 330 | is_private: False |
445 | 346 | text: I appear to have become a perfectly safe penguin. | 331 | text: I appear to have become a perfectly safe penguin. |
447 | 347 | time: 20080617T20:28:40 | 332 | time: 2008-06-17 20:28:40 |
448 | 348 | <BLANKLINE> | 333 | <BLANKLINE> |
449 | 349 | <BLANKLINE> | 334 | <BLANKLINE> |
450 | 350 | 335 | ||
451 | @@ -366,14 +351,14 @@ | |||
452 | 366 | id: 1 | 351 | id: 1 |
453 | 367 | is_private: False | 352 | is_private: False |
454 | 368 | text: I'd really appreciate it if Marvin would enjoy life a bit. | 353 | text: I'd really appreciate it if Marvin would enjoy life a bit. |
456 | 369 | time: 20080616T12:44:29 | 354 | time: 2008-06-16 12:44:29 |
457 | 370 | Comment 4: | 355 | Comment 4: |
458 | 371 | author: Ford Prefect <ford.prefect@h2g2.com> | 356 | author: Ford Prefect <ford.prefect@h2g2.com> |
459 | 372 | bug_id: 2 | 357 | bug_id: 2 |
460 | 373 | id: 4 | 358 | id: 4 |
461 | 374 | is_private: False | 359 | is_private: False |
462 | 375 | text: I appear to have become a perfectly safe penguin. | 360 | text: I appear to have become a perfectly safe penguin. |
464 | 376 | time: 20080617T20:28:40 | 361 | time: 2008-06-17 20:28:40 |
465 | 377 | <BLANKLINE> | 362 | <BLANKLINE> |
466 | 378 | 363 | ||
467 | 379 | Note that only comments have been returned when only 'comment_ids' have | 364 | Note that only comments have been returned when only 'comment_ids' have |
468 | @@ -499,11 +484,11 @@ | |||
469 | 499 | alias: | 484 | alias: |
470 | 500 | assigned_to: test@canonical.com | 485 | assigned_to: test@canonical.com |
471 | 501 | component: GPPSystems | 486 | component: GPPSystems |
473 | 502 | creation_time: 20080610T16:19:53 | 487 | creation_time: 2008-06-10 16:19:53 |
474 | 503 | id: 1 | 488 | id: 1 |
475 | 504 | internals:... | 489 | internals:... |
476 | 505 | is_open: True | 490 | is_open: True |
478 | 506 | last_change_time: 20080610T16:19:53 | 491 | last_change_time: 2008-06-10 16:19:53 |
479 | 507 | priority: P1 | 492 | priority: P1 |
480 | 508 | product: Marvin | 493 | product: Marvin |
481 | 509 | resolution: FIXED | 494 | resolution: FIXED |
482 | 510 | 495 | ||
483 | === modified file 'lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt' | |||
484 | --- lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt 2009-12-11 16:05:52 +0000 | |||
485 | +++ lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt 2009-12-23 10:38:25 +0000 | |||
486 | @@ -105,9 +105,9 @@ | |||
487 | 105 | >>> time_dict = server.Launchpad.time() | 105 | >>> time_dict = server.Launchpad.time() |
488 | 106 | >>> for key in sorted(time_dict): | 106 | >>> for key in sorted(time_dict): |
489 | 107 | ... print "%s: %s" % (key, time_dict[key]) | 107 | ... print "%s: %s" % (key, time_dict[key]) |
491 | 108 | local_time: 20080501T01:01:01 | 108 | local_time: 2008-05-01 01:01:01 |
492 | 109 | tz_name: UTC | 109 | tz_name: UTC |
494 | 110 | utc_time: 20080501T01:01:01 | 110 | utc_time: 2008-05-01 01:01:01 |
495 | 111 | 111 | ||
496 | 112 | We can set the local time value on the remote server to make testing | 112 | We can set the local time value on the remote server to make testing |
497 | 113 | more useful. | 113 | more useful. |
498 | @@ -122,9 +122,9 @@ | |||
499 | 122 | >>> time_dict = server.Launchpad.time() | 122 | >>> time_dict = server.Launchpad.time() |
500 | 123 | >>> for key in sorted(time_dict): | 123 | >>> for key in sorted(time_dict): |
501 | 124 | ... print "%s: %s" % (key, time_dict[key]) | 124 | ... print "%s: %s" % (key, time_dict[key]) |
503 | 125 | local_time: 20080515T16:19:53 | 125 | local_time: 2008-05-15 16:19:53 |
504 | 126 | tz_name: US/Central | 126 | tz_name: US/Central |
506 | 127 | utc_time: 20080515T22:19:53 | 127 | utc_time: 2008-05-15 22:19:53 |
507 | 128 | 128 | ||
508 | 129 | 129 | ||
509 | 130 | Launchpad.get_bugs() | 130 | Launchpad.get_bugs() |
510 | @@ -144,11 +144,11 @@ | |||
511 | 144 | alias: | 144 | alias: |
512 | 145 | assigned_to: test@canonical.com | 145 | assigned_to: test@canonical.com |
513 | 146 | component: GPPSystems | 146 | component: GPPSystems |
515 | 147 | creation_time: 20080610T16:19:53 | 147 | creation_time: 2008-06-10 16:19:53 |
516 | 148 | id: 1 | 148 | id: 1 |
517 | 149 | internals:... | 149 | internals:... |
518 | 150 | is_open: True | 150 | is_open: True |
520 | 151 | last_change_time: 20080610T16:19:53 | 151 | last_change_time: 2008-06-10 16:19:53 |
521 | 152 | priority: P1 | 152 | priority: P1 |
522 | 153 | product: Marvin | 153 | product: Marvin |
523 | 154 | resolution: FIXED | 154 | resolution: FIXED |
524 | @@ -170,11 +170,11 @@ | |||
525 | 170 | alias: | 170 | alias: |
526 | 171 | assigned_to: test@canonical.com | 171 | assigned_to: test@canonical.com |
527 | 172 | component: GPPSystems | 172 | component: GPPSystems |
529 | 173 | creation_time: 20080610T16:19:53 | 173 | creation_time: 2008-06-10 16:19:53 |
530 | 174 | id: 1 | 174 | id: 1 |
531 | 175 | internals:... | 175 | internals:... |
532 | 176 | is_open: True | 176 | is_open: True |
534 | 177 | last_change_time: 20080610T16:19:53 | 177 | last_change_time: 2008-06-10 16:19:53 |
535 | 178 | priority: P1 | 178 | priority: P1 |
536 | 179 | product: Marvin | 179 | product: Marvin |
537 | 180 | resolution: FIXED | 180 | resolution: FIXED |
538 | @@ -186,11 +186,11 @@ | |||
539 | 186 | alias: bug-two | 186 | alias: bug-two |
540 | 187 | assigned_to: marvin@heartofgold.ship | 187 | assigned_to: marvin@heartofgold.ship |
541 | 188 | component: Crew | 188 | component: Crew |
543 | 189 | creation_time: 20080611T09:23:12 | 189 | creation_time: 2008-06-11 09:23:12 |
544 | 190 | id: 2 | 190 | id: 2 |
545 | 191 | internals:... | 191 | internals:... |
546 | 192 | is_open: True | 192 | is_open: True |
548 | 193 | last_change_time: 20080611T09:24:29 | 193 | last_change_time: 2008-06-11 09:24:29 |
549 | 194 | priority: P1 | 194 | priority: P1 |
550 | 195 | product: HeartOfGold | 195 | product: HeartOfGold |
551 | 196 | resolution: | 196 | resolution: |
552 | @@ -209,11 +209,11 @@ | |||
553 | 209 | alias: bug-two | 209 | alias: bug-two |
554 | 210 | assigned_to: marvin@heartofgold.ship | 210 | assigned_to: marvin@heartofgold.ship |
555 | 211 | component: Crew | 211 | component: Crew |
557 | 212 | creation_time: 20080611T09:23:12 | 212 | creation_time: 2008-06-11 09:23:12 |
558 | 213 | id: 2 | 213 | id: 2 |
559 | 214 | internals:... | 214 | internals:... |
560 | 215 | is_open: True | 215 | is_open: True |
562 | 216 | last_change_time: 20080611T09:24:29 | 216 | last_change_time: 2008-06-11 09:24:29 |
563 | 217 | priority: P1 | 217 | priority: P1 |
564 | 218 | product: HeartOfGold | 218 | product: HeartOfGold |
565 | 219 | resolution: | 219 | resolution: |
566 | @@ -228,17 +228,8 @@ | |||
567 | 228 | allowing Launchpad to get only the recently-updated subset of a given | 228 | allowing Launchpad to get only the recently-updated subset of a given |
568 | 229 | set of remote bugs. | 229 | set of remote bugs. |
569 | 230 | 230 | ||
570 | 231 | >>> from xmlrpclib import DateTime | ||
571 | 232 | |||
572 | 233 | >>> changed_since = datetime(2008, 6, 11, 9, 0, 0) | 231 | >>> changed_since = datetime(2008, 6, 11, 9, 0, 0) |
573 | 234 | 232 | ||
574 | 235 | >>> # We encode changed_since into an XML-RPC DateTime manually. | ||
575 | 236 | >>> # This is because xmlrpclib can't handle DateTime encoding | ||
576 | 237 | >>> # within a dict. | ||
577 | 238 | >>> # XXX 2008-08-05 gmb (bug 254999): | ||
578 | 239 | >>> # We can remove this once we upgrade to python 2.5. | ||
579 | 240 | >>> changed_since = DateTime(changed_since.timetuple()) | ||
580 | 241 | |||
581 | 242 | >>> return_value = server.Launchpad.get_bugs({ | 233 | >>> return_value = server.Launchpad.get_bugs({ |
582 | 243 | ... 'ids': [1, 2], | 234 | ... 'ids': [1, 2], |
583 | 244 | ... 'changed_since': changed_since, | 235 | ... 'changed_since': changed_since, |
584 | @@ -254,11 +245,11 @@ | |||
585 | 254 | alias: bug-two | 245 | alias: bug-two |
586 | 255 | assigned_to: marvin@heartofgold.ship | 246 | assigned_to: marvin@heartofgold.ship |
587 | 256 | component: Crew | 247 | component: Crew |
589 | 257 | creation_time: 20080611T09:23:12 | 248 | creation_time: 2008-06-11 09:23:12 |
590 | 258 | id: 2 | 249 | id: 2 |
591 | 259 | internals:... | 250 | internals:... |
592 | 260 | is_open: True | 251 | is_open: True |
594 | 261 | last_change_time: 20080611T09:24:29 | 252 | last_change_time: 2008-06-11 09:24:29 |
595 | 262 | priority: P1 | 253 | priority: P1 |
596 | 263 | product: HeartOfGold | 254 | product: HeartOfGold |
597 | 264 | resolution: | 255 | resolution: |
598 | @@ -273,10 +264,6 @@ | |||
599 | 273 | >>> from datetime import timedelta | 264 | >>> from datetime import timedelta |
600 | 274 | >>> changed_since = datetime.now() + timedelta(days=42) | 265 | >>> changed_since = datetime.now() + timedelta(days=42) |
601 | 275 | 266 | ||
602 | 276 | >>> # XXX 2008-08-05 gmb (bug 254999): | ||
603 | 277 | >>> # We can remove this once we upgrade to python 2.5. | ||
604 | 278 | >>> changed_since = DateTime(changed_since.timetuple()) | ||
605 | 279 | |||
606 | 280 | >>> return_value = server.Launchpad.get_bugs({ | 267 | >>> return_value = server.Launchpad.get_bugs({ |
607 | 281 | ... 'ids': [1, 2], | 268 | ... 'ids': [1, 2], |
608 | 282 | ... 'changed_since': changed_since, | 269 | ... 'changed_since': changed_since, |
609 | @@ -304,11 +291,11 @@ | |||
610 | 304 | alias: bug-two | 291 | alias: bug-two |
611 | 305 | assigned_to: marvin@heartofgold.ship | 292 | assigned_to: marvin@heartofgold.ship |
612 | 306 | component: Crew | 293 | component: Crew |
614 | 307 | creation_time: 20080611T09:23:12 | 294 | creation_time: 2008-06-11 09:23:12 |
615 | 308 | id: 2 | 295 | id: 2 |
616 | 309 | internals:... | 296 | internals:... |
617 | 310 | is_open: True | 297 | is_open: True |
619 | 311 | last_change_time: 20080611T09:24:29 | 298 | last_change_time: 2008-06-11 09:24:29 |
620 | 312 | priority: P1 | 299 | priority: P1 |
621 | 313 | product: HeartOfGold | 300 | product: HeartOfGold |
622 | 314 | resolution: | 301 | resolution: |
623 | @@ -366,13 +353,13 @@ | |||
624 | 366 | id: 1 | 353 | id: 1 |
625 | 367 | number: 1 | 354 | number: 1 |
626 | 368 | text: I'd really appreciate it if Marvin would enjoy life a bit. | 355 | text: I'd really appreciate it if Marvin would enjoy life a bit. |
628 | 369 | time: 20080616T12:44:29 | 356 | time: 2008-06-16 12:44:29 |
629 | 370 | <BLANKLINE> | 357 | <BLANKLINE> |
630 | 371 | author: marvin | 358 | author: marvin |
631 | 372 | id: 3 | 359 | id: 3 |
632 | 373 | number: 2 | 360 | number: 2 |
633 | 374 | text: Life? Don't talk to me about life. | 361 | text: Life? Don't talk to me about life. |
635 | 375 | time: 20080616T13:22:29 | 362 | time: 2008-06-16 13:22:29 |
636 | 376 | <BLANKLINE> | 363 | <BLANKLINE> |
637 | 377 | <BLANKLINE> | 364 | <BLANKLINE> |
638 | 378 | Bug 2: | 365 | Bug 2: |
639 | @@ -380,13 +367,13 @@ | |||
640 | 380 | id: 2 | 367 | id: 2 |
641 | 381 | number: 1 | 368 | number: 1 |
642 | 382 | text: Bring the passengers to the bridge please Marvin. | 369 | text: Bring the passengers to the bridge please Marvin. |
644 | 383 | time: 20080616T13:08:08 | 370 | time: 2008-06-16 13:08:08 |
645 | 384 | <BLANKLINE> | 371 | <BLANKLINE> |
646 | 385 | author: Ford Prefect <ford.prefect@h2g2.com> | 372 | author: Ford Prefect <ford.prefect@h2g2.com> |
647 | 386 | id: 4 | 373 | id: 4 |
648 | 387 | number: 2 | 374 | number: 2 |
649 | 388 | text: I appear to have become a perfectly safe penguin. | 375 | text: I appear to have become a perfectly safe penguin. |
651 | 389 | time: 20080617T20:28:40 | 376 | time: 2008-06-17 20:28:40 |
652 | 390 | 377 | ||
653 | 391 | If an ids parameter is specified along with bug_ids, only the comments | 378 | If an ids parameter is specified along with bug_ids, only the comments |
654 | 392 | whose IDs are in the list of IDs passed will be returned. | 379 | whose IDs are in the list of IDs passed will be returned. |
655 | @@ -401,7 +388,7 @@ | |||
656 | 401 | id: 1 | 388 | id: 1 |
657 | 402 | number: 1 | 389 | number: 1 |
658 | 403 | text: I'd really appreciate it if Marvin would enjoy life a bit. | 390 | text: I'd really appreciate it if Marvin would enjoy life a bit. |
660 | 404 | time: 20080616T12:44:29 | 391 | time: 2008-06-16 12:44:29 |
661 | 405 | <BLANKLINE> | 392 | <BLANKLINE> |
662 | 406 | <BLANKLINE> | 393 | <BLANKLINE> |
663 | 407 | Bug 2: | 394 | Bug 2: |
664 | @@ -409,7 +396,7 @@ | |||
665 | 409 | id: 2 | 396 | id: 2 |
666 | 410 | number: 1 | 397 | number: 1 |
667 | 411 | text: Bring the passengers to the bridge please Marvin. | 398 | text: Bring the passengers to the bridge please Marvin. |
669 | 412 | time: 20080616T13:08:08 | 399 | time: 2008-06-16 13:08:08 |
670 | 413 | 400 | ||
671 | 414 | Passing an include_fields parameter allows us to limit which fields are | 401 | Passing an include_fields parameter allows us to limit which fields are |
672 | 415 | returned for each comment. | 402 | returned for each comment. |
673 | 416 | 403 | ||
674 | === modified file 'lib/lp/bugs/tests/externalbugtracker.py' | |||
675 | --- lib/lp/bugs/tests/externalbugtracker.py 2009-12-18 17:40:01 +0000 | |||
676 | +++ lib/lp/bugs/tests/externalbugtracker.py 2009-12-23 12:09:36 +0000 | |||
677 | @@ -526,17 +526,12 @@ | |||
678 | 526 | if local_datetime is None: | 526 | if local_datetime is None: |
679 | 527 | local_datetime = datetime(2008, 5, 1, 1, 1, 1) | 527 | local_datetime = datetime(2008, 5, 1, 1, 1, 1) |
680 | 528 | 528 | ||
681 | 529 | # We return xmlrpc dateTimes rather than doubles since that's | ||
682 | 530 | # what BugZilla will return. | ||
683 | 531 | local_time = xmlrpclib.DateTime(local_datetime.timetuple()) | ||
684 | 532 | |||
685 | 533 | utc_offset_delta = timedelta(seconds=self.utc_offset) | 529 | utc_offset_delta = timedelta(seconds=self.utc_offset) |
686 | 534 | utc_date_time = local_datetime - utc_offset_delta | 530 | utc_date_time = local_datetime - utc_offset_delta |
687 | 535 | 531 | ||
688 | 536 | utc_time = xmlrpclib.DateTime(utc_date_time.timetuple()) | ||
689 | 537 | return { | 532 | return { |
692 | 538 | 'local_time': local_time, | 533 | 'local_time': local_datetime, |
693 | 539 | 'utc_time': utc_time, | 534 | 'utc_time': utc_date_time, |
694 | 540 | 'tz_name': self.timezone, | 535 | 'tz_name': self.timezone, |
695 | 541 | } | 536 | } |
696 | 542 | 537 | ||
697 | @@ -599,14 +594,14 @@ | |||
698 | 599 | assert permissive, "get_bugs() must be called with permissive=True" | 594 | assert permissive, "get_bugs() must be called with permissive=True" |
699 | 600 | 595 | ||
700 | 601 | # If a changed_since argument is specified, marshall it into a | 596 | # If a changed_since argument is specified, marshall it into a |
704 | 602 | # datetime so that we can use it for comparisons. | 597 | # datetime so that we can use it for comparisons. Even though |
705 | 603 | # XXX 2008-08-05 gmb (bug 254999): | 598 | # xmlrpclib in Python 2.5 groks datetime, by the time this |
706 | 604 | # We can remove these lines once we upgrade to python 2.5. | 599 | # method is called xmlrpclib has already converted all |
707 | 600 | # datetimes to xmlrpclib.DateTime. | ||
708 | 605 | changed_since = arguments.get('changed_since') | 601 | changed_since = arguments.get('changed_since') |
709 | 606 | if changed_since is not None: | 602 | if changed_since is not None: |
713 | 607 | changed_since_timetuple = time.strptime( | 603 | changed_since = datetime.strptime( |
714 | 608 | str(changed_since), '%Y%m%dT%H:%M:%S') | 604 | changed_since.value, '%Y%m%dT%H:%M:%S') |
712 | 609 | changed_since = datetime(*changed_since_timetuple[:6]) | ||
715 | 610 | 605 | ||
716 | 611 | # If we have some products but no bug_ids we just get all the | 606 | # If we have some products but no bug_ids we just get all the |
717 | 612 | # bug IDs for those products and stuff them in the bug_ids list | 607 | # bug IDs for those products and stuff them in the bug_ids list |
718 | @@ -642,14 +637,6 @@ | |||
719 | 642 | bug_dict['product'] not in products): | 637 | bug_dict['product'] not in products): |
720 | 643 | continue | 638 | continue |
721 | 644 | 639 | ||
722 | 645 | # Update the DateTime fields of the bug dict so that they | ||
723 | 646 | # look like ones that would be sent over XML-RPC. | ||
724 | 647 | for time_field in ('creation_time', 'last_change_time'): | ||
725 | 648 | datetime_value = bug_dict[time_field] | ||
726 | 649 | timestamp = time.mktime(datetime_value.timetuple()) | ||
727 | 650 | xmlrpc_datetime = xmlrpclib.DateTime(timestamp) | ||
728 | 651 | bug_dict[time_field] = xmlrpc_datetime | ||
729 | 652 | |||
730 | 653 | bugs_to_return.append(bug_dict) | 640 | bugs_to_return.append(bug_dict) |
731 | 654 | 641 | ||
732 | 655 | # "Why are you returning a list here?" I hear you cry. Well, | 642 | # "Why are you returning a list here?" I hear you cry. Well, |
733 | @@ -660,15 +647,9 @@ | |||
734 | 660 | 647 | ||
735 | 661 | def _copy_comment(self, comment, fields_to_return=None): | 648 | def _copy_comment(self, comment, fields_to_return=None): |
736 | 662 | # Copy wanted fields. | 649 | # Copy wanted fields. |
738 | 663 | comment = dict( | 650 | return dict( |
739 | 664 | (key, value) for (key, value) in comment.iteritems() | 651 | (key, value) for (key, value) in comment.iteritems() |
740 | 665 | if fields_to_return is None or key in fields_to_return) | 652 | if fields_to_return is None or key in fields_to_return) |
741 | 666 | # Replace the time field with an XML-RPC DateTime. | ||
742 | 667 | if 'time' in comment: | ||
743 | 668 | comment['time'] = xmlrpclib.DateTime( | ||
744 | 669 | comment['time'].timetuple()) | ||
745 | 670 | return comment | ||
746 | 671 | |||
747 | 672 | 653 | ||
748 | 673 | def comments(self, arguments): | 654 | def comments(self, arguments): |
749 | 674 | """Return comments for a given set of bugs.""" | 655 | """Return comments for a given set of bugs.""" |
Brad Crittenden (bac) wrote : | # |
Thanks for the additional changes Gavin. It looks good now.
Preview Diff
1 | === modified file 'lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt' | |||
2 | --- lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt 2009-12-21 15:03:42 +0000 | |||
3 | +++ lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt 2009-12-23 12:17:18 +0000 | |||
4 | @@ -139,8 +139,8 @@ | |||
5 | 139 | >>> def print_bugs(bugs): | 139 | >>> def print_bugs(bugs): |
6 | 140 | ... for bug in sorted(bugs): | 140 | ... for bug in sorted(bugs): |
7 | 141 | ... print "Bug %s:" % bug | 141 | ... print "Bug %s:" % bug |
10 | 142 | ... for key in sorted(bugzilla._bugs[bug]): | 142 | ... for key in sorted(bugs[bug]): |
11 | 143 | ... print " %s: %s" % (key, bugzilla._bugs[bug][key]) | 143 | ... print " %s: %s" % (key, bugs[bug][key]) |
12 | 144 | ... print "\n" | 144 | ... print "\n" |
13 | 145 | 145 | ||
14 | 146 | >>> print_bugs(bugzilla._bugs) | 146 | >>> print_bugs(bugzilla._bugs) |
15 | @@ -148,11 +148,11 @@ | |||
16 | 148 | alias: | 148 | alias: |
17 | 149 | assigned_to: test@canonical.com | 149 | assigned_to: test@canonical.com |
18 | 150 | component: GPPSystems | 150 | component: GPPSystems |
20 | 151 | creation_time: 20080610T16:19:53 | 151 | creation_time: 2008-06-10 16:19:53 |
21 | 152 | id: 1 | 152 | id: 1 |
22 | 153 | internals:... | 153 | internals:... |
23 | 154 | is_open: True | 154 | is_open: True |
25 | 155 | last_change_time: 20080610T16:19:53 | 155 | last_change_time: 2008-06-10 16:19:53 |
26 | 156 | priority: P1 | 156 | priority: P1 |
27 | 157 | product: Marvin | 157 | product: Marvin |
28 | 158 | resolution: FIXED | 158 | resolution: FIXED |
29 | @@ -165,11 +165,11 @@ | |||
30 | 165 | alias: bug-two | 165 | alias: bug-two |
31 | 166 | assigned_to: marvin@heartofgold.ship | 166 | assigned_to: marvin@heartofgold.ship |
32 | 167 | component: Crew | 167 | component: Crew |
34 | 168 | creation_time: 20080611T09:23:12 | 168 | creation_time: 2008-06-11 09:23:12 |
35 | 169 | id: 2 | 169 | id: 2 |
36 | 170 | internals:... | 170 | internals:... |
37 | 171 | is_open: True | 171 | is_open: True |
39 | 172 | last_change_time: 20080611T09:24:29 | 172 | last_change_time: 2008-06-11 09:24:29 |
40 | 173 | priority: P1 | 173 | priority: P1 |
41 | 174 | product: HeartOfGold | 174 | product: HeartOfGold |
42 | 175 | resolution: | 175 | resolution: |
43 | @@ -194,20 +194,16 @@ | |||
44 | 194 | >>> bugzilla.initializeRemoteBugDB([2, 'bug-two']) | 194 | >>> bugzilla.initializeRemoteBugDB([2, 'bug-two']) |
45 | 195 | CALLED Bug.get({'ids': [2, 'bug-two'], 'permissive': True}) | 195 | CALLED Bug.get({'ids': [2, 'bug-two'], 'permissive': True}) |
46 | 196 | 196 | ||
52 | 197 | >>> for bug in sorted(bugzilla._bugs): | 197 | >>> print_bugs(bugzilla._bugs) |
48 | 198 | ... print "Bug %r:" % bug | ||
49 | 199 | ... for key in sorted(bugzilla._bugs[bug]): | ||
50 | 200 | ... print " %s: %s" % (key, bugzilla._bugs[bug][key]) | ||
51 | 201 | ... print "\n" | ||
53 | 202 | Bug 2: | 198 | Bug 2: |
54 | 203 | alias: bug-two | 199 | alias: bug-two |
55 | 204 | assigned_to: marvin@heartofgold.ship | 200 | assigned_to: marvin@heartofgold.ship |
56 | 205 | component: Crew | 201 | component: Crew |
58 | 206 | creation_time: 20080611T09:23:12 | 202 | creation_time: 2008-06-11 09:23:12 |
59 | 207 | id: 2 | 203 | id: 2 |
60 | 208 | internals:... | 204 | internals:... |
61 | 209 | is_open: True | 205 | is_open: True |
63 | 210 | last_change_time: 20080611T09:24:29 | 206 | last_change_time: 2008-06-11 09:24:29 |
64 | 211 | priority: P1 | 207 | priority: P1 |
65 | 212 | product: HeartOfGold | 208 | product: HeartOfGold |
66 | 213 | resolution: | 209 | resolution: |
67 | @@ -450,14 +446,14 @@ | |||
68 | 450 | id: 1 | 446 | id: 1 |
69 | 451 | is_private: False | 447 | is_private: False |
70 | 452 | text: I'd really appreciate it if Marvin would enjoy life a bit. | 448 | text: I'd really appreciate it if Marvin would enjoy life a bit. |
72 | 453 | time: 20080616T12:44:29 | 449 | time: 2008-06-16 12:44:29 |
73 | 454 | Comment 3: | 450 | Comment 3: |
74 | 455 | author: marvin | 451 | author: marvin |
75 | 456 | bug_id: 1 | 452 | bug_id: 1 |
76 | 457 | id: 3 | 453 | id: 3 |
77 | 458 | is_private: False | 454 | is_private: False |
78 | 459 | text: Life? Don't talk to me about life. | 455 | text: Life? Don't talk to me about life. |
80 | 460 | time: 20080616T13:22:29 | 456 | time: 2008-06-16 13:22:29 |
81 | 461 | 457 | ||
82 | 462 | If we try to fetch comments that don't belong to the current bug | 458 | If we try to fetch comments that don't belong to the current bug |
83 | 463 | fetchComments() will silently ignore them. | 459 | fetchComments() will silently ignore them. |
84 | @@ -477,7 +473,7 @@ | |||
85 | 477 | id: 1 | 473 | id: 1 |
86 | 478 | is_private: False | 474 | is_private: False |
87 | 479 | text: I'd really appreciate it if Marvin would enjoy life a bit. | 475 | text: I'd really appreciate it if Marvin would enjoy life a bit. |
89 | 480 | time: 20080616T12:44:29 | 476 | time: 2008-06-16 12:44:29 |
90 | 481 | 477 | ||
91 | 482 | 478 | ||
92 | 483 | getPosterForComment() | 479 | getPosterForComment() |
93 | @@ -521,7 +517,7 @@ | |||
94 | 521 | field on the imported comment. | 517 | field on the imported comment. |
95 | 522 | 518 | ||
96 | 523 | >>> print bugzilla._bugs[2]['comments'][2]['time'] | 519 | >>> print bugzilla._bugs[2]['comments'][2]['time'] |
98 | 524 | 20080616T13:08:08 | 520 | 2008-06-16 13:08:08 |
99 | 525 | 521 | ||
100 | 526 | >>> print message.datecreated | 522 | >>> print message.datecreated |
101 | 527 | 2008-06-16 13:08:08+00:00 | 523 | 2008-06-16 13:08:08+00:00 |
102 | 528 | 524 | ||
103 | === modified file 'lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt' | |||
104 | --- lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt 2009-12-21 15:03:42 +0000 | |||
105 | +++ lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt 2009-12-23 12:17:18 +0000 | |||
106 | @@ -204,8 +204,8 @@ | |||
107 | 204 | >>> def print_bugs(bugs): | 204 | >>> def print_bugs(bugs): |
108 | 205 | ... for bug in sorted(bugs): | 205 | ... for bug in sorted(bugs): |
109 | 206 | ... print "Bug %s:" % bug | 206 | ... print "Bug %s:" % bug |
112 | 207 | ... for key in sorted(bugzilla._bugs[bug]): | 207 | ... for key in sorted(bugs[bug]): |
113 | 208 | ... print " %s: %s" % (key, bugzilla._bugs[bug][key]) | 208 | ... print " %s: %s" % (key, bugs[bug][key]) |
114 | 209 | ... print "\n" | 209 | ... print "\n" |
115 | 210 | 210 | ||
116 | 211 | >>> print_bugs(bugzilla._bugs) | 211 | >>> print_bugs(bugzilla._bugs) |
117 | @@ -213,11 +213,11 @@ | |||
118 | 213 | alias: | 213 | alias: |
119 | 214 | assigned_to: test@canonical.com | 214 | assigned_to: test@canonical.com |
120 | 215 | component: GPPSystems | 215 | component: GPPSystems |
122 | 216 | creation_time: 20080610T16:19:53 | 216 | creation_time: 2008-06-10 16:19:53 |
123 | 217 | id: 1 | 217 | id: 1 |
124 | 218 | internals:... | 218 | internals:... |
125 | 219 | is_open: True | 219 | is_open: True |
127 | 220 | last_change_time: 20080610T16:19:53 | 220 | last_change_time: 2008-06-10 16:19:53 |
128 | 221 | priority: P1 | 221 | priority: P1 |
129 | 222 | product: Marvin | 222 | product: Marvin |
130 | 223 | resolution: FIXED | 223 | resolution: FIXED |
131 | @@ -230,11 +230,11 @@ | |||
132 | 230 | alias: bug-two | 230 | alias: bug-two |
133 | 231 | assigned_to: marvin@heartofgold.ship | 231 | assigned_to: marvin@heartofgold.ship |
134 | 232 | component: Crew | 232 | component: Crew |
136 | 233 | creation_time: 20080611T09:23:12 | 233 | creation_time: 2008-06-11 09:23:12 |
137 | 234 | id: 2 | 234 | id: 2 |
138 | 235 | internals:... | 235 | internals:... |
139 | 236 | is_open: True | 236 | is_open: True |
141 | 237 | last_change_time: 20080611T09:24:29 | 237 | last_change_time: 2008-06-11 09:24:29 |
142 | 238 | priority: P1 | 238 | priority: P1 |
143 | 239 | product: HeartOfGold | 239 | product: HeartOfGold |
144 | 240 | resolution: | 240 | resolution: |
145 | @@ -416,13 +416,13 @@ | |||
146 | 416 | id: 1 | 416 | id: 1 |
147 | 417 | number: 1 | 417 | number: 1 |
148 | 418 | text: I'd really appreciate it if Marvin would enjoy life a bit. | 418 | text: I'd really appreciate it if Marvin would enjoy life a bit. |
150 | 419 | time: 20080616T12:44:29 | 419 | time: 2008-06-16 12:44:29 |
151 | 420 | Comment 3: | 420 | Comment 3: |
152 | 421 | author: marvin | 421 | author: marvin |
153 | 422 | id: 3 | 422 | id: 3 |
154 | 423 | number: 2 | 423 | number: 2 |
155 | 424 | text: Life? Don't talk to me about life. | 424 | text: Life? Don't talk to me about life. |
157 | 425 | time: 20080616T13:22:29 | 425 | time: 2008-06-16 13:22:29 |
158 | 426 | 426 | ||
159 | 427 | 427 | ||
160 | 428 | Pushing comments to remote systems | 428 | Pushing comments to remote systems |
161 | @@ -560,11 +560,11 @@ | |||
162 | 560 | alias: bug-two | 560 | alias: bug-two |
163 | 561 | assigned_to: marvin@heartofgold.ship | 561 | assigned_to: marvin@heartofgold.ship |
164 | 562 | component: Crew | 562 | component: Crew |
166 | 563 | creation_time: 20080611T09:23:12 | 563 | creation_time: 2008-06-11 09:23:12 |
167 | 564 | id: 2 | 564 | id: 2 |
168 | 565 | internals:... | 565 | internals:... |
169 | 566 | is_open: True | 566 | is_open: True |
171 | 567 | last_change_time: 20080611T09:24:29 | 567 | last_change_time: 2008-06-11 09:24:29 |
172 | 568 | priority: P1 | 568 | priority: P1 |
173 | 569 | product: HeartOfGold | 569 | product: HeartOfGold |
174 | 570 | resolution: | 570 | resolution: |
175 | 571 | 571 | ||
176 | === modified file 'lib/lp/bugs/externalbugtracker/bugzilla.py' | |||
177 | --- lib/lp/bugs/externalbugtracker/bugzilla.py 2009-12-21 14:46:05 +0000 | |||
178 | +++ lib/lp/bugs/externalbugtracker/bugzilla.py 2009-12-23 12:17:18 +0000 | |||
179 | @@ -12,11 +12,9 @@ | |||
180 | 12 | ] | 12 | ] |
181 | 13 | 13 | ||
182 | 14 | import pytz | 14 | import pytz |
183 | 15 | import time | ||
184 | 16 | import xml.parsers.expat | 15 | import xml.parsers.expat |
185 | 17 | import xmlrpclib | 16 | import xmlrpclib |
186 | 18 | 17 | ||
187 | 19 | from datetime import datetime | ||
188 | 20 | from email.Utils import parseaddr | 18 | from email.Utils import parseaddr |
189 | 21 | from xml.dom import minidom | 19 | from xml.dom import minidom |
190 | 22 | 20 | ||
191 | @@ -505,28 +503,17 @@ | |||
192 | 505 | """See `IExternalBugTracker`.""" | 503 | """See `IExternalBugTracker`.""" |
193 | 506 | time_dict = self.xmlrpc_proxy.Bugzilla.time() | 504 | time_dict = self.xmlrpc_proxy.Bugzilla.time() |
194 | 507 | 505 | ||
195 | 508 | # Convert the XML-RPC DateTime we get back into a regular Python | ||
196 | 509 | # datetime. | ||
197 | 510 | server_db_timetuple = time.strptime( | ||
198 | 511 | str(time_dict['db_time']), '%Y%m%dT%H:%M:%S') | ||
199 | 512 | server_db_datetime = datetime(*server_db_timetuple[:6]) | ||
200 | 513 | |||
201 | 514 | # The server's DB time is the one that we want to use. However, | 506 | # The server's DB time is the one that we want to use. However, |
202 | 515 | # this may not be in UTC, so we need to convert it. Since we | 507 | # this may not be in UTC, so we need to convert it. Since we |
203 | 516 | # can't guarantee that the timezone data returned by the server | 508 | # can't guarantee that the timezone data returned by the server |
204 | 517 | # is sane, we work out the server's offset from UTC by looking | 509 | # is sane, we work out the server's offset from UTC by looking |
205 | 518 | # at the difference between the web_time and the web_time_utc | 510 | # at the difference between the web_time and the web_time_utc |
206 | 519 | # values. | 511 | # values. |
214 | 520 | server_web_time = time.strptime( | 512 | server_web_datetime = time_dict['web_time'] |
215 | 521 | str(time_dict['web_time']), '%Y%m%dT%H:%M:%S') | 513 | server_web_datetime_utc = time_dict['web_time_utc'] |
209 | 522 | server_web_datetime = datetime(*server_web_time[:6]) | ||
210 | 523 | server_web_time_utc = time.strptime( | ||
211 | 524 | str(time_dict['web_time_utc']), '%Y%m%dT%H:%M:%S') | ||
212 | 525 | server_web_datetime_utc = datetime(*server_web_time_utc[:6]) | ||
213 | 526 | |||
216 | 527 | server_utc_offset = server_web_datetime - server_web_datetime_utc | 514 | server_utc_offset = server_web_datetime - server_web_datetime_utc |
217 | 515 | server_db_datetime = time_dict['db_time'] | ||
218 | 528 | server_utc_datetime = server_db_datetime - server_utc_offset | 516 | server_utc_datetime = server_db_datetime - server_utc_offset |
219 | 529 | |||
220 | 530 | return server_utc_datetime.replace(tzinfo=pytz.timezone('UTC')) | 517 | return server_utc_datetime.replace(tzinfo=pytz.timezone('UTC')) |
221 | 531 | 518 | ||
222 | 532 | def _getActualBugId(self, bug_id): | 519 | def _getActualBugId(self, bug_id): |
223 | @@ -558,7 +545,7 @@ | |||
224 | 558 | bug_ids_to_retrieve = [] | 545 | bug_ids_to_retrieve = [] |
225 | 559 | for bug_id in bug_ids: | 546 | for bug_id in bug_ids: |
226 | 560 | try: | 547 | try: |
228 | 561 | actual_bug_id = self._getActualBugId(bug_id) | 548 | self._getActualBugId(bug_id) |
229 | 562 | except BugNotFound: | 549 | except BugNotFound: |
230 | 563 | bug_ids_to_retrieve.append(bug_id) | 550 | bug_ids_to_retrieve.append(bug_id) |
231 | 564 | 551 | ||
232 | @@ -590,7 +577,7 @@ | |||
233 | 590 | try: | 577 | try: |
234 | 591 | status = self._bugs[actual_bug_id]['status'] | 578 | status = self._bugs[actual_bug_id]['status'] |
235 | 592 | resolution = self._bugs[actual_bug_id]['resolution'] | 579 | resolution = self._bugs[actual_bug_id]['resolution'] |
237 | 593 | except KeyError, error: | 580 | except KeyError: |
238 | 594 | raise UnparseableBugData | 581 | raise UnparseableBugData |
239 | 595 | 582 | ||
240 | 596 | if resolution != '': | 583 | if resolution != '': |
241 | @@ -600,27 +587,14 @@ | |||
242 | 600 | 587 | ||
243 | 601 | def getModifiedRemoteBugs(self, bug_ids, last_checked): | 588 | def getModifiedRemoteBugs(self, bug_ids, last_checked): |
244 | 602 | """See `IExternalBugTracker`.""" | 589 | """See `IExternalBugTracker`.""" |
256 | 603 | # We marshal last_checked into an xmlrpclib.DateTime since | 590 | response_dict = self.xmlrpc_proxy.Bug.search( |
257 | 604 | # xmlrpclib can't do so cleanly itself. | 591 | {'id': bug_ids, 'last_change_time': last_checked}) |
247 | 605 | # XXX 2009-08-21 gmb (bug 254999): | ||
248 | 606 | # We can remove this once we upgrade to python 2.5. | ||
249 | 607 | changed_since = xmlrpclib.DateTime(last_checked.timetuple()) | ||
250 | 608 | |||
251 | 609 | search_args = { | ||
252 | 610 | 'id': bug_ids, | ||
253 | 611 | 'last_change_time': changed_since, | ||
254 | 612 | } | ||
255 | 613 | response_dict = self.xmlrpc_proxy.Bug.search(search_args) | ||
258 | 614 | remote_bugs = response_dict['bugs'] | 592 | remote_bugs = response_dict['bugs'] |
259 | 615 | |||
260 | 616 | # Store the bugs we've imported and return only their IDs. | 593 | # Store the bugs we've imported and return only their IDs. |
261 | 617 | self._storeBugs(remote_bugs) | 594 | self._storeBugs(remote_bugs) |
262 | 618 | |||
263 | 619 | # Marshal the bug IDs into strings before returning them since | 595 | # Marshal the bug IDs into strings before returning them since |
264 | 620 | # the remote Bugzilla may return ints rather than strings. | 596 | # the remote Bugzilla may return ints rather than strings. |
268 | 621 | bug_ids = [str(remote_bug['id']) for remote_bug in remote_bugs] | 597 | return [str(remote_bug['id']) for remote_bug in remote_bugs] |
266 | 622 | |||
267 | 623 | return bug_ids | ||
269 | 624 | 598 | ||
270 | 625 | def getRemoteProduct(self, remote_bug): | 599 | def getRemoteProduct(self, remote_bug): |
271 | 626 | """See `IExternalBugTracker`.""" | 600 | """See `IExternalBugTracker`.""" |
272 | @@ -728,22 +702,9 @@ | |||
273 | 728 | # bug 248938). | 702 | # bug 248938). |
274 | 729 | comment_id = int(comment_id) | 703 | comment_id = int(comment_id) |
275 | 730 | comment = self._bugs[actual_bug_id]['comments'][comment_id] | 704 | comment = self._bugs[actual_bug_id]['comments'][comment_id] |
288 | 731 | 705 | return getUtility(IMessageSet).fromText( | |
277 | 732 | # Turn the time in the comment, which is an XML-RPC datetime | ||
278 | 733 | # into something more useful to us. | ||
279 | 734 | # XXX 2008-08-05 gmb (bug 254999): | ||
280 | 735 | # We can remove these lines once we upgrade to python 2.5. | ||
281 | 736 | comment_timestamp = time.mktime( | ||
282 | 737 | time.strptime(str(comment['time']), '%Y%m%dT%H:%M:%S')) | ||
283 | 738 | comment_datetime = datetime.fromtimestamp(comment_timestamp) | ||
284 | 739 | comment_datetime = comment_datetime.replace( | ||
285 | 740 | tzinfo=pytz.timezone('UTC')) | ||
286 | 741 | |||
287 | 742 | message = getUtility(IMessageSet).fromText( | ||
289 | 743 | owner=poster, subject='', content=comment['text'], | 706 | owner=poster, subject='', content=comment['text'], |
293 | 744 | datecreated=comment_datetime) | 707 | datecreated=comment['time'].replace(tzinfo=pytz.timezone('UTC'))) |
291 | 745 | |||
292 | 746 | return message | ||
294 | 747 | 708 | ||
295 | 748 | @needs_authentication | 709 | @needs_authentication |
296 | 749 | def addRemoteComment(self, remote_bug, comment_body, rfc822msgid): | 710 | def addRemoteComment(self, remote_bug, comment_body, rfc822msgid): |
297 | @@ -826,7 +787,7 @@ | |||
298 | 826 | token_text = internal_xmlrpc_server.newBugTrackerToken() | 787 | token_text = internal_xmlrpc_server.newBugTrackerToken() |
299 | 827 | 788 | ||
300 | 828 | try: | 789 | try: |
302 | 829 | user_id = self.xmlrpc_proxy.Launchpad.login( | 790 | self.xmlrpc_proxy.Launchpad.login( |
303 | 830 | {'token': token_text}) | 791 | {'token': token_text}) |
304 | 831 | except xmlrpclib.Fault, fault: | 792 | except xmlrpclib.Fault, fault: |
305 | 832 | message = 'XML-RPC Fault: %s "%s"' % ( | 793 | message = 'XML-RPC Fault: %s "%s"' % ( |
306 | @@ -841,28 +802,17 @@ | |||
307 | 841 | 802 | ||
308 | 842 | def getModifiedRemoteBugs(self, bug_ids, last_checked): | 803 | def getModifiedRemoteBugs(self, bug_ids, last_checked): |
309 | 843 | """See `IExternalBugTracker`.""" | 804 | """See `IExternalBugTracker`.""" |
320 | 844 | # We marshal last_checked into an xmlrpclib.DateTime since | 805 | # We pass permissive=True to ensure that Bugzilla won't error |
321 | 845 | # xmlrpclib can't do so cleanly itself. | 806 | # if we ask for a bug that doesn't exist. |
322 | 846 | # XXX 2008-08-05 gmb (bug 254999): | 807 | response_dict = self.xmlrpc_proxy.Launchpad.get_bugs({ |
313 | 847 | # We can remove this once we upgrade to python 2.5. | ||
314 | 848 | changed_since = xmlrpclib.DateTime(last_checked.timetuple()) | ||
315 | 849 | |||
316 | 850 | # Create the arguments that we're going to send to the remote | ||
317 | 851 | # server. We pass permissive=True to ensure that Bugzilla won't | ||
318 | 852 | # error if we ask for a bug that doesn't exist. | ||
319 | 853 | request_args = { | ||
323 | 854 | 'ids': bug_ids, | 808 | 'ids': bug_ids, |
325 | 855 | 'changed_since': changed_since, | 809 | 'changed_since': last_checked, |
326 | 856 | 'permissive': True, | 810 | 'permissive': True, |
329 | 857 | } | 811 | }) |
328 | 858 | response_dict = self.xmlrpc_proxy.Launchpad.get_bugs(request_args) | ||
330 | 859 | remote_bugs = response_dict['bugs'] | 812 | remote_bugs = response_dict['bugs'] |
331 | 860 | |||
332 | 861 | # Store the bugs we've imported and return only their IDs. | 813 | # Store the bugs we've imported and return only their IDs. |
333 | 862 | self._storeBugs(remote_bugs) | 814 | self._storeBugs(remote_bugs) |
337 | 863 | bug_ids = [remote_bug['id'] for remote_bug in remote_bugs] | 815 | return [remote_bug['id'] for remote_bug in remote_bugs] |
335 | 864 | |||
336 | 865 | return bug_ids | ||
338 | 866 | 816 | ||
339 | 867 | def initializeRemoteBugDB(self, bug_ids, products=None): | 817 | def initializeRemoteBugDB(self, bug_ids, products=None): |
340 | 868 | """See `IExternalBugTracker`.""" | 818 | """See `IExternalBugTracker`.""" |
341 | @@ -892,10 +842,7 @@ | |||
342 | 892 | 842 | ||
343 | 893 | # Return the UTC time sent by the server so that we don't have | 843 | # Return the UTC time sent by the server so that we don't have |
344 | 894 | # to care about timezones. | 844 | # to care about timezones. |
349 | 895 | server_timetuple = time.strptime( | 845 | server_utc_time = time_dict['utc_time'] |
346 | 896 | str(time_dict['utc_time']), '%Y%m%dT%H:%M:%S') | ||
347 | 897 | |||
348 | 898 | server_utc_time = datetime(*server_timetuple[:6]) | ||
350 | 899 | return server_utc_time.replace(tzinfo=pytz.timezone('UTC')) | 846 | return server_utc_time.replace(tzinfo=pytz.timezone('UTC')) |
351 | 900 | 847 | ||
352 | 901 | def getCommentIds(self, bug_watch): | 848 | def getCommentIds(self, bug_watch): |
353 | 902 | 849 | ||
354 | === modified file 'lib/lp/bugs/externalbugtracker/xmlrpc.py' | |||
355 | --- lib/lp/bugs/externalbugtracker/xmlrpc.py 2009-10-16 22:00:45 +0000 | |||
356 | +++ lib/lp/bugs/externalbugtracker/xmlrpc.py 2009-12-23 12:17:18 +0000 | |||
357 | @@ -64,10 +64,9 @@ | |||
358 | 64 | verbose = False | 64 | verbose = False |
359 | 65 | 65 | ||
360 | 66 | def __init__(self, endpoint, cookie_jar=None): | 66 | def __init__(self, endpoint, cookie_jar=None): |
362 | 67 | Transport.__init__(self) | 67 | Transport.__init__(self, use_datetime=True) |
363 | 68 | self.scheme, self.host = urlparse(endpoint)[:2] | 68 | self.scheme, self.host = urlparse(endpoint)[:2] |
366 | 69 | assert ( | 69 | assert self.scheme in ('http', 'https'), ( |
365 | 70 | self.scheme in ('http', 'https'), | ||
367 | 71 | "Unsupported URL scheme: %s" % self.scheme) | 70 | "Unsupported URL scheme: %s" % self.scheme) |
368 | 72 | self.cookie_processor = HTTPCookieProcessor(cookie_jar) | 71 | self.cookie_processor = HTTPCookieProcessor(cookie_jar) |
369 | 73 | self.redirect_handler = XMLRPCRedirectHandler() | 72 | self.redirect_handler = XMLRPCRedirectHandler() |
370 | 74 | 73 | ||
371 | === modified file 'lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt' | |||
372 | --- lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt 2009-11-30 09:33:24 +0000 | |||
373 | +++ lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt 2009-12-23 12:17:18 +0000 | |||
374 | @@ -66,12 +66,12 @@ | |||
375 | 66 | >>> time_dict = server.Bugzilla.time() | 66 | >>> time_dict = server.Bugzilla.time() |
376 | 67 | >>> for key in sorted(time_dict): | 67 | >>> for key in sorted(time_dict): |
377 | 68 | ... print "%s: %s" % (key, time_dict[key]) | 68 | ... print "%s: %s" % (key, time_dict[key]) |
379 | 69 | db_time: 20080501T01:01:01 | 69 | db_time: 2008-05-01 01:01:01 |
380 | 70 | tz_name: UTC | 70 | tz_name: UTC |
381 | 71 | tz_offset: +0000 | 71 | tz_offset: +0000 |
382 | 72 | tz_short_name: UTC | 72 | tz_short_name: UTC |
385 | 73 | web_time: 20080501T01:01:01 | 73 | web_time: 2008-05-01 01:01:01 |
386 | 74 | web_time_utc: 20080501T01:01:01 | 74 | web_time_utc: 2008-05-01 01:01:01 |
387 | 75 | 75 | ||
388 | 76 | If the remote server is in a different timezone, the db_time and | 76 | If the remote server is in a different timezone, the db_time and |
389 | 77 | web_time items will be in the server's local timezone whilst | 77 | web_time items will be in the server's local timezone whilst |
390 | @@ -82,12 +82,12 @@ | |||
391 | 82 | >>> time_dict = server.Bugzilla.time() | 82 | >>> time_dict = server.Bugzilla.time() |
392 | 83 | >>> for key in sorted(time_dict): | 83 | >>> for key in sorted(time_dict): |
393 | 84 | ... print "%s: %s" % (key, time_dict[key]) | 84 | ... print "%s: %s" % (key, time_dict[key]) |
395 | 85 | db_time: 20080501T01:01:01 | 85 | db_time: 2008-05-01 01:01:01 |
396 | 86 | tz_name: CET | 86 | tz_name: CET |
397 | 87 | tz_offset: +0100 | 87 | tz_offset: +0100 |
398 | 88 | tz_short_name: CET | 88 | tz_short_name: CET |
401 | 89 | web_time: 20080501T01:01:01 | 89 | web_time: 2008-05-01 01:01:01 |
402 | 90 | web_time_utc: 20080501T00:01:01 | 90 | web_time_utc: 2008-05-01 00:01:01 |
403 | 91 | 91 | ||
404 | 92 | 92 | ||
405 | 93 | Getting bugs from the server | 93 | Getting bugs from the server |
406 | @@ -105,11 +105,11 @@ | |||
407 | 105 | alias: | 105 | alias: |
408 | 106 | assigned_to: test@canonical.com | 106 | assigned_to: test@canonical.com |
409 | 107 | component: GPPSystems | 107 | component: GPPSystems |
411 | 108 | creation_time: 20080610T16:19:53 | 108 | creation_time: 2008-06-10 16:19:53 |
412 | 109 | id: 1 | 109 | id: 1 |
413 | 110 | internals:... | 110 | internals:... |
414 | 111 | is_open: True | 111 | is_open: True |
416 | 112 | last_change_time: 20080610T16:19:53 | 112 | last_change_time: 2008-06-10 16:19:53 |
417 | 113 | priority: P1 | 113 | priority: P1 |
418 | 114 | product: Marvin | 114 | product: Marvin |
419 | 115 | resolution: FIXED | 115 | resolution: FIXED |
420 | @@ -135,16 +135,7 @@ | |||
421 | 135 | date / time. | 135 | date / time. |
422 | 136 | 136 | ||
423 | 137 | >>> from datetime import datetime | 137 | >>> from datetime import datetime |
424 | 138 | >>> from xmlrpclib import DateTime | ||
425 | 139 | >>> last_change_time = datetime(2008, 6, 11, 9, 0, 0) | 138 | >>> last_change_time = datetime(2008, 6, 11, 9, 0, 0) |
426 | 140 | |||
427 | 141 | # XXX 2009-08-21 gmb (bug 254999): | ||
428 | 142 | # We can remove this once we upgrade to python 2.5. We encode | ||
429 | 143 | # last_change_time into an XML-RPC DateTime manually. This is | ||
430 | 144 | # because xmlrpclib can't handle DateTime encoding within a | ||
431 | 145 | # dict. | ||
432 | 146 | >>> last_change_time = DateTime(last_change_time.timetuple()) | ||
433 | 147 | |||
434 | 148 | >>> return_value = server.Bug.search({ | 139 | >>> return_value = server.Bug.search({ |
435 | 149 | ... 'last_change_time': last_change_time, | 140 | ... 'last_change_time': last_change_time, |
436 | 150 | ... }) | 141 | ... }) |
437 | @@ -158,11 +149,11 @@ | |||
438 | 158 | alias: bug-two | 149 | alias: bug-two |
439 | 159 | assigned_to: marvin@heartofgold.ship | 150 | assigned_to: marvin@heartofgold.ship |
440 | 160 | component: Crew | 151 | component: Crew |
442 | 161 | creation_time: 20080611T09:23:12 | 152 | creation_time: 2008-06-11 09:23:12 |
443 | 162 | id: 2 | 153 | id: 2 |
444 | 163 | internals:... | 154 | internals:... |
445 | 164 | is_open: True | 155 | is_open: True |
447 | 165 | last_change_time: 20080611T09:24:29 | 156 | last_change_time: 2008-06-11 09:24:29 |
448 | 166 | priority: P1 | 157 | priority: P1 |
449 | 167 | product: HeartOfGold | 158 | product: HeartOfGold |
450 | 168 | resolution: | 159 | resolution: |
451 | @@ -175,7 +166,6 @@ | |||
452 | 175 | results to those IDs. | 166 | results to those IDs. |
453 | 176 | 167 | ||
454 | 177 | >>> last_change_time = datetime(2007, 6, 10, 1, 1, 1) | 168 | >>> last_change_time = datetime(2007, 6, 10, 1, 1, 1) |
455 | 178 | >>> last_change_time = DateTime(last_change_time.timetuple()) | ||
456 | 179 | >>> return_value = server.Bug.search({ | 169 | >>> return_value = server.Bug.search({ |
457 | 180 | ... 'id': [1], | 170 | ... 'id': [1], |
458 | 181 | ... 'last_change_time': last_change_time, | 171 | ... 'last_change_time': last_change_time, |
459 | @@ -188,11 +178,11 @@ | |||
460 | 188 | alias: | 178 | alias: |
461 | 189 | assigned_to: test@canonical.com | 179 | assigned_to: test@canonical.com |
462 | 190 | component: GPPSystems | 180 | component: GPPSystems |
464 | 191 | creation_time: 20080610T16:19:53 | 181 | creation_time: 2008-06-10 16:19:53 |
465 | 192 | id: 1 | 182 | id: 1 |
466 | 193 | internals:... | 183 | internals:... |
467 | 194 | is_open: True | 184 | is_open: True |
469 | 195 | last_change_time: 20080610T16:19:53 | 185 | last_change_time: 2008-06-10 16:19:53 |
470 | 196 | priority: P1 | 186 | priority: P1 |
471 | 197 | product: Marvin | 187 | product: Marvin |
472 | 198 | resolution: FIXED | 188 | resolution: FIXED |
473 | @@ -206,11 +196,6 @@ | |||
474 | 206 | 196 | ||
475 | 207 | >>> from datetime import timedelta | 197 | >>> from datetime import timedelta |
476 | 208 | >>> last_change_time = datetime.now() + timedelta(days=42) | 198 | >>> last_change_time = datetime.now() + timedelta(days=42) |
477 | 209 | |||
478 | 210 | >>> # XXX 2008-08-05 gmb (bug 254999): | ||
479 | 211 | >>> # We can remove this once we upgrade to python 2.5. | ||
480 | 212 | >>> last_change_time = DateTime(last_change_time.timetuple()) | ||
481 | 213 | |||
482 | 214 | >>> return_value = server.Bug.search({ | 199 | >>> return_value = server.Bug.search({ |
483 | 215 | ... 'last_change_time': last_change_time, | 200 | ... 'last_change_time': last_change_time, |
484 | 216 | ... }) | 201 | ... }) |
485 | @@ -232,11 +217,11 @@ | |||
486 | 232 | alias: bug-two | 217 | alias: bug-two |
487 | 233 | assigned_to: marvin@heartofgold.ship | 218 | assigned_to: marvin@heartofgold.ship |
488 | 234 | component: Crew | 219 | component: Crew |
490 | 235 | creation_time: 20080611T09:23:12 | 220 | creation_time: 2008-06-11 09:23:12 |
491 | 236 | id: 2 | 221 | id: 2 |
492 | 237 | internals:... | 222 | internals:... |
493 | 238 | is_open: True | 223 | is_open: True |
495 | 239 | last_change_time: 20080611T09:24:29 | 224 | last_change_time: 2008-06-11 09:24:29 |
496 | 240 | priority: P1 | 225 | priority: P1 |
497 | 241 | product: HeartOfGold | 226 | product: HeartOfGold |
498 | 242 | resolution: | 227 | resolution: |
499 | @@ -257,11 +242,11 @@ | |||
500 | 257 | alias: | 242 | alias: |
501 | 258 | assigned_to: test@canonical.com | 243 | assigned_to: test@canonical.com |
502 | 259 | component: GPPSystems | 244 | component: GPPSystems |
504 | 260 | creation_time: 20080610T16:19:53 | 245 | creation_time: 2008-06-10 16:19:53 |
505 | 261 | id: 1 | 246 | id: 1 |
506 | 262 | internals:... | 247 | internals:... |
507 | 263 | is_open: True | 248 | is_open: True |
509 | 264 | last_change_time: 20080610T16:19:53 | 249 | last_change_time: 2008-06-10 16:19:53 |
510 | 265 | priority: P1 | 250 | priority: P1 |
511 | 266 | product: Marvin | 251 | product: Marvin |
512 | 267 | resolution: FIXED | 252 | resolution: FIXED |
513 | @@ -272,11 +257,11 @@ | |||
514 | 272 | alias: bug-two | 257 | alias: bug-two |
515 | 273 | assigned_to: marvin@heartofgold.ship | 258 | assigned_to: marvin@heartofgold.ship |
516 | 274 | component: Crew | 259 | component: Crew |
518 | 275 | creation_time: 20080611T09:23:12 | 260 | creation_time: 2008-06-11 09:23:12 |
519 | 276 | id: 2 | 261 | id: 2 |
520 | 277 | internals:... | 262 | internals:... |
521 | 278 | is_open: True | 263 | is_open: True |
523 | 279 | last_change_time: 20080611T09:24:29 | 264 | last_change_time: 2008-06-11 09:24:29 |
524 | 280 | priority: P1 | 265 | priority: P1 |
525 | 281 | product: HeartOfGold | 266 | product: HeartOfGold |
526 | 282 | resolution: | 267 | resolution: |
527 | @@ -321,14 +306,14 @@ | |||
528 | 321 | id: 1 | 306 | id: 1 |
529 | 322 | is_private: False | 307 | is_private: False |
530 | 323 | text: I'd really appreciate it if Marvin would enjoy life a bit. | 308 | text: I'd really appreciate it if Marvin would enjoy life a bit. |
532 | 324 | time: 20080616T12:44:29 | 309 | time: 2008-06-16 12:44:29 |
533 | 325 | <BLANKLINE> | 310 | <BLANKLINE> |
534 | 326 | author: marvin | 311 | author: marvin |
535 | 327 | bug_id: 1 | 312 | bug_id: 1 |
536 | 328 | id: 3 | 313 | id: 3 |
537 | 329 | is_private: False | 314 | is_private: False |
538 | 330 | text: Life? Don't talk to me about life. | 315 | text: Life? Don't talk to me about life. |
540 | 331 | time: 20080616T13:22:29 | 316 | time: 2008-06-16 13:22:29 |
541 | 332 | <BLANKLINE> | 317 | <BLANKLINE> |
542 | 333 | <BLANKLINE> | 318 | <BLANKLINE> |
543 | 334 | Bug 2: | 319 | Bug 2: |
544 | @@ -337,14 +322,14 @@ | |||
545 | 337 | id: 2 | 322 | id: 2 |
546 | 338 | is_private: False | 323 | is_private: False |
547 | 339 | text: Bring the passengers to the bridge please Marvin. | 324 | text: Bring the passengers to the bridge please Marvin. |
549 | 340 | time: 20080616T13:08:08 | 325 | time: 2008-06-16 13:08:08 |
550 | 341 | <BLANKLINE> | 326 | <BLANKLINE> |
551 | 342 | author: Ford Prefect <ford.prefect@h2g2.com> | 327 | author: Ford Prefect <ford.prefect@h2g2.com> |
552 | 343 | bug_id: 2 | 328 | bug_id: 2 |
553 | 344 | id: 4 | 329 | id: 4 |
554 | 345 | is_private: False | 330 | is_private: False |
555 | 346 | text: I appear to have become a perfectly safe penguin. | 331 | text: I appear to have become a perfectly safe penguin. |
557 | 347 | time: 20080617T20:28:40 | 332 | time: 2008-06-17 20:28:40 |
558 | 348 | <BLANKLINE> | 333 | <BLANKLINE> |
559 | 349 | <BLANKLINE> | 334 | <BLANKLINE> |
560 | 350 | 335 | ||
561 | @@ -366,14 +351,14 @@ | |||
562 | 366 | id: 1 | 351 | id: 1 |
563 | 367 | is_private: False | 352 | is_private: False |
564 | 368 | text: I'd really appreciate it if Marvin would enjoy life a bit. | 353 | text: I'd really appreciate it if Marvin would enjoy life a bit. |
566 | 369 | time: 20080616T12:44:29 | 354 | time: 2008-06-16 12:44:29 |
567 | 370 | Comment 4: | 355 | Comment 4: |
568 | 371 | author: Ford Prefect <ford.prefect@h2g2.com> | 356 | author: Ford Prefect <ford.prefect@h2g2.com> |
569 | 372 | bug_id: 2 | 357 | bug_id: 2 |
570 | 373 | id: 4 | 358 | id: 4 |
571 | 374 | is_private: False | 359 | is_private: False |
572 | 375 | text: I appear to have become a perfectly safe penguin. | 360 | text: I appear to have become a perfectly safe penguin. |
574 | 376 | time: 20080617T20:28:40 | 361 | time: 2008-06-17 20:28:40 |
575 | 377 | <BLANKLINE> | 362 | <BLANKLINE> |
576 | 378 | 363 | ||
577 | 379 | Note that only comments have been returned when only 'comment_ids' have | 364 | Note that only comments have been returned when only 'comment_ids' have |
578 | @@ -499,11 +484,11 @@ | |||
579 | 499 | alias: | 484 | alias: |
580 | 500 | assigned_to: test@canonical.com | 485 | assigned_to: test@canonical.com |
581 | 501 | component: GPPSystems | 486 | component: GPPSystems |
583 | 502 | creation_time: 20080610T16:19:53 | 487 | creation_time: 2008-06-10 16:19:53 |
584 | 503 | id: 1 | 488 | id: 1 |
585 | 504 | internals:... | 489 | internals:... |
586 | 505 | is_open: True | 490 | is_open: True |
588 | 506 | last_change_time: 20080610T16:19:53 | 491 | last_change_time: 2008-06-10 16:19:53 |
589 | 507 | priority: P1 | 492 | priority: P1 |
590 | 508 | product: Marvin | 493 | product: Marvin |
591 | 509 | resolution: FIXED | 494 | resolution: FIXED |
592 | 510 | 495 | ||
593 | === modified file 'lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt' | |||
594 | --- lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt 2009-12-11 16:05:52 +0000 | |||
595 | +++ lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt 2009-12-23 12:17:18 +0000 | |||
596 | @@ -105,9 +105,9 @@ | |||
597 | 105 | >>> time_dict = server.Launchpad.time() | 105 | >>> time_dict = server.Launchpad.time() |
598 | 106 | >>> for key in sorted(time_dict): | 106 | >>> for key in sorted(time_dict): |
599 | 107 | ... print "%s: %s" % (key, time_dict[key]) | 107 | ... print "%s: %s" % (key, time_dict[key]) |
601 | 108 | local_time: 20080501T01:01:01 | 108 | local_time: 2008-05-01 01:01:01 |
602 | 109 | tz_name: UTC | 109 | tz_name: UTC |
604 | 110 | utc_time: 20080501T01:01:01 | 110 | utc_time: 2008-05-01 01:01:01 |
605 | 111 | 111 | ||
606 | 112 | We can set the local time value on the remote server to make testing | 112 | We can set the local time value on the remote server to make testing |
607 | 113 | more useful. | 113 | more useful. |
608 | @@ -122,9 +122,9 @@ | |||
609 | 122 | >>> time_dict = server.Launchpad.time() | 122 | >>> time_dict = server.Launchpad.time() |
610 | 123 | >>> for key in sorted(time_dict): | 123 | >>> for key in sorted(time_dict): |
611 | 124 | ... print "%s: %s" % (key, time_dict[key]) | 124 | ... print "%s: %s" % (key, time_dict[key]) |
613 | 125 | local_time: 20080515T16:19:53 | 125 | local_time: 2008-05-15 16:19:53 |
614 | 126 | tz_name: US/Central | 126 | tz_name: US/Central |
616 | 127 | utc_time: 20080515T22:19:53 | 127 | utc_time: 2008-05-15 22:19:53 |
617 | 128 | 128 | ||
618 | 129 | 129 | ||
619 | 130 | Launchpad.get_bugs() | 130 | Launchpad.get_bugs() |
620 | @@ -144,11 +144,11 @@ | |||
621 | 144 | alias: | 144 | alias: |
622 | 145 | assigned_to: test@canonical.com | 145 | assigned_to: test@canonical.com |
623 | 146 | component: GPPSystems | 146 | component: GPPSystems |
625 | 147 | creation_time: 20080610T16:19:53 | 147 | creation_time: 2008-06-10 16:19:53 |
626 | 148 | id: 1 | 148 | id: 1 |
627 | 149 | internals:... | 149 | internals:... |
628 | 150 | is_open: True | 150 | is_open: True |
630 | 151 | last_change_time: 20080610T16:19:53 | 151 | last_change_time: 2008-06-10 16:19:53 |
631 | 152 | priority: P1 | 152 | priority: P1 |
632 | 153 | product: Marvin | 153 | product: Marvin |
633 | 154 | resolution: FIXED | 154 | resolution: FIXED |
634 | @@ -170,11 +170,11 @@ | |||
635 | 170 | alias: | 170 | alias: |
636 | 171 | assigned_to: test@canonical.com | 171 | assigned_to: test@canonical.com |
637 | 172 | component: GPPSystems | 172 | component: GPPSystems |
639 | 173 | creation_time: 20080610T16:19:53 | 173 | creation_time: 2008-06-10 16:19:53 |
640 | 174 | id: 1 | 174 | id: 1 |
641 | 175 | internals:... | 175 | internals:... |
642 | 176 | is_open: True | 176 | is_open: True |
644 | 177 | last_change_time: 20080610T16:19:53 | 177 | last_change_time: 2008-06-10 16:19:53 |
645 | 178 | priority: P1 | 178 | priority: P1 |
646 | 179 | product: Marvin | 179 | product: Marvin |
647 | 180 | resolution: FIXED | 180 | resolution: FIXED |
648 | @@ -186,11 +186,11 @@ | |||
649 | 186 | alias: bug-two | 186 | alias: bug-two |
650 | 187 | assigned_to: marvin@heartofgold.ship | 187 | assigned_to: marvin@heartofgold.ship |
651 | 188 | component: Crew | 188 | component: Crew |
653 | 189 | creation_time: 20080611T09:23:12 | 189 | creation_time: 2008-06-11 09:23:12 |
654 | 190 | id: 2 | 190 | id: 2 |
655 | 191 | internals:... | 191 | internals:... |
656 | 192 | is_open: True | 192 | is_open: True |
658 | 193 | last_change_time: 20080611T09:24:29 | 193 | last_change_time: 2008-06-11 09:24:29 |
659 | 194 | priority: P1 | 194 | priority: P1 |
660 | 195 | product: HeartOfGold | 195 | product: HeartOfGold |
661 | 196 | resolution: | 196 | resolution: |
662 | @@ -209,11 +209,11 @@ | |||
663 | 209 | alias: bug-two | 209 | alias: bug-two |
664 | 210 | assigned_to: marvin@heartofgold.ship | 210 | assigned_to: marvin@heartofgold.ship |
665 | 211 | component: Crew | 211 | component: Crew |
667 | 212 | creation_time: 20080611T09:23:12 | 212 | creation_time: 2008-06-11 09:23:12 |
668 | 213 | id: 2 | 213 | id: 2 |
669 | 214 | internals:... | 214 | internals:... |
670 | 215 | is_open: True | 215 | is_open: True |
672 | 216 | last_change_time: 20080611T09:24:29 | 216 | last_change_time: 2008-06-11 09:24:29 |
673 | 217 | priority: P1 | 217 | priority: P1 |
674 | 218 | product: HeartOfGold | 218 | product: HeartOfGold |
675 | 219 | resolution: | 219 | resolution: |
676 | @@ -228,17 +228,8 @@ | |||
677 | 228 | allowing Launchpad to get only the recently-updated subset of a given | 228 | allowing Launchpad to get only the recently-updated subset of a given |
678 | 229 | set of remote bugs. | 229 | set of remote bugs. |
679 | 230 | 230 | ||
680 | 231 | >>> from xmlrpclib import DateTime | ||
681 | 232 | |||
682 | 233 | >>> changed_since = datetime(2008, 6, 11, 9, 0, 0) | 231 | >>> changed_since = datetime(2008, 6, 11, 9, 0, 0) |
683 | 234 | 232 | ||
684 | 235 | >>> # We encode changed_since into an XML-RPC DateTime manually. | ||
685 | 236 | >>> # This is because xmlrpclib can't handle DateTime encoding | ||
686 | 237 | >>> # within a dict. | ||
687 | 238 | >>> # XXX 2008-08-05 gmb (bug 254999): | ||
688 | 239 | >>> # We can remove this once we upgrade to python 2.5. | ||
689 | 240 | >>> changed_since = DateTime(changed_since.timetuple()) | ||
690 | 241 | |||
691 | 242 | >>> return_value = server.Launchpad.get_bugs({ | 233 | >>> return_value = server.Launchpad.get_bugs({ |
692 | 243 | ... 'ids': [1, 2], | 234 | ... 'ids': [1, 2], |
693 | 244 | ... 'changed_since': changed_since, | 235 | ... 'changed_since': changed_since, |
694 | @@ -254,11 +245,11 @@ | |||
695 | 254 | alias: bug-two | 245 | alias: bug-two |
696 | 255 | assigned_to: marvin@heartofgold.ship | 246 | assigned_to: marvin@heartofgold.ship |
697 | 256 | component: Crew | 247 | component: Crew |
699 | 257 | creation_time: 20080611T09:23:12 | 248 | creation_time: 2008-06-11 09:23:12 |
700 | 258 | id: 2 | 249 | id: 2 |
701 | 259 | internals:... | 250 | internals:... |
702 | 260 | is_open: True | 251 | is_open: True |
704 | 261 | last_change_time: 20080611T09:24:29 | 252 | last_change_time: 2008-06-11 09:24:29 |
705 | 262 | priority: P1 | 253 | priority: P1 |
706 | 263 | product: HeartOfGold | 254 | product: HeartOfGold |
707 | 264 | resolution: | 255 | resolution: |
708 | @@ -273,10 +264,6 @@ | |||
709 | 273 | >>> from datetime import timedelta | 264 | >>> from datetime import timedelta |
710 | 274 | >>> changed_since = datetime.now() + timedelta(days=42) | 265 | >>> changed_since = datetime.now() + timedelta(days=42) |
711 | 275 | 266 | ||
712 | 276 | >>> # XXX 2008-08-05 gmb (bug 254999): | ||
713 | 277 | >>> # We can remove this once we upgrade to python 2.5. | ||
714 | 278 | >>> changed_since = DateTime(changed_since.timetuple()) | ||
715 | 279 | |||
716 | 280 | >>> return_value = server.Launchpad.get_bugs({ | 267 | >>> return_value = server.Launchpad.get_bugs({ |
717 | 281 | ... 'ids': [1, 2], | 268 | ... 'ids': [1, 2], |
718 | 282 | ... 'changed_since': changed_since, | 269 | ... 'changed_since': changed_since, |
719 | @@ -304,11 +291,11 @@ | |||
720 | 304 | alias: bug-two | 291 | alias: bug-two |
721 | 305 | assigned_to: marvin@heartofgold.ship | 292 | assigned_to: marvin@heartofgold.ship |
722 | 306 | component: Crew | 293 | component: Crew |
724 | 307 | creation_time: 20080611T09:23:12 | 294 | creation_time: 2008-06-11 09:23:12 |
725 | 308 | id: 2 | 295 | id: 2 |
726 | 309 | internals:... | 296 | internals:... |
727 | 310 | is_open: True | 297 | is_open: True |
729 | 311 | last_change_time: 20080611T09:24:29 | 298 | last_change_time: 2008-06-11 09:24:29 |
730 | 312 | priority: P1 | 299 | priority: P1 |
731 | 313 | product: HeartOfGold | 300 | product: HeartOfGold |
732 | 314 | resolution: | 301 | resolution: |
733 | @@ -366,13 +353,13 @@ | |||
734 | 366 | id: 1 | 353 | id: 1 |
735 | 367 | number: 1 | 354 | number: 1 |
736 | 368 | text: I'd really appreciate it if Marvin would enjoy life a bit. | 355 | text: I'd really appreciate it if Marvin would enjoy life a bit. |
738 | 369 | time: 20080616T12:44:29 | 356 | time: 2008-06-16 12:44:29 |
739 | 370 | <BLANKLINE> | 357 | <BLANKLINE> |
740 | 371 | author: marvin | 358 | author: marvin |
741 | 372 | id: 3 | 359 | id: 3 |
742 | 373 | number: 2 | 360 | number: 2 |
743 | 374 | text: Life? Don't talk to me about life. | 361 | text: Life? Don't talk to me about life. |
745 | 375 | time: 20080616T13:22:29 | 362 | time: 2008-06-16 13:22:29 |
746 | 376 | <BLANKLINE> | 363 | <BLANKLINE> |
747 | 377 | <BLANKLINE> | 364 | <BLANKLINE> |
748 | 378 | Bug 2: | 365 | Bug 2: |
749 | @@ -380,13 +367,13 @@ | |||
750 | 380 | id: 2 | 367 | id: 2 |
751 | 381 | number: 1 | 368 | number: 1 |
752 | 382 | text: Bring the passengers to the bridge please Marvin. | 369 | text: Bring the passengers to the bridge please Marvin. |
754 | 383 | time: 20080616T13:08:08 | 370 | time: 2008-06-16 13:08:08 |
755 | 384 | <BLANKLINE> | 371 | <BLANKLINE> |
756 | 385 | author: Ford Prefect <ford.prefect@h2g2.com> | 372 | author: Ford Prefect <ford.prefect@h2g2.com> |
757 | 386 | id: 4 | 373 | id: 4 |
758 | 387 | number: 2 | 374 | number: 2 |
759 | 388 | text: I appear to have become a perfectly safe penguin. | 375 | text: I appear to have become a perfectly safe penguin. |
761 | 389 | time: 20080617T20:28:40 | 376 | time: 2008-06-17 20:28:40 |
762 | 390 | 377 | ||
763 | 391 | If an ids parameter is specified along with bug_ids, only the comments | 378 | If an ids parameter is specified along with bug_ids, only the comments |
764 | 392 | whose IDs are in the list of IDs passed will be returned. | 379 | whose IDs are in the list of IDs passed will be returned. |
765 | @@ -401,7 +388,7 @@ | |||
766 | 401 | id: 1 | 388 | id: 1 |
767 | 402 | number: 1 | 389 | number: 1 |
768 | 403 | text: I'd really appreciate it if Marvin would enjoy life a bit. | 390 | text: I'd really appreciate it if Marvin would enjoy life a bit. |
770 | 404 | time: 20080616T12:44:29 | 391 | time: 2008-06-16 12:44:29 |
771 | 405 | <BLANKLINE> | 392 | <BLANKLINE> |
772 | 406 | <BLANKLINE> | 393 | <BLANKLINE> |
773 | 407 | Bug 2: | 394 | Bug 2: |
774 | @@ -409,7 +396,7 @@ | |||
775 | 409 | id: 2 | 396 | id: 2 |
776 | 410 | number: 1 | 397 | number: 1 |
777 | 411 | text: Bring the passengers to the bridge please Marvin. | 398 | text: Bring the passengers to the bridge please Marvin. |
779 | 412 | time: 20080616T13:08:08 | 399 | time: 2008-06-16 13:08:08 |
780 | 413 | 400 | ||
781 | 414 | Passing an include_fields parameter allows us to limit which fields are | 401 | Passing an include_fields parameter allows us to limit which fields are |
782 | 415 | returned for each comment. | 402 | returned for each comment. |
783 | 416 | 403 | ||
784 | === modified file 'lib/lp/bugs/tests/externalbugtracker.py' | |||
785 | --- lib/lp/bugs/tests/externalbugtracker.py 2009-11-30 10:21:23 +0000 | |||
786 | +++ lib/lp/bugs/tests/externalbugtracker.py 2009-12-23 12:17:18 +0000 | |||
787 | @@ -65,7 +65,7 @@ | |||
788 | 65 | while bugtracker_set.getByName("%s-%d" % (name, index)) is not None: | 65 | while bugtracker_set.getByName("%s-%d" % (name, index)) is not None: |
789 | 66 | index += 1 | 66 | index += 1 |
790 | 67 | name += '-%d' % index | 67 | name += '-%d' % index |
792 | 68 | bugtracker = BugTracker( | 68 | BugTracker( |
793 | 69 | name=name, | 69 | name=name, |
794 | 70 | title='%s *TESTING*' % (bugtracker_type.title,), | 70 | title='%s *TESTING*' % (bugtracker_type.title,), |
795 | 71 | bugtrackertype=bugtracker_type, | 71 | bugtrackertype=bugtracker_type, |
796 | @@ -282,7 +282,6 @@ | |||
797 | 282 | buglist_xml = read_test_file(self.buglist_file) | 282 | buglist_xml = read_test_file(self.buglist_file) |
798 | 283 | bug_ids = str(form[self.bug_id_form_element]).split(',') | 283 | bug_ids = str(form[self.bug_id_form_element]).split(',') |
799 | 284 | bug_li_items = [] | 284 | bug_li_items = [] |
800 | 285 | status_tag = None | ||
801 | 286 | for bug_id in bug_ids: | 285 | for bug_id in bug_ids: |
802 | 287 | bug_id = int(bug_id) | 286 | bug_id = int(bug_id) |
803 | 288 | if bug_id not in self.bugzilla_bugs: | 287 | if bug_id not in self.bugzilla_bugs: |
804 | @@ -527,17 +526,12 @@ | |||
805 | 527 | if local_datetime is None: | 526 | if local_datetime is None: |
806 | 528 | local_datetime = datetime(2008, 5, 1, 1, 1, 1) | 527 | local_datetime = datetime(2008, 5, 1, 1, 1, 1) |
807 | 529 | 528 | ||
808 | 530 | # We return xmlrpc dateTimes rather than doubles since that's | ||
809 | 531 | # what BugZilla will return. | ||
810 | 532 | local_time = xmlrpclib.DateTime(local_datetime.timetuple()) | ||
811 | 533 | |||
812 | 534 | utc_offset_delta = timedelta(seconds=self.utc_offset) | 529 | utc_offset_delta = timedelta(seconds=self.utc_offset) |
813 | 535 | utc_date_time = local_datetime - utc_offset_delta | 530 | utc_date_time = local_datetime - utc_offset_delta |
814 | 536 | 531 | ||
815 | 537 | utc_time = xmlrpclib.DateTime(utc_date_time.timetuple()) | ||
816 | 538 | return { | 532 | return { |
819 | 539 | 'local_time': local_time, | 533 | 'local_time': local_datetime, |
820 | 540 | 'utc_time': utc_time, | 534 | 'utc_time': utc_date_time, |
821 | 541 | 'tz_name': self.timezone, | 535 | 'tz_name': self.timezone, |
822 | 542 | } | 536 | } |
823 | 543 | 537 | ||
824 | @@ -593,7 +587,6 @@ | |||
825 | 593 | "One of ('ids', 'products') should be specified") | 587 | "One of ('ids', 'products') should be specified") |
826 | 594 | 588 | ||
827 | 595 | bugs_to_return = [] | 589 | bugs_to_return = [] |
828 | 596 | bugs = dict(self.bugs) | ||
829 | 597 | 590 | ||
830 | 598 | # We enforce permissiveness, since we'll always call this method | 591 | # We enforce permissiveness, since we'll always call this method |
831 | 599 | # with permissive=True in the Real World. | 592 | # with permissive=True in the Real World. |
832 | @@ -601,14 +594,14 @@ | |||
833 | 601 | assert permissive, "get_bugs() must be called with permissive=True" | 594 | assert permissive, "get_bugs() must be called with permissive=True" |
834 | 602 | 595 | ||
835 | 603 | # If a changed_since argument is specified, marshall it into a | 596 | # If a changed_since argument is specified, marshall it into a |
839 | 604 | # datetime so that we can use it for comparisons. | 597 | # datetime so that we can use it for comparisons. Even though |
840 | 605 | # XXX 2008-08-05 gmb (bug 254999): | 598 | # xmlrpclib in Python 2.5 groks datetime, by the time this |
841 | 606 | # We can remove these lines once we upgrade to python 2.5. | 599 | # method is called xmlrpclib has already converted all |
842 | 600 | # datetimes to xmlrpclib.DateTime. | ||
843 | 607 | changed_since = arguments.get('changed_since') | 601 | changed_since = arguments.get('changed_since') |
844 | 608 | if changed_since is not None: | 602 | if changed_since is not None: |
848 | 609 | changed_since_timetuple = time.strptime( | 603 | changed_since = datetime.strptime( |
849 | 610 | str(changed_since), '%Y%m%dT%H:%M:%S') | 604 | changed_since.value, '%Y%m%dT%H:%M:%S') |
847 | 611 | changed_since = datetime(*changed_since_timetuple[:6]) | ||
850 | 612 | 605 | ||
851 | 613 | # If we have some products but no bug_ids we just get all the | 606 | # If we have some products but no bug_ids we just get all the |
852 | 614 | # bug IDs for those products and stuff them in the bug_ids list | 607 | # bug IDs for those products and stuff them in the bug_ids list |
853 | @@ -644,14 +637,6 @@ | |||
854 | 644 | bug_dict['product'] not in products): | 637 | bug_dict['product'] not in products): |
855 | 645 | continue | 638 | continue |
856 | 646 | 639 | ||
857 | 647 | # Update the DateTime fields of the bug dict so that they | ||
858 | 648 | # look like ones that would be sent over XML-RPC. | ||
859 | 649 | for time_field in ('creation_time', 'last_change_time'): | ||
860 | 650 | datetime_value = bug_dict[time_field] | ||
861 | 651 | timestamp = time.mktime(datetime_value.timetuple()) | ||
862 | 652 | xmlrpc_datetime = xmlrpclib.DateTime(timestamp) | ||
863 | 653 | bug_dict[time_field] = xmlrpc_datetime | ||
864 | 654 | |||
865 | 655 | bugs_to_return.append(bug_dict) | 640 | bugs_to_return.append(bug_dict) |
866 | 656 | 641 | ||
867 | 657 | # "Why are you returning a list here?" I hear you cry. Well, | 642 | # "Why are you returning a list here?" I hear you cry. Well, |
868 | @@ -662,15 +647,9 @@ | |||
869 | 662 | 647 | ||
870 | 663 | def _copy_comment(self, comment, fields_to_return=None): | 648 | def _copy_comment(self, comment, fields_to_return=None): |
871 | 664 | # Copy wanted fields. | 649 | # Copy wanted fields. |
873 | 665 | comment = dict( | 650 | return dict( |
874 | 666 | (key, value) for (key, value) in comment.iteritems() | 651 | (key, value) for (key, value) in comment.iteritems() |
875 | 667 | if fields_to_return is None or key in fields_to_return) | 652 | if fields_to_return is None or key in fields_to_return) |
876 | 668 | # Replace the time field with an XML-RPC DateTime. | ||
877 | 669 | if 'time' in comment: | ||
878 | 670 | comment['time'] = xmlrpclib.DateTime( | ||
879 | 671 | comment['time'].timetuple()) | ||
880 | 672 | return comment | ||
881 | 673 | |||
882 | 674 | 653 | ||
883 | 675 | def comments(self, arguments): | 654 | def comments(self, arguments): |
884 | 676 | """Return comments for a given set of bugs.""" | 655 | """Return comments for a given set of bugs.""" |
885 | @@ -1617,8 +1596,7 @@ | |||
886 | 1617 | The response body is an XMLRPC response. In addition we set the | 1596 | The response body is an XMLRPC response. In addition we set the |
887 | 1618 | info of the response to contain a cookie. | 1597 | info of the response to contain a cookie. |
888 | 1619 | """ | 1598 | """ |
891 | 1620 | assert ( | 1599 | assert isinstance(req, Request), ( |
890 | 1621 | isinstance(req, Request), | ||
892 | 1622 | 'Expected a urllib2.Request, got %s' % req) | 1600 | 'Expected a urllib2.Request, got %s' % req) |
893 | 1623 | 1601 | ||
894 | 1624 | if 'testError' in req.data: | 1602 | if 'testError' in req.data: |
Removes the xmlrpclib. DateTime( ) hacks in the external bug tracker code, as it's not needed with the version of xmlrpclib in Python 2.5. I've also done a fair bit of de-linting, but it's still a small change so I haven't broken it out into a separate patch.