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

feat(api core): simplify from_rfc3339 methods #9641

Merged
merged 29 commits into from
Nov 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
49d6100
API Core: simplify methods
emar-kar Jul 22, 2019
ddbcb99
Update test_datetime_helpers.py
emar-kar Jul 24, 2019
1cfaf61
Update datetime_helpers.py
emar-kar Jul 25, 2019
59a49b9
Update datetime_helpers.py
emar-kar Jul 26, 2019
7b5dfa6
Merge remote-tracking branch 'upstream/master' into Methods-Combining
emar-kar Jul 26, 2019
0481ad4
Update test_datetime_helpers.py
emar-kar Jul 26, 2019
710978b
Update datetime_helpers.py
emar-kar Jul 26, 2019
70bf8bc
Update datetime_helpers.py
emar-kar Aug 23, 2019
69fef2e
Merge branch 'master' into Methods-Combining
emar-kar Aug 28, 2019
91a1ece
Merge branch 'master' into Methods-Combining
emar-kar Sep 5, 2019
06bee67
update datetime_helpers
emar-kar Sep 5, 2019
873a60d
API Core: simplify methods
emar-kar Jul 22, 2019
796204c
Update test_datetime_helpers.py
emar-kar Jul 24, 2019
0503e92
Update datetime_helpers.py
emar-kar Jul 25, 2019
dc4f896
Update datetime_helpers.py
emar-kar Jul 26, 2019
4bcf651
Update test_datetime_helpers.py
emar-kar Jul 26, 2019
8151cae
Update datetime_helpers.py
emar-kar Jul 26, 2019
447ed3e
Update datetime_helpers.py
emar-kar Aug 23, 2019
1fc8661
update datetime_helpers
emar-kar Sep 5, 2019
93f8883
Merge branch 'Methods-Combining' of https://github.com/q-logic/google…
emar-kar Nov 8, 2019
9dcffee
update comments
emar-kar Nov 8, 2019
bc18ddb
update as requested
emar-kar Nov 8, 2019
fcd3e6a
black
emar-kar Nov 8, 2019
ed1ac2f
flake8 + test fix
emar-kar Nov 8, 2019
3b8f432
remove warning test
emar-kar Nov 8, 2019
c7e5b06
test fix
emar-kar Nov 8, 2019
0951c9a
try flake8 I202 fix
emar-kar Nov 8, 2019
05630fc
remove _nanos method + modified tests
emar-kar Nov 11, 2019
97e8662
flake8 update
emar-kar Nov 11, 2019
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
10 changes: 5 additions & 5 deletions api_core/google/api_core/bidi.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@ def __init__(self, access_limit, time_window):

self._time_window = time_window
self._access_limit = access_limit
self._past_entries = collections.deque(maxlen=access_limit) # least recent first
self._past_entries = collections.deque(
maxlen=access_limit
crwilcox marked this conversation as resolved.
Show resolved Hide resolved
) # least recent first
self._entry_lock = threading.Lock()

def __enter__(self):
Expand All @@ -198,9 +200,7 @@ def __exit__(self, *_):

def __repr__(self):
return "{}(access_limit={}, time_window={})".format(
self.__class__.__name__,
self._access_limit,
repr(self._time_window),
self.__class__.__name__, self._access_limit, repr(self._time_window)
)


Expand Down Expand Up @@ -423,7 +423,7 @@ def __init__(

if throttle_reopen:
self._reopen_throttle = _Throttle(
access_limit=5, time_window=datetime.timedelta(seconds=10),
access_limit=5, time_window=datetime.timedelta(seconds=10)
)
else:
self._reopen_throttle = None
Expand Down
37 changes: 15 additions & 22 deletions api_core/google/api_core/datetime_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,20 +115,10 @@ def from_iso8601_time(value):


def from_rfc3339(value):
"""Convert a microsecond-precision timestamp to datetime.
"""Convert an RFC3339-format timestamp to a native datetime.

Args:
value (str): The RFC3339 string to convert.

Returns:
datetime.datetime: The datetime object equivalent to the timestamp in
UTC.
"""
return datetime.datetime.strptime(value, _RFC3339_MICROS).replace(tzinfo=pytz.utc)


def from_rfc3339_nanos(value):
"""Convert a nanosecond-precision timestamp to a native datetime.
Supported formats include those without fractional seconds, or with
any fraction up to nanosecond precision.

.. note::
Python datetimes do not support nanosecond precision; this function
Expand All @@ -138,11 +128,11 @@ def from_rfc3339_nanos(value):
value (str): The RFC3339 string to convert.

Returns:
datetime.datetime: The datetime object equivalent to the timestamp in
UTC.
datetime.datetime: The datetime object equivalent to the timestamp
in UTC.

Raises:
ValueError: If the timestamp does not match the RFC 3339
ValueError: If the timestamp does not match the RFC3339
regular expression.
"""
with_nanos = _RFC3339_NANOS.match(value)
Expand All @@ -169,6 +159,9 @@ def from_rfc3339_nanos(value):
return bare_seconds.replace(microsecond=micros, tzinfo=pytz.utc)


from_rfc3339_nanos = from_rfc3339 # from_rfc3339_nanos method was deprecated.


def to_rfc3339(value, ignore_zone=True):
"""Convert a datetime to an RFC3339 timestamp string.

Expand Down Expand Up @@ -215,22 +208,22 @@ def nanosecond(self):
return self._nanosecond

def rfc3339(self):
"""Return an RFC 3339-compliant timestamp.
"""Return an RFC3339-compliant timestamp.

Returns:
(str): Timestamp string according to RFC 3339 spec.
(str): Timestamp string according to RFC3339 spec.
"""
if self._nanosecond == 0:
return to_rfc3339(self)
nanos = str(self._nanosecond).rjust(9, '0').rstrip("0")
nanos = str(self._nanosecond).rjust(9, "0").rstrip("0")
return "{}.{}Z".format(self.strftime(_RFC3339_NO_FRACTION), nanos)

@classmethod
def from_rfc3339(cls, stamp):
"""Parse RFC 3339-compliant timestamp, preserving nanoseconds.
"""Parse RFC3339-compliant timestamp, preserving nanoseconds.

Args:
stamp (str): RFC 3339 stamp, with up to nanosecond precision
stamp (str): RFC3339 stamp, with up to nanosecond precision

Returns:
:class:`DatetimeWithNanoseconds`:
Expand Down Expand Up @@ -280,7 +273,7 @@ def timestamp_pb(self):

@classmethod
def from_timestamp_pb(cls, stamp):
"""Parse RFC 3339-compliant timestamp, preserving nanoseconds.
"""Parse RFC3339-compliant timestamp, preserving nanoseconds.

Args:
stamp (:class:`~google.protobuf.timestamp_pb2.Timestamp`): timestamp message
Expand Down
3 changes: 2 additions & 1 deletion api_core/google/api_core/iam.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@
"""

import collections
import warnings

try:
from collections import abc as collections_abc
except ImportError: # Python 2.7
import collections as collections_abc
import warnings

# Generic IAM roles

Expand Down
10 changes: 6 additions & 4 deletions api_core/google/api_core/protobuf_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@
"""Helpers for :mod:`protobuf`."""

import collections
try:
from collections import abc as collections_abc
except ImportError: # Python 2.7
import collections as collections_abc
import copy
import inspect

from google.protobuf import field_mask_pb2
from google.protobuf import message
from google.protobuf import wrappers_pb2

try:
crwilcox marked this conversation as resolved.
Show resolved Hide resolved
from collections import abc as collections_abc
except ImportError: # Python 2.7
import collections as collections_abc


_SENTINEL = object()
_WRAPPER_TYPES = (
wrappers_pb2.BoolValue,
Expand Down
2 changes: 1 addition & 1 deletion api_core/google/api_core/retry.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ def __init__(
maximum=_DEFAULT_MAXIMUM_DELAY,
multiplier=_DEFAULT_DELAY_MULTIPLIER,
deadline=_DEFAULT_DEADLINE,
on_error=None
on_error=None,
):
self._predicate = predicate
self._initial = initial
Expand Down
88 changes: 64 additions & 24 deletions api_core/tests/unit/test_datetime_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,18 @@ def test_from_rfc3339():
)


def test_from_rfc3339_with_bad_tz():
value = "2009-12-17T12:44:32.123456BAD"

with pytest.raises(ValueError):
datetime_helpers.from_rfc3339(value)

def test_from_rfc3339_nanos():
value = "2009-12-17T12:44:32.123456Z"
assert datetime_helpers.from_rfc3339_nanos(value) == datetime.datetime(
2009, 12, 17, 12, 44, 32, 123456, pytz.utc
)

def test_from_rfc3339_with_nanos():
value = "2009-12-17T12:44:32.123456789Z"

with pytest.raises(ValueError):
datetime_helpers.from_rfc3339(value)
def test_from_rfc3339_without_nanos():
value = "2009-12-17T12:44:32Z"
assert datetime_helpers.from_rfc3339(value) == datetime.datetime(
2009, 12, 17, 12, 44, 32, 0, pytz.utc
)


def test_from_rfc3339_nanos_without_nanos():
Expand All @@ -103,11 +103,33 @@ def test_from_rfc3339_nanos_without_nanos():
)


def test_from_rfc3339_nanos_with_bad_tz():
value = "2009-12-17T12:44:32.123456789BAD"
@pytest.mark.parametrize(
"truncated, micros",
[
("12345678", 123456),
("1234567", 123456),
("123456", 123456),
("12345", 123450),
("1234", 123400),
("123", 123000),
("12", 120000),
("1", 100000),
],
)
def test_from_rfc3339_with_truncated_nanos(truncated, micros):
value = "2009-12-17T12:44:32.{}Z".format(truncated)
assert datetime_helpers.from_rfc3339(value) == datetime.datetime(
2009, 12, 17, 12, 44, 32, micros, pytz.utc
)


def test_from_rfc3339_nanos_is_deprecated():
value = "2009-12-17T12:44:32.123456Z"

with pytest.raises(ValueError):
datetime_helpers.from_rfc3339_nanos(value)
result = datetime_helpers.from_rfc3339(value)
result_nanos = datetime_helpers.from_rfc3339_nanos(value)

assert result == result_nanos


@pytest.mark.parametrize(
Expand All @@ -130,6 +152,18 @@ def test_from_rfc3339_nanos_with_truncated_nanos(truncated, micros):
)


def test_from_rfc3339_wo_nanos_raise_exception():
value = "2009-12-17T12:44:32"
with pytest.raises(ValueError):
datetime_helpers.from_rfc3339(value)


def test_from_rfc3339_w_nanos_raise_exception():
value = "2009-12-17T12:44:32.123456"
with pytest.raises(ValueError):
datetime_helpers.from_rfc3339(value)


def test_to_rfc3339():
value = datetime.datetime(2016, 4, 5, 13, 30, 0)
expected = "2016-04-05T13:30:00.000000Z"
Expand Down Expand Up @@ -157,10 +191,11 @@ def test_to_rfc3339_with_non_utc_ignore_zone():


class Test_DateTimeWithNanos(object):

@staticmethod
def test_ctor_wo_nanos():
stamp = datetime_helpers.DatetimeWithNanoseconds(2016, 12, 20, 21, 13, 47, 123456)
stamp = datetime_helpers.DatetimeWithNanoseconds(
2016, 12, 20, 21, 13, 47, 123456
)
assert stamp.year == 2016
assert stamp.month == 12
assert stamp.day == 20
Expand Down Expand Up @@ -200,7 +235,9 @@ def test_ctor_w_micros_keyword_and_nanos():

@staticmethod
def test_rfc3339_wo_nanos():
stamp = datetime_helpers.DatetimeWithNanoseconds(2016, 12, 20, 21, 13, 47, 123456)
stamp = datetime_helpers.DatetimeWithNanoseconds(
2016, 12, 20, 21, 13, 47, 123456
)
assert stamp.rfc3339() == "2016-12-20T21:13:47.123456Z"

@staticmethod
Expand Down Expand Up @@ -285,12 +322,16 @@ def test_from_rfc3339_w_full_precision():
)
def test_from_rfc3339_test_nanoseconds(fractional, nanos):
value = "2009-12-17T12:44:32.{}Z".format(fractional)
assert datetime_helpers.DatetimeWithNanoseconds.from_rfc3339(value).nanosecond == nanos
assert (
datetime_helpers.DatetimeWithNanoseconds.from_rfc3339(value).nanosecond
== nanos
)

@staticmethod
def test_timestamp_pb_wo_nanos_naive():
stamp = datetime_helpers.DatetimeWithNanoseconds(
2016, 12, 20, 21, 13, 47, 123456)
2016, 12, 20, 21, 13, 47, 123456
)
delta = stamp.replace(tzinfo=pytz.UTC) - datetime_helpers._UTC_EPOCH
seconds = int(delta.total_seconds())
nanos = 123456000
Expand All @@ -304,7 +345,8 @@ def test_timestamp_pb_w_nanos():
)
delta = stamp - datetime_helpers._UTC_EPOCH
timestamp = timestamp_pb2.Timestamp(
seconds=int(delta.total_seconds()), nanos=123456789)
seconds=int(delta.total_seconds()), nanos=123456789
)
assert stamp.timestamp_pb() == timestamp

@staticmethod
Expand All @@ -314,8 +356,7 @@ def test_from_timestamp_pb_wo_nanos():
seconds = int(delta.total_seconds())
timestamp = timestamp_pb2.Timestamp(seconds=seconds)

stamp = datetime_helpers.DatetimeWithNanoseconds.from_timestamp_pb(
timestamp)
stamp = datetime_helpers.DatetimeWithNanoseconds.from_timestamp_pb(timestamp)

assert _to_seconds(when) == _to_seconds(stamp)
assert stamp.microsecond == 0
Expand All @@ -329,8 +370,7 @@ def test_from_timestamp_pb_w_nanos():
seconds = int(delta.total_seconds())
timestamp = timestamp_pb2.Timestamp(seconds=seconds, nanos=123456789)

stamp = datetime_helpers.DatetimeWithNanoseconds.from_timestamp_pb(
timestamp)
stamp = datetime_helpers.DatetimeWithNanoseconds.from_timestamp_pb(timestamp)

assert _to_seconds(when) == _to_seconds(stamp)
assert stamp.microsecond == 123456
Expand Down