← Back to team overview

launchpad-reviewers team mailing list archive

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

 

Jonathan Lange has proposed merging lp:~jml/launchpad/utc-now into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~jml/launchpad/utc-now/+merge/66437

Add a utc_now() helper and change many callsites to use it.
-- 
https://code.launchpad.net/~jml/launchpad/utc-now/+merge/66437
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jml/launchpad/utc-now into lp:launchpad.
=== modified file 'lib/canonical/launchpad/database/temporaryblobstorage.py'
--- lib/canonical/launchpad/database/temporaryblobstorage.py	2011-03-09 04:49:00 +0000
+++ lib/canonical/launchpad/database/temporaryblobstorage.py	2011-06-30 11:34:26 +0000
@@ -12,13 +12,9 @@
 
 
 from cStringIO import StringIO
-from datetime import (
-    datetime,
-    timedelta,
-    )
+from datetime import timedelta
 import uuid
 
-from pytz import utc
 from sqlobject import (
     ForeignKey,
     SQLObjectNotFound,
@@ -31,15 +27,14 @@
 from canonical.database.constants import DEFAULT
 from canonical.database.datetimecol import UtcDateTimeCol
 from canonical.database.sqlbase import SQLBase
-from canonical.launchpad.database.librarian import LibraryFileAlias
 from canonical.launchpad.interfaces.temporaryblobstorage import (
     BlobTooLarge,
     ITemporaryBlobStorage,
     ITemporaryStorageManager,
     )
 from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet
-from canonical.launchpad.interfaces.lpstorm import IStore
 from lp.services.job.interfaces.job import JobStatus
+from lp.services.utils import utc_now
 
 
 class TemporaryBlobStorage(SQLBase):
@@ -104,8 +99,7 @@
             # A week might be quite a long time, but it shouldn't hurt,
             # and it gives people enough time to create an account
             # before accessing the uploaded blob.
-            expires = (
-                datetime.utcnow().replace(tzinfo=utc) + timedelta(weeks=1))
+            expires = utc_now() + timedelta(weeks=1)
 
         # At this stage we could do some sort of throttling if we were
         # concerned about abuse of the temporary storage facility. For

=== modified file 'lib/canonical/launchpad/scripts/ftests/librarianformatter.txt'
--- lib/canonical/launchpad/scripts/ftests/librarianformatter.txt	2010-12-22 14:50:08 +0000
+++ lib/canonical/launchpad/scripts/ftests/librarianformatter.txt	2011-06-30 11:34:26 +0000
@@ -36,6 +36,8 @@
 >>> from canonical.testing.layers import LibrarianLayer
 >>> LibrarianLayer.hide()
 
+>>> from lp.services.utils import utc_now
+
 >>> normal_log, normal_out= make_logger(logging.Formatter)
 >>> librarian_log, librarian_out = make_logger(LibrarianFormatter)
 >>> import time
@@ -95,8 +97,7 @@
 >>> from canonical.launchpad.database.librarian import LibraryFileAlias
 >>> transaction.abort() # To see db changes made by the librarian
 >>> alias = LibraryFileAlias.get(alias_id)
->>> now = datetime.now().replace(tzinfo=utc)
->>> alias.expires > now + timedelta(days=89)
+>>> alias.expires > utc_now() + timedelta(days=89)
 True
 
 Note that we also need to remain informative with dud exceptions, such as

=== modified file 'lib/canonical/launchpad/scripts/logger.py'
--- lib/canonical/launchpad/scripts/logger.py	2011-02-23 13:49:47 +0000
+++ lib/canonical/launchpad/scripts/logger.py	2011-06-30 11:34:26 +0000
@@ -34,7 +34,6 @@
 from contextlib import contextmanager
 from cStringIO import StringIO
 from datetime import (
-    datetime,
     timedelta,
     )
 import hashlib
@@ -47,7 +46,6 @@
 import time
 from traceback import format_exception_only
 
-from pytz import utc
 from zope.component import getUtility
 from zope.exceptions.log import Formatter
 
@@ -61,7 +59,10 @@
     UploadFailed,
     )
 from lp.services.log import loglevels
-from lp.services.utils import compress_hash
+from lp.services.utils import (
+    compress_hash,
+    utc_now,
+    )
 
 # Reexport our custom loglevels for old callsites. These callsites
 # should be importing the symbols from lp.services.log.loglevels
@@ -148,7 +149,7 @@
         if not exception_string:
             exception_string = ei[0].__name__
 
-        expiry = datetime.now().replace(tzinfo=utc) + timedelta(days=90)
+        expiry = utc_now() + timedelta(days=90)
         try:
             filename = compress_hash(hashlib.sha1(traceback)) + '.txt'
             url = librarian.remoteAddFile(

=== modified file 'lib/canonical/lazr/feed/feed.py'
--- lib/canonical/lazr/feed/feed.py	2010-11-08 12:52:43 +0000
+++ lib/canonical/lazr/feed/feed.py	2011-06-30 11:34:26 +0000
@@ -17,7 +17,6 @@
     'MINUTES',
     ]
 
-from datetime import datetime
 import operator
 import os
 import time
@@ -25,7 +24,6 @@
 from xml.sax.saxutils import escape as xml_escape
 
 from BeautifulSoup import BeautifulSoup
-import pytz
 from z3c.ptcompat import ViewPageTemplateFile
 from zope.component import getUtility
 from zope.datetime import rfc1123_date
@@ -51,6 +49,7 @@
     UnsupportedFeedFormat,
     )
 from lp.services.propertycache import cachedproperty
+from lp.services.utils import utc_now
 
 
 SUPPORTED_FEEDS = ('.atom', '.html')
@@ -181,7 +180,7 @@
             # datetime.isoformat() doesn't place the necessary "+00:00"
             # for the feedvalidator's check of the iso8601 date format
             # unless a timezone is specified with tzinfo.
-            return datetime.utcnow().replace(tzinfo=pytz.utc)
+            return utc_now()
         last_modified = sorted_items[0].last_modified
         if last_modified is None:
             raise AssertionError, 'All feed entries require a date updated.'
@@ -257,8 +256,6 @@
         if authors is None:
             authors = []
         self.authors = authors
-        if contributors is None:
-            contribuors = []
         self.contributors = contributors
         if id_ is None:
             self.id = self.construct_id()

=== modified file 'lib/canonical/librarian/ftests/test_gc.py'
--- lib/canonical/librarian/ftests/test_gc.py	2010-12-23 00:38:29 +0000
+++ lib/canonical/librarian/ftests/test_gc.py	2011-06-30 11:34:26 +0000
@@ -6,7 +6,7 @@
 __metaclass__ = type
 
 from cStringIO import StringIO
-from datetime import datetime, timedelta
+from datetime import timedelta
 import os
 import shutil
 from subprocess import Popen, PIPE, STDOUT
@@ -14,7 +14,6 @@
 import tempfile
 from unittest import TestLoader
 
-from pytz import utc
 from sqlobject import SQLObjectNotFound
 import transaction
 
@@ -32,6 +31,7 @@
 from canonical.librarian.client import LibrarianClient
 from canonical.testing.layers import LaunchpadZopelessLayer
 from lp.services.log.logger import BufferLogger
+from lp.services.utils import utc_now
 from lp.testing import TestCase
 
 
@@ -52,12 +52,9 @@
         # far enough so that how long it takes the test to run
         # is not an issue. 'stay_of_excution - 1 hour' fits these
         # criteria.
-        self.recent_past = (
-            datetime.utcnow().replace(tzinfo=utc)
-            - timedelta(days=6, hours=23))
+        self.recent_past = utc_now() - timedelta(days=6, hours=23)
         # A time beyond the stay of execution.
-        self.ancient_past = (
-            datetime.utcnow().replace(tzinfo=utc) - timedelta(days=30))
+        self.ancient_past = utc_now - timedelta(days=30)
 
         self.f1_id, self.f2_id = self._makeDupes()
 

=== modified file 'lib/lp/app/browser/launchpad.py'
--- lib/lp/app/browser/launchpad.py	2011-06-27 15:36:25 +0000
+++ lib/lp/app/browser/launchpad.py	2011-06-30 11:34:26 +0000
@@ -24,7 +24,6 @@
 
 import cgi
 from datetime import (
-    datetime,
     timedelta,
     )
 import operator
@@ -43,7 +42,6 @@
 from zope.datetime import (
     DateTimeError,
     parseDatetimetz,
-    tzinfo,
     )
 from zope.i18nmessageid import Message
 from zope.interface import implements
@@ -143,6 +141,7 @@
 from lp.registry.interfaces.projectgroup import IProjectGroupSet
 from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet
 from lp.services.propertycache import cachedproperty
+from lp.services.utils import utc_now
 from lp.services.worlddata.interfaces.country import ICountrySet
 from lp.services.worlddata.interfaces.language import ILanguageSet
 from lp.soyuz.interfaces.binarypackagename import IBinaryPackageNameSet
@@ -374,8 +373,7 @@
             except DateTimeError:
                 # XXX SteveAlexander 2005-09-22: log a warning here.
                 return ''
-            nowtz = datetime.utcnow().replace(tzinfo=tzinfo(0))
-            timeleft = maintenancetime - nowtz
+            timeleft = maintenancetime - utc_now()
             if timeleft > self.toomuchtime:
                 return ''
             elif timeleft < self.notmuchtime:

=== modified file 'lib/lp/bugs/doc/bug-heat.txt'
--- lib/lp/bugs/doc/bug-heat.txt	2010-12-23 13:36:01 +0000
+++ lib/lp/bugs/doc/bug-heat.txt	2011-06-30 11:34:26 +0000
@@ -176,10 +176,11 @@
 
     >>> from datetime import datetime, timedelta
     >>> from pytz import timezone
+    >>> from lp.services.utils import utc_now
 
     >>> from lp.bugs.adapters.bugchange import BugDescriptionChange
     >>> change = BugDescriptionChange(
-    ...     when=datetime.now().replace(tzinfo=timezone('UTC')),
+    ...     when=utc_now(),
     ...     person=bug.owner, what_changed='description',
     ...     old_value=bug.description, new_value='Some text')
     >>> bug.addChange(change)

=== modified file 'lib/lp/registry/browser/tests/poll-views.txt'
--- lib/lp/registry/browser/tests/poll-views.txt	2011-01-05 19:18:57 +0000
+++ lib/lp/registry/browser/tests/poll-views.txt	2011-06-30 11:34:26 +0000
@@ -52,11 +52,10 @@
 The portlet shows a link to polls to all users when there is a poll, but it
 has not opened.
 
-    >>> import pytz
-    >>> from datetime import datetime, timedelta
     >>> from lp.registry.interfaces.poll import IPollSubset, PollSecrecy
+    >>> from lp.services.utils import utc_now
 
-    >>> open_date = datetime.now().replace(tzinfo=pytz.timezone('UTC'))
+    >>> open_date = utc_now()
     >>> close_date = open_date + timedelta(weeks=1)
     >>> poll_subset = IPollSubset(team)
     >>> poll = poll_subset.new(

=== modified file 'lib/lp/registry/doc/announcement.txt'
--- lib/lp/registry/doc/announcement.txt	2011-05-27 19:53:20 +0000
+++ lib/lp/registry/doc/announcement.txt	2011-06-30 11:34:26 +0000
@@ -11,7 +11,8 @@
     >>> from zope.component import getUtility
     >>> from datetime import datetime, timedelta
     >>> import pytz
-    >>> NOW = datetime.utcnow().replace(tzinfo=pytz.utc)
+    >>> from lp.services.utils import utc_now
+    >>> NOW = utc_now()
     >>> FUTURE = NOW + timedelta(days=10)
     >>> from lp.registry.interfaces.announcement import IAnnouncementSet
     >>> from lp.registry.interfaces.distribution import IDistributionSet
@@ -49,8 +50,6 @@
 In this first example, we will specify a date and time the announcement was
 published:
 
-    >>> from datetime import datetime
-    >>> import pytz
     >>> apache_asia = apache.announce(
     ...  mark,
     ...  "OS Summit Asia 2007 - New Event by Apache and Eclipse",

=== modified file 'lib/lp/registry/model/announcement.py'
--- lib/lp/registry/model/announcement.py	2010-08-20 20:31:18 +0000
+++ lib/lp/registry/model/announcement.py	2011-06-30 11:34:26 +0000
@@ -11,9 +11,6 @@
     'MakesAnnouncements',
     ]
 
-import datetime
-
-import pytz
 from sqlobject import (
     BoolCol,
     ForeignKey,
@@ -36,6 +33,7 @@
 from lp.registry.interfaces.person import validate_public_person
 from lp.registry.interfaces.product import IProduct
 from lp.registry.interfaces.projectgroup import IProjectGroup
+from lp.services.utils import utc_now
 
 
 class Announcement(SQLBase):
@@ -125,8 +123,7 @@
         """See `IAnnouncement`."""
         if self.date_announced is None:
             return True
-        return self.date_announced > \
-               datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
+        return self.date_announced > utc_now()
 
     @property
     def published(self):

=== modified file 'lib/lp/services/tests/test_utils.py'
--- lib/lp/services/tests/test_utils.py	2011-03-31 05:12:09 +0000
+++ lib/lp/services/tests/test_utils.py	2011-06-30 11:34:26 +0000
@@ -6,11 +6,18 @@
 __metaclass__ = type
 
 from contextlib import contextmanager
+from datetime import datetime
 import hashlib
 import itertools
 import os
 import sys
 
+from pytz import UTC
+from testtools.matchers import (
+    GreaterThan,
+    LessThan,
+    )
+
 from lp.services.utils import (
     AutoDecorate,
     base,
@@ -22,6 +29,7 @@
     iter_split,
     run_capturing_output,
     traceback_info,
+    utc_now,
     )
 from lp.testing import TestCase
 
@@ -299,3 +307,21 @@
     def test_is_not_upset_by_missing_directory(self):
         self.assertFalse(
             file_exists("a-nonexistent-directory/a-nonexistent-file.txt"))
+
+
+class TestUTCNow(TestCase):
+    """Tests for `utc_now`."""
+
+    def test_tzinfo(self):
+        # utc_now() returns a timezone-aware timestamp with the timezone of
+        # UTC.
+        now = utc_now()
+        self.assertEqual(now.tzinfo, UTC)
+
+    def test_time_is_now(self):
+        # utc_now() returns a timestamp which is now.
+        old_now = datetime.now().replace(tzinfo=UTC)
+        now = utc_now()
+        new_now = datetime.now().replace(tzinfo=UTC)
+        self.assertThat(now, GreaterThan(old_now))
+        self.assertThat(now, LessThan(new_now))

=== modified file 'lib/lp/services/utils.py'
--- lib/lp/services/utils.py	2011-06-28 23:43:37 +0000
+++ lib/lp/services/utils.py	2011-06-30 11:34:26 +0000
@@ -22,9 +22,11 @@
     'synchronize',
     'text_delta',
     'traceback_info',
+    'utc_now',
     'value_string',
     ]
 
+from datetime import datetime
 from itertools import tee
 import os
 from StringIO import StringIO
@@ -38,6 +40,7 @@
     MonkeyPatch,
     )
 from lazr.enum import BaseItem
+import pytz
 from twisted.python.util import mergeFunctionMetadata
 from zope.security.proxy import isinstance as zope_isinstance
 
@@ -285,3 +288,8 @@
     variables, and helps to avoid typos.
     """
     sys._getframe(1).f_locals["__traceback_info__"] = info
+
+
+def utc_now():
+    """Return a timezone-aware timestamp for the current time."""
+    return datetime.now().replace(tzinfo=pytz.UTC)

=== modified file 'versions.cfg'
--- versions.cfg	2011-06-27 23:06:19 +0000
+++ versions.cfg	2011-06-30 11:34:26 +0000
@@ -75,7 +75,7 @@
 soupmatchers = 0.1r53
 sourcecodegen = 0.6.9
 storm = 0.18.0.99-lpwithnodatetime-r393
-testtools = 0.9.11
+testtools = 0.9.12-r194
 transaction = 1.0.0
 Twisted = 11.0.0
 uuid = 1.30