Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions gcloud/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

This module is not part of the public API surface of `gcloud`.
"""

import datetime
import os
import socket

Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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.
7 changes: 4 additions & 3 deletions gcloud/bigquery/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.



def _millis(when):
Expand Down Expand Up @@ -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)

Expand Down
40 changes: 25 additions & 15 deletions gcloud/bigquery/test__helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)


Expand All @@ -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)

Expand All @@ -59,34 +61,42 @@ 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))
self.assertEqual(result, MILLIS)

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):

This comment was marked as spam.

This comment was marked as spam.

_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))
self.assertEqual(result, MILLIS)

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))
Expand Down
5 changes: 3 additions & 2 deletions gcloud/bigquery/test_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
42 changes: 25 additions & 17 deletions gcloud/bigquery/test_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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' % (
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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'
Expand All @@ -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
Expand Down Expand Up @@ -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'
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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'
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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({})
Expand Down
9 changes: 5 additions & 4 deletions gcloud/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -274,17 +275,17 @@ 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.
if isinstance(expiration, datetime.datetime):
# 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()))
Expand Down
8 changes: 4 additions & 4 deletions gcloud/datastore/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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)
Expand Down
Loading