From b8bce1693c971580c3ef506590006f1f9a8084f6 Mon Sep 17 00:00:00 2001 From: Danny Hermes Date: Fri, 7 Aug 2015 17:34:58 -0700 Subject: [PATCH] Removing use of pytz module / implementing our own UTC. --- gcloud/_helpers.py | 43 ++++++++++++++++++++++++++++ gcloud/bigquery/_helpers.py | 7 +++-- gcloud/bigquery/test__helpers.py | 40 ++++++++++++++++---------- gcloud/bigquery/test_dataset.py | 5 ++-- gcloud/bigquery/test_table.py | 42 ++++++++++++++++----------- gcloud/credentials.py | 9 +++--- gcloud/datastore/helpers.py | 8 +++--- gcloud/datastore/test_helpers.py | 16 +++++------ gcloud/pubsub/message.py | 5 ++-- gcloud/pubsub/test_message.py | 4 +-- gcloud/storage/blob.py | 8 +++--- gcloud/storage/bucket.py | 6 ++-- gcloud/storage/test_blob.py | 8 +++--- gcloud/storage/test_bucket.py | 4 +-- gcloud/test__helpers.py | 49 ++++++++++++++++++++++++++++++++ gcloud/test_credentials.py | 12 +++++--- setup.py | 1 - system_tests/datastore.py | 4 +-- 18 files changed, 193 insertions(+), 78 deletions(-) diff --git a/gcloud/_helpers.py b/gcloud/_helpers.py index 1fe6bed12f99..7e0644ef7cb7 100644 --- a/gcloud/_helpers.py +++ b/gcloud/_helpers.py @@ -15,6 +15,8 @@ This module is not part of the public API surface of `gcloud`. """ + +import datetime import os import socket @@ -75,6 +77,41 @@ def top(self): return self._stack[-1] +class _UTC(datetime.tzinfo): + """Basic UTC implementation. + + Implementing a small surface area to avoid depending on ``pytz``. + """ + + _dst = datetime.timedelta(0) + _tzname = 'UTC' + _utcoffset = _dst + + def dst(self, dt): # pylint: disable=unused-argument + """Daylight savings time offset.""" + return self._dst + + def fromutc(self, dt): + """Convert a timestamp from (naive) UTC to this timezone.""" + if dt.tzinfo is None: + return dt.replace(tzinfo=self) + return super(_UTC, self).fromutc(dt) + + def tzname(self, dt): # pylint: disable=unused-argument + """Get the name of this timezone.""" + return self._tzname + + def utcoffset(self, dt): # pylint: disable=unused-argument + """UTC offset of this timezone.""" + return self._utcoffset + + def __repr__(self): + return '<%s>' % (self._tzname,) + + def __str__(self): + return self._tzname + + def _ensure_tuple_or_list(arg_name, tuple_or_list): """Ensures an input is a tuple or list. @@ -168,3 +205,9 @@ def _determine_default_project(project=None): project = _get_production_project() return project + + +try: + from pytz import UTC # pylint: disable=unused-import +except ImportError: + UTC = _UTC() # Singleton instance to be used throughout. diff --git a/gcloud/bigquery/_helpers.py b/gcloud/bigquery/_helpers.py index 66ace56bf988..df6215721c7d 100644 --- a/gcloud/bigquery/_helpers.py +++ b/gcloud/bigquery/_helpers.py @@ -18,9 +18,10 @@ import datetime import sys -import pytz +from gcloud._helpers import UTC -_EPOCH = datetime.datetime.utcfromtimestamp(0).replace(tzinfo=pytz.utc) + +_EPOCH = datetime.datetime.utcfromtimestamp(0).replace(tzinfo=UTC) def _millis(when): @@ -62,7 +63,7 @@ def _prop_from_datetime(value): if value is not None: if value.tzinfo is None: # Assume UTC - value = value.replace(tzinfo=pytz.utc) + value = value.replace(tzinfo=UTC) # back-end wants timestamps as milliseconds since the epoch return _millis(value) diff --git a/gcloud/bigquery/test__helpers.py b/gcloud/bigquery/test__helpers.py index 17be6af5ac5d..ee97717ef9f6 100644 --- a/gcloud/bigquery/test__helpers.py +++ b/gcloud/bigquery/test__helpers.py @@ -23,8 +23,9 @@ def _callFUT(self, value): def test_one_second_from_epoch(self): import datetime - import pytz - WHEN = datetime.datetime(1970, 1, 1, 0, 0, 1, tzinfo=pytz.utc) + from gcloud._helpers import UTC + + WHEN = datetime.datetime(1970, 1, 1, 0, 0, 1, tzinfo=UTC) self.assertEqual(self._callFUT(WHEN), 1000) @@ -39,11 +40,12 @@ def test_w_none(self): def test_w_millis(self): import datetime - import pytz + from gcloud._helpers import UTC from gcloud.bigquery._helpers import _total_seconds + NOW = datetime.datetime(2015, 7, 29, 17, 45, 21, 123456, - tzinfo=pytz.utc) - EPOCH = datetime.datetime(1970, 1, 1, tzinfo=pytz.utc) + tzinfo=UTC) + EPOCH = datetime.datetime(1970, 1, 1, tzinfo=UTC) MILLIS = _total_seconds(NOW - EPOCH) * 1000 self.assertEqual(self._callFUT(MILLIS), NOW) @@ -59,10 +61,11 @@ def test_w_none(self): def test_w_utc_datetime(self): import datetime - import pytz + from gcloud._helpers import UTC from gcloud.bigquery._helpers import _total_seconds - NOW = datetime.datetime.utcnow().replace(tzinfo=pytz.utc) - EPOCH = datetime.datetime(1970, 1, 1, tzinfo=pytz.utc) + + NOW = datetime.datetime.utcnow().replace(tzinfo=UTC) + EPOCH = datetime.datetime(1970, 1, 1, tzinfo=UTC) MILLIS = int(_total_seconds(NOW - EPOCH) * 1000) result = self._callFUT(NOW) self.assertTrue(isinstance(result, int)) @@ -70,11 +73,17 @@ def test_w_utc_datetime(self): def test_w_non_utc_datetime(self): import datetime - import pytz + from gcloud._helpers import UTC + from gcloud._helpers import _UTC from gcloud.bigquery._helpers import _total_seconds - eastern = pytz.timezone('US/Eastern') - NOW = datetime.datetime(2015, 7, 28, 16, 34, 47, tzinfo=eastern) - EPOCH = datetime.datetime(1970, 1, 1, tzinfo=pytz.utc) + + class CET(_UTC): + _tzname = 'CET' + _utcoffset = datetime.timedelta(hours=-1) + + zone = CET() + NOW = datetime.datetime(2015, 7, 28, 16, 34, 47, tzinfo=zone) + EPOCH = datetime.datetime(1970, 1, 1, tzinfo=UTC) MILLIS = int(_total_seconds(NOW - EPOCH) * 1000) result = self._callFUT(NOW) self.assertTrue(isinstance(result, int)) @@ -82,11 +91,12 @@ def test_w_non_utc_datetime(self): def test_w_naive_datetime(self): import datetime - import pytz + from gcloud._helpers import UTC from gcloud.bigquery._helpers import _total_seconds + NOW = datetime.datetime.utcnow() - UTC_NOW = NOW.replace(tzinfo=pytz.utc) - EPOCH = datetime.datetime(1970, 1, 1, tzinfo=pytz.utc) + UTC_NOW = NOW.replace(tzinfo=UTC) + EPOCH = datetime.datetime(1970, 1, 1, tzinfo=UTC) MILLIS = int(_total_seconds(UTC_NOW - EPOCH) * 1000) result = self._callFUT(NOW) self.assertTrue(isinstance(result, int)) diff --git a/gcloud/bigquery/test_dataset.py b/gcloud/bigquery/test_dataset.py index 1ae3699c2e57..91b8e8281fe6 100644 --- a/gcloud/bigquery/test_dataset.py +++ b/gcloud/bigquery/test_dataset.py @@ -28,10 +28,11 @@ def _makeOne(self, *args, **kw): def _makeResource(self): import datetime - import pytz + from gcloud._helpers import UTC + self.WHEN_TS = 1437767599.006 self.WHEN = datetime.datetime.utcfromtimestamp(self.WHEN_TS).replace( - tzinfo=pytz.UTC) + tzinfo=UTC) self.ETAG = 'ETAG' self.DS_ID = '%s:%s' % (self.PROJECT, self.DS_NAME) self.RESOURCE_URL = 'http://example.com/path/to/resource' diff --git a/gcloud/bigquery/test_table.py b/gcloud/bigquery/test_table.py index 5c678ebe545f..1d84757acfb4 100644 --- a/gcloud/bigquery/test_table.py +++ b/gcloud/bigquery/test_table.py @@ -76,10 +76,11 @@ def _makeOne(self, *args, **kw): def _makeResource(self): import datetime - import pytz + from gcloud._helpers import UTC + self.WHEN_TS = 1437767599.006 self.WHEN = datetime.datetime.utcfromtimestamp(self.WHEN_TS).replace( - tzinfo=pytz.UTC) + tzinfo=UTC) self.ETAG = 'ETAG' self.TABLE_ID = '%s:%s:%s' % ( self.PROJECT, self.DS_NAME, self.TABLE_NAME) @@ -206,10 +207,11 @@ def test_schema_setter(self): def test_props_set_by_server(self): import datetime - import pytz + from gcloud._helpers import UTC from gcloud.bigquery._helpers import _millis - CREATED = datetime.datetime(2015, 7, 29, 12, 13, 22, tzinfo=pytz.utc) - MODIFIED = datetime.datetime(2015, 7, 29, 14, 47, 15, tzinfo=pytz.utc) + + CREATED = datetime.datetime(2015, 7, 29, 12, 13, 22, tzinfo=UTC) + MODIFIED = datetime.datetime(2015, 7, 29, 14, 47, 15, tzinfo=UTC) TABLE_ID = '%s:%s:%s' % ( self.PROJECT, self.DS_NAME, self.TABLE_NAME) URL = 'http://example.com/projects/%s/datasets/%s/tables/%s' % ( @@ -258,8 +260,9 @@ def test_expires_setter_bad_value(self): def test_expires_setter(self): import datetime - import pytz - WHEN = datetime.datetime(2015, 7, 28, 16, 39, tzinfo=pytz.utc) + from gcloud._helpers import UTC + + WHEN = datetime.datetime(2015, 7, 28, 16, 39, tzinfo=UTC) client = _Client(self.PROJECT) dataset = _Dataset(client) table = self._makeOne(self.TABLE_NAME, dataset) @@ -443,9 +446,10 @@ def test_create_w_bound_client(self): def test_create_w_alternate_client(self): import datetime - import pytz + from gcloud._helpers import UTC from gcloud.bigquery.table import SchemaField from gcloud.bigquery._helpers import _millis + PATH = 'projects/%s/datasets/%s/tables' % (self.PROJECT, self.DS_NAME) DESCRIPTION = 'DESCRIPTION' TITLE = 'TITLE' @@ -454,7 +458,7 @@ def test_create_w_alternate_client(self): RESOURCE['description'] = DESCRIPTION RESOURCE['friendlyName'] = TITLE self.EXP_TIME = datetime.datetime(2015, 8, 1, 23, 59, 59, - tzinfo=pytz.utc) + tzinfo=UTC) RESOURCE['expirationTime'] = _millis(self.EXP_TIME) RESOURCE['view'] = {} RESOURCE['view']['query'] = QUERY @@ -642,9 +646,10 @@ def test_patch_w_bound_client(self): def test_patch_w_alternate_client(self): import datetime - import pytz + from gcloud._helpers import UTC from gcloud.bigquery._helpers import _millis from gcloud.bigquery.table import SchemaField + PATH = 'projects/%s/datasets/%s/tables/%s' % ( self.PROJECT, self.DS_NAME, self.TABLE_NAME) QUERY = 'select fullname, age from person_ages' @@ -654,7 +659,7 @@ def test_patch_w_alternate_client(self): RESOURCE['type'] = 'VIEW' RESOURCE['location'] = LOCATION self.EXP_TIME = datetime.datetime(2015, 8, 1, 23, 59, 59, - tzinfo=pytz.utc) + tzinfo=UTC) RESOURCE['expirationTime'] = _millis(self.EXP_TIME) conn1 = _Connection() client1 = _Client(project=self.PROJECT, connection=conn1) @@ -750,9 +755,10 @@ def test_update_w_bound_client(self): def test_update_w_alternate_client(self): import datetime - import pytz + from gcloud._helpers import UTC from gcloud.bigquery._helpers import _millis from gcloud.bigquery.table import SchemaField + PATH = 'projects/%s/datasets/%s/tables/%s' % ( self.PROJECT, self.DS_NAME, self.TABLE_NAME) DEF_TABLE_EXP = 12345 @@ -762,7 +768,7 @@ def test_update_w_alternate_client(self): RESOURCE['defaultTableExpirationMs'] = 12345 RESOURCE['location'] = LOCATION self.EXP_TIME = datetime.datetime(2015, 8, 1, 23, 59, 59, - tzinfo=pytz.utc) + tzinfo=UTC) RESOURCE['expirationTime'] = _millis(self.EXP_TIME) RESOURCE['view'] = {'query': QUERY} RESOURCE['type'] = 'VIEW' @@ -837,14 +843,15 @@ def test_delete_w_alternate_client(self): def test_fetch_data_w_bound_client(self): import datetime - import pytz + from gcloud._helpers import UTC from gcloud.bigquery.table import SchemaField from gcloud.bigquery._helpers import _prop_from_datetime + PATH = 'projects/%s/datasets/%s/tables/%s/data' % ( self.PROJECT, self.DS_NAME, self.TABLE_NAME) WHEN_TS = 1437767599.006 WHEN = datetime.datetime.utcfromtimestamp(WHEN_TS).replace( - tzinfo=pytz.UTC) + tzinfo=UTC) WHEN_1 = WHEN + datetime.timedelta(seconds=1) WHEN_2 = WHEN + datetime.timedelta(seconds=2) ROWS = 1234 @@ -1068,12 +1075,13 @@ def test_fetch_data_w_record_schema(self): def test_insert_data_w_bound_client(self): import datetime - import pytz + from gcloud._helpers import UTC from gcloud.bigquery._helpers import _prop_from_datetime from gcloud.bigquery.table import SchemaField + WHEN_TS = 1437767599.006 WHEN = datetime.datetime.utcfromtimestamp(WHEN_TS).replace( - tzinfo=pytz.UTC) + tzinfo=UTC) PATH = 'projects/%s/datasets/%s/tables/%s/insertAll' % ( self.PROJECT, self.DS_NAME, self.TABLE_NAME) conn = _Connection({}) diff --git a/gcloud/credentials.py b/gcloud/credentials.py index 43a7a7bd790f..843937021eef 100644 --- a/gcloud/credentials.py +++ b/gcloud/credentials.py @@ -27,7 +27,6 @@ from oauth2client.client import _get_application_default_credential_from_file from oauth2client import crypt from oauth2client import service_account -import pytz try: from google.appengine.api import app_identity @@ -40,6 +39,8 @@ class _GAECreds(object): """Dummy class if not in App Engine environment.""" +from gcloud._helpers import UTC + def get_credentials(): """Gets credentials implicitly from the current environment. @@ -274,7 +275,7 @@ def _get_expiration_seconds(expiration): """ # If it's a timedelta, add it to `now` in UTC. if isinstance(expiration, datetime.timedelta): - now = _utcnow().replace(tzinfo=pytz.utc) + now = _utcnow().replace(tzinfo=UTC) expiration = now + expiration # If it's a datetime, convert to a timestamp. @@ -282,9 +283,9 @@ def _get_expiration_seconds(expiration): # Make sure the timezone on the value is UTC # (either by converting or replacing the value). if expiration.tzinfo: - expiration = expiration.astimezone(pytz.utc) + expiration = expiration.astimezone(UTC) else: - expiration = expiration.replace(tzinfo=pytz.utc) + expiration = expiration.replace(tzinfo=UTC) # Turn the datetime into a timestamp (seconds, not microseconds). expiration = int(calendar.timegm(expiration.timetuple())) diff --git a/gcloud/datastore/helpers.py b/gcloud/datastore/helpers.py index 47673d468869..ccf428c83a47 100644 --- a/gcloud/datastore/helpers.py +++ b/gcloud/datastore/helpers.py @@ -21,9 +21,9 @@ import datetime from google.protobuf.internal.type_checkers import Int64ValueChecker -import pytz import six +from gcloud._helpers import UTC from gcloud.datastore import _datastore_v1_pb2 as datastore_pb from gcloud.datastore.entity import Entity from gcloud.datastore.key import Key @@ -185,9 +185,9 @@ def _pb_attr_value(val): # If the datetime is naive (no timezone), consider that it was # intended to be UTC and replace the tzinfo to that effect. if not val.tzinfo: - val = val.replace(tzinfo=pytz.utc) + val = val.replace(tzinfo=UTC) # Regardless of what timezone is on the value, convert it to UTC. - val = val.astimezone(pytz.utc) + val = val.astimezone(UTC) # Convert the datetime to a microsecond timestamp. value = int(calendar.timegm(val.timetuple()) * 1e6) + val.microsecond elif isinstance(val, Key): @@ -233,7 +233,7 @@ def _get_value_from_value_pb(value_pb): microseconds = value_pb.timestamp_microseconds_value naive = (datetime.datetime.utcfromtimestamp(0) + datetime.timedelta(microseconds=microseconds)) - result = naive.replace(tzinfo=pytz.utc) + result = naive.replace(tzinfo=UTC) elif value_pb.HasField('key_value'): result = key_from_protobuf(value_pb.key_value) diff --git a/gcloud/datastore/test_helpers.py b/gcloud/datastore/test_helpers.py index e3487d77830d..51e81acf6492 100644 --- a/gcloud/datastore/test_helpers.py +++ b/gcloud/datastore/test_helpers.py @@ -202,10 +202,10 @@ def _callFUT(self, val): def test_datetime_naive(self): import calendar import datetime - import pytz + from gcloud._helpers import UTC naive = datetime.datetime(2014, 9, 16, 10, 19, 32, 4375) # No zone. - utc = datetime.datetime(2014, 9, 16, 10, 19, 32, 4375, pytz.utc) + utc = datetime.datetime(2014, 9, 16, 10, 19, 32, 4375, UTC) name, value = self._callFUT(naive) self.assertEqual(name, 'timestamp_microseconds_value') self.assertEqual(value // 1000000, calendar.timegm(utc.timetuple())) @@ -214,9 +214,9 @@ def test_datetime_naive(self): def test_datetime_w_zone(self): import calendar import datetime - import pytz + from gcloud._helpers import UTC - utc = datetime.datetime(2014, 9, 16, 10, 19, 32, 4375, pytz.utc) + utc = datetime.datetime(2014, 9, 16, 10, 19, 32, 4375, UTC) name, value = self._callFUT(utc) self.assertEqual(name, 'timestamp_microseconds_value') self.assertEqual(value // 1000000, calendar.timegm(utc.timetuple())) @@ -312,9 +312,9 @@ def _makePB(self, attr_name, value): def test_datetime(self): import calendar import datetime - import pytz + from gcloud._helpers import UTC - utc = datetime.datetime(2014, 9, 16, 10, 19, 32, 4375, pytz.utc) + utc = datetime.datetime(2014, 9, 16, 10, 19, 32, 4375, UTC) micros = (calendar.timegm(utc.timetuple()) * 1000000) + 4375 pb = self._makePB('timestamp_microseconds_value', micros) self.assertEqual(self._callFUT(pb), utc) @@ -413,10 +413,10 @@ def _makePB(self): def test_datetime(self): import calendar import datetime - import pytz + from gcloud._helpers import UTC pb = self._makePB() - utc = datetime.datetime(2014, 9, 16, 10, 19, 32, 4375, pytz.utc) + utc = datetime.datetime(2014, 9, 16, 10, 19, 32, 4375, UTC) self._callFUT(pb, utc) value = pb.timestamp_microseconds_value self.assertEqual(value // 1000000, calendar.timegm(utc.timetuple())) diff --git a/gcloud/pubsub/message.py b/gcloud/pubsub/message.py index aff2da167cf5..f888c6ad6743 100644 --- a/gcloud/pubsub/message.py +++ b/gcloud/pubsub/message.py @@ -17,9 +17,8 @@ import base64 import datetime -import pytz - from gcloud._helpers import _RFC3339_MICROS +from gcloud._helpers import UTC class Message(object): @@ -66,7 +65,7 @@ def timestamp(self): if stamp is None: raise ValueError('No timestamp') return datetime.datetime.strptime(stamp, _RFC3339_MICROS).replace( - tzinfo=pytz.UTC) + tzinfo=UTC) @classmethod def from_api_repr(cls, api_repr): diff --git a/gcloud/pubsub/test_message.py b/gcloud/pubsub/test_message.py index 38ad240e6199..693f34405289 100644 --- a/gcloud/pubsub/test_message.py +++ b/gcloud/pubsub/test_message.py @@ -91,13 +91,13 @@ def _to_fail(): def test_timestamp_w_timestamp_in_attributes(self): from datetime import datetime - from pytz import utc from gcloud._helpers import _RFC3339_MICROS + from gcloud._helpers import UTC DATA = b'DEADBEEF' MESSAGE_ID = b'12345' TIMESTAMP = '2015-04-10T18:42:27.131956Z' naive = datetime.strptime(TIMESTAMP, _RFC3339_MICROS) - timestamp = naive.replace(tzinfo=utc) + timestamp = naive.replace(tzinfo=UTC) ATTRS = {'timestamp': TIMESTAMP} message = self._makeOne(data=DATA, message_id=MESSAGE_ID, attributes=ATTRS) diff --git a/gcloud/storage/blob.py b/gcloud/storage/blob.py index 6eef1af093e0..688c3a244d49 100644 --- a/gcloud/storage/blob.py +++ b/gcloud/storage/blob.py @@ -22,19 +22,19 @@ import os import time -import pytz import six from six.moves.urllib.parse import quote # pylint: disable=F0401 from apitools.base.py import http_wrapper from apitools.base.py import transfer +from gcloud._helpers import _RFC3339_MICROS +from gcloud._helpers import UTC from gcloud.credentials import generate_signed_url from gcloud.exceptions import NotFound from gcloud.storage._helpers import _PropertyMixin from gcloud.storage._helpers import _scalar_property from gcloud.storage.acl import ObjectACL -from gcloud._helpers import _RFC3339_MICROS _API_ACCESS_ENDPOINT = 'https://storage.googleapis.com' @@ -781,7 +781,7 @@ def time_deleted(self): value = self._properties.get('timeDeleted') if value is not None: naive = datetime.datetime.strptime(value, _RFC3339_MICROS) - return naive.replace(tzinfo=pytz.utc) + return naive.replace(tzinfo=UTC) @property def updated(self): @@ -796,7 +796,7 @@ def updated(self): value = self._properties.get('updated') if value is not None: naive = datetime.datetime.strptime(value, _RFC3339_MICROS) - return naive.replace(tzinfo=pytz.utc) + return naive.replace(tzinfo=UTC) class _UploadConfig(object): diff --git a/gcloud/storage/bucket.py b/gcloud/storage/bucket.py index bc4c0977dfc2..309a333af3e1 100644 --- a/gcloud/storage/bucket.py +++ b/gcloud/storage/bucket.py @@ -17,9 +17,10 @@ import datetime import copy -import pytz import six +from gcloud._helpers import _RFC3339_MICROS +from gcloud._helpers import UTC from gcloud.exceptions import NotFound from gcloud.iterator import Iterator from gcloud.storage._helpers import _PropertyMixin @@ -27,7 +28,6 @@ from gcloud.storage.acl import BucketACL from gcloud.storage.acl import DefaultObjectACL from gcloud.storage.blob import Blob -from gcloud._helpers import _RFC3339_MICROS class _BlobIterator(Iterator): @@ -659,7 +659,7 @@ def time_created(self): value = self._properties.get('timeCreated') if value is not None: naive = datetime.datetime.strptime(value, _RFC3339_MICROS) - return naive.replace(tzinfo=pytz.utc) + return naive.replace(tzinfo=UTC) @property def versioning_enabled(self): diff --git a/gcloud/storage/test_blob.py b/gcloud/storage/test_blob.py index e4541ff2b38d..46433800b08a 100644 --- a/gcloud/storage/test_blob.py +++ b/gcloud/storage/test_blob.py @@ -959,11 +959,11 @@ def test_storage_class(self): def test_time_deleted(self): import datetime - from pytz import utc from gcloud._helpers import _RFC3339_MICROS + from gcloud._helpers import UTC BLOB_NAME = 'blob-name' bucket = _Bucket() - TIMESTAMP = datetime.datetime(2014, 11, 5, 20, 34, 37, tzinfo=utc) + TIMESTAMP = datetime.datetime(2014, 11, 5, 20, 34, 37, tzinfo=UTC) TIME_DELETED = TIMESTAMP.strftime(_RFC3339_MICROS) properties = {'timeDeleted': TIME_DELETED} blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties) @@ -976,11 +976,11 @@ def test_time_deleted_unset(self): def test_updated(self): import datetime - from pytz import utc from gcloud._helpers import _RFC3339_MICROS + from gcloud._helpers import UTC BLOB_NAME = 'blob-name' bucket = _Bucket() - TIMESTAMP = datetime.datetime(2014, 11, 5, 20, 34, 37, tzinfo=utc) + TIMESTAMP = datetime.datetime(2014, 11, 5, 20, 34, 37, tzinfo=UTC) UPDATED = TIMESTAMP.strftime(_RFC3339_MICROS) properties = {'updated': UPDATED} blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties) diff --git a/gcloud/storage/test_bucket.py b/gcloud/storage/test_bucket.py index d15ccef3f4d6..9589ff4ed1f6 100644 --- a/gcloud/storage/test_bucket.py +++ b/gcloud/storage/test_bucket.py @@ -694,9 +694,9 @@ def test_storage_class(self): def test_time_created(self): import datetime - from pytz import utc from gcloud._helpers import _RFC3339_MICROS - TIMESTAMP = datetime.datetime(2014, 11, 5, 20, 34, 37, tzinfo=utc) + from gcloud._helpers import UTC + TIMESTAMP = datetime.datetime(2014, 11, 5, 20, 34, 37, tzinfo=UTC) TIME_CREATED = TIMESTAMP.strftime(_RFC3339_MICROS) properties = {'timeCreated': TIME_CREATED} bucket = self._makeOne(properties=properties) diff --git a/gcloud/test__helpers.py b/gcloud/test__helpers.py index 97599f79ef40..72715470f6f2 100644 --- a/gcloud/test__helpers.py +++ b/gcloud/test__helpers.py @@ -43,6 +43,55 @@ def test_it(self): self.assertEqual(list(batches), []) +class Test__UTC(unittest2.TestCase): + + def _getTargetClass(self): + from gcloud._helpers import _UTC + return _UTC + + def _makeOne(self): + return self._getTargetClass()() + + def test_module_property(self): + from gcloud import _helpers as MUT + + klass = self._getTargetClass() + self.assertTrue(isinstance(MUT.UTC, klass)) + + def test_dst(self): + import datetime + + tz = self._makeOne() + self.assertEqual(tz.dst(None), datetime.timedelta(0)) + + def test_fromutc(self): + import datetime + + naive_epoch = datetime.datetime.utcfromtimestamp(0) + self.assertEqual(naive_epoch.tzinfo, None) + tz = self._makeOne() + epoch = tz.fromutc(naive_epoch) + self.assertEqual(epoch.tzinfo, tz) + + def test_tzname(self): + tz = self._makeOne() + self.assertEqual(tz.tzname(None), 'UTC') + + def test_utcoffset(self): + import datetime + + tz = self._makeOne() + self.assertEqual(tz.utcoffset(None), datetime.timedelta(0)) + + def test___repr__(self): + tz = self._makeOne() + self.assertEqual(repr(tz), '') + + def test___str__(self): + tz = self._makeOne() + self.assertEqual(str(tz), 'UTC') + + class Test__ensure_tuple_or_list(unittest2.TestCase): def _callFUT(self, arg_name, tuple_or_list): diff --git a/gcloud/test_credentials.py b/gcloud/test_credentials.py index b76211a7bc18..33987f5db74c 100644 --- a/gcloud/test_credentials.py +++ b/gcloud/test_credentials.py @@ -512,17 +512,21 @@ def test_w_naive_datetime(self): def test_w_utc_datetime(self): import datetime - import pytz + from gcloud._helpers import UTC - expiration_utc = datetime.datetime(2004, 8, 19, 0, 0, 0, 0, pytz.utc) + expiration_utc = datetime.datetime(2004, 8, 19, 0, 0, 0, 0, UTC) utc_seconds = self._utc_seconds(expiration_utc) self.assertEqual(self._callFUT(expiration_utc), utc_seconds) def test_w_other_zone_datetime(self): import datetime - import pytz + from gcloud._helpers import _UTC - zone = pytz.timezone('CET') + class CET(_UTC): + _tzname = 'CET' + _utcoffset = datetime.timedelta(hours=1) + + zone = CET() expiration_other = datetime.datetime(2004, 8, 19, 0, 0, 0, 0, zone) utc_seconds = self._utc_seconds(expiration_other) cet_seconds = utc_seconds - (60 * 60) # CET one hour earlier than UTC diff --git a/setup.py b/setup.py index cd7e507c2d20..0c89547dc011 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,6 @@ 'oauth2client >= 1.4.6', 'protobuf == 3.0.0-alpha-1', 'pycrypto', - 'pytz', 'six', ] diff --git a/system_tests/datastore.py b/system_tests/datastore.py index 8b362389e971..3d48d14990da 100644 --- a/system_tests/datastore.py +++ b/system_tests/datastore.py @@ -13,9 +13,9 @@ # limitations under the License. import datetime -import pytz import unittest2 +from gcloud._helpers import UTC from gcloud import datastore from gcloud.datastore import client from gcloud.environment_vars import TESTS_DATASET @@ -63,7 +63,7 @@ def _get_post(self, id_or_name=None, post_content=None): post_content = post_content or { 'title': u'How to make the perfect pizza in your grill', 'tags': [u'pizza', u'grill'], - 'publishedAt': datetime.datetime(2001, 1, 1, tzinfo=pytz.utc), + 'publishedAt': datetime.datetime(2001, 1, 1, tzinfo=UTC), 'author': u'Silvano', 'isDraft': False, 'wordCount': 400,