8000 feat(api core): simplify from_rfc3339 methods (#9641) · googleapis/python-api-core@74326f4 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 74326f4

Browse files
authored
feat(api core): simplify from_rfc3339 methods (#9641)
1 parent 0f6ad2a commit 74326f4

File tree

6 files changed

+93
-57
lines changed

6 files changed

+93
-57
lines changed

google/api_core/bidi.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@ def __init__(self, access_limit, time_window):
172172

173173
self._time_window = time_window
174174
self._access_limit = access_limit
175-
self._past_entries = collections.deque(maxlen=access_limit) # least recent first
175+
self._past_entries = collections.deque(
176+
maxlen=access_limit
177+
) # least recent first
176178
self._entry_lock = threading.Lock()
177179

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

199201
def __repr__(self):
200202
return "{}(access_limit={}, time_window={})".format(
201-
self.__class__.__name__,
202-
self._access_limit,
203-
repr(self._time_window),
203+
self.__class__.__name__, self._access_limit, repr(self._time_window)
204204
)
205205

206206

@@ -423,7 +423,7 @@ def __init__(
423423

424424
if throttle_reopen:
425425
self._reopen_throttle = _Throttle(
426-
access_limit=5, time_window=datetime.timedelta(seconds=10),
426+
access_limit=5, time_window=datetime.timedelta(seconds=10)
427427
)
428428
else:
429429
self._reopen_throttle = None

google/api_core/datetime_helpers.py

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -115,20 +115,10 @@ def from_iso8601_time(value):
115115

116116

117117
def from_rfc3339(value):
118-
"""Convert a microsecond-precision timestamp to datetime.
118+
"""Convert an RFC3339-format timestamp to a native datetime.
119119
120-
Args:
121-
value (str): The RFC3339 string to convert.
122-
123-
Returns:
124-
datetime.datetime: The datetime object equivalent to the timestamp in
125-
UTC.
126-
"""
127-
return datetime.datetime.strptime(value, _RFC3339_MICROS).replace(tzinfo=pytz.utc)
128-
129-
130-
def from_rfc3339_nanos(value):
131-
"""Convert a nanosecond-precision timestamp to a native datetime.
120+
Supported formats include those without fractional seconds, or with
121+
any fraction up to nanosecond precision.
132122
133123
.. note::
134124
Python datetimes do not support nanosecond precision; this function
@@ -138,11 +128,11 @@ def from_rfc3339_nanos(value):
138128
value (str): The RFC3339 string to convert.
139129
140130
Returns:
141-
datetime.datetime: The datetime object equivalent to the timestamp in
142-
UTC.
131+
datetime.datetime: The datetime object equivalent to the timestamp
132+
in UTC.
143133
144134
Raises:
145-
ValueError: If the timestamp does not match the RFC 3339
135+
ValueError: If the timestamp does not match the RFC3339
146136
regular expression.
147137
"""
148138
with_nanos = _RFC3339_NANOS.match(value)
@@ -169,6 +159,9 @@ def from_rfc3339_nanos(value):
169159
return bare_seconds.replace(microsecond=micros, tzinfo=pytz.utc)
170160

171161

162+
from_rfc3339_nanos = from_rfc3339 # from_rfc3339_nanos method was deprecated.
163+
164+
172165
def to_rfc3339(value, ignore_zone=True):
173166
"""Convert a datetime to an RFC3339 timestamp string.
174167
@@ -215,22 +208,22 @@ def nanosecond(self):
215208
return self._nanosecond
216209

217210
def rfc3339(self):
218-
"""Return an RFC 3339-compliant timestamp.
211+
"""Return an RFC3339-compliant timestamp.
219212
220213
Returns:
221-
(str): Timestamp string according to RFC 3339 spec.
214+
(str): Timestamp string according to RFC3339 spec.
222215
"""
223216
if self._nanosecond == 0:
224217
return to_rfc3339(self)
225-
nanos = str(self._nanosecond).rjust(9, '0').rstrip("0")
218+
nanos = str(self._nanosecond).rjust(9, "0").rstrip("0")
226219
return "{}.{}Z".format(self.strftime(_RFC3339_NO_FRACTION), nanos)
227220

228221
@classmethod
229222
def from_rfc3339(cls, stamp):
230-
"""Parse RFC 3339-compliant timestamp, preserving nanoseconds.
223+
"""Parse RFC3339-compliant timestamp, preserving nanoseconds.
231224
232225
Args:
233-
stamp (str): RFC 3339 stamp, with up to nanosecond precision
226+
stamp (str): RFC3339 stamp, with up to nanosecond precision
234227
235228
Returns:
236229
:class:`DatetimeWithNanoseconds`:
@@ -280,7 +273,7 @@ def timestamp_pb(self):
280273

281274
@classmethod
282275
def from_timestamp_pb(cls, stamp):
283-
"""Parse RFC 3339-compliant timestamp, preserving nanoseconds.
276+
"""Parse RFC3339-compliant timestamp, preserving nanoseconds.
284277
285278
Args:
286279
stamp (:class:`~google.protobuf.timestamp_pb2.Timestamp`): timestamp message

google/api_core/iam.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,12 @@
3434
"""
3535

3636
import collections
37+
import warnings
38+
3739
try:
3840
from collections import abc as collections_abc
3941
except ImportError: # Python 2.7
4042
import collections as collections_abc
41-
import warnings
4243

4344
# Generic IAM roles
4445

google/api_core/protobuf_helpers.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,19 @@
1515
"""Helpers for :mod:`protobuf`."""
1616

1717
import collections
18-
try:
19-
from collections import abc as collections_abc
20-
except ImportError: # Python 2.7
21-
import collections as collections_abc
2218
import copy
2319
import inspect
2420

2521
from google.protobuf import field_mask_pb2
2622
from google.protobuf import message
2723
from google.protobuf import wrappers_pb2
2824

25+
try:
26+
from collections import abc as collections_abc
27+
except ImportError: # Python 2.7
28+
import collections as collections_abc
29+
30+
2931
_SENTINEL = object()
3032
_WRAPPER_TYPES = (
3133
wrappers_pb2.BoolValue,

google/api_core/retry.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ def __init__(
237237
maximum=_DEFAULT_MAXIMUM_DELAY,
238238
multiplier=_DEFAULT_DELAY_MULTIPLIER,
239239
deadline=_DEFAULT_DEADLINE,
240-
on_error=None
240+
on_error=None,
241241
):
242242
self._predicate = predicate
243243
self._initial = initial

tests/unit/test_datetime_helpers.py

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -82,18 +82,18 @@ def test_from_rfc3339():
8282
)
8383

8484

85-
def test_from_rfc3339_with_bad_tz():
86-
value = "2009-12-17T12:44:32.123456BAD"
87-
88-
with pytest.raises(ValueError):
89-
datetime_helpers.from_rfc3339(value)
90-
85+
def test_from_rfc3339_nanos():
86+
value = "2009-12-17T12:44:32.123456Z"
87+
assert datetime_helpers.from_rfc3339_nanos(value) == datetime.datetime(
88+
2009, 12, 17, 12, 44, 32, 123456, pytz.utc
89+
)
9190

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

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

9898

9999
def test_from_rfc3339_nanos_without_nanos():
@@ -103,11 +103,33 @@ def test_from_rfc3339_nanos_without_nanos():
103103
)
104104

105105

106-
def test_from_rfc3339_nanos_with_bad_tz():
107-
value = "2009-12-17T12:44:32.123456789BAD"
106+
@pytest.mark.parametrize(
107+
"truncated, micros",
108+
[
109+
("12345678", 123456),
110+
("1234567", 123456),
111+
("123456", 123456),
112+
("12345", 123450),
113+
("1234", 123400),
114+
("123", 123000),
115+
("12", 120000),
116+
("1", 100000),
117+
],
118+
)
119+
def test_from_rfc3339_with_truncated_nanos(truncated, micros):
120+
value = "2009-12-17T12:44:32.{}Z".format(truncated)
121+
assert datetime_helpers.from_rfc3339(value) == datetime.datetime(
122+
2009, 12, 17, 12, 44, 32, micros, pytz.utc
123+
)
124+
125+
126+
def test_from_rfc3339_nanos_is_deprecated():
127+
value = "2009-12-17T12:44:32.123456Z"
108128

109-
with pytest.raises(ValueError):
110-
datetime_helpers.from_rfc3339_nanos(value)
129+
result = datetime_helpers.from_rfc3339(value)
130+
result_nanos = datetime_helpers.from_rfc3339_nanos(value)
131+
132+
assert result == result_nanos
111133

112134

113135
@pytest.mark.parametrize(
@@ -130,6 +152,18 @@ def test_from_rfc3339_nanos_with_truncated_nanos(truncated, micros):
130152
)
131153

132154

155+
def test_from_rfc3339_wo_nanos_raise_exception():
156+
value = "2009-12-17T12:44:32"
157+
with pytest.raises(ValueError):
158+
datetime_helpers.from_rfc3339(value)
159+
160+
161+
def test_from_rfc3339_w_nanos_raise_exception():
162+
value = "2009-12-17T12:44:32.123456"
163+
with pytest.raises(ValueError):
164+
datetime_helpers.from_rfc3339(value)
165+
166+
133167
def test_to_rfc3339():
134168
value = datetime.datetime(2016, 4, 5, 13, 30, 0)
135169
expected = "2016-04-05T13:30:00.000000Z"
@@ -157,10 +191,11 @@ def test_to_rfc3339_with_non_utc_ignore_zone():
157191

158192

159193
class Test_DateTimeWithNanos(object):
160-
161194
@staticmethod
162195
def test_ctor_wo_nanos():
163-
stamp = datetime_helpers.DatetimeWithNanoseconds(2016, 12, 20, 21, 13, 47, 123456)
196+
stamp = datetime_helpers.DatetimeWithNanoseconds(
197+
2016, 12, 20, 21, 13, 47, 123456
198+
)
164199
assert stamp.year == 2016
165200
assert stamp.month == 12
166201
assert stamp.day == 20
@@ -200,7 +235,9 @@ def test_ctor_w_micros_keyword_and_nanos():
200235

201236
@staticmethod
202237
def test_rfc3339_wo_nanos():
203-
stamp = datetime_helpers.DatetimeWithNanoseconds(2016, 12, 20, 21, 13, 47, 123456)
238+
stamp = datetime_helpers.DatetimeWithNanoseconds(
239+
2016, 12, 20, 21, 13, 47, 123456
240+
)
204241
assert stamp.rfc3339() == "2016-12-20T21:13:47.123456Z"
205242

206243
@staticmethod
@@ -285,12 +322,16 @@ def test_from_rfc3339_w_full_precision():
285322
)
286323
def test_from_rfc3339_test_nanoseconds(fractional, nanos):
287324
value = "2009-12-17T12:44:32.{}Z".format(fractional)
288-
assert datetime_helpers.DatetimeWithNanoseconds.from_rfc3339(value).nanosecond == nanos
325+
assert (
326+
datetime_helpers.DatetimeWithNanoseconds.from_rfc3339(value).nanosecond
327+
== nanos
328+
)
289329

290330
@staticmethod
291331
def test_timestamp_pb_wo_nanos_naive():
292332
stamp = datetime_helpers.DatetimeWithNanoseconds(
293-
2016, 12, 20, 21, 13, 47, 123456)
333+
2016, 12, 20, 21, 13, 47, 123456
334+
)
294335
delta = stamp.replace(tzinfo=pytz.UTC) - datetime_helpers._UTC_EPOCH
295336
seconds = int(delta.total_seconds())
296337
nanos = 123456000
@@ -304,7 +345,8 @@ def test_timestamp_pb_w_nanos():
304345
)
305346
delta = stamp - datetime_helpers._UTC_EPOCH
306347
timestamp = timestamp_pb2.Timestamp(
307-
seconds=int(delta.total_seconds()), nanos=123456789)
348+
seconds=int(delta.total_seconds()), nanos=123456789
349+
)
308350
assert stamp.timestamp_pb() == timestamp
309351

310352
@staticmethod
@@ -314,8 +356,7 @@ def test_from_timestamp_pb_wo_nanos():
314356
seconds = int(delta.total_seconds())
315357
timestamp = timestamp_pb2.Timestamp(seconds=seconds)
316358

317-
stamp = datetime_helpers.DatetimeWithNanoseconds.from_timestamp_pb(
318-
timestamp)
359+
stamp = datetime_helpers.DatetimeWithNanoseconds.from_timestamp_pb(timestamp)
319360

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

332-
stamp = datetime_helpers.DatetimeWithNanoseconds.from_timestamp_pb(
333-
timestamp)
373+
stamp = datetime_helpers.DatetimeWithNanoseconds.from_timestamp_pb(timestamp)
334374

335375
assert _to_seconds(when) == _to_seconds(stamp)
336376
assert stamp.microsecond == 123456

0 commit comments

Comments
 (0)
0