diff --git a/bigtable/google/cloud/bigtable/column_family.py b/bigtable/google/cloud/bigtable/column_family.py index cb7dcdc4ff60..c34e75ed2c1f 100644 --- a/bigtable/google/cloud/bigtable/column_family.py +++ b/bigtable/google/cloud/bigtable/column_family.py @@ -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. @@ -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) @@ -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) diff --git a/bigtable/unit_tests/test_column_family.py b/bigtable/unit_tests/test_column_family.py index 36f4c99c0032..126a18da3003 100644 --- a/bigtable/unit_tests/test_column_family.py +++ b/bigtable/unit_tests/test_column_family.py @@ -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 diff --git a/core/google/cloud/_helpers.py b/core/google/cloud/_helpers.py index 03f6d2fdb60c..f2fceb8526ed 100644 --- a/core/google/cloud/_helpers.py +++ b/core/google/cloud/_helpers.py @@ -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 @@ -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. diff --git a/core/unit_tests/test__helpers.py b/core/unit_tests/test__helpers.py index f9fa5d58ea0f..e0642780c0a4 100644 --- a/core/unit_tests/test__helpers.py +++ b/core/unit_tests/test__helpers.py @@ -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'