Skip to content

Commit

Permalink
added comments according to review
Browse files Browse the repository at this point in the history
  • Loading branch information
charbonnierg committed Mar 20, 2024
1 parent 2e55a5c commit 469e8a8
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 46 deletions.
25 changes: 16 additions & 9 deletions nats/js/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,25 +96,32 @@ def _convert_rfc3339(resp: Dict[str, Any], field: str) -> None:
val = resp.get(field, None)
if val is None:
return None
# Handle Zulu
offset = "+00:00"
# Handle Zulu (UTC)
# Until python < 3.11, fromisoformat() do not accept "Z" as a valid
# timezone. See: https://github.com/python/cpython/issues/80010
if val.endswith("Z"):
offset = "+00:00"
raw_date = val[:-1]
# There MUST be an offset if not Zulu
# There MUST be an offset if not Zulu.
# Until python3.11, fromisoformat() only accepts 3 or 6 decimal places for
# fractional seconds. See: https://github.com/python/cpython/issues/95221
# In order to pad missing microseconds, we need to temporary remove the offset.
# Offset has a fixed sized of 5 characters.
else:
offset = val[-6:]
raw_date = val[:-6]
# Padd missing milliseconds
if "." not in raw_date:
raw_date += ".000000"
else:
# Pad missing microseconds by adding "0" until length is 26.
# 26 is the length of a valid RFC3339 string with microseconds precision.
# Since python datetimes do not support nanosecond precision, we need to
# truncate the string if it has more than 6 decimal places for fractional seconds.
if "." in raw_date:
raw_date = raw_date[:26]
length = len(raw_date)
if length < 26:
raw_date += "0" * (26 - length)
# Add offset
# Add offset back
raw_date = raw_date + offset
# Parse into datetime using fromisoformat
# Parse string into datetime using fromisoformat
resp[field] = datetime.datetime.fromisoformat(raw_date).astimezone(
datetime.timezone.utc
)
Expand Down
109 changes: 72 additions & 37 deletions tests/test_js.py
Original file line number Diff line number Diff line change
Expand Up @@ -1400,7 +1400,9 @@ async def test_consumer_with_opt_start_time_date_only(self):
deliver_policy=api.DeliverPolicy.BY_START_TIME,
)
assert isinstance(con.created, datetime.datetime)
assert con.config.opt_start_time == datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
assert con.config.opt_start_time == datetime.datetime(
1970, 1, 1, tzinfo=datetime.timezone.utc
)
await nc.close()

@async_test
Expand All @@ -1415,7 +1417,9 @@ async def test_consumer_with_opt_start_time_timestamp(self):
deliver_policy=api.DeliverPolicy.BY_START_TIME,
)
assert isinstance(con.created, datetime.datetime)
assert con.config.opt_start_time == datetime.datetime(1970, 1, 1, 1, 1, 1, tzinfo=datetime.timezone.utc)
assert con.config.opt_start_time == datetime.datetime(
1970, 1, 1, 1, 1, 1, tzinfo=datetime.timezone.utc
)
await nc.close()

@async_test
Expand All @@ -1426,12 +1430,21 @@ async def test_consumer_with_opt_start_time_microseconds(self):
await jsm.add_stream(name="ctests", subjects=["a", "b", "c.>"])
con = await jsm.add_consumer(
"ctests",
opt_start_time=datetime.datetime(1970, 1, 1, 1, 1, 1, microsecond=123456),
opt_start_time=datetime.datetime(
1970, 1, 1, 1, 1, 1, microsecond=123456
),
deliver_policy=api.DeliverPolicy.BY_START_TIME,
)
assert isinstance(con.created, datetime.datetime)
assert con.config.opt_start_time == datetime.datetime(
1970, 1, 1, 1, 1, 1, microsecond=123456, tzinfo=datetime.timezone.utc
1970,
1,
1,
1,
1,
1,
microsecond=123456,
tzinfo=datetime.timezone.utc
)
await nc.close()

Expand All @@ -1443,11 +1456,15 @@ async def test_consumer_with_opt_start_time_date_tz(self):
await jsm.add_stream(name="ctests", subjects=["a", "b", "c.>"])
con = await jsm.add_consumer(
"ctests",
opt_start_time=datetime.datetime(1970, 1, 1, tzinfo=pytz.timezone("Europe/Paris")),
opt_start_time=datetime.datetime(
1970, 1, 1, tzinfo=pytz.timezone("Europe/Paris")
),
deliver_policy=api.DeliverPolicy.BY_START_TIME,
)
assert isinstance(con.created, datetime.datetime)
assert con.config.opt_start_time == datetime.datetime(1970, 1, 1, tzinfo=pytz.timezone("Europe/Paris"))
assert con.config.opt_start_time == datetime.datetime(
1970, 1, 1, tzinfo=pytz.timezone("Europe/Paris")
)
await nc.close()

@async_test
Expand All @@ -1458,11 +1475,15 @@ async def test_consumer_with_opt_start_time_timestamp_tz(self):
await jsm.add_stream(name="ctests", subjects=["a", "b", "c.>"])
con = await jsm.add_consumer(
"ctests",
opt_start_time=datetime.datetime(1970, 1, 1, 1, 1, 1, tzinfo=pytz.timezone("Europe/Paris")),
opt_start_time=datetime.datetime(
1970, 1, 1, 1, 1, 1, tzinfo=pytz.timezone("Europe/Paris")
),
deliver_policy=api.DeliverPolicy.BY_START_TIME,
)
assert isinstance(con.created, datetime.datetime)
assert con.config.opt_start_time == datetime.datetime(1970, 1, 1, 1, 1, 1, tzinfo=pytz.timezone("Europe/Paris"))
assert con.config.opt_start_time == datetime.datetime(
1970, 1, 1, 1, 1, 1, tzinfo=pytz.timezone("Europe/Paris")
)
await nc.close()

@async_test
Expand All @@ -1474,30 +1495,44 @@ async def test_consumer_with_opt_start_time_microseconds_tz(self):
con = await jsm.add_consumer(
"ctests",
opt_start_time=datetime.datetime(
1970, 1, 1, 1, 1, 1, microsecond=123456, tzinfo=pytz.timezone("Europe/Paris")
1970,
1,
1,
1,
1,
1,
microsecond=123456,
tzinfo=pytz.timezone("Europe/Paris")
),
deliver_policy=api.DeliverPolicy.BY_START_TIME,
)
assert isinstance(con.created, datetime.datetime)
assert con.config.opt_start_time == datetime.datetime(
1970, 1, 1, 1, 1, 1, microsecond=123456, tzinfo=pytz.timezone("Europe/Paris")
1970,
1,
1,
1,
1,
1,
microsecond=123456,
tzinfo=pytz.timezone("Europe/Paris")
)
await nc.close()

def test_parser_consumer_info_with_created_timestamp(self):
for created in [
"1970-01-01T01:02:03Z",
"1970-01-01T02:02:03+01:00",
"1970-01-01T01:02:03.0Z",
"1970-01-01T01:02:03.00Z",
"1970-01-01T01:02:03.000Z",
"1970-01-01T01:02:03.0000Z",
"1970-01-01T01:02:03.00000Z",
"1970-01-01T01:02:03.000000Z",
"1970-01-01T01:02:03.0000000Z",
"1970-01-01T01:02:03.00000000Z",
"1970-01-01T01:02:03.000000000Z",
"1970-01-01T02:02:03.000000000Z+01:00",
"1970-01-01T01:02:03Z",
"1970-01-01T02:02:03+01:00",
"1970-01-01T01:02:03.0Z",
"1970-01-01T01:02:03.00Z",
"1970-01-01T01:02:03.000Z",
"1970-01-01T01:02:03.0000Z",
"1970-01-01T01:02:03.00000Z",
"1970-01-01T01:02:03.000000Z",
"1970-01-01T01:02:03.0000000Z",
"1970-01-01T01:02:03.00000000Z",
"1970-01-01T01:02:03.000000000Z",
"1970-01-01T02:02:03.000000000Z+01:00",
]:
info = api.ConsumerInfo.from_response({
"name": "test",
Expand All @@ -1510,21 +1545,21 @@ def test_parser_consumer_info_with_created_timestamp(self):
1970, 1, 1, 1, 2, 3, tzinfo=datetime.timezone.utc
)
for created in [
"1970-01-01T01:02:03.4Z",
"1970-01-01T01:02:03.4+00:00",
"1970-01-01T01:02:03.40Z",
"1970-01-01T02:02:03.40+01:00",
"1970-01-01T01:02:03.400Z",
"1970-01-01T04:02:03.400+03:00",
"1970-01-01T01:02:03.4000Z",
"1970-01-01T07:22:03.4000+06:20",
"1970-01-01T01:02:03.40000Z",
"1970-01-01T00:02:03.400000-01:00",
"1970-01-01T01:02:03.400000Z",
"1970-01-01T01:02:03.4000000Z",
"1970-01-01T01:02:03.40000000Z",
"1970-01-01T01:02:03.400000000Z",
"1970-01-01T02:02:03.400000000Z+01:00",
"1970-01-01T01:02:03.4Z",
"1970-01-01T01:02:03.4+00:00",
"1970-01-01T01:02:03.40Z",
"1970-01-01T02:02:03.40+01:00",
"1970-01-01T01:02:03.400Z",
"1970-01-01T04:02:03.400+03:00",
"1970-01-01T01:02:03.4000Z",
"1970-01-01T07:22:03.4000+06:20",
"1970-01-01T01:02:03.40000Z",
"1970-01-01T00:02:03.400000-01:00",
"1970-01-01T01:02:03.400000Z",
"1970-01-01T01:02:03.4000000Z",
"1970-01-01T01:02:03.40000000Z",
"1970-01-01T01:02:03.400000000Z",
"1970-01-01T02:02:03.400000000Z+01:00",
]:
info = api.ConsumerInfo.from_response({
"name": "test",
Expand Down

0 comments on commit 469e8a8

Please sign in to comment.