Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moving Bigtable helpers for duration protobufs into core. #2952

Merged
merged 1 commit into from
Jan 20, 2017
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
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