From d3058f3ab28bb2982c665b4f909447b545f4be24 Mon Sep 17 00:00:00 2001 From: Danny Hermes Date: Thu, 14 Jan 2016 13:33:23 -0800 Subject: [PATCH] Moving _pb_timestamp_to_datetime into core. This is in advance of `v1beta3`, where it will be needed to parse `Value.timestamp_value` (which is of type `timestamp_pb2.Timestamp`). Also adding `_datetime_to_pb_timestamp` for the other direction. --- gcloud/_helpers.py | 34 ++++++++++++++++++++++++++ gcloud/bigtable/cluster.py | 21 +---------------- gcloud/bigtable/test_cluster.py | 21 ----------------- gcloud/test__helpers.py | 42 +++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 41 deletions(-) diff --git a/gcloud/_helpers.py b/gcloud/_helpers.py index 89a98da4ad41..010981568e29 100644 --- a/gcloud/_helpers.py +++ b/gcloud/_helpers.py @@ -23,6 +23,7 @@ import socket import sys +from google.protobuf import timestamp_pb2 import six from six.moves.http_client import HTTPConnection # pylint: disable=F0401 @@ -354,6 +355,39 @@ def _to_bytes(value, encoding='ascii'): raise TypeError('%r could not be converted to bytes' % (value,)) +def _pb_timestamp_to_datetime(timestamp): + """Convert a Timestamp protobuf to a datetime object. + + :type timestamp: :class:`google.protobuf.timestamp_pb2.Timestamp` + :param timestamp: A Google returned timestamp protobuf. + + :rtype: :class:`datetime.datetime` + :returns: A UTC datetime object converted from a protobuf timestamp. + """ + return ( + _EPOCH + + datetime.timedelta( + seconds=timestamp.seconds, + microseconds=(timestamp.nanos / 1000.0), + ) + ) + + +def _datetime_to_pb_timestamp(when): + """Convert a datetime object to a Timestamp protobuf. + + :type when: :class:`datetime.datetime` + :param when: the datetime to convert + + :rtype: :class:`google.protobuf.timestamp_pb2.Timestamp` + :returns: A timestamp protobuf corresponding to the object. + """ + ms_value = _microseconds_from_datetime(when) + seconds, micros = divmod(ms_value, 10**6) + nanos = micros * 10**3 + return timestamp_pb2.Timestamp(seconds=seconds, nanos=nanos) + + try: from pytz import UTC # pylint: disable=unused-import,wrong-import-position except ImportError: diff --git a/gcloud/bigtable/cluster.py b/gcloud/bigtable/cluster.py index f087658d58d1..efedc11e7110 100644 --- a/gcloud/bigtable/cluster.py +++ b/gcloud/bigtable/cluster.py @@ -15,12 +15,11 @@ """User friendly container for Google Cloud Bigtable Cluster.""" -import datetime import re from google.longrunning import operations_pb2 -from gcloud._helpers import _EPOCH +from gcloud._helpers import _pb_timestamp_to_datetime from gcloud.bigtable._generated import bigtable_cluster_data_pb2 as data_pb2 from gcloud.bigtable._generated import ( bigtable_cluster_service_messages_pb2 as messages_pb2) @@ -93,24 +92,6 @@ def _prepare_create_request(cluster): ) -def _pb_timestamp_to_datetime(timestamp): - """Convert a Timestamp protobuf to a datetime object. - - :type timestamp: :class:`google.protobuf.timestamp_pb2.Timestamp` - :param timestamp: A Google returned timestamp protobuf. - - :rtype: :class:`datetime.datetime` - :returns: A UTC datetime object converted from a protobuf timestamp. - """ - return ( - _EPOCH + - datetime.timedelta( - seconds=timestamp.seconds, - microseconds=(timestamp.nanos / 1000.0), - ) - ) - - def _parse_pb_any_to_native(any_val, expected_type=None): """Convert a serialized "google.protobuf.Any" value to actual type. diff --git a/gcloud/bigtable/test_cluster.py b/gcloud/bigtable/test_cluster.py index 74fbce7a146c..8ff2ffa68bb8 100644 --- a/gcloud/bigtable/test_cluster.py +++ b/gcloud/bigtable/test_cluster.py @@ -686,27 +686,6 @@ def test_it(self): self.assertEqual(request_pb.cluster.serve_nodes, serve_nodes) -class Test__pb_timestamp_to_datetime(unittest2.TestCase): - - def _callFUT(self, timestamp): - from gcloud.bigtable.cluster import _pb_timestamp_to_datetime - return _pb_timestamp_to_datetime(timestamp) - - def test_it(self): - import datetime - from google.protobuf.timestamp_pb2 import Timestamp - from gcloud._helpers import UTC - - # Epoch is midnight on January 1, 1970 ... - dt_stamp = datetime.datetime(1970, month=1, day=1, hour=0, - minute=1, second=1, microsecond=1234, - tzinfo=UTC) - # ... so 1 minute and 1 second after is 61 seconds and 1234 - # microseconds is 1234000 nanoseconds. - timestamp = Timestamp(seconds=61, nanos=1234000) - self.assertEqual(self._callFUT(timestamp), dt_stamp) - - class Test__parse_pb_any_to_native(unittest2.TestCase): def _callFUT(self, any_val, expected_type=None): diff --git a/gcloud/test__helpers.py b/gcloud/test__helpers.py index 84f6d35aa752..5b6f329d2cb8 100644 --- a/gcloud/test__helpers.py +++ b/gcloud/test__helpers.py @@ -484,6 +484,48 @@ def test_with_nonstring_type(self): self.assertRaises(TypeError, self._callFUT, value) +class Test__pb_timestamp_to_datetime(unittest2.TestCase): + + def _callFUT(self, timestamp): + from gcloud._helpers import _pb_timestamp_to_datetime + return _pb_timestamp_to_datetime(timestamp) + + def test_it(self): + import datetime + from google.protobuf.timestamp_pb2 import Timestamp + from gcloud._helpers import UTC + + # Epoch is midnight on January 1, 1970 ... + dt_stamp = datetime.datetime(1970, month=1, day=1, hour=0, + minute=1, second=1, microsecond=1234, + tzinfo=UTC) + # ... so 1 minute and 1 second after is 61 seconds and 1234 + # microseconds is 1234000 nanoseconds. + timestamp = Timestamp(seconds=61, nanos=1234000) + self.assertEqual(self._callFUT(timestamp), dt_stamp) + + +class Test__datetime_to_pb_timestamp(unittest2.TestCase): + + def _callFUT(self, when): + from gcloud._helpers import _datetime_to_pb_timestamp + return _datetime_to_pb_timestamp(when) + + def test_it(self): + import datetime + from google.protobuf.timestamp_pb2 import Timestamp + from gcloud._helpers import UTC + + # Epoch is midnight on January 1, 1970 ... + dt_stamp = datetime.datetime(1970, month=1, day=1, hour=0, + minute=1, second=1, microsecond=1234, + tzinfo=UTC) + # ... so 1 minute and 1 second after is 61 seconds and 1234 + # microseconds is 1234000 nanoseconds. + timestamp = Timestamp(seconds=61, nanos=1234000) + self.assertEqual(self._callFUT(dt_stamp), timestamp) + + class _AppIdentity(object): def __init__(self, app_id):