Merge lp:~allenap/launchpad/remove-xmlrpclib-marshalling-bug-254999 into lp:launchpad

Proposed by Gavin Panella
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
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.

To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) wrote :

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.

Revision history for this message
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/bugs/externalbugtracker/bugzilla.py:717: # XXX 2008-08-05 gmb (bug 254999):
lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt:141: # XXX 2009-08-21 gmb (bug 254999):
lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt:210: >>> # XXX 2008-08-05 gmb (bug 254999):
lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt:238: >>> # XXX 2008-08-05 gmb (bug 254999):
lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt:276: >>> # XXX 2008-08-05 gmb (bug 254999):
lib/lp/bugs/tests/externalbugtracker.py:603: # XXX 2008-08-05 gmb (bug 254999):

review: Needs Fixing (code)
Revision history for this message
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.

=== modified file 'lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt'
--- lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt 2009-12-21 15:03:42 +0000
+++ lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt 2009-12-23 10:18:19 +0000
@@ -139,8 +139,8 @@
139 >>> def print_bugs(bugs):139 >>> def print_bugs(bugs):
140 ... for bug in sorted(bugs):140 ... for bug in sorted(bugs):
141 ... print "Bug %s:" % bug141 ... print "Bug %s:" % bug
142 ... for key in sorted(bugzilla._bugs[bug]):142 ... for key in sorted(bugs[bug]):
143 ... print " %s: %s" % (key, bugzilla._bugs[bug][key])143 ... print " %s: %s" % (key, bugs[bug][key])
144 ... print "\n"144 ... print "\n"
145145
146 >>> print_bugs(bugzilla._bugs)146 >>> print_bugs(bugzilla._bugs)
@@ -148,11 +148,11 @@
148 alias:148 alias:
149 assigned_to: test@canonical.com149 assigned_to: test@canonical.com
150 component: GPPSystems150 component: GPPSystems
151 creation_time: 20080610T16:19:53151 creation_time: 2008-06-10 16:19:53
152 id: 1152 id: 1
153 internals:...153 internals:...
154 is_open: True154 is_open: True
155 last_change_time: 20080610T16:19:53155 last_change_time: 2008-06-10 16:19:53
156 priority: P1156 priority: P1
157 product: Marvin157 product: Marvin
158 resolution: FIXED158 resolution: FIXED
@@ -165,11 +165,11 @@
165 alias: bug-two165 alias: bug-two
166 assigned_to: marvin@heartofgold.ship166 assigned_to: marvin@heartofgold.ship
167 component: Crew167 component: Crew
168 creation_time: 20080611T09:23:12168 creation_time: 2008-06-11 09:23:12
169 id: 2169 id: 2
170 internals:...170 internals:...
171 is_open: True171 is_open: True
172 last_change_time: 20080611T09:24:29172 last_change_time: 2008-06-11 09:24:29
173 priority: P1173 priority: P1
174 product: HeartOfGold174 product: HeartOfGold
175 resolution:175 resolution:
@@ -194,20 +194,16 @@
194 >>> bugzilla.initializeRemoteBugDB([2, 'bug-two'])194 >>> bugzilla.initializeRemoteBugDB([2, 'bug-two'])
195 CALLED Bug.get({'ids': [2, 'bug-two'], 'permissive': True})195 CALLED Bug.get({'ids': [2, 'bug-two'], 'permissive': True})
196196
197 >>> for bug in sorted(bugzilla._bugs):197 >>> print_bugs(bugzilla._bugs)
198 ... print "Bug %r:" % bug
199 ... for key in sorted(bugzilla._bugs[bug]):
200 ... print " %s: %s" % (key, bugzilla._bugs[bug][key])
201 ... print "\n"
202 Bug 2:198 Bug 2:
203 alias: bug-two199 alias: bug-two
204 assigned_to: marvin@heartofgold.ship200 assigned_to: marvin@heartofgold.ship
205 component: Crew201 component: Crew
206 creation_time: 20080611T09:23:12202 creation_time: 2008-06-11 09:23:12
207 id: 2203 id: 2
208 internals:...204 internals:...
209 is_open: True205 is_open: True
210 last_change_time: 20080611T09:24:29206 last_change_time: 2008-06-11 09:24:29
211 priority: P1207 priority: P1
212 product: HeartOfGold208 product: HeartOfGold
213 resolution:209 resolution:
@@ -450,14 +446,14 @@
450 id: 1446 id: 1
451 is_private: False447 is_private: False
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.
453 time: 20080616T12:44:29449 time: 2008-06-16 12:44:29
454 Comment 3:450 Comment 3:
455 author: marvin451 author: marvin
456 bug_id: 1452 bug_id: 1
457 id: 3453 id: 3
458 is_private: False454 is_private: False
459 text: Life? Don't talk to me about life.455 text: Life? Don't talk to me about life.
460 time: 20080616T13:22:29456 time: 2008-06-16 13:22:29
461457
462If we try to fetch comments that don't belong to the current bug458If we try to fetch comments that don't belong to the current bug
463fetchComments() will silently ignore them.459fetchComments() will silently ignore them.
@@ -477,7 +473,7 @@
477 id: 1473 id: 1
478 is_private: False474 is_private: False
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.
480 time: 20080616T12:44:29476 time: 2008-06-16 12:44:29
481477
482478
483getPosterForComment()479getPosterForComment()
@@ -521,7 +517,7 @@
521field on the imported comment.517field on the imported comment.
522518
523 >>> print bugzilla._bugs[2]['comments'][2]['time']519 >>> print bugzilla._bugs[2]['comments'][2]['time']
524 20080616T13:08:08520 2008-06-16 13:08:08
525521
526 >>> print message.datecreated522 >>> print message.datecreated
527 2008-06-16 13:08:08+00:00523 2008-06-16 13:08:08+00:00
528524
=== modified file 'lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt'
--- lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt 2009-12-21 15:03:42 +0000
+++ lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt 2009-12-23 10:23:47 +0000
@@ -204,8 +204,8 @@
204 >>> def print_bugs(bugs):204 >>> def print_bugs(bugs):
205 ... for bug in sorted(bugs):205 ... for bug in sorted(bugs):
206 ... print "Bug %s:" % bug206 ... print "Bug %s:" % bug
207 ... for key in sorted(bugzilla._bugs[bug]):207 ... for key in sorted(bugs[bug]):
208 ... print " %s: %s" % (key, bugzilla._bugs[bug][key])208 ... print " %s: %s" % (key, bugs[bug][key])
209 ... print "\n"209 ... print "\n"
210210
211 >>> print_bugs(bugzilla._bugs)211 >>> print_bugs(bugzilla._bugs)
@@ -213,11 +213,11 @@
213 alias:213 alias:
214 assigned_to: test@canonical.com214 assigned_to: test@canonical.com
215 component: GPPSystems215 component: GPPSystems
216 creation_time: 20080610T16:19:53216 creation_time: 2008-06-10 16:19:53
217 id: 1217 id: 1
218 internals:...218 internals:...
219 is_open: True219 is_open: True
220 last_change_time: 20080610T16:19:53220 last_change_time: 2008-06-10 16:19:53
221 priority: P1221 priority: P1
222 product: Marvin222 product: Marvin
223 resolution: FIXED223 resolution: FIXED
@@ -230,11 +230,11 @@
230 alias: bug-two230 alias: bug-two
231 assigned_to: marvin@heartofgold.ship231 assigned_to: marvin@heartofgold.ship
232 component: Crew232 component: Crew
233 creation_time: 20080611T09:23:12233 creation_time: 2008-06-11 09:23:12
234 id: 2234 id: 2
235 internals:...235 internals:...
236 is_open: True236 is_open: True
237 last_change_time: 20080611T09:24:29237 last_change_time: 2008-06-11 09:24:29
238 priority: P1238 priority: P1
239 product: HeartOfGold239 product: HeartOfGold
240 resolution:240 resolution:
@@ -416,13 +416,13 @@
416 id: 1416 id: 1
417 number: 1417 number: 1
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.
419 time: 20080616T12:44:29419 time: 2008-06-16 12:44:29
420 Comment 3:420 Comment 3:
421 author: marvin421 author: marvin
422 id: 3422 id: 3
423 number: 2423 number: 2
424 text: Life? Don't talk to me about life.424 text: Life? Don't talk to me about life.
425 time: 20080616T13:22:29425 time: 2008-06-16 13:22:29
426426
427427
428Pushing comments to remote systems428Pushing comments to remote systems
@@ -560,11 +560,11 @@
560 alias: bug-two560 alias: bug-two
561 assigned_to: marvin@heartofgold.ship561 assigned_to: marvin@heartofgold.ship
562 component: Crew562 component: Crew
563 creation_time: 20080611T09:23:12563 creation_time: 2008-06-11 09:23:12
564 id: 2564 id: 2
565 internals:...565 internals:...
566 is_open: True566 is_open: True
567 last_change_time: 20080611T09:24:29567 last_change_time: 2008-06-11 09:24:29
568 priority: P1568 priority: P1
569 product: HeartOfGold569 product: HeartOfGold
570 resolution:570 resolution:
571571
=== modified file 'lib/lp/bugs/externalbugtracker/bugzilla.py'
--- lib/lp/bugs/externalbugtracker/bugzilla.py 2009-12-22 21:08:42 +0000
+++ lib/lp/bugs/externalbugtracker/bugzilla.py 2009-12-23 10:21:32 +0000
@@ -12,11 +12,9 @@
12 ]12 ]
1313
14import pytz14import pytz
15import time
16import xml.parsers.expat15import xml.parsers.expat
17import xmlrpclib16import xmlrpclib
1817
19from datetime import datetime
20from email.Utils import parseaddr18from email.Utils import parseaddr
21from xml.dom import minidom19from xml.dom import minidom
2220
@@ -505,28 +503,17 @@
505 """See `IExternalBugTracker`."""503 """See `IExternalBugTracker`."""
506 time_dict = self.xmlrpc_proxy.Bugzilla.time()504 time_dict = self.xmlrpc_proxy.Bugzilla.time()
507505
508 # Convert the XML-RPC DateTime we get back into a regular Python
509 # datetime.
510 server_db_timetuple = time.strptime(
511 str(time_dict['db_time']), '%Y%m%dT%H:%M:%S')
512 server_db_datetime = datetime(*server_db_timetuple[:6])
513
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,
515 # this may not be in UTC, so we need to convert it. Since we507 # this may not be in UTC, so we need to convert it. Since we
516 # can't guarantee that the timezone data returned by the server508 # can't guarantee that the timezone data returned by the server
517 # is sane, we work out the server's offset from UTC by looking509 # is sane, we work out the server's offset from UTC by looking
518 # at the difference between the web_time and the web_time_utc510 # at the difference between the web_time and the web_time_utc
519 # values.511 # values.
520 server_web_time = time.strptime(512 server_web_datetime = time_dict['web_time']
521 str(time_dict['web_time']), '%Y%m%dT%H:%M:%S')513 server_web_datetime_utc = time_dict['web_time_utc']
522 server_web_datetime = datetime(*server_web_time[:6])
523 server_web_time_utc = time.strptime(
524 str(time_dict['web_time_utc']), '%Y%m%dT%H:%M:%S')
525 server_web_datetime_utc = datetime(*server_web_time_utc[:6])
526
527 server_utc_offset = server_web_datetime - server_web_datetime_utc514 server_utc_offset = server_web_datetime - server_web_datetime_utc
515 server_db_datetime = time_dict['db_time']
528 server_utc_datetime = server_db_datetime - server_utc_offset516 server_utc_datetime = server_db_datetime - server_utc_offset
529
530 return server_utc_datetime.replace(tzinfo=pytz.timezone('UTC'))517 return server_utc_datetime.replace(tzinfo=pytz.timezone('UTC'))
531518
532 def _getActualBugId(self, bug_id):519 def _getActualBugId(self, bug_id):
@@ -715,22 +702,9 @@
715 # bug 248938).702 # bug 248938).
716 comment_id = int(comment_id)703 comment_id = int(comment_id)
717 comment = self._bugs[actual_bug_id]['comments'][comment_id]704 comment = self._bugs[actual_bug_id]['comments'][comment_id]
718705 return getUtility(IMessageSet).fromText(
719 # Turn the time in the comment, which is an XML-RPC datetime
720 # into something more useful to us.
721 # XXX 2008-08-05 gmb (bug 254999):
722 # We can remove these lines once we upgrade to python 2.5.
723 comment_timestamp = time.mktime(
724 time.strptime(str(comment['time']), '%Y%m%dT%H:%M:%S'))
725 comment_datetime = datetime.fromtimestamp(comment_timestamp)
726 comment_datetime = comment_datetime.replace(
727 tzinfo=pytz.timezone('UTC'))
728
729 message = getUtility(IMessageSet).fromText(
730 owner=poster, subject='', content=comment['text'],706 owner=poster, subject='', content=comment['text'],
731 datecreated=comment_datetime)707 datecreated=comment['time'].replace(tzinfo=pytz.timezone('UTC')))
732
733 return message
734708
735 @needs_authentication709 @needs_authentication
736 def addRemoteComment(self, remote_bug, comment_body, rfc822msgid):710 def addRemoteComment(self, remote_bug, comment_body, rfc822msgid):
@@ -868,10 +842,7 @@
868842
869 # Return the UTC time sent by the server so that we don't have843 # Return the UTC time sent by the server so that we don't have
870 # to care about timezones.844 # to care about timezones.
871 server_timetuple = time.strptime(845 server_utc_time = time_dict['utc_time']
872 str(time_dict['utc_time']), '%Y%m%dT%H:%M:%S')
873
874 server_utc_time = datetime(*server_timetuple[:6])
875 return server_utc_time.replace(tzinfo=pytz.timezone('UTC'))846 return server_utc_time.replace(tzinfo=pytz.timezone('UTC'))
876847
877 def getCommentIds(self, bug_watch):848 def getCommentIds(self, bug_watch):
878849
=== modified file 'lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt'
--- lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt 2009-11-30 09:33:24 +0000
+++ lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt 2009-12-23 10:53:40 +0000
@@ -66,12 +66,12 @@
66 >>> time_dict = server.Bugzilla.time()66 >>> time_dict = server.Bugzilla.time()
67 >>> for key in sorted(time_dict):67 >>> for key in sorted(time_dict):
68 ... print "%s: %s" % (key, time_dict[key])68 ... print "%s: %s" % (key, time_dict[key])
69 db_time: 20080501T01:01:0169 db_time: 2008-05-01 01:01:01
70 tz_name: UTC70 tz_name: UTC
71 tz_offset: +000071 tz_offset: +0000
72 tz_short_name: UTC72 tz_short_name: UTC
73 web_time: 20080501T01:01:0173 web_time: 2008-05-01 01:01:01
74 web_time_utc: 20080501T01:01:0174 web_time_utc: 2008-05-01 01:01:01
7575
76If the remote server is in a different timezone, the db_time and76If the remote server is in a different timezone, the db_time and
77web_time items will be in the server's local timezone whilst77web_time items will be in the server's local timezone whilst
@@ -82,12 +82,12 @@
82 >>> time_dict = server.Bugzilla.time()82 >>> time_dict = server.Bugzilla.time()
83 >>> for key in sorted(time_dict):83 >>> for key in sorted(time_dict):
84 ... print "%s: %s" % (key, time_dict[key])84 ... print "%s: %s" % (key, time_dict[key])
85 db_time: 20080501T01:01:0185 db_time: 2008-05-01 01:01:01
86 tz_name: CET86 tz_name: CET
87 tz_offset: +010087 tz_offset: +0100
88 tz_short_name: CET88 tz_short_name: CET
89 web_time: 20080501T01:01:0189 web_time: 2008-05-01 01:01:01
90 web_time_utc: 20080501T00:01:0190 web_time_utc: 2008-05-01 00:01:01
9191
9292
93Getting bugs from the server93Getting bugs from the server
@@ -105,11 +105,11 @@
105 alias: 105 alias:
106 assigned_to: test@canonical.com106 assigned_to: test@canonical.com
107 component: GPPSystems107 component: GPPSystems
108 creation_time: 20080610T16:19:53108 creation_time: 2008-06-10 16:19:53
109 id: 1109 id: 1
110 internals:...110 internals:...
111 is_open: True111 is_open: True
112 last_change_time: 20080610T16:19:53112 last_change_time: 2008-06-10 16:19:53
113 priority: P1113 priority: P1
114 product: Marvin114 product: Marvin
115 resolution: FIXED115 resolution: FIXED
@@ -135,16 +135,7 @@
135date / time.135date / time.
136136
137 >>> from datetime import datetime137 >>> from datetime import datetime
138 >>> from xmlrpclib import DateTime
139 >>> last_change_time = datetime(2008, 6, 11, 9, 0, 0)138 >>> last_change_time = datetime(2008, 6, 11, 9, 0, 0)
140
141 # XXX 2009-08-21 gmb (bug 254999):
142 # We can remove this once we upgrade to python 2.5. We encode
143 # last_change_time into an XML-RPC DateTime manually. This is
144 # because xmlrpclib can't handle DateTime encoding within a
145 # dict.
146 >>> last_change_time = DateTime(last_change_time.timetuple())
147
148 >>> return_value = server.Bug.search({139 >>> return_value = server.Bug.search({
149 ... 'last_change_time': last_change_time,140 ... 'last_change_time': last_change_time,
150 ... })141 ... })
@@ -158,11 +149,11 @@
158 alias: bug-two149 alias: bug-two
159 assigned_to: marvin@heartofgold.ship150 assigned_to: marvin@heartofgold.ship
160 component: Crew151 component: Crew
161 creation_time: 20080611T09:23:12152 creation_time: 2008-06-11 09:23:12
162 id: 2153 id: 2
163 internals:...154 internals:...
164 is_open: True155 is_open: True
165 last_change_time: 20080611T09:24:29156 last_change_time: 2008-06-11 09:24:29
166 priority: P1157 priority: P1
167 product: HeartOfGold158 product: HeartOfGold
168 resolution: 159 resolution:
@@ -175,7 +166,6 @@
175results to those IDs.166results to those IDs.
176167
177 >>> last_change_time = datetime(2007, 6, 10, 1, 1, 1)168 >>> last_change_time = datetime(2007, 6, 10, 1, 1, 1)
178 >>> last_change_time = DateTime(last_change_time.timetuple())
179 >>> return_value = server.Bug.search({169 >>> return_value = server.Bug.search({
180 ... 'id': [1],170 ... 'id': [1],
181 ... 'last_change_time': last_change_time,171 ... 'last_change_time': last_change_time,
@@ -188,11 +178,11 @@
188 alias: 178 alias:
189 assigned_to: test@canonical.com179 assigned_to: test@canonical.com
190 component: GPPSystems180 component: GPPSystems
191 creation_time: 20080610T16:19:53181 creation_time: 2008-06-10 16:19:53
192 id: 1182 id: 1
193 internals:...183 internals:...
194 is_open: True184 is_open: True
195 last_change_time: 20080610T16:19:53185 last_change_time: 2008-06-10 16:19:53
196 priority: P1186 priority: P1
197 product: Marvin187 product: Marvin
198 resolution: FIXED188 resolution: FIXED
@@ -206,11 +196,6 @@
206196
207 >>> from datetime import timedelta197 >>> from datetime import timedelta
208 >>> last_change_time = datetime.now() + timedelta(days=42)198 >>> last_change_time = datetime.now() + timedelta(days=42)
209
210 >>> # XXX 2008-08-05 gmb (bug 254999):
211 >>> # We can remove this once we upgrade to python 2.5.
212 >>> last_change_time = DateTime(last_change_time.timetuple())
213
214 >>> return_value = server.Bug.search({199 >>> return_value = server.Bug.search({
215 ... 'last_change_time': last_change_time,200 ... 'last_change_time': last_change_time,
216 ... })201 ... })
@@ -232,11 +217,11 @@
232 alias: bug-two217 alias: bug-two
233 assigned_to: marvin@heartofgold.ship218 assigned_to: marvin@heartofgold.ship
234 component: Crew219 component: Crew
235 creation_time: 20080611T09:23:12220 creation_time: 2008-06-11 09:23:12
236 id: 2221 id: 2
237 internals:...222 internals:...
238 is_open: True223 is_open: True
239 last_change_time: 20080611T09:24:29224 last_change_time: 2008-06-11 09:24:29
240 priority: P1225 priority: P1
241 product: HeartOfGold226 product: HeartOfGold
242 resolution: 227 resolution:
@@ -257,11 +242,11 @@
257 alias: 242 alias:
258 assigned_to: test@canonical.com243 assigned_to: test@canonical.com
259 component: GPPSystems244 component: GPPSystems
260 creation_time: 20080610T16:19:53245 creation_time: 2008-06-10 16:19:53
261 id: 1246 id: 1
262 internals:...247 internals:...
263 is_open: True248 is_open: True
264 last_change_time: 20080610T16:19:53249 last_change_time: 2008-06-10 16:19:53
265 priority: P1250 priority: P1
266 product: Marvin251 product: Marvin
267 resolution: FIXED252 resolution: FIXED
@@ -272,11 +257,11 @@
272 alias: bug-two257 alias: bug-two
273 assigned_to: marvin@heartofgold.ship258 assigned_to: marvin@heartofgold.ship
274 component: Crew259 component: Crew
275 creation_time: 20080611T09:23:12260 creation_time: 2008-06-11 09:23:12
276 id: 2261 id: 2
277 internals:...262 internals:...
278 is_open: True263 is_open: True
279 last_change_time: 20080611T09:24:29264 last_change_time: 2008-06-11 09:24:29
280 priority: P1265 priority: P1
281 product: HeartOfGold266 product: HeartOfGold
282 resolution: 267 resolution:
@@ -321,14 +306,14 @@
321 id: 1306 id: 1
322 is_private: False307 is_private: False
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.
324 time: 20080616T12:44:29309 time: 2008-06-16 12:44:29
325 <BLANKLINE>310 <BLANKLINE>
326 author: marvin311 author: marvin
327 bug_id: 1312 bug_id: 1
328 id: 3313 id: 3
329 is_private: False314 is_private: False
330 text: Life? Don't talk to me about life.315 text: Life? Don't talk to me about life.
331 time: 20080616T13:22:29316 time: 2008-06-16 13:22:29
332 <BLANKLINE>317 <BLANKLINE>
333 <BLANKLINE>318 <BLANKLINE>
334 Bug 2:319 Bug 2:
@@ -337,14 +322,14 @@
337 id: 2322 id: 2
338 is_private: False323 is_private: False
339 text: Bring the passengers to the bridge please Marvin.324 text: Bring the passengers to the bridge please Marvin.
340 time: 20080616T13:08:08325 time: 2008-06-16 13:08:08
341 <BLANKLINE>326 <BLANKLINE>
342 author: Ford Prefect <ford.prefect@h2g2.com>327 author: Ford Prefect <ford.prefect@h2g2.com>
343 bug_id: 2328 bug_id: 2
344 id: 4329 id: 4
345 is_private: False330 is_private: False
346 text: I appear to have become a perfectly safe penguin.331 text: I appear to have become a perfectly safe penguin.
347 time: 20080617T20:28:40332 time: 2008-06-17 20:28:40
348 <BLANKLINE>333 <BLANKLINE>
349 <BLANKLINE>334 <BLANKLINE>
350335
@@ -366,14 +351,14 @@
366 id: 1351 id: 1
367 is_private: False352 is_private: False
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.
369 time: 20080616T12:44:29354 time: 2008-06-16 12:44:29
370 Comment 4:355 Comment 4:
371 author: Ford Prefect <ford.prefect@h2g2.com>356 author: Ford Prefect <ford.prefect@h2g2.com>
372 bug_id: 2357 bug_id: 2
373 id: 4358 id: 4
374 is_private: False359 is_private: False
375 text: I appear to have become a perfectly safe penguin.360 text: I appear to have become a perfectly safe penguin.
376 time: 20080617T20:28:40361 time: 2008-06-17 20:28:40
377 <BLANKLINE>362 <BLANKLINE>
378363
379Note that only comments have been returned when only 'comment_ids' have364Note that only comments have been returned when only 'comment_ids' have
@@ -499,11 +484,11 @@
499 alias: 484 alias:
500 assigned_to: test@canonical.com485 assigned_to: test@canonical.com
501 component: GPPSystems486 component: GPPSystems
502 creation_time: 20080610T16:19:53487 creation_time: 2008-06-10 16:19:53
503 id: 1488 id: 1
504 internals:...489 internals:...
505 is_open: True490 is_open: True
506 last_change_time: 20080610T16:19:53491 last_change_time: 2008-06-10 16:19:53
507 priority: P1492 priority: P1
508 product: Marvin493 product: Marvin
509 resolution: FIXED494 resolution: FIXED
510495
=== modified file 'lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt'
--- lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt 2009-12-11 16:05:52 +0000
+++ lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt 2009-12-23 10:38:25 +0000
@@ -105,9 +105,9 @@
105 >>> time_dict = server.Launchpad.time()105 >>> time_dict = server.Launchpad.time()
106 >>> for key in sorted(time_dict):106 >>> for key in sorted(time_dict):
107 ... print "%s: %s" % (key, time_dict[key])107 ... print "%s: %s" % (key, time_dict[key])
108 local_time: 20080501T01:01:01108 local_time: 2008-05-01 01:01:01
109 tz_name: UTC109 tz_name: UTC
110 utc_time: 20080501T01:01:01110 utc_time: 2008-05-01 01:01:01
111111
112We can set the local time value on the remote server to make testing112We can set the local time value on the remote server to make testing
113more useful.113more useful.
@@ -122,9 +122,9 @@
122 >>> time_dict = server.Launchpad.time()122 >>> time_dict = server.Launchpad.time()
123 >>> for key in sorted(time_dict):123 >>> for key in sorted(time_dict):
124 ... print "%s: %s" % (key, time_dict[key])124 ... print "%s: %s" % (key, time_dict[key])
125 local_time: 20080515T16:19:53125 local_time: 2008-05-15 16:19:53
126 tz_name: US/Central126 tz_name: US/Central
127 utc_time: 20080515T22:19:53127 utc_time: 2008-05-15 22:19:53
128128
129129
130Launchpad.get_bugs()130Launchpad.get_bugs()
@@ -144,11 +144,11 @@
144 alias: 144 alias:
145 assigned_to: test@canonical.com145 assigned_to: test@canonical.com
146 component: GPPSystems146 component: GPPSystems
147 creation_time: 20080610T16:19:53147 creation_time: 2008-06-10 16:19:53
148 id: 1148 id: 1
149 internals:...149 internals:...
150 is_open: True150 is_open: True
151 last_change_time: 20080610T16:19:53151 last_change_time: 2008-06-10 16:19:53
152 priority: P1152 priority: P1
153 product: Marvin153 product: Marvin
154 resolution: FIXED154 resolution: FIXED
@@ -170,11 +170,11 @@
170 alias: 170 alias:
171 assigned_to: test@canonical.com171 assigned_to: test@canonical.com
172 component: GPPSystems172 component: GPPSystems
173 creation_time: 20080610T16:19:53173 creation_time: 2008-06-10 16:19:53
174 id: 1174 id: 1
175 internals:...175 internals:...
176 is_open: True176 is_open: True
177 last_change_time: 20080610T16:19:53177 last_change_time: 2008-06-10 16:19:53
178 priority: P1178 priority: P1
179 product: Marvin179 product: Marvin
180 resolution: FIXED180 resolution: FIXED
@@ -186,11 +186,11 @@
186 alias: bug-two186 alias: bug-two
187 assigned_to: marvin@heartofgold.ship187 assigned_to: marvin@heartofgold.ship
188 component: Crew188 component: Crew
189 creation_time: 20080611T09:23:12189 creation_time: 2008-06-11 09:23:12
190 id: 2190 id: 2
191 internals:...191 internals:...
192 is_open: True192 is_open: True
193 last_change_time: 20080611T09:24:29193 last_change_time: 2008-06-11 09:24:29
194 priority: P1194 priority: P1
195 product: HeartOfGold195 product: HeartOfGold
196 resolution:196 resolution:
@@ -209,11 +209,11 @@
209 alias: bug-two209 alias: bug-two
210 assigned_to: marvin@heartofgold.ship210 assigned_to: marvin@heartofgold.ship
211 component: Crew211 component: Crew
212 creation_time: 20080611T09:23:12212 creation_time: 2008-06-11 09:23:12
213 id: 2213 id: 2
214 internals:...214 internals:...
215 is_open: True215 is_open: True
216 last_change_time: 20080611T09:24:29216 last_change_time: 2008-06-11 09:24:29
217 priority: P1217 priority: P1
218 product: HeartOfGold218 product: HeartOfGold
219 resolution: 219 resolution:
@@ -228,17 +228,8 @@
228allowing Launchpad to get only the recently-updated subset of a given228allowing Launchpad to get only the recently-updated subset of a given
229set of remote bugs.229set of remote bugs.
230230
231 >>> from xmlrpclib import DateTime
232
233 >>> changed_since = datetime(2008, 6, 11, 9, 0, 0)231 >>> changed_since = datetime(2008, 6, 11, 9, 0, 0)
234232
235 >>> # We encode changed_since into an XML-RPC DateTime manually.
236 >>> # This is because xmlrpclib can't handle DateTime encoding
237 >>> # within a dict.
238 >>> # XXX 2008-08-05 gmb (bug 254999):
239 >>> # We can remove this once we upgrade to python 2.5.
240 >>> changed_since = DateTime(changed_since.timetuple())
241
242 >>> return_value = server.Launchpad.get_bugs({233 >>> return_value = server.Launchpad.get_bugs({
243 ... 'ids': [1, 2],234 ... 'ids': [1, 2],
244 ... 'changed_since': changed_since,235 ... 'changed_since': changed_since,
@@ -254,11 +245,11 @@
254 alias: bug-two245 alias: bug-two
255 assigned_to: marvin@heartofgold.ship246 assigned_to: marvin@heartofgold.ship
256 component: Crew247 component: Crew
257 creation_time: 20080611T09:23:12248 creation_time: 2008-06-11 09:23:12
258 id: 2249 id: 2
259 internals:...250 internals:...
260 is_open: True251 is_open: True
261 last_change_time: 20080611T09:24:29252 last_change_time: 2008-06-11 09:24:29
262 priority: P1253 priority: P1
263 product: HeartOfGold254 product: HeartOfGold
264 resolution: 255 resolution:
@@ -273,10 +264,6 @@
273 >>> from datetime import timedelta264 >>> from datetime import timedelta
274 >>> changed_since = datetime.now() + timedelta(days=42)265 >>> changed_since = datetime.now() + timedelta(days=42)
275266
276 >>> # XXX 2008-08-05 gmb (bug 254999):
277 >>> # We can remove this once we upgrade to python 2.5.
278 >>> changed_since = DateTime(changed_since.timetuple())
279
280 >>> return_value = server.Launchpad.get_bugs({267 >>> return_value = server.Launchpad.get_bugs({
281 ... 'ids': [1, 2],268 ... 'ids': [1, 2],
282 ... 'changed_since': changed_since,269 ... 'changed_since': changed_since,
@@ -304,11 +291,11 @@
304 alias: bug-two291 alias: bug-two
305 assigned_to: marvin@heartofgold.ship292 assigned_to: marvin@heartofgold.ship
306 component: Crew293 component: Crew
307 creation_time: 20080611T09:23:12294 creation_time: 2008-06-11 09:23:12
308 id: 2295 id: 2
309 internals:...296 internals:...
310 is_open: True297 is_open: True
311 last_change_time: 20080611T09:24:29298 last_change_time: 2008-06-11 09:24:29
312 priority: P1299 priority: P1
313 product: HeartOfGold300 product: HeartOfGold
314 resolution: 301 resolution:
@@ -366,13 +353,13 @@
366 id: 1353 id: 1
367 number: 1354 number: 1
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.
369 time: 20080616T12:44:29356 time: 2008-06-16 12:44:29
370 <BLANKLINE>357 <BLANKLINE>
371 author: marvin358 author: marvin
372 id: 3359 id: 3
373 number: 2360 number: 2
374 text: Life? Don't talk to me about life.361 text: Life? Don't talk to me about life.
375 time: 20080616T13:22:29362 time: 2008-06-16 13:22:29
376 <BLANKLINE>363 <BLANKLINE>
377 <BLANKLINE>364 <BLANKLINE>
378 Bug 2:365 Bug 2:
@@ -380,13 +367,13 @@
380 id: 2367 id: 2
381 number: 1368 number: 1
382 text: Bring the passengers to the bridge please Marvin.369 text: Bring the passengers to the bridge please Marvin.
383 time: 20080616T13:08:08370 time: 2008-06-16 13:08:08
384 <BLANKLINE>371 <BLANKLINE>
385 author: Ford Prefect <ford.prefect@h2g2.com>372 author: Ford Prefect <ford.prefect@h2g2.com>
386 id: 4373 id: 4
387 number: 2374 number: 2
388 text: I appear to have become a perfectly safe penguin.375 text: I appear to have become a perfectly safe penguin.
389 time: 20080617T20:28:40376 time: 2008-06-17 20:28:40
390377
391If an ids parameter is specified along with bug_ids, only the comments378If an ids parameter is specified along with bug_ids, only the comments
392whose IDs are in the list of IDs passed will be returned.379whose IDs are in the list of IDs passed will be returned.
@@ -401,7 +388,7 @@
401 id: 1388 id: 1
402 number: 1389 number: 1
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.
404 time: 20080616T12:44:29391 time: 2008-06-16 12:44:29
405 <BLANKLINE>392 <BLANKLINE>
406 <BLANKLINE>393 <BLANKLINE>
407 Bug 2:394 Bug 2:
@@ -409,7 +396,7 @@
409 id: 2396 id: 2
410 number: 1397 number: 1
411 text: Bring the passengers to the bridge please Marvin.398 text: Bring the passengers to the bridge please Marvin.
412 time: 20080616T13:08:08399 time: 2008-06-16 13:08:08
413400
414Passing an include_fields parameter allows us to limit which fields are401Passing an include_fields parameter allows us to limit which fields are
415returned for each comment.402returned for each comment.
416403
=== modified file 'lib/lp/bugs/tests/externalbugtracker.py'
--- lib/lp/bugs/tests/externalbugtracker.py 2009-12-18 17:40:01 +0000
+++ lib/lp/bugs/tests/externalbugtracker.py 2009-12-23 12:09:36 +0000
@@ -526,17 +526,12 @@
526 if local_datetime is None:526 if local_datetime is None:
527 local_datetime = datetime(2008, 5, 1, 1, 1, 1)527 local_datetime = datetime(2008, 5, 1, 1, 1, 1)
528528
529 # We return xmlrpc dateTimes rather than doubles since that's
530 # what BugZilla will return.
531 local_time = xmlrpclib.DateTime(local_datetime.timetuple())
532
533 utc_offset_delta = timedelta(seconds=self.utc_offset)529 utc_offset_delta = timedelta(seconds=self.utc_offset)
534 utc_date_time = local_datetime - utc_offset_delta530 utc_date_time = local_datetime - utc_offset_delta
535531
536 utc_time = xmlrpclib.DateTime(utc_date_time.timetuple())
537 return {532 return {
538 'local_time': local_time,533 'local_time': local_datetime,
539 'utc_time': utc_time,534 'utc_time': utc_date_time,
540 'tz_name': self.timezone,535 'tz_name': self.timezone,
541 }536 }
542537
@@ -599,14 +594,14 @@
599 assert permissive, "get_bugs() must be called with permissive=True"594 assert permissive, "get_bugs() must be called with permissive=True"
600595
601 # If a changed_since argument is specified, marshall it into a596 # If a changed_since argument is specified, marshall it into a
602 # datetime so that we can use it for comparisons.597 # datetime so that we can use it for comparisons. Even though
603 # XXX 2008-08-05 gmb (bug 254999):598 # xmlrpclib in Python 2.5 groks datetime, by the time this
604 # We can remove these lines once we upgrade to python 2.5.599 # method is called xmlrpclib has already converted all
600 # datetimes to xmlrpclib.DateTime.
605 changed_since = arguments.get('changed_since')601 changed_since = arguments.get('changed_since')
606 if changed_since is not None:602 if changed_since is not None:
607 changed_since_timetuple = time.strptime(603 changed_since = datetime.strptime(
608 str(changed_since), '%Y%m%dT%H:%M:%S')604 changed_since.value, '%Y%m%dT%H:%M:%S')
609 changed_since = datetime(*changed_since_timetuple[:6])
610605
611 # If we have some products but no bug_ids we just get all the606 # If we have some products but no bug_ids we just get all the
612 # bug IDs for those products and stuff them in the bug_ids list607 # bug IDs for those products and stuff them in the bug_ids list
@@ -642,14 +637,6 @@
642 bug_dict['product'] not in products):637 bug_dict['product'] not in products):
643 continue638 continue
644639
645 # Update the DateTime fields of the bug dict so that they
646 # look like ones that would be sent over XML-RPC.
647 for time_field in ('creation_time', 'last_change_time'):
648 datetime_value = bug_dict[time_field]
649 timestamp = time.mktime(datetime_value.timetuple())
650 xmlrpc_datetime = xmlrpclib.DateTime(timestamp)
651 bug_dict[time_field] = xmlrpc_datetime
652
653 bugs_to_return.append(bug_dict)640 bugs_to_return.append(bug_dict)
654641
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,
@@ -660,15 +647,9 @@
660647
661 def _copy_comment(self, comment, fields_to_return=None):648 def _copy_comment(self, comment, fields_to_return=None):
662 # Copy wanted fields.649 # Copy wanted fields.
663 comment = dict(650 return dict(
664 (key, value) for (key, value) in comment.iteritems()651 (key, value) for (key, value) in comment.iteritems()
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)
666 # Replace the time field with an XML-RPC DateTime.
667 if 'time' in comment:
668 comment['time'] = xmlrpclib.DateTime(
669 comment['time'].timetuple())
670 return comment
671
672653
673 def comments(self, arguments):654 def comments(self, arguments):
674 """Return comments for a given set of bugs."""655 """Return comments for a given set of bugs."""
Revision history for this message
Brad Crittenden (bac) wrote :

Thanks for the additional changes Gavin. It looks good now.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt'
--- lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt 2009-12-21 15:03:42 +0000
+++ lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt 2009-12-23 12:17:18 +0000
@@ -139,8 +139,8 @@
139 >>> def print_bugs(bugs):139 >>> def print_bugs(bugs):
140 ... for bug in sorted(bugs):140 ... for bug in sorted(bugs):
141 ... print "Bug %s:" % bug141 ... print "Bug %s:" % bug
142 ... for key in sorted(bugzilla._bugs[bug]):142 ... for key in sorted(bugs[bug]):
143 ... print " %s: %s" % (key, bugzilla._bugs[bug][key])143 ... print " %s: %s" % (key, bugs[bug][key])
144 ... print "\n"144 ... print "\n"
145145
146 >>> print_bugs(bugzilla._bugs)146 >>> print_bugs(bugzilla._bugs)
@@ -148,11 +148,11 @@
148 alias:148 alias:
149 assigned_to: test@canonical.com149 assigned_to: test@canonical.com
150 component: GPPSystems150 component: GPPSystems
151 creation_time: 20080610T16:19:53151 creation_time: 2008-06-10 16:19:53
152 id: 1152 id: 1
153 internals:...153 internals:...
154 is_open: True154 is_open: True
155 last_change_time: 20080610T16:19:53155 last_change_time: 2008-06-10 16:19:53
156 priority: P1156 priority: P1
157 product: Marvin157 product: Marvin
158 resolution: FIXED158 resolution: FIXED
@@ -165,11 +165,11 @@
165 alias: bug-two165 alias: bug-two
166 assigned_to: marvin@heartofgold.ship166 assigned_to: marvin@heartofgold.ship
167 component: Crew167 component: Crew
168 creation_time: 20080611T09:23:12168 creation_time: 2008-06-11 09:23:12
169 id: 2169 id: 2
170 internals:...170 internals:...
171 is_open: True171 is_open: True
172 last_change_time: 20080611T09:24:29172 last_change_time: 2008-06-11 09:24:29
173 priority: P1173 priority: P1
174 product: HeartOfGold174 product: HeartOfGold
175 resolution:175 resolution:
@@ -194,20 +194,16 @@
194 >>> bugzilla.initializeRemoteBugDB([2, 'bug-two'])194 >>> bugzilla.initializeRemoteBugDB([2, 'bug-two'])
195 CALLED Bug.get({'ids': [2, 'bug-two'], 'permissive': True})195 CALLED Bug.get({'ids': [2, 'bug-two'], 'permissive': True})
196196
197 >>> for bug in sorted(bugzilla._bugs):197 >>> print_bugs(bugzilla._bugs)
198 ... print "Bug %r:" % bug
199 ... for key in sorted(bugzilla._bugs[bug]):
200 ... print " %s: %s" % (key, bugzilla._bugs[bug][key])
201 ... print "\n"
202 Bug 2:198 Bug 2:
203 alias: bug-two199 alias: bug-two
204 assigned_to: marvin@heartofgold.ship200 assigned_to: marvin@heartofgold.ship
205 component: Crew201 component: Crew
206 creation_time: 20080611T09:23:12202 creation_time: 2008-06-11 09:23:12
207 id: 2203 id: 2
208 internals:...204 internals:...
209 is_open: True205 is_open: True
210 last_change_time: 20080611T09:24:29206 last_change_time: 2008-06-11 09:24:29
211 priority: P1207 priority: P1
212 product: HeartOfGold208 product: HeartOfGold
213 resolution:209 resolution:
@@ -450,14 +446,14 @@
450 id: 1446 id: 1
451 is_private: False447 is_private: False
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.
453 time: 20080616T12:44:29449 time: 2008-06-16 12:44:29
454 Comment 3:450 Comment 3:
455 author: marvin451 author: marvin
456 bug_id: 1452 bug_id: 1
457 id: 3453 id: 3
458 is_private: False454 is_private: False
459 text: Life? Don't talk to me about life.455 text: Life? Don't talk to me about life.
460 time: 20080616T13:22:29456 time: 2008-06-16 13:22:29
461457
462If we try to fetch comments that don't belong to the current bug458If we try to fetch comments that don't belong to the current bug
463fetchComments() will silently ignore them.459fetchComments() will silently ignore them.
@@ -477,7 +473,7 @@
477 id: 1473 id: 1
478 is_private: False474 is_private: False
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.
480 time: 20080616T12:44:29476 time: 2008-06-16 12:44:29
481477
482478
483getPosterForComment()479getPosterForComment()
@@ -521,7 +517,7 @@
521field on the imported comment.517field on the imported comment.
522518
523 >>> print bugzilla._bugs[2]['comments'][2]['time']519 >>> print bugzilla._bugs[2]['comments'][2]['time']
524 20080616T13:08:08520 2008-06-16 13:08:08
525521
526 >>> print message.datecreated522 >>> print message.datecreated
527 2008-06-16 13:08:08+00:00523 2008-06-16 13:08:08+00:00
528524
=== modified file 'lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt'
--- lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt 2009-12-21 15:03:42 +0000
+++ lib/lp/bugs/doc/externalbugtracker-bugzilla-lp-plugin.txt 2009-12-23 12:17:18 +0000
@@ -204,8 +204,8 @@
204 >>> def print_bugs(bugs):204 >>> def print_bugs(bugs):
205 ... for bug in sorted(bugs):205 ... for bug in sorted(bugs):
206 ... print "Bug %s:" % bug206 ... print "Bug %s:" % bug
207 ... for key in sorted(bugzilla._bugs[bug]):207 ... for key in sorted(bugs[bug]):
208 ... print " %s: %s" % (key, bugzilla._bugs[bug][key])208 ... print " %s: %s" % (key, bugs[bug][key])
209 ... print "\n"209 ... print "\n"
210210
211 >>> print_bugs(bugzilla._bugs)211 >>> print_bugs(bugzilla._bugs)
@@ -213,11 +213,11 @@
213 alias:213 alias:
214 assigned_to: test@canonical.com214 assigned_to: test@canonical.com
215 component: GPPSystems215 component: GPPSystems
216 creation_time: 20080610T16:19:53216 creation_time: 2008-06-10 16:19:53
217 id: 1217 id: 1
218 internals:...218 internals:...
219 is_open: True219 is_open: True
220 last_change_time: 20080610T16:19:53220 last_change_time: 2008-06-10 16:19:53
221 priority: P1221 priority: P1
222 product: Marvin222 product: Marvin
223 resolution: FIXED223 resolution: FIXED
@@ -230,11 +230,11 @@
230 alias: bug-two230 alias: bug-two
231 assigned_to: marvin@heartofgold.ship231 assigned_to: marvin@heartofgold.ship
232 component: Crew232 component: Crew
233 creation_time: 20080611T09:23:12233 creation_time: 2008-06-11 09:23:12
234 id: 2234 id: 2
235 internals:...235 internals:...
236 is_open: True236 is_open: True
237 last_change_time: 20080611T09:24:29237 last_change_time: 2008-06-11 09:24:29
238 priority: P1238 priority: P1
239 product: HeartOfGold239 product: HeartOfGold
240 resolution:240 resolution:
@@ -416,13 +416,13 @@
416 id: 1416 id: 1
417 number: 1417 number: 1
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.
419 time: 20080616T12:44:29419 time: 2008-06-16 12:44:29
420 Comment 3:420 Comment 3:
421 author: marvin421 author: marvin
422 id: 3422 id: 3
423 number: 2423 number: 2
424 text: Life? Don't talk to me about life.424 text: Life? Don't talk to me about life.
425 time: 20080616T13:22:29425 time: 2008-06-16 13:22:29
426426
427427
428Pushing comments to remote systems428Pushing comments to remote systems
@@ -560,11 +560,11 @@
560 alias: bug-two560 alias: bug-two
561 assigned_to: marvin@heartofgold.ship561 assigned_to: marvin@heartofgold.ship
562 component: Crew562 component: Crew
563 creation_time: 20080611T09:23:12563 creation_time: 2008-06-11 09:23:12
564 id: 2564 id: 2
565 internals:...565 internals:...
566 is_open: True566 is_open: True
567 last_change_time: 20080611T09:24:29567 last_change_time: 2008-06-11 09:24:29
568 priority: P1568 priority: P1
569 product: HeartOfGold569 product: HeartOfGold
570 resolution:570 resolution:
571571
=== modified file 'lib/lp/bugs/externalbugtracker/bugzilla.py'
--- lib/lp/bugs/externalbugtracker/bugzilla.py 2009-12-21 14:46:05 +0000
+++ lib/lp/bugs/externalbugtracker/bugzilla.py 2009-12-23 12:17:18 +0000
@@ -12,11 +12,9 @@
12 ]12 ]
1313
14import pytz14import pytz
15import time
16import xml.parsers.expat15import xml.parsers.expat
17import xmlrpclib16import xmlrpclib
1817
19from datetime import datetime
20from email.Utils import parseaddr18from email.Utils import parseaddr
21from xml.dom import minidom19from xml.dom import minidom
2220
@@ -505,28 +503,17 @@
505 """See `IExternalBugTracker`."""503 """See `IExternalBugTracker`."""
506 time_dict = self.xmlrpc_proxy.Bugzilla.time()504 time_dict = self.xmlrpc_proxy.Bugzilla.time()
507505
508 # Convert the XML-RPC DateTime we get back into a regular Python
509 # datetime.
510 server_db_timetuple = time.strptime(
511 str(time_dict['db_time']), '%Y%m%dT%H:%M:%S')
512 server_db_datetime = datetime(*server_db_timetuple[:6])
513
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,
515 # this may not be in UTC, so we need to convert it. Since we507 # this may not be in UTC, so we need to convert it. Since we
516 # can't guarantee that the timezone data returned by the server508 # can't guarantee that the timezone data returned by the server
517 # is sane, we work out the server's offset from UTC by looking509 # is sane, we work out the server's offset from UTC by looking
518 # at the difference between the web_time and the web_time_utc510 # at the difference between the web_time and the web_time_utc
519 # values.511 # values.
520 server_web_time = time.strptime(512 server_web_datetime = time_dict['web_time']
521 str(time_dict['web_time']), '%Y%m%dT%H:%M:%S')513 server_web_datetime_utc = time_dict['web_time_utc']
522 server_web_datetime = datetime(*server_web_time[:6])
523 server_web_time_utc = time.strptime(
524 str(time_dict['web_time_utc']), '%Y%m%dT%H:%M:%S')
525 server_web_datetime_utc = datetime(*server_web_time_utc[:6])
526
527 server_utc_offset = server_web_datetime - server_web_datetime_utc514 server_utc_offset = server_web_datetime - server_web_datetime_utc
515 server_db_datetime = time_dict['db_time']
528 server_utc_datetime = server_db_datetime - server_utc_offset516 server_utc_datetime = server_db_datetime - server_utc_offset
529
530 return server_utc_datetime.replace(tzinfo=pytz.timezone('UTC'))517 return server_utc_datetime.replace(tzinfo=pytz.timezone('UTC'))
531518
532 def _getActualBugId(self, bug_id):519 def _getActualBugId(self, bug_id):
@@ -558,7 +545,7 @@
558 bug_ids_to_retrieve = []545 bug_ids_to_retrieve = []
559 for bug_id in bug_ids:546 for bug_id in bug_ids:
560 try:547 try:
561 actual_bug_id = self._getActualBugId(bug_id)548 self._getActualBugId(bug_id)
562 except BugNotFound:549 except BugNotFound:
563 bug_ids_to_retrieve.append(bug_id)550 bug_ids_to_retrieve.append(bug_id)
564551
@@ -590,7 +577,7 @@
590 try:577 try:
591 status = self._bugs[actual_bug_id]['status']578 status = self._bugs[actual_bug_id]['status']
592 resolution = self._bugs[actual_bug_id]['resolution']579 resolution = self._bugs[actual_bug_id]['resolution']
593 except KeyError, error:580 except KeyError:
594 raise UnparseableBugData581 raise UnparseableBugData
595582
596 if resolution != '':583 if resolution != '':
@@ -600,27 +587,14 @@
600587
601 def getModifiedRemoteBugs(self, bug_ids, last_checked):588 def getModifiedRemoteBugs(self, bug_ids, last_checked):
602 """See `IExternalBugTracker`."""589 """See `IExternalBugTracker`."""
603 # We marshal last_checked into an xmlrpclib.DateTime since590 response_dict = self.xmlrpc_proxy.Bug.search(
604 # xmlrpclib can't do so cleanly itself.591 {'id': bug_ids, 'last_change_time': last_checked})
605 # XXX 2009-08-21 gmb (bug 254999):
606 # We can remove this once we upgrade to python 2.5.
607 changed_since = xmlrpclib.DateTime(last_checked.timetuple())
608
609 search_args = {
610 'id': bug_ids,
611 'last_change_time': changed_since,
612 }
613 response_dict = self.xmlrpc_proxy.Bug.search(search_args)
614 remote_bugs = response_dict['bugs']592 remote_bugs = response_dict['bugs']
615
616 # Store the bugs we've imported and return only their IDs.593 # Store the bugs we've imported and return only their IDs.
617 self._storeBugs(remote_bugs)594 self._storeBugs(remote_bugs)
618
619 # Marshal the bug IDs into strings before returning them since595 # Marshal the bug IDs into strings before returning them since
620 # the remote Bugzilla may return ints rather than strings.596 # the remote Bugzilla may return ints rather than strings.
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]
622
623 return bug_ids
624598
625 def getRemoteProduct(self, remote_bug):599 def getRemoteProduct(self, remote_bug):
626 """See `IExternalBugTracker`."""600 """See `IExternalBugTracker`."""
@@ -728,22 +702,9 @@
728 # bug 248938).702 # bug 248938).
729 comment_id = int(comment_id)703 comment_id = int(comment_id)
730 comment = self._bugs[actual_bug_id]['comments'][comment_id]704 comment = self._bugs[actual_bug_id]['comments'][comment_id]
731705 return getUtility(IMessageSet).fromText(
732 # Turn the time in the comment, which is an XML-RPC datetime
733 # into something more useful to us.
734 # XXX 2008-08-05 gmb (bug 254999):
735 # We can remove these lines once we upgrade to python 2.5.
736 comment_timestamp = time.mktime(
737 time.strptime(str(comment['time']), '%Y%m%dT%H:%M:%S'))
738 comment_datetime = datetime.fromtimestamp(comment_timestamp)
739 comment_datetime = comment_datetime.replace(
740 tzinfo=pytz.timezone('UTC'))
741
742 message = getUtility(IMessageSet).fromText(
743 owner=poster, subject='', content=comment['text'],706 owner=poster, subject='', content=comment['text'],
744 datecreated=comment_datetime)707 datecreated=comment['time'].replace(tzinfo=pytz.timezone('UTC')))
745
746 return message
747708
748 @needs_authentication709 @needs_authentication
749 def addRemoteComment(self, remote_bug, comment_body, rfc822msgid):710 def addRemoteComment(self, remote_bug, comment_body, rfc822msgid):
@@ -826,7 +787,7 @@
826 token_text = internal_xmlrpc_server.newBugTrackerToken()787 token_text = internal_xmlrpc_server.newBugTrackerToken()
827788
828 try:789 try:
829 user_id = self.xmlrpc_proxy.Launchpad.login(790 self.xmlrpc_proxy.Launchpad.login(
830 {'token': token_text})791 {'token': token_text})
831 except xmlrpclib.Fault, fault:792 except xmlrpclib.Fault, fault:
832 message = 'XML-RPC Fault: %s "%s"' % (793 message = 'XML-RPC Fault: %s "%s"' % (
@@ -841,28 +802,17 @@
841802
842 def getModifiedRemoteBugs(self, bug_ids, last_checked):803 def getModifiedRemoteBugs(self, bug_ids, last_checked):
843 """See `IExternalBugTracker`."""804 """See `IExternalBugTracker`."""
844 # We marshal last_checked into an xmlrpclib.DateTime since805 # We pass permissive=True to ensure that Bugzilla won't error
845 # xmlrpclib can't do so cleanly itself.806 # if we ask for a bug that doesn't exist.
846 # XXX 2008-08-05 gmb (bug 254999):807 response_dict = self.xmlrpc_proxy.Launchpad.get_bugs({
847 # We can remove this once we upgrade to python 2.5.
848 changed_since = xmlrpclib.DateTime(last_checked.timetuple())
849
850 # Create the arguments that we're going to send to the remote
851 # server. We pass permissive=True to ensure that Bugzilla won't
852 # error if we ask for a bug that doesn't exist.
853 request_args = {
854 'ids': bug_ids,808 'ids': bug_ids,
855 'changed_since': changed_since,809 'changed_since': last_checked,
856 'permissive': True,810 'permissive': True,
857 }811 })
858 response_dict = self.xmlrpc_proxy.Launchpad.get_bugs(request_args)
859 remote_bugs = response_dict['bugs']812 remote_bugs = response_dict['bugs']
860
861 # Store the bugs we've imported and return only their IDs.813 # Store the bugs we've imported and return only their IDs.
862 self._storeBugs(remote_bugs)814 self._storeBugs(remote_bugs)
863 bug_ids = [remote_bug['id'] for remote_bug in remote_bugs]815 return [remote_bug['id'] for remote_bug in remote_bugs]
864
865 return bug_ids
866816
867 def initializeRemoteBugDB(self, bug_ids, products=None):817 def initializeRemoteBugDB(self, bug_ids, products=None):
868 """See `IExternalBugTracker`."""818 """See `IExternalBugTracker`."""
@@ -892,10 +842,7 @@
892842
893 # Return the UTC time sent by the server so that we don't have843 # Return the UTC time sent by the server so that we don't have
894 # to care about timezones.844 # to care about timezones.
895 server_timetuple = time.strptime(845 server_utc_time = time_dict['utc_time']
896 str(time_dict['utc_time']), '%Y%m%dT%H:%M:%S')
897
898 server_utc_time = datetime(*server_timetuple[:6])
899 return server_utc_time.replace(tzinfo=pytz.timezone('UTC'))846 return server_utc_time.replace(tzinfo=pytz.timezone('UTC'))
900847
901 def getCommentIds(self, bug_watch):848 def getCommentIds(self, bug_watch):
902849
=== modified file 'lib/lp/bugs/externalbugtracker/xmlrpc.py'
--- lib/lp/bugs/externalbugtracker/xmlrpc.py 2009-10-16 22:00:45 +0000
+++ lib/lp/bugs/externalbugtracker/xmlrpc.py 2009-12-23 12:17:18 +0000
@@ -64,10 +64,9 @@
64 verbose = False64 verbose = False
6565
66 def __init__(self, endpoint, cookie_jar=None):66 def __init__(self, endpoint, cookie_jar=None):
67 Transport.__init__(self)67 Transport.__init__(self, use_datetime=True)
68 self.scheme, self.host = urlparse(endpoint)[:2]68 self.scheme, self.host = urlparse(endpoint)[:2]
69 assert (69 assert self.scheme in ('http', 'https'), (
70 self.scheme in ('http', 'https'),
71 "Unsupported URL scheme: %s" % self.scheme)70 "Unsupported URL scheme: %s" % self.scheme)
72 self.cookie_processor = HTTPCookieProcessor(cookie_jar)71 self.cookie_processor = HTTPCookieProcessor(cookie_jar)
73 self.redirect_handler = XMLRPCRedirectHandler()72 self.redirect_handler = XMLRPCRedirectHandler()
7473
=== modified file 'lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt'
--- lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt 2009-11-30 09:33:24 +0000
+++ lib/lp/bugs/tests/bugzilla-api-xmlrpc-transport.txt 2009-12-23 12:17:18 +0000
@@ -66,12 +66,12 @@
66 >>> time_dict = server.Bugzilla.time()66 >>> time_dict = server.Bugzilla.time()
67 >>> for key in sorted(time_dict):67 >>> for key in sorted(time_dict):
68 ... print "%s: %s" % (key, time_dict[key])68 ... print "%s: %s" % (key, time_dict[key])
69 db_time: 20080501T01:01:0169 db_time: 2008-05-01 01:01:01
70 tz_name: UTC70 tz_name: UTC
71 tz_offset: +000071 tz_offset: +0000
72 tz_short_name: UTC72 tz_short_name: UTC
73 web_time: 20080501T01:01:0173 web_time: 2008-05-01 01:01:01
74 web_time_utc: 20080501T01:01:0174 web_time_utc: 2008-05-01 01:01:01
7575
76If the remote server is in a different timezone, the db_time and76If the remote server is in a different timezone, the db_time and
77web_time items will be in the server's local timezone whilst77web_time items will be in the server's local timezone whilst
@@ -82,12 +82,12 @@
82 >>> time_dict = server.Bugzilla.time()82 >>> time_dict = server.Bugzilla.time()
83 >>> for key in sorted(time_dict):83 >>> for key in sorted(time_dict):
84 ... print "%s: %s" % (key, time_dict[key])84 ... print "%s: %s" % (key, time_dict[key])
85 db_time: 20080501T01:01:0185 db_time: 2008-05-01 01:01:01
86 tz_name: CET86 tz_name: CET
87 tz_offset: +010087 tz_offset: +0100
88 tz_short_name: CET88 tz_short_name: CET
89 web_time: 20080501T01:01:0189 web_time: 2008-05-01 01:01:01
90 web_time_utc: 20080501T00:01:0190 web_time_utc: 2008-05-01 00:01:01
9191
9292
93Getting bugs from the server93Getting bugs from the server
@@ -105,11 +105,11 @@
105 alias: 105 alias:
106 assigned_to: test@canonical.com106 assigned_to: test@canonical.com
107 component: GPPSystems107 component: GPPSystems
108 creation_time: 20080610T16:19:53108 creation_time: 2008-06-10 16:19:53
109 id: 1109 id: 1
110 internals:...110 internals:...
111 is_open: True111 is_open: True
112 last_change_time: 20080610T16:19:53112 last_change_time: 2008-06-10 16:19:53
113 priority: P1113 priority: P1
114 product: Marvin114 product: Marvin
115 resolution: FIXED115 resolution: FIXED
@@ -135,16 +135,7 @@
135date / time.135date / time.
136136
137 >>> from datetime import datetime137 >>> from datetime import datetime
138 >>> from xmlrpclib import DateTime
139 >>> last_change_time = datetime(2008, 6, 11, 9, 0, 0)138 >>> last_change_time = datetime(2008, 6, 11, 9, 0, 0)
140
141 # XXX 2009-08-21 gmb (bug 254999):
142 # We can remove this once we upgrade to python 2.5. We encode
143 # last_change_time into an XML-RPC DateTime manually. This is
144 # because xmlrpclib can't handle DateTime encoding within a
145 # dict.
146 >>> last_change_time = DateTime(last_change_time.timetuple())
147
148 >>> return_value = server.Bug.search({139 >>> return_value = server.Bug.search({
149 ... 'last_change_time': last_change_time,140 ... 'last_change_time': last_change_time,
150 ... })141 ... })
@@ -158,11 +149,11 @@
158 alias: bug-two149 alias: bug-two
159 assigned_to: marvin@heartofgold.ship150 assigned_to: marvin@heartofgold.ship
160 component: Crew151 component: Crew
161 creation_time: 20080611T09:23:12152 creation_time: 2008-06-11 09:23:12
162 id: 2153 id: 2
163 internals:...154 internals:...
164 is_open: True155 is_open: True
165 last_change_time: 20080611T09:24:29156 last_change_time: 2008-06-11 09:24:29
166 priority: P1157 priority: P1
167 product: HeartOfGold158 product: HeartOfGold
168 resolution: 159 resolution:
@@ -175,7 +166,6 @@
175results to those IDs.166results to those IDs.
176167
177 >>> last_change_time = datetime(2007, 6, 10, 1, 1, 1)168 >>> last_change_time = datetime(2007, 6, 10, 1, 1, 1)
178 >>> last_change_time = DateTime(last_change_time.timetuple())
179 >>> return_value = server.Bug.search({169 >>> return_value = server.Bug.search({
180 ... 'id': [1],170 ... 'id': [1],
181 ... 'last_change_time': last_change_time,171 ... 'last_change_time': last_change_time,
@@ -188,11 +178,11 @@
188 alias: 178 alias:
189 assigned_to: test@canonical.com179 assigned_to: test@canonical.com
190 component: GPPSystems180 component: GPPSystems
191 creation_time: 20080610T16:19:53181 creation_time: 2008-06-10 16:19:53
192 id: 1182 id: 1
193 internals:...183 internals:...
194 is_open: True184 is_open: True
195 last_change_time: 20080610T16:19:53185 last_change_time: 2008-06-10 16:19:53
196 priority: P1186 priority: P1
197 product: Marvin187 product: Marvin
198 resolution: FIXED188 resolution: FIXED
@@ -206,11 +196,6 @@
206196
207 >>> from datetime import timedelta197 >>> from datetime import timedelta
208 >>> last_change_time = datetime.now() + timedelta(days=42)198 >>> last_change_time = datetime.now() + timedelta(days=42)
209
210 >>> # XXX 2008-08-05 gmb (bug 254999):
211 >>> # We can remove this once we upgrade to python 2.5.
212 >>> last_change_time = DateTime(last_change_time.timetuple())
213
214 >>> return_value = server.Bug.search({199 >>> return_value = server.Bug.search({
215 ... 'last_change_time': last_change_time,200 ... 'last_change_time': last_change_time,
216 ... })201 ... })
@@ -232,11 +217,11 @@
232 alias: bug-two217 alias: bug-two
233 assigned_to: marvin@heartofgold.ship218 assigned_to: marvin@heartofgold.ship
234 component: Crew219 component: Crew
235 creation_time: 20080611T09:23:12220 creation_time: 2008-06-11 09:23:12
236 id: 2221 id: 2
237 internals:...222 internals:...
238 is_open: True223 is_open: True
239 last_change_time: 20080611T09:24:29224 last_change_time: 2008-06-11 09:24:29
240 priority: P1225 priority: P1
241 product: HeartOfGold226 product: HeartOfGold
242 resolution: 227 resolution:
@@ -257,11 +242,11 @@
257 alias: 242 alias:
258 assigned_to: test@canonical.com243 assigned_to: test@canonical.com
259 component: GPPSystems244 component: GPPSystems
260 creation_time: 20080610T16:19:53245 creation_time: 2008-06-10 16:19:53
261 id: 1246 id: 1
262 internals:...247 internals:...
263 is_open: True248 is_open: True
264 last_change_time: 20080610T16:19:53249 last_change_time: 2008-06-10 16:19:53
265 priority: P1250 priority: P1
266 product: Marvin251 product: Marvin
267 resolution: FIXED252 resolution: FIXED
@@ -272,11 +257,11 @@
272 alias: bug-two257 alias: bug-two
273 assigned_to: marvin@heartofgold.ship258 assigned_to: marvin@heartofgold.ship
274 component: Crew259 component: Crew
275 creation_time: 20080611T09:23:12260 creation_time: 2008-06-11 09:23:12
276 id: 2261 id: 2
277 internals:...262 internals:...
278 is_open: True263 is_open: True
279 last_change_time: 20080611T09:24:29264 last_change_time: 2008-06-11 09:24:29
280 priority: P1265 priority: P1
281 product: HeartOfGold266 product: HeartOfGold
282 resolution: 267 resolution:
@@ -321,14 +306,14 @@
321 id: 1306 id: 1
322 is_private: False307 is_private: False
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.
324 time: 20080616T12:44:29309 time: 2008-06-16 12:44:29
325 <BLANKLINE>310 <BLANKLINE>
326 author: marvin311 author: marvin
327 bug_id: 1312 bug_id: 1
328 id: 3313 id: 3
329 is_private: False314 is_private: False
330 text: Life? Don't talk to me about life.315 text: Life? Don't talk to me about life.
331 time: 20080616T13:22:29316 time: 2008-06-16 13:22:29
332 <BLANKLINE>317 <BLANKLINE>
333 <BLANKLINE>318 <BLANKLINE>
334 Bug 2:319 Bug 2:
@@ -337,14 +322,14 @@
337 id: 2322 id: 2
338 is_private: False323 is_private: False
339 text: Bring the passengers to the bridge please Marvin.324 text: Bring the passengers to the bridge please Marvin.
340 time: 20080616T13:08:08325 time: 2008-06-16 13:08:08
341 <BLANKLINE>326 <BLANKLINE>
342 author: Ford Prefect <ford.prefect@h2g2.com>327 author: Ford Prefect <ford.prefect@h2g2.com>
343 bug_id: 2328 bug_id: 2
344 id: 4329 id: 4
345 is_private: False330 is_private: False
346 text: I appear to have become a perfectly safe penguin.331 text: I appear to have become a perfectly safe penguin.
347 time: 20080617T20:28:40332 time: 2008-06-17 20:28:40
348 <BLANKLINE>333 <BLANKLINE>
349 <BLANKLINE>334 <BLANKLINE>
350335
@@ -366,14 +351,14 @@
366 id: 1351 id: 1
367 is_private: False352 is_private: False
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.
369 time: 20080616T12:44:29354 time: 2008-06-16 12:44:29
370 Comment 4:355 Comment 4:
371 author: Ford Prefect <ford.prefect@h2g2.com>356 author: Ford Prefect <ford.prefect@h2g2.com>
372 bug_id: 2357 bug_id: 2
373 id: 4358 id: 4
374 is_private: False359 is_private: False
375 text: I appear to have become a perfectly safe penguin.360 text: I appear to have become a perfectly safe penguin.
376 time: 20080617T20:28:40361 time: 2008-06-17 20:28:40
377 <BLANKLINE>362 <BLANKLINE>
378363
379Note that only comments have been returned when only 'comment_ids' have364Note that only comments have been returned when only 'comment_ids' have
@@ -499,11 +484,11 @@
499 alias: 484 alias:
500 assigned_to: test@canonical.com485 assigned_to: test@canonical.com
501 component: GPPSystems486 component: GPPSystems
502 creation_time: 20080610T16:19:53487 creation_time: 2008-06-10 16:19:53
503 id: 1488 id: 1
504 internals:...489 internals:...
505 is_open: True490 is_open: True
506 last_change_time: 20080610T16:19:53491 last_change_time: 2008-06-10 16:19:53
507 priority: P1492 priority: P1
508 product: Marvin493 product: Marvin
509 resolution: FIXED494 resolution: FIXED
510495
=== modified file 'lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt'
--- lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt 2009-12-11 16:05:52 +0000
+++ lib/lp/bugs/tests/bugzilla-xmlrpc-transport.txt 2009-12-23 12:17:18 +0000
@@ -105,9 +105,9 @@
105 >>> time_dict = server.Launchpad.time()105 >>> time_dict = server.Launchpad.time()
106 >>> for key in sorted(time_dict):106 >>> for key in sorted(time_dict):
107 ... print "%s: %s" % (key, time_dict[key])107 ... print "%s: %s" % (key, time_dict[key])
108 local_time: 20080501T01:01:01108 local_time: 2008-05-01 01:01:01
109 tz_name: UTC109 tz_name: UTC
110 utc_time: 20080501T01:01:01110 utc_time: 2008-05-01 01:01:01
111111
112We can set the local time value on the remote server to make testing112We can set the local time value on the remote server to make testing
113more useful.113more useful.
@@ -122,9 +122,9 @@
122 >>> time_dict = server.Launchpad.time()122 >>> time_dict = server.Launchpad.time()
123 >>> for key in sorted(time_dict):123 >>> for key in sorted(time_dict):
124 ... print "%s: %s" % (key, time_dict[key])124 ... print "%s: %s" % (key, time_dict[key])
125 local_time: 20080515T16:19:53125 local_time: 2008-05-15 16:19:53
126 tz_name: US/Central126 tz_name: US/Central
127 utc_time: 20080515T22:19:53127 utc_time: 2008-05-15 22:19:53
128128
129129
130Launchpad.get_bugs()130Launchpad.get_bugs()
@@ -144,11 +144,11 @@
144 alias: 144 alias:
145 assigned_to: test@canonical.com145 assigned_to: test@canonical.com
146 component: GPPSystems146 component: GPPSystems
147 creation_time: 20080610T16:19:53147 creation_time: 2008-06-10 16:19:53
148 id: 1148 id: 1
149 internals:...149 internals:...
150 is_open: True150 is_open: True
151 last_change_time: 20080610T16:19:53151 last_change_time: 2008-06-10 16:19:53
152 priority: P1152 priority: P1
153 product: Marvin153 product: Marvin
154 resolution: FIXED154 resolution: FIXED
@@ -170,11 +170,11 @@
170 alias: 170 alias:
171 assigned_to: test@canonical.com171 assigned_to: test@canonical.com
172 component: GPPSystems172 component: GPPSystems
173 creation_time: 20080610T16:19:53173 creation_time: 2008-06-10 16:19:53
174 id: 1174 id: 1
175 internals:...175 internals:...
176 is_open: True176 is_open: True
177 last_change_time: 20080610T16:19:53177 last_change_time: 2008-06-10 16:19:53
178 priority: P1178 priority: P1
179 product: Marvin179 product: Marvin
180 resolution: FIXED180 resolution: FIXED
@@ -186,11 +186,11 @@
186 alias: bug-two186 alias: bug-two
187 assigned_to: marvin@heartofgold.ship187 assigned_to: marvin@heartofgold.ship
188 component: Crew188 component: Crew
189 creation_time: 20080611T09:23:12189 creation_time: 2008-06-11 09:23:12
190 id: 2190 id: 2
191 internals:...191 internals:...
192 is_open: True192 is_open: True
193 last_change_time: 20080611T09:24:29193 last_change_time: 2008-06-11 09:24:29
194 priority: P1194 priority: P1
195 product: HeartOfGold195 product: HeartOfGold
196 resolution:196 resolution:
@@ -209,11 +209,11 @@
209 alias: bug-two209 alias: bug-two
210 assigned_to: marvin@heartofgold.ship210 assigned_to: marvin@heartofgold.ship
211 component: Crew211 component: Crew
212 creation_time: 20080611T09:23:12212 creation_time: 2008-06-11 09:23:12
213 id: 2213 id: 2
214 internals:...214 internals:...
215 is_open: True215 is_open: True
216 last_change_time: 20080611T09:24:29216 last_change_time: 2008-06-11 09:24:29
217 priority: P1217 priority: P1
218 product: HeartOfGold218 product: HeartOfGold
219 resolution: 219 resolution:
@@ -228,17 +228,8 @@
228allowing Launchpad to get only the recently-updated subset of a given228allowing Launchpad to get only the recently-updated subset of a given
229set of remote bugs.229set of remote bugs.
230230
231 >>> from xmlrpclib import DateTime
232
233 >>> changed_since = datetime(2008, 6, 11, 9, 0, 0)231 >>> changed_since = datetime(2008, 6, 11, 9, 0, 0)
234232
235 >>> # We encode changed_since into an XML-RPC DateTime manually.
236 >>> # This is because xmlrpclib can't handle DateTime encoding
237 >>> # within a dict.
238 >>> # XXX 2008-08-05 gmb (bug 254999):
239 >>> # We can remove this once we upgrade to python 2.5.
240 >>> changed_since = DateTime(changed_since.timetuple())
241
242 >>> return_value = server.Launchpad.get_bugs({233 >>> return_value = server.Launchpad.get_bugs({
243 ... 'ids': [1, 2],234 ... 'ids': [1, 2],
244 ... 'changed_since': changed_since,235 ... 'changed_since': changed_since,
@@ -254,11 +245,11 @@
254 alias: bug-two245 alias: bug-two
255 assigned_to: marvin@heartofgold.ship246 assigned_to: marvin@heartofgold.ship
256 component: Crew247 component: Crew
257 creation_time: 20080611T09:23:12248 creation_time: 2008-06-11 09:23:12
258 id: 2249 id: 2
259 internals:...250 internals:...
260 is_open: True251 is_open: True
261 last_change_time: 20080611T09:24:29252 last_change_time: 2008-06-11 09:24:29
262 priority: P1253 priority: P1
263 product: HeartOfGold254 product: HeartOfGold
264 resolution: 255 resolution:
@@ -273,10 +264,6 @@
273 >>> from datetime import timedelta264 >>> from datetime import timedelta
274 >>> changed_since = datetime.now() + timedelta(days=42)265 >>> changed_since = datetime.now() + timedelta(days=42)
275266
276 >>> # XXX 2008-08-05 gmb (bug 254999):
277 >>> # We can remove this once we upgrade to python 2.5.
278 >>> changed_since = DateTime(changed_since.timetuple())
279
280 >>> return_value = server.Launchpad.get_bugs({267 >>> return_value = server.Launchpad.get_bugs({
281 ... 'ids': [1, 2],268 ... 'ids': [1, 2],
282 ... 'changed_since': changed_since,269 ... 'changed_since': changed_since,
@@ -304,11 +291,11 @@
304 alias: bug-two291 alias: bug-two
305 assigned_to: marvin@heartofgold.ship292 assigned_to: marvin@heartofgold.ship
306 component: Crew293 component: Crew
307 creation_time: 20080611T09:23:12294 creation_time: 2008-06-11 09:23:12
308 id: 2295 id: 2
309 internals:...296 internals:...
310 is_open: True297 is_open: True
311 last_change_time: 20080611T09:24:29298 last_change_time: 2008-06-11 09:24:29
312 priority: P1299 priority: P1
313 product: HeartOfGold300 product: HeartOfGold
314 resolution: 301 resolution:
@@ -366,13 +353,13 @@
366 id: 1353 id: 1
367 number: 1354 number: 1
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.
369 time: 20080616T12:44:29356 time: 2008-06-16 12:44:29
370 <BLANKLINE>357 <BLANKLINE>
371 author: marvin358 author: marvin
372 id: 3359 id: 3
373 number: 2360 number: 2
374 text: Life? Don't talk to me about life.361 text: Life? Don't talk to me about life.
375 time: 20080616T13:22:29362 time: 2008-06-16 13:22:29
376 <BLANKLINE>363 <BLANKLINE>
377 <BLANKLINE>364 <BLANKLINE>
378 Bug 2:365 Bug 2:
@@ -380,13 +367,13 @@
380 id: 2367 id: 2
381 number: 1368 number: 1
382 text: Bring the passengers to the bridge please Marvin.369 text: Bring the passengers to the bridge please Marvin.
383 time: 20080616T13:08:08370 time: 2008-06-16 13:08:08
384 <BLANKLINE>371 <BLANKLINE>
385 author: Ford Prefect <ford.prefect@h2g2.com>372 author: Ford Prefect <ford.prefect@h2g2.com>
386 id: 4373 id: 4
387 number: 2374 number: 2
388 text: I appear to have become a perfectly safe penguin.375 text: I appear to have become a perfectly safe penguin.
389 time: 20080617T20:28:40376 time: 2008-06-17 20:28:40
390377
391If an ids parameter is specified along with bug_ids, only the comments378If an ids parameter is specified along with bug_ids, only the comments
392whose IDs are in the list of IDs passed will be returned.379whose IDs are in the list of IDs passed will be returned.
@@ -401,7 +388,7 @@
401 id: 1388 id: 1
402 number: 1389 number: 1
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.
404 time: 20080616T12:44:29391 time: 2008-06-16 12:44:29
405 <BLANKLINE>392 <BLANKLINE>
406 <BLANKLINE>393 <BLANKLINE>
407 Bug 2:394 Bug 2:
@@ -409,7 +396,7 @@
409 id: 2396 id: 2
410 number: 1397 number: 1
411 text: Bring the passengers to the bridge please Marvin.398 text: Bring the passengers to the bridge please Marvin.
412 time: 20080616T13:08:08399 time: 2008-06-16 13:08:08
413400
414Passing an include_fields parameter allows us to limit which fields are401Passing an include_fields parameter allows us to limit which fields are
415returned for each comment.402returned for each comment.
416403
=== modified file 'lib/lp/bugs/tests/externalbugtracker.py'
--- lib/lp/bugs/tests/externalbugtracker.py 2009-11-30 10:21:23 +0000
+++ lib/lp/bugs/tests/externalbugtracker.py 2009-12-23 12:17:18 +0000
@@ -65,7 +65,7 @@
65 while bugtracker_set.getByName("%s-%d" % (name, index)) is not None:65 while bugtracker_set.getByName("%s-%d" % (name, index)) is not None:
66 index += 166 index += 1
67 name += '-%d' % index67 name += '-%d' % index
68 bugtracker = BugTracker(68 BugTracker(
69 name=name,69 name=name,
70 title='%s *TESTING*' % (bugtracker_type.title,),70 title='%s *TESTING*' % (bugtracker_type.title,),
71 bugtrackertype=bugtracker_type,71 bugtrackertype=bugtracker_type,
@@ -282,7 +282,6 @@
282 buglist_xml = read_test_file(self.buglist_file)282 buglist_xml = read_test_file(self.buglist_file)
283 bug_ids = str(form[self.bug_id_form_element]).split(',')283 bug_ids = str(form[self.bug_id_form_element]).split(',')
284 bug_li_items = []284 bug_li_items = []
285 status_tag = None
286 for bug_id in bug_ids:285 for bug_id in bug_ids:
287 bug_id = int(bug_id)286 bug_id = int(bug_id)
288 if bug_id not in self.bugzilla_bugs:287 if bug_id not in self.bugzilla_bugs:
@@ -527,17 +526,12 @@
527 if local_datetime is None:526 if local_datetime is None:
528 local_datetime = datetime(2008, 5, 1, 1, 1, 1)527 local_datetime = datetime(2008, 5, 1, 1, 1, 1)
529528
530 # We return xmlrpc dateTimes rather than doubles since that's
531 # what BugZilla will return.
532 local_time = xmlrpclib.DateTime(local_datetime.timetuple())
533
534 utc_offset_delta = timedelta(seconds=self.utc_offset)529 utc_offset_delta = timedelta(seconds=self.utc_offset)
535 utc_date_time = local_datetime - utc_offset_delta530 utc_date_time = local_datetime - utc_offset_delta
536531
537 utc_time = xmlrpclib.DateTime(utc_date_time.timetuple())
538 return {532 return {
539 'local_time': local_time,533 'local_time': local_datetime,
540 'utc_time': utc_time,534 'utc_time': utc_date_time,
541 'tz_name': self.timezone,535 'tz_name': self.timezone,
542 }536 }
543537
@@ -593,7 +587,6 @@
593 "One of ('ids', 'products') should be specified")587 "One of ('ids', 'products') should be specified")
594588
595 bugs_to_return = []589 bugs_to_return = []
596 bugs = dict(self.bugs)
597590
598 # We enforce permissiveness, since we'll always call this method591 # We enforce permissiveness, since we'll always call this method
599 # with permissive=True in the Real World.592 # with permissive=True in the Real World.
@@ -601,14 +594,14 @@
601 assert permissive, "get_bugs() must be called with permissive=True"594 assert permissive, "get_bugs() must be called with permissive=True"
602595
603 # If a changed_since argument is specified, marshall it into a596 # If a changed_since argument is specified, marshall it into a
604 # datetime so that we can use it for comparisons.597 # datetime so that we can use it for comparisons. Even though
605 # XXX 2008-08-05 gmb (bug 254999):598 # xmlrpclib in Python 2.5 groks datetime, by the time this
606 # We can remove these lines once we upgrade to python 2.5.599 # method is called xmlrpclib has already converted all
600 # datetimes to xmlrpclib.DateTime.
607 changed_since = arguments.get('changed_since')601 changed_since = arguments.get('changed_since')
608 if changed_since is not None:602 if changed_since is not None:
609 changed_since_timetuple = time.strptime(603 changed_since = datetime.strptime(
610 str(changed_since), '%Y%m%dT%H:%M:%S')604 changed_since.value, '%Y%m%dT%H:%M:%S')
611 changed_since = datetime(*changed_since_timetuple[:6])
612605
613 # If we have some products but no bug_ids we just get all the606 # If we have some products but no bug_ids we just get all the
614 # bug IDs for those products and stuff them in the bug_ids list607 # bug IDs for those products and stuff them in the bug_ids list
@@ -644,14 +637,6 @@
644 bug_dict['product'] not in products):637 bug_dict['product'] not in products):
645 continue638 continue
646639
647 # Update the DateTime fields of the bug dict so that they
648 # look like ones that would be sent over XML-RPC.
649 for time_field in ('creation_time', 'last_change_time'):
650 datetime_value = bug_dict[time_field]
651 timestamp = time.mktime(datetime_value.timetuple())
652 xmlrpc_datetime = xmlrpclib.DateTime(timestamp)
653 bug_dict[time_field] = xmlrpc_datetime
654
655 bugs_to_return.append(bug_dict)640 bugs_to_return.append(bug_dict)
656641
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,
@@ -662,15 +647,9 @@
662647
663 def _copy_comment(self, comment, fields_to_return=None):648 def _copy_comment(self, comment, fields_to_return=None):
664 # Copy wanted fields.649 # Copy wanted fields.
665 comment = dict(650 return dict(
666 (key, value) for (key, value) in comment.iteritems()651 (key, value) for (key, value) in comment.iteritems()
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)
668 # Replace the time field with an XML-RPC DateTime.
669 if 'time' in comment:
670 comment['time'] = xmlrpclib.DateTime(
671 comment['time'].timetuple())
672 return comment
673
674653
675 def comments(self, arguments):654 def comments(self, arguments):
676 """Return comments for a given set of bugs."""655 """Return comments for a given set of bugs."""
@@ -1617,8 +1596,7 @@
1617 The response body is an XMLRPC response. In addition we set the1596 The response body is an XMLRPC response. In addition we set the
1618 info of the response to contain a cookie.1597 info of the response to contain a cookie.
1619 """1598 """
1620 assert (1599 assert isinstance(req, Request), (
1621 isinstance(req, Request),
1622 'Expected a urllib2.Request, got %s' % req)1600 'Expected a urllib2.Request, got %s' % req)
16231601
1624 if 'testError' in req.data:1602 if 'testError' in req.data: