| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent ed3c300 commit 543112a
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -19,80 +19,12 @@ | |||
| 19 | 19 | ||
| 20 | 20 | import six | |
| 21 | 21 | ||
| 22 | - from google.protobuf.struct_pb2 import ListValue | ||
| 23 | - from google.protobuf.struct_pb2 import Value | ||
| 24 | - from google.cloud.spanner_v1.proto import type_pb2 | ||
| 25 | - | ||
| 22 | + from google.api_core import datetime_helpers | ||
| 26 | 23 | from google.cloud._helpers import _date_from_iso8601_date | |
| 27 | 24 | from google.cloud._helpers import _datetime_to_rfc3339 | |
| 28 | - from google.cloud._helpers import _RFC3339_NANOS | ||
| 29 | - from google.cloud._helpers import _RFC3339_NO_FRACTION | ||
| 30 | - from google.cloud._helpers import UTC | ||
| 31 | - | ||
| 32 | - | ||
| 33 | - class TimestampWithNanoseconds(datetime.datetime): | ||
| 34 | - """Track nanosecond in addition to normal datetime attrs. | ||
| 35 | - | ||
| 36 | - nanosecond can be passed only as a keyword argument. | ||
| 37 | - """ | ||
| 38 | - __slots__ = ('_nanosecond',) | ||
| 39 | - | ||
| 40 | - # pylint: disable=arguments-differ | ||
| 41 | - def __new__(cls, *args, **kw): | ||
| 42 | - nanos = kw.pop('nanosecond', 0) | ||
| 43 | - if nanos > 0: | ||
| 44 | - if 'microsecond' in kw: | ||
| 45 | - raise TypeError( | ||
| 46 | - "Specify only one of 'microsecond' or 'nanosecond'") | ||
| 47 | - kw['microsecond'] = nanos // 1000 | ||
| 48 | - inst = datetime.datetime.__new__(cls, *args, **kw) | ||
| 49 | - inst._nanosecond = nanos or 0 | ||
| 50 | - return inst | ||
| 51 | - # pylint: disable=arguments-differ | ||
| 52 | - | ||
| 53 | - @property | ||
| 54 | - def nanosecond(self): | ||
| 55 | - """Read-only: nanosecond precision.""" | ||
| 56 | - return self._nanosecond | ||
| 57 | - | ||
| 58 | - def rfc3339(self): | ||
| 59 | - """RFC 3339-compliant timestamp. | ||
| 60 | - | ||
| 61 | - :rtype: str | ||
| 62 | - :returns: Timestamp string according to RFC 3339 spec. | ||
| 63 | - """ | ||
| 64 | - if self._nanosecond == 0: | ||
| 65 | - return _datetime_to_rfc3339(self) | ||
| 66 | - nanos = str(self._nanosecond).rstrip('0') | ||
| 67 | - return '%s.%sZ' % (self.strftime(_RFC3339_NO_FRACTION), nanos) | ||
| 68 | - | ||
| 69 | - @classmethod | ||
| 70 | - def from_rfc3339(cls, stamp): | ||
| 71 | - """Parse RFC 3339-compliant timestamp, preserving nanoseconds. | ||
| 72 | - | ||
| 73 | - :type stamp: str | ||
| 74 | - :param stamp: RFC 3339 stamp, with up to nanosecond precision | ||
| 75 | - | ||
| 76 | - :rtype: :class:`TimestampWithNanoseconds` | ||
| 77 | - :returns: an instance matching the timestamp string | ||
| 78 | - :raises ValueError: if ``stamp`` does not match the expected format | ||
| 79 | - """ | ||
| 80 | - with_nanos = _RFC3339_NANOS.match(stamp) | ||
| 81 | - if with_nanos is None: | ||
| 82 | - raise ValueError( | ||
| 83 | - 'Timestamp: %r, does not match pattern: %r' % ( | ||
| 84 | - stamp, _RFC3339_NANOS.pattern)) | ||
| 85 | - bare = datetime.datetime.strptime( | ||
| 86 | - with_nanos.group('no_fraction'), _RFC3339_NO_FRACTION) | ||
| 87 | - fraction = with_nanos.group('nanos') | ||
| 88 | - if fraction is None: | ||
| 89 | - nanos = 0 | ||
| 90 | - else: | ||
| 91 | - scale = 9 - len(fraction) | ||
| 92 | - nanos = int(fraction) * (10 ** scale) | ||
| 93 | - return cls(bare.year, bare.month, bare.day, | ||
| 94 | - bare.hour, bare.minute, bare.second, | ||
| 95 | - nanosecond=nanos, tzinfo=UTC) | ||
| 25 | + from google.cloud.spanner_v1.proto import type_pb2 | ||
| 26 | + from google.protobuf.struct_pb2 import ListValue | ||
| 27 | + from google.protobuf.struct_pb2 import Value | ||
| 96 | 28 | ||
| 97 | 29 | ||
| 98 | 30 | def _try_to_coerce_bytes(bytestring): | |
@@ -140,7 +72,7 @@ def _make_value_pb(value): | |||
| 140 | 72 | else: | |
| 141 | 73 | return Value(string_value='-Infinity') | |
| 142 | 74 | return Value(number_value=value) | |
| 143 | - if isinstance(value, TimestampWithNanoseconds): | ||
| 75 | + if isinstance(value, datetime_helpers.DatetimeWithNanoseconds): | ||
| 144 | 76 | return Value(string_value=value.rfc3339()) | |
| 145 | 77 | if isinstance(value, datetime.datetime): | |
| 146 | 78 | return Value(string_value=_datetime_to_rfc3339(value)) | |
@@ -211,7 +143,8 @@ def _parse_value_pb(value_pb, field_type): | |||
| 211 | 143 | elif field_type.code == type_pb2.DATE: | |
| 212 | 144 | result = _date_from_iso8601_date(value_pb.string_value) | |
| 213 | 145 | elif field_type.code == type_pb2.TIMESTAMP: | |
| 214 | - result = TimestampWithNanoseconds.from_rfc3339(value_pb.string_value) | ||
| 146 | + DatetimeWithNanoseconds = datetime_helpers.DatetimeWithNanoseconds | ||
| 147 | + result = DatetimeWithNanoseconds.from_rfc3339(value_pb.string_value) | ||
| 215 | 148 | elif field_type.code == type_pb2.ARRAY: | |
| 216 | 149 | result = [ | |
| 217 | 150 | _parse_value_pb(item_pb, field_type.array_element_type) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -22,6 +22,7 @@ | |||
| 22 | 22 | import unittest | |
| 23 | 23 | ||
| 24 | 24 | from google.api_core import exceptions | |
| 25 | + from google.api_core.datetime_helpers import DatetimeWithNanoseconds | ||
| 25 | 26 | from google.cloud.spanner_v1.proto.type_pb2 import ARRAY | |
| 26 | 27 | from google.cloud.spanner_v1.proto.type_pb2 import BOOL | |
| 27 | 28 | from google.cloud.spanner_v1.proto.type_pb2 import BYTES | |
@@ -33,7 +34,6 @@ | |||
| 33 | 34 | from google.cloud.spanner_v1.proto.type_pb2 import Type | |
| 34 | 35 | ||
| 35 | 36 | from google.cloud._helpers import UTC | |
| 36 | - from google.cloud.spanner_v1._helpers import TimestampWithNanoseconds | ||
| 37 | 37 | from google.cloud.spanner import Client | |
| 38 | 38 | from google.cloud.spanner import KeyRange | |
| 39 | 39 | from google.cloud.spanner import KeySet | |
@@ -206,7 +206,7 @@ def _assert_timestamp(self, value, nano_value): | |||
| 206 | 206 | self.assertEqual(value.minute, nano_value.minute) | |
| 207 | 207 | self.assertEqual(value.second, nano_value.second) | |
| 208 | 208 | self.assertEqual(value.microsecond, nano_value.microsecond) | |
| 209 | - if isinstance(value, TimestampWithNanoseconds): | ||
| 209 | + if isinstance(value, DatetimeWithNanoseconds): | ||
| 210 | 210 | self.assertEqual(value.nanosecond, nano_value.nanosecond) | |
| 211 | 211 | else: | |
| 212 | 212 | self.assertEqual(value.microsecond * 1000, nano_value.nanosecond) | |
@@ -222,7 +222,7 @@ def _check_rows_data(self, rows_data, expected=None): | |||
| 222 | 222 | def _check_row_data(self, row_data, expected): | |
| 223 | 223 | self.assertEqual(len(row_data), len(expected)) | |
| 224 | 224 | for found_cell, expected_cell in zip(row_data, expected): | |
| 225 | - if isinstance(found_cell, TimestampWithNanoseconds): | ||
| 225 | + if isinstance(found_cell, DatetimeWithNanoseconds): | ||
| 226 | 226 | self._assert_timestamp(expected_cell, found_cell) | |
| 227 | 227 | elif isinstance(found_cell, float) and math.isnan(found_cell): | |
| 228 | 228 | self.assertTrue(math.isnan(expected_cell)) | |
@@ -410,7 +410,7 @@ class TestSessionAPI(unittest.TestCase, _TestData): | |||
| 410 | 410 | ) | |
| 411 | 411 | SOME_DATE = datetime.date(2011, 1, 17) | |
| 412 | 412 | SOME_TIME = datetime.datetime(1989, 1, 17, 17, 59, 12, 345612) | |
| 413 | - NANO_TIME = TimestampWithNanoseconds(1995, 8, 31, nanosecond=987654321) | ||
| 413 | + NANO_TIME = DatetimeWithNanoseconds(1995, 8, 31, nanosecond=987654321) | ||
| 414 | 414 | OTHER_NAN, = struct.unpack('<d', b'\x01\x00\x01\x00\x00\x00\xf8\xff') | |
| 415 | 415 | BYTES_1 = b'Ymlu' | |
| 416 | 416 | BYTES_2 = b'Ym9vdHM=' | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,101 +16,6 @@ | |||
| 16 | 16 | import unittest | |
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | - class TestTimestampWithNanoseconds(unittest.TestCase): | ||
| 20 | - | ||
| 21 | - def _get_target_class(self): | ||
| 22 | - from google.cloud.spanner_v1._helpers import TimestampWithNanoseconds | ||
| 23 | - | ||
| 24 | - return TimestampWithNanoseconds | ||
| 25 | - | ||
| 26 | - def _make_one(self, *args, **kw): | ||
| 27 | - return self._get_target_class()(*args, **kw) | ||
| 28 | - | ||
| 29 | - def test_ctor_wo_nanos(self): | ||
| 30 | - stamp = self._make_one(2016, 12, 20, 21, 13, 47, 123456) | ||
| 31 | - self.assertEqual(stamp.year, 2016) | ||
| 32 | - self.assertEqual(stamp.month, 12) | ||
| 33 | - self.assertEqual(stamp.day, 20) | ||
| 34 | - self.assertEqual(stamp.hour, 21) | ||
| 35 | - self.assertEqual(stamp.minute, 13) | ||
| 36 | - self.assertEqual(stamp.second, 47) | ||
| 37 | - self.assertEqual(stamp.microsecond, 123456) | ||
| 38 | - self.assertEqual(stamp.nanosecond, 0) | ||
| 39 | - | ||
| 40 | - def test_ctor_w_nanos(self): | ||
| 41 | - stamp = self._make_one( | ||
| 42 | - 2016, 12, 20, 21, 13, 47, nanosecond=123456789) | ||
| 43 | - self.assertEqual(stamp.year, 2016) | ||
| 44 | - self.assertEqual(stamp.month, 12) | ||
| 45 | - self.assertEqual(stamp.day, 20) | ||
| 46 | - self.assertEqual(stamp.hour, 21) | ||
| 47 | - self.assertEqual(stamp.minute, 13) | ||
| 48 | - self.assertEqual(stamp.second, 47) | ||
| 49 | - self.assertEqual(stamp.microsecond, 123456) | ||
| 50 | - self.assertEqual(stamp.nanosecond, 123456789) | ||
| 51 | - | ||
| 52 | - def test_ctor_w_micros_positional_and_nanos(self): | ||
| 53 | - with self.assertRaises(TypeError): | ||
| 54 | - self._make_one( | ||
| 55 | - 2016, 12, 20, 21, 13, 47, 123456, nanosecond=123456789) | ||
| 56 | - | ||
| 57 | - def test_ctor_w_micros_keyword_and_nanos(self): | ||
| 58 | - with self.assertRaises(TypeError): | ||
| 59 | - self._make_one( | ||
| 60 | - 2016, 12, 20, 21, 13, 47, | ||
| 61 | - microsecond=123456, nanosecond=123456789) | ||
| 62 | - | ||
| 63 | - def test_rfc339_wo_nanos(self): | ||
| 64 | - stamp = self._make_one(2016, 12, 20, 21, 13, 47, 123456) | ||
| 65 | - self.assertEqual(stamp.rfc3339(), | ||
| 66 | - '2016-12-20T21:13:47.123456Z') | ||
| 67 | - | ||
| 68 | - def test_rfc339_w_nanos(self): | ||
| 69 | - stamp = self._make_one(2016, 12, 20, 21, 13, 47, nanosecond=123456789) | ||
| 70 | - self.assertEqual(stamp.rfc3339(), | ||
| 71 | - '2016-12-20T21:13:47.123456789Z') | ||
| 72 | - | ||
| 73 | - def test_rfc339_w_nanos_no_trailing_zeroes(self): | ||
| 74 | - stamp = self._make_one(2016, 12, 20, 21, 13, 47, nanosecond=100000000) | ||
| 75 | - self.assertEqual(stamp.rfc3339(), | ||
| 76 | - '2016-12-20T21:13:47.1Z') | ||
| 77 | - | ||
| 78 | - def test_from_rfc3339_w_invalid(self): | ||
| 79 | - klass = self._get_target_class() | ||
| 80 | - STAMP = '2016-12-20T21:13:47' | ||
| 81 | - with self.assertRaises(ValueError): | ||
| 82 | - klass.from_rfc3339(STAMP) | ||
| 83 | - | ||
| 84 | - def test_from_rfc3339_wo_fraction(self): | ||
| 85 | - from google.cloud._helpers import UTC | ||
| 86 | - | ||
| 87 | - klass = self._get_target_class() | ||
| 88 | - STAMP = '2016-12-20T21:13:47Z' | ||
| 89 | - expected = self._make_one(2016, 12, 20, 21, 13, 47, tzinfo=UTC) | ||
| 90 | - stamp = klass.from_rfc3339(STAMP) | ||
| 91 | - self.assertEqual(stamp, expected) | ||
| 92 | - | ||
| 93 | - def test_from_rfc3339_w_partial_precision(self): | ||
| 94 | - from google.cloud._helpers import UTC | ||
| 95 | - | ||
| 96 | - klass = self._get_target_class() | ||
| 97 | - STAMP = '2016-12-20T21:13:47.1Z' | ||
| 98 | - expected = self._make_one(2016, 12, 20, 21, 13, 47, | ||
| 99 | - microsecond=100000, tzinfo=UTC) | ||
| 100 | - stamp = klass.from_rfc3339(STAMP) | ||
| 101 | - self.assertEqual(stamp, expected) | ||
| 102 | - | ||
| 103 | - def test_from_rfc3339_w_full_precision(self): | ||
| 104 | - from google.cloud._helpers import UTC | ||
| 105 | - | ||
| 106 | - klass = self._get_target_class() | ||
| 107 | - STAMP = '2016-12-20T21:13:47.123456789Z' | ||
| 108 | - expected = self._make_one(2016, 12, 20, 21, 13, 47, | ||
| 109 | - nanosecond=123456789, tzinfo=UTC) | ||
| 110 | - stamp = klass.from_rfc3339(STAMP) | ||
| 111 | - self.assertEqual(stamp, expected) | ||
| 112 | - | ||
| 113 | - | ||
| 114 | 19 | class Test_make_value_pb(unittest.TestCase): | |
| 115 | 20 | ||
| 116 | 21 | def _callFUT(self, *args, **kw): | |
@@ -209,25 +114,28 @@ def test_w_date(self): | |||
| 209 | 114 | self.assertEqual(value_pb.string_value, today.isoformat()) | |
| 210 | 115 | ||
| 211 | 116 | def test_w_timestamp_w_nanos(self): | |
| 117 | + import pytz | ||
| 118 | + from google.api_core import datetime_helpers | ||
| 212 | 119 | from google.protobuf.struct_pb2 import Value | |
| 213 | - from google.cloud._helpers import UTC | ||
| 214 | - from google.cloud.spanner_v1._helpers import TimestampWithNanoseconds | ||
| 215 | 120 | ||
| 216 | - when = TimestampWithNanoseconds( | ||
| 217 | - 2016, 12, 20, 21, 13, 47, nanosecond=123456789, tzinfo=UTC) | ||
| 121 | + when = datetime_helpers.DatetimeWithNanoseconds( | ||
| 122 | + 2016, 12, 20, 21, 13, 47, nanosecond=123456789, tzinfo=pytz.UTC) | ||
| 218 | 123 | value_pb = self._callFUT(when) | |
| 219 | 124 | self.assertIsInstance(value_pb, Value) | |
| 220 | 125 | self.assertEqual(value_pb.string_value, when.rfc3339()) | |
| 221 | 126 | ||
| 222 | 127 | def test_w_datetime(self): | |
| 223 | 128 | import datetime | |
| 129 | + import pytz | ||
| 130 | + from google.api_core import datetime_helpers | ||
| 224 | 131 | from google.protobuf.struct_pb2 import Value | |
| 225 | - from google.cloud._helpers import UTC, _datetime_to_rfc3339 | ||
| 226 | 132 | ||
| 227 | - now = datetime.datetime.utcnow().replace(tzinfo=UTC) | ||
| 133 | + now = datetime.datetime.utcnow().replace(tzinfo=pytz.UTC) | ||
| 228 | 134 | value_pb = self._callFUT(now) | |
| 229 | 135 | self.assertIsInstance(value_pb, Value) | |
| 230 | - self.assertEqual(value_pb.string_value, _datetime_to_rfc3339(now)) | ||
| 136 | + self.assertEqual( | ||
| 137 | + value_pb.string_value, | ||
| 138 | + datetime_helpers.to_rfc3339(now)) | ||
| 231 | 139 | ||
| 232 | 140 | def test_w_unknown_type(self): | |
| 233 | 141 | with self.assertRaises(ValueError): | |
@@ -382,34 +290,46 @@ def test_w_date(self): | |||
| 382 | 290 | self.assertEqual(self._callFUT(value_pb, field_type), VALUE) | |
| 383 | 291 | ||
| 384 | 292 | def test_w_timestamp_wo_nanos(self): | |
| 293 | + import pytz | ||
| 294 | + from google.api_core import datetime_helpers | ||
| 295 | + from google.cloud.spanner_v1.proto.type_pb2 import TIMESTAMP | ||
| 296 | + from google.cloud.spanner_v1.proto.type_pb2 import Type | ||
| 385 | 297 | from google.protobuf.struct_pb2 import Value | |
| 386 | - from google.cloud.spanner_v1.proto.type_pb2 import Type, TIMESTAMP | ||
| 387 | - from google.cloud._helpers import UTC, _datetime_to_rfc3339 | ||
| 388 | - from google.cloud.spanner_v1._helpers import TimestampWithNanoseconds | ||
| 389 | 298 | ||
| 390 | - VALUE = TimestampWithNanoseconds( | ||
| 391 | - 2016, 12, 20, 21, 13, 47, microsecond=123456, tzinfo=UTC) | ||
| 299 | + value = datetime_helpers.DatetimeWithNanoseconds( | ||
| 300 | + 2016, 12, 20, 21, 13, 47, | ||
| 301 | + microsecond=123456, | ||
| 302 | + tzinfo=pytz.UTC) | ||
| 392 | 303 | field_type = Type(code=TIMESTAMP) | |
| 393 | - value_pb = Value(string_value=_datetime_to_rfc3339(VALUE)) | ||
| 304 | + value_pb = Value( | ||
| 305 | + string_value=datetime_helpers.to_rfc3339(value)) | ||
| 394 | 306 | ||
| 395 | 307 | parsed = self._callFUT(value_pb, field_type) | |
| 396 | - self.assertIsInstance(parsed, TimestampWithNanoseconds) | ||
| 397 | - self.assertEqual(parsed, VALUE) | ||
| 308 | + self.assertIsInstance( | ||
| 309 | + parsed, | ||
| 310 | + datetime_helpers.DatetimeWithNanoseconds) | ||
| 311 | + self.assertEqual(parsed, value) | ||
| 398 | 312 | ||
| 399 | 313 | def test_w_timestamp_w_nanos(self): | |
| 314 | + import pytz | ||
| 315 | + from google.api_core import datetime_helpers | ||
| 316 | + from google.cloud.spanner_v1.proto.type_pb2 import TIMESTAMP | ||
| 317 | + from google.cloud.spanner_v1.proto.type_pb2 import Type | ||
| 400 | 318 | from google.protobuf.struct_pb2 import Value | |
| 401 | - from google.cloud.spanner_v1.proto.type_pb2 import Type, TIMESTAMP | ||
| 402 | - from google.cloud._helpers import UTC, _datetime_to_rfc3339 | ||
| 403 | - from google.cloud.spanner_v1._helpers import TimestampWithNanoseconds | ||
| 404 | 319 | ||
| 405 | - VALUE = TimestampWithNanoseconds( | ||
| 406 | - 2016, 12, 20, 21, 13, 47, nanosecond=123456789, tzinfo=UTC) | ||
| 320 | + value = datetime_helpers.DatetimeWithNanoseconds( | ||
| 321 | + 2016, 12, 20, 21, 13, 47, | ||
| 322 | + nanosecond=123456789, | ||
| 323 | + tzinfo=pytz.UTC) | ||
| 407 | 324 | field_type = Type(code=TIMESTAMP) | |
| 408 | - value_pb = Value(string_value=_datetime_to_rfc3339(VALUE)) | ||
| 325 | + value_pb = Value( | ||
| 326 | + string_value=datetime_helpers.to_rfc3339(value)) | ||
| 409 | 327 | ||
| 410 | 328 | parsed = self._callFUT(value_pb, field_type) | |
| 411 | - self.assertIsInstance(parsed, TimestampWithNanoseconds) | ||
| 412 | - self.assertEqual(parsed, VALUE) | ||
| 329 | + self.assertIsInstance( | ||
| 330 | + parsed, | ||
| 331 | + datetime_helpers.DatetimeWithNanoseconds) | ||
| 332 | + self.assertEqual(parsed, value) | ||
| 413 | 333 | ||
| 414 | 334 | def test_w_array_empty(self): | |
| 415 | 335 | from google.protobuf.struct_pb2 import Value | |
| Back | FazBrowse Home | New Git URL |
0 commit comments