Skip to content

Commit

Permalink
Merge pull request #2952 from dhermes/upstream-timestamp-changes
Browse files Browse the repository at this point in the history
Moving Bigtable helpers for duration protobufs into core.
  • Loading branch information
dhermes authored Jan 20, 2017
2 parents 7124a15 + dd25e45 commit 172d788
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 121 deletions.
55 changes: 3 additions & 52 deletions bigtable/google/cloud/bigtable/column_family.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,62 +15,13 @@
"""User friendly container for Google Cloud Bigtable Column Family."""


import datetime

from google.protobuf import duration_pb2

from google.cloud import _helpers
from google.cloud.bigtable._generated import (
table_pb2 as table_v2_pb2)
from google.cloud.bigtable._generated import (
bigtable_table_admin_pb2 as table_admin_v2_pb2)


def _timedelta_to_duration_pb(timedelta_val):
"""Convert a Python timedelta object to a duration protobuf.
.. note::
The Python timedelta has a granularity of microseconds while
the protobuf duration type has a duration of nanoseconds.
:type timedelta_val: :class:`datetime.timedelta`
:param timedelta_val: A timedelta object.
:rtype: :class:`google.protobuf.duration_pb2.Duration`
:returns: A duration object equivalent to the time delta.
"""
seconds_decimal = timedelta_val.total_seconds()
# Truncate the parts other than the integer.
seconds = int(seconds_decimal)
if seconds_decimal < 0:
signed_micros = timedelta_val.microseconds - 10**6
else:
signed_micros = timedelta_val.microseconds
# Convert nanoseconds to microseconds.
nanos = 1000 * signed_micros
return duration_pb2.Duration(seconds=seconds, nanos=nanos)


def _duration_pb_to_timedelta(duration_pb):
"""Convert a duration protobuf to a Python timedelta object.
.. note::
The Python timedelta has a granularity of microseconds while
the protobuf duration type has a duration of nanoseconds.
:type duration_pb: :class:`google.protobuf.duration_pb2.Duration`
:param duration_pb: A protobuf duration object.
:rtype: :class:`datetime.timedelta`
:returns: The converted timedelta object.
"""
return datetime.timedelta(
seconds=duration_pb.seconds,
microseconds=(duration_pb.nanos / 1000.0),
)


class GarbageCollectionRule(object):
"""Garbage collection rule for column families within a table.
Expand Down Expand Up @@ -137,7 +88,7 @@ def to_pb(self):
:rtype: :class:`.table_v2_pb2.GcRule`
:returns: The converted current object.
"""
max_age = _timedelta_to_duration_pb(self.max_age)
max_age = _helpers._timedelta_to_duration_pb(self.max_age)
return table_v2_pb2.GcRule(max_age=max_age)


Expand Down Expand Up @@ -325,7 +276,7 @@ def _gc_rule_from_pb(gc_rule_pb):
if rule_name == 'max_num_versions':
return MaxVersionsGCRule(gc_rule_pb.max_num_versions)
elif rule_name == 'max_age':
max_age = _duration_pb_to_timedelta(gc_rule_pb.max_age)
max_age = _helpers._duration_pb_to_timedelta(gc_rule_pb.max_age)
return MaxAgeGCRule(max_age)
elif rule_name == 'union':
return GCRuleUnion([_gc_rule_from_pb(rule)
Expand Down
69 changes: 0 additions & 69 deletions bigtable/unit_tests/test_column_family.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,75 +16,6 @@
import unittest


class Test__timedelta_to_duration_pb(unittest.TestCase):

def _call_fut(self, *args, **kwargs):
from google.cloud.bigtable.column_family import (
_timedelta_to_duration_pb)

return _timedelta_to_duration_pb(*args, **kwargs)

def test_it(self):
import datetime
from google.protobuf import duration_pb2

seconds = microseconds = 1
timedelta_val = datetime.timedelta(seconds=seconds,
microseconds=microseconds)
result = self._call_fut(timedelta_val)
self.assertIsInstance(result, duration_pb2.Duration)
self.assertEqual(result.seconds, seconds)
self.assertEqual(result.nanos, 1000 * microseconds)

def test_with_negative_microseconds(self):
import datetime
from google.protobuf import duration_pb2

seconds = 1
microseconds = -5
timedelta_val = datetime.timedelta(seconds=seconds,
microseconds=microseconds)
result = self._call_fut(timedelta_val)
self.assertIsInstance(result, duration_pb2.Duration)
self.assertEqual(result.seconds, seconds - 1)
self.assertEqual(result.nanos, 10**9 + 1000 * microseconds)

def test_with_negative_seconds(self):
import datetime
from google.protobuf import duration_pb2

seconds = -1
microseconds = 5
timedelta_val = datetime.timedelta(seconds=seconds,
microseconds=microseconds)
result = self._call_fut(timedelta_val)
self.assertIsInstance(result, duration_pb2.Duration)
self.assertEqual(result.seconds, seconds + 1)
self.assertEqual(result.nanos, -(10**9 - 1000 * microseconds))


class Test__duration_pb_to_timedelta(unittest.TestCase):

def _call_fut(self, *args, **kwargs):
from google.cloud.bigtable.column_family import (
_duration_pb_to_timedelta)

return _duration_pb_to_timedelta(*args, **kwargs)

def test_it(self):
import datetime
from google.protobuf import duration_pb2

seconds = microseconds = 1
duration_pb = duration_pb2.Duration(seconds=seconds,
nanos=1000 * microseconds)
timedelta_val = datetime.timedelta(seconds=seconds,
microseconds=microseconds)
result = self._call_fut(duration_pb)
self.assertIsInstance(result, datetime.timedelta)
self.assertEqual(result, timedelta_val)


class TestMaxVersionsGCRule(unittest.TestCase):

@staticmethod
Expand Down
47 changes: 47 additions & 0 deletions core/google/cloud/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from threading import local as Local

import google.auth
from google.protobuf import duration_pb2
from google.protobuf import timestamp_pb2
import google_auth_httplib2

Expand Down Expand Up @@ -424,6 +425,52 @@ def _datetime_to_pb_timestamp(when):
return timestamp_pb2.Timestamp(seconds=seconds, nanos=nanos)


def _timedelta_to_duration_pb(timedelta_val):
"""Convert a Python timedelta object to a duration protobuf.
.. note::
The Python timedelta has a granularity of microseconds while
the protobuf duration type has a duration of nanoseconds.
:type timedelta_val: :class:`datetime.timedelta`
:param timedelta_val: A timedelta object.
:rtype: :class:`google.protobuf.duration_pb2.Duration`
:returns: A duration object equivalent to the time delta.
"""
seconds_decimal = timedelta_val.total_seconds()
# Truncate the parts other than the integer.
seconds = int(seconds_decimal)
if seconds_decimal < 0:
signed_micros = timedelta_val.microseconds - 10**6
else:
signed_micros = timedelta_val.microseconds
# Convert nanoseconds to microseconds.
nanos = 1000 * signed_micros
return duration_pb2.Duration(seconds=seconds, nanos=nanos)


def _duration_pb_to_timedelta(duration_pb):
"""Convert a duration protobuf to a Python timedelta object.
.. note::
The Python timedelta has a granularity of microseconds while
the protobuf duration type has a duration of nanoseconds.
:type duration_pb: :class:`google.protobuf.duration_pb2.Duration`
:param duration_pb: A protobuf duration object.
:rtype: :class:`datetime.timedelta`
:returns: The converted timedelta object.
"""
return datetime.timedelta(
seconds=duration_pb.seconds,
microseconds=(duration_pb.nanos / 1000.0),
)


def _name_from_project_path(path, project, template):
"""Validate a URI path and get the leaf object's name.
Expand Down
67 changes: 67 additions & 0 deletions core/unit_tests/test__helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,73 @@ def test_it(self):
self.assertEqual(self._call_fut(dt_stamp), timestamp)


class Test__timedelta_to_duration_pb(unittest.TestCase):

def _call_fut(self, *args, **kwargs):
from google.cloud._helpers import _timedelta_to_duration_pb

return _timedelta_to_duration_pb(*args, **kwargs)

def test_it(self):
import datetime
from google.protobuf import duration_pb2

seconds = microseconds = 1
timedelta_val = datetime.timedelta(seconds=seconds,
microseconds=microseconds)
result = self._call_fut(timedelta_val)
self.assertIsInstance(result, duration_pb2.Duration)
self.assertEqual(result.seconds, seconds)
self.assertEqual(result.nanos, 1000 * microseconds)

def test_with_negative_microseconds(self):
import datetime
from google.protobuf import duration_pb2

seconds = 1
microseconds = -5
timedelta_val = datetime.timedelta(seconds=seconds,
microseconds=microseconds)
result = self._call_fut(timedelta_val)
self.assertIsInstance(result, duration_pb2.Duration)
self.assertEqual(result.seconds, seconds - 1)
self.assertEqual(result.nanos, 10**9 + 1000 * microseconds)

def test_with_negative_seconds(self):
import datetime
from google.protobuf import duration_pb2

seconds = -1
microseconds = 5
timedelta_val = datetime.timedelta(seconds=seconds,
microseconds=microseconds)
result = self._call_fut(timedelta_val)
self.assertIsInstance(result, duration_pb2.Duration)
self.assertEqual(result.seconds, seconds + 1)
self.assertEqual(result.nanos, -(10**9 - 1000 * microseconds))


class Test__duration_pb_to_timedelta(unittest.TestCase):

def _call_fut(self, *args, **kwargs):
from google.cloud._helpers import _duration_pb_to_timedelta

return _duration_pb_to_timedelta(*args, **kwargs)

def test_it(self):
import datetime
from google.protobuf import duration_pb2

seconds = microseconds = 1
duration_pb = duration_pb2.Duration(seconds=seconds,
nanos=1000 * microseconds)
timedelta_val = datetime.timedelta(seconds=seconds,
microseconds=microseconds)
result = self._call_fut(duration_pb)
self.assertIsInstance(result, datetime.timedelta)
self.assertEqual(result, timedelta_val)


class Test__name_from_project_path(unittest.TestCase):

PROJECT = 'PROJECT'
Expand Down

0 comments on commit 172d788

Please sign in to comment.