Merge lp:~jml/launchpad/utc-now into lp:launchpad

Proposed by Jonathan Lange
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merged at revision: 13368
Proposed branch: lp:~jml/launchpad/utc-now
Merge into: lp:launchpad
Diff against target: 438 lines (+67/-44)
13 files modified
lib/canonical/launchpad/database/temporaryblobstorage.py (+3/-9)
lib/canonical/launchpad/scripts/ftests/librarianformatter.txt (+3/-2)
lib/canonical/launchpad/scripts/logger.py (+5/-4)
lib/canonical/lazr/feed/feed.py (+2/-5)
lib/canonical/librarian/ftests/test_gc.py (+4/-7)
lib/lp/app/browser/launchpad.py (+2/-4)
lib/lp/bugs/doc/bug-heat.txt (+2/-1)
lib/lp/registry/browser/tests/poll-views.txt (+3/-3)
lib/lp/registry/doc/announcement.txt (+2/-3)
lib/lp/registry/model/announcement.py (+2/-5)
lib/lp/services/tests/test_utils.py (+30/-0)
lib/lp/services/utils.py (+8/-0)
versions.cfg (+1/-1)
To merge this branch: bzr merge lp:~jml/launchpad/utc-now
Reviewer Review Type Date Requested Status
Jelmer Vernooij (community) code Approve
Review via email: mp+66437@code.launchpad.net

Commit message

[r=jelmer][no-qa] Create a utc_now convenience and use it

Description of the change

Add a utc_now() helper and change many callsites to use it.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

Hooray for cleanups.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/database/temporaryblobstorage.py'
2--- lib/canonical/launchpad/database/temporaryblobstorage.py 2011-03-09 04:49:00 +0000
3+++ lib/canonical/launchpad/database/temporaryblobstorage.py 2011-07-04 11:09:59 +0000
4@@ -12,13 +12,9 @@
5
6
7 from cStringIO import StringIO
8-from datetime import (
9- datetime,
10- timedelta,
11- )
12+from datetime import timedelta
13 import uuid
14
15-from pytz import utc
16 from sqlobject import (
17 ForeignKey,
18 SQLObjectNotFound,
19@@ -31,15 +27,14 @@
20 from canonical.database.constants import DEFAULT
21 from canonical.database.datetimecol import UtcDateTimeCol
22 from canonical.database.sqlbase import SQLBase
23-from canonical.launchpad.database.librarian import LibraryFileAlias
24 from canonical.launchpad.interfaces.temporaryblobstorage import (
25 BlobTooLarge,
26 ITemporaryBlobStorage,
27 ITemporaryStorageManager,
28 )
29 from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet
30-from canonical.launchpad.interfaces.lpstorm import IStore
31 from lp.services.job.interfaces.job import JobStatus
32+from lp.services.utils import utc_now
33
34
35 class TemporaryBlobStorage(SQLBase):
36@@ -104,8 +99,7 @@
37 # A week might be quite a long time, but it shouldn't hurt,
38 # and it gives people enough time to create an account
39 # before accessing the uploaded blob.
40- expires = (
41- datetime.utcnow().replace(tzinfo=utc) + timedelta(weeks=1))
42+ expires = utc_now() + timedelta(weeks=1)
43
44 # At this stage we could do some sort of throttling if we were
45 # concerned about abuse of the temporary storage facility. For
46
47=== modified file 'lib/canonical/launchpad/scripts/ftests/librarianformatter.txt'
48--- lib/canonical/launchpad/scripts/ftests/librarianformatter.txt 2010-12-22 14:50:08 +0000
49+++ lib/canonical/launchpad/scripts/ftests/librarianformatter.txt 2011-07-04 11:09:59 +0000
50@@ -36,6 +36,8 @@
51 >>> from canonical.testing.layers import LibrarianLayer
52 >>> LibrarianLayer.hide()
53
54+>>> from lp.services.utils import utc_now
55+
56 >>> normal_log, normal_out= make_logger(logging.Formatter)
57 >>> librarian_log, librarian_out = make_logger(LibrarianFormatter)
58 >>> import time
59@@ -95,8 +97,7 @@
60 >>> from canonical.launchpad.database.librarian import LibraryFileAlias
61 >>> transaction.abort() # To see db changes made by the librarian
62 >>> alias = LibraryFileAlias.get(alias_id)
63->>> now = datetime.now().replace(tzinfo=utc)
64->>> alias.expires > now + timedelta(days=89)
65+>>> alias.expires > utc_now() + timedelta(days=89)
66 True
67
68 Note that we also need to remain informative with dud exceptions, such as
69
70=== modified file 'lib/canonical/launchpad/scripts/logger.py'
71--- lib/canonical/launchpad/scripts/logger.py 2011-02-23 13:49:47 +0000
72+++ lib/canonical/launchpad/scripts/logger.py 2011-07-04 11:09:59 +0000
73@@ -34,7 +34,6 @@
74 from contextlib import contextmanager
75 from cStringIO import StringIO
76 from datetime import (
77- datetime,
78 timedelta,
79 )
80 import hashlib
81@@ -47,7 +46,6 @@
82 import time
83 from traceback import format_exception_only
84
85-from pytz import utc
86 from zope.component import getUtility
87 from zope.exceptions.log import Formatter
88
89@@ -61,7 +59,10 @@
90 UploadFailed,
91 )
92 from lp.services.log import loglevels
93-from lp.services.utils import compress_hash
94+from lp.services.utils import (
95+ compress_hash,
96+ utc_now,
97+ )
98
99 # Reexport our custom loglevels for old callsites. These callsites
100 # should be importing the symbols from lp.services.log.loglevels
101@@ -148,7 +149,7 @@
102 if not exception_string:
103 exception_string = ei[0].__name__
104
105- expiry = datetime.now().replace(tzinfo=utc) + timedelta(days=90)
106+ expiry = utc_now() + timedelta(days=90)
107 try:
108 filename = compress_hash(hashlib.sha1(traceback)) + '.txt'
109 url = librarian.remoteAddFile(
110
111=== modified file 'lib/canonical/lazr/feed/feed.py'
112--- lib/canonical/lazr/feed/feed.py 2010-11-08 12:52:43 +0000
113+++ lib/canonical/lazr/feed/feed.py 2011-07-04 11:09:59 +0000
114@@ -17,7 +17,6 @@
115 'MINUTES',
116 ]
117
118-from datetime import datetime
119 import operator
120 import os
121 import time
122@@ -25,7 +24,6 @@
123 from xml.sax.saxutils import escape as xml_escape
124
125 from BeautifulSoup import BeautifulSoup
126-import pytz
127 from z3c.ptcompat import ViewPageTemplateFile
128 from zope.component import getUtility
129 from zope.datetime import rfc1123_date
130@@ -51,6 +49,7 @@
131 UnsupportedFeedFormat,
132 )
133 from lp.services.propertycache import cachedproperty
134+from lp.services.utils import utc_now
135
136
137 SUPPORTED_FEEDS = ('.atom', '.html')
138@@ -181,7 +180,7 @@
139 # datetime.isoformat() doesn't place the necessary "+00:00"
140 # for the feedvalidator's check of the iso8601 date format
141 # unless a timezone is specified with tzinfo.
142- return datetime.utcnow().replace(tzinfo=pytz.utc)
143+ return utc_now()
144 last_modified = sorted_items[0].last_modified
145 if last_modified is None:
146 raise AssertionError, 'All feed entries require a date updated.'
147@@ -257,8 +256,6 @@
148 if authors is None:
149 authors = []
150 self.authors = authors
151- if contributors is None:
152- contribuors = []
153 self.contributors = contributors
154 if id_ is None:
155 self.id = self.construct_id()
156
157=== modified file 'lib/canonical/librarian/ftests/test_gc.py'
158--- lib/canonical/librarian/ftests/test_gc.py 2010-12-23 00:38:29 +0000
159+++ lib/canonical/librarian/ftests/test_gc.py 2011-07-04 11:09:59 +0000
160@@ -6,7 +6,7 @@
161 __metaclass__ = type
162
163 from cStringIO import StringIO
164-from datetime import datetime, timedelta
165+from datetime import timedelta
166 import os
167 import shutil
168 from subprocess import Popen, PIPE, STDOUT
169@@ -14,7 +14,6 @@
170 import tempfile
171 from unittest import TestLoader
172
173-from pytz import utc
174 from sqlobject import SQLObjectNotFound
175 import transaction
176
177@@ -32,6 +31,7 @@
178 from canonical.librarian.client import LibrarianClient
179 from canonical.testing.layers import LaunchpadZopelessLayer
180 from lp.services.log.logger import BufferLogger
181+from lp.services.utils import utc_now
182 from lp.testing import TestCase
183
184
185@@ -52,12 +52,9 @@
186 # far enough so that how long it takes the test to run
187 # is not an issue. 'stay_of_excution - 1 hour' fits these
188 # criteria.
189- self.recent_past = (
190- datetime.utcnow().replace(tzinfo=utc)
191- - timedelta(days=6, hours=23))
192+ self.recent_past = utc_now() - timedelta(days=6, hours=23)
193 # A time beyond the stay of execution.
194- self.ancient_past = (
195- datetime.utcnow().replace(tzinfo=utc) - timedelta(days=30))
196+ self.ancient_past = utc_now() - timedelta(days=30)
197
198 self.f1_id, self.f2_id = self._makeDupes()
199
200
201=== modified file 'lib/lp/app/browser/launchpad.py'
202--- lib/lp/app/browser/launchpad.py 2011-06-27 15:36:25 +0000
203+++ lib/lp/app/browser/launchpad.py 2011-07-04 11:09:59 +0000
204@@ -24,7 +24,6 @@
205
206 import cgi
207 from datetime import (
208- datetime,
209 timedelta,
210 )
211 import operator
212@@ -43,7 +42,6 @@
213 from zope.datetime import (
214 DateTimeError,
215 parseDatetimetz,
216- tzinfo,
217 )
218 from zope.i18nmessageid import Message
219 from zope.interface import implements
220@@ -143,6 +141,7 @@
221 from lp.registry.interfaces.projectgroup import IProjectGroupSet
222 from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet
223 from lp.services.propertycache import cachedproperty
224+from lp.services.utils import utc_now
225 from lp.services.worlddata.interfaces.country import ICountrySet
226 from lp.services.worlddata.interfaces.language import ILanguageSet
227 from lp.soyuz.interfaces.binarypackagename import IBinaryPackageNameSet
228@@ -374,8 +373,7 @@
229 except DateTimeError:
230 # XXX SteveAlexander 2005-09-22: log a warning here.
231 return ''
232- nowtz = datetime.utcnow().replace(tzinfo=tzinfo(0))
233- timeleft = maintenancetime - nowtz
234+ timeleft = maintenancetime - utc_now()
235 if timeleft > self.toomuchtime:
236 return ''
237 elif timeleft < self.notmuchtime:
238
239=== modified file 'lib/lp/bugs/doc/bug-heat.txt'
240--- lib/lp/bugs/doc/bug-heat.txt 2010-12-23 13:36:01 +0000
241+++ lib/lp/bugs/doc/bug-heat.txt 2011-07-04 11:09:59 +0000
242@@ -176,10 +176,11 @@
243
244 >>> from datetime import datetime, timedelta
245 >>> from pytz import timezone
246+ >>> from lp.services.utils import utc_now
247
248 >>> from lp.bugs.adapters.bugchange import BugDescriptionChange
249 >>> change = BugDescriptionChange(
250- ... when=datetime.now().replace(tzinfo=timezone('UTC')),
251+ ... when=utc_now(),
252 ... person=bug.owner, what_changed='description',
253 ... old_value=bug.description, new_value='Some text')
254 >>> bug.addChange(change)
255
256=== modified file 'lib/lp/registry/browser/tests/poll-views.txt'
257--- lib/lp/registry/browser/tests/poll-views.txt 2011-07-01 19:17:03 +0000
258+++ lib/lp/registry/browser/tests/poll-views.txt 2011-07-04 11:09:59 +0000
259@@ -5,6 +5,7 @@
260 polls.
261
262 >>> from canonical.launchpad.testing.pages import extract_text
263+ >>> from datetime import timedelta
264
265 >>> user = factory.makePerson()
266 >>> team = factory.makeTeam(name='team')
267@@ -52,11 +53,10 @@
268 The portlet shows a link to polls to all users when there is a poll, but it
269 has not opened.
270
271- >>> import pytz
272- >>> from datetime import datetime, timedelta
273 >>> from lp.registry.interfaces.poll import IPollSubset, PollSecrecy
274+ >>> from lp.services.utils import utc_now
275
276- >>> open_date = datetime.now().replace(tzinfo=pytz.timezone('UTC'))
277+ >>> open_date = utc_now() + timedelta(hours=6)
278 >>> close_date = open_date + timedelta(weeks=1)
279 >>> poll_subset = IPollSubset(team)
280 >>> poll = poll_subset.new(
281
282=== modified file 'lib/lp/registry/doc/announcement.txt'
283--- lib/lp/registry/doc/announcement.txt 2011-05-27 19:53:20 +0000
284+++ lib/lp/registry/doc/announcement.txt 2011-07-04 11:09:59 +0000
285@@ -11,7 +11,8 @@
286 >>> from zope.component import getUtility
287 >>> from datetime import datetime, timedelta
288 >>> import pytz
289- >>> NOW = datetime.utcnow().replace(tzinfo=pytz.utc)
290+ >>> from lp.services.utils import utc_now
291+ >>> NOW = utc_now()
292 >>> FUTURE = NOW + timedelta(days=10)
293 >>> from lp.registry.interfaces.announcement import IAnnouncementSet
294 >>> from lp.registry.interfaces.distribution import IDistributionSet
295@@ -49,8 +50,6 @@
296 In this first example, we will specify a date and time the announcement was
297 published:
298
299- >>> from datetime import datetime
300- >>> import pytz
301 >>> apache_asia = apache.announce(
302 ... mark,
303 ... "OS Summit Asia 2007 - New Event by Apache and Eclipse",
304
305=== modified file 'lib/lp/registry/model/announcement.py'
306--- lib/lp/registry/model/announcement.py 2010-08-20 20:31:18 +0000
307+++ lib/lp/registry/model/announcement.py 2011-07-04 11:09:59 +0000
308@@ -11,9 +11,6 @@
309 'MakesAnnouncements',
310 ]
311
312-import datetime
313-
314-import pytz
315 from sqlobject import (
316 BoolCol,
317 ForeignKey,
318@@ -36,6 +33,7 @@
319 from lp.registry.interfaces.person import validate_public_person
320 from lp.registry.interfaces.product import IProduct
321 from lp.registry.interfaces.projectgroup import IProjectGroup
322+from lp.services.utils import utc_now
323
324
325 class Announcement(SQLBase):
326@@ -125,8 +123,7 @@
327 """See `IAnnouncement`."""
328 if self.date_announced is None:
329 return True
330- return self.date_announced > \
331- datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
332+ return self.date_announced > utc_now()
333
334 @property
335 def published(self):
336
337=== modified file 'lib/lp/services/tests/test_utils.py'
338--- lib/lp/services/tests/test_utils.py 2011-03-31 05:12:09 +0000
339+++ lib/lp/services/tests/test_utils.py 2011-07-04 11:09:59 +0000
340@@ -6,11 +6,20 @@
341 __metaclass__ = type
342
343 from contextlib import contextmanager
344+from datetime import datetime
345 import hashlib
346 import itertools
347 import os
348 import sys
349
350+from pytz import UTC
351+from testtools.matchers import (
352+ Equals,
353+ GreaterThan,
354+ LessThan,
355+ MatchesAny,
356+ )
357+
358 from lp.services.utils import (
359 AutoDecorate,
360 base,
361@@ -22,6 +31,7 @@
362 iter_split,
363 run_capturing_output,
364 traceback_info,
365+ utc_now,
366 )
367 from lp.testing import TestCase
368
369@@ -299,3 +309,23 @@
370 def test_is_not_upset_by_missing_directory(self):
371 self.assertFalse(
372 file_exists("a-nonexistent-directory/a-nonexistent-file.txt"))
373+
374+
375+class TestUTCNow(TestCase):
376+ """Tests for `utc_now`."""
377+
378+ def test_tzinfo(self):
379+ # utc_now() returns a timezone-aware timestamp with the timezone of
380+ # UTC.
381+ now = utc_now()
382+ self.assertEqual(now.tzinfo, UTC)
383+
384+ def test_time_is_now(self):
385+ # utc_now() returns a timestamp which is now.
386+ LessThanOrEqual = lambda x: MatchesAny(LessThan(x), Equals(x))
387+ GreaterThanOrEqual = lambda x: MatchesAny(GreaterThan(x), Equals(x))
388+ old_now = datetime.utcnow().replace(tzinfo=UTC)
389+ now = utc_now()
390+ new_now = datetime.utcnow().replace(tzinfo=UTC)
391+ self.assertThat(now, GreaterThanOrEqual(old_now))
392+ self.assertThat(now, LessThanOrEqual(new_now))
393
394=== modified file 'lib/lp/services/utils.py'
395--- lib/lp/services/utils.py 2011-06-28 23:43:37 +0000
396+++ lib/lp/services/utils.py 2011-07-04 11:09:59 +0000
397@@ -22,9 +22,11 @@
398 'synchronize',
399 'text_delta',
400 'traceback_info',
401+ 'utc_now',
402 'value_string',
403 ]
404
405+from datetime import datetime
406 from itertools import tee
407 import os
408 from StringIO import StringIO
409@@ -38,6 +40,7 @@
410 MonkeyPatch,
411 )
412 from lazr.enum import BaseItem
413+import pytz
414 from twisted.python.util import mergeFunctionMetadata
415 from zope.security.proxy import isinstance as zope_isinstance
416
417@@ -285,3 +288,8 @@
418 variables, and helps to avoid typos.
419 """
420 sys._getframe(1).f_locals["__traceback_info__"] = info
421+
422+
423+def utc_now():
424+ """Return a timezone-aware timestamp for the current time."""
425+ return datetime.now(tz=pytz.UTC)
426
427=== modified file 'versions.cfg'
428--- versions.cfg 2011-07-01 10:19:20 +0000
429+++ versions.cfg 2011-07-04 11:09:59 +0000
430@@ -79,7 +79,7 @@
431 sourcecodegen = 0.6.9
432 storm = 0.18.0.99-lpwithnodatetime-r393
433 testresources = 0.2.4-r58
434-testtools = 0.9.11
435+testtools = 0.9.12-r194
436 transaction = 1.0.0
437 txamqp = 0.4
438 Twisted = 11.0.0