Skip to content

Commit e81be78

Browse files
committed
added comments according to review
1 parent 2e55a5c commit e81be78

File tree

2 files changed

+88
-46
lines changed

2 files changed

+88
-46
lines changed

nats/js/api.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,25 +96,32 @@ def _convert_rfc3339(resp: Dict[str, Any], field: str) -> None:
9696
val = resp.get(field, None)
9797
if val is None:
9898
return None
99-
# Handle Zulu
100-
offset = "+00:00"
99+
# Handle Zulu (UTC)
100+
# Until python < 3.11, fromisoformat() do not accept "Z" as a valid
101+
# timezone. See: https://github.com/python/cpython/issues/80010
101102
if val.endswith("Z"):
103+
offset = "+00:00"
102104
raw_date = val[:-1]
103-
# There MUST be an offset if not Zulu
105+
# There MUST be an offset if not Zulu.
106+
# Until python3.11, fromisoformat() only accepts 3 or 6 decimal places for
107+
# fractional seconds. See: https://github.com/python/cpython/issues/95221
108+
# In order to pad missing microseconds, we need to temporary remove the offset.
109+
# Offset has a fixed sized of 5 characters.
104110
else:
105111
offset = val[-6:]
106112
raw_date = val[:-6]
107-
# Padd missing milliseconds
108-
if "." not in raw_date:
109-
raw_date += ".000000"
110-
else:
113+
# Pad missing microseconds by adding "0" until length is 26.
114+
# 26 is the length of a valid RFC3339 string with microseconds precision.
115+
# Since python datetimes do not support more than 6 decimal places
116+
# we need to truncate the string if it has more than 6 decimal places
117+
if "." in raw_date:
111118
raw_date = raw_date[:26]
112119
length = len(raw_date)
113120
if length < 26:
114121
raw_date += "0" * (26 - length)
115-
# Add offset
122+
# Add offset back
116123
raw_date = raw_date + offset
117-
# Parse into datetime using fromisoformat
124+
# Parse string into datetime using fromisoformat
118125
resp[field] = datetime.datetime.fromisoformat(raw_date).astimezone(
119126
datetime.timezone.utc
120127
)

tests/test_js.py

Lines changed: 72 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,7 +1400,9 @@ async def test_consumer_with_opt_start_time_date_only(self):
14001400
deliver_policy=api.DeliverPolicy.BY_START_TIME,
14011401
)
14021402
assert isinstance(con.created, datetime.datetime)
1403-
assert con.config.opt_start_time == datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
1403+
assert con.config.opt_start_time == datetime.datetime(
1404+
1970, 1, 1, tzinfo=datetime.timezone.utc
1405+
)
14041406
await nc.close()
14051407

14061408
@async_test
@@ -1415,7 +1417,9 @@ async def test_consumer_with_opt_start_time_timestamp(self):
14151417
deliver_policy=api.DeliverPolicy.BY_START_TIME,
14161418
)
14171419
assert isinstance(con.created, datetime.datetime)
1418-
assert con.config.opt_start_time == datetime.datetime(1970, 1, 1, 1, 1, 1, tzinfo=datetime.timezone.utc)
1420+
assert con.config.opt_start_time == datetime.datetime(
1421+
1970, 1, 1, 1, 1, 1, tzinfo=datetime.timezone.utc
1422+
)
14191423
await nc.close()
14201424

14211425
@async_test
@@ -1426,12 +1430,21 @@ async def test_consumer_with_opt_start_time_microseconds(self):
14261430
await jsm.add_stream(name="ctests", subjects=["a", "b", "c.>"])
14271431
con = await jsm.add_consumer(
14281432
"ctests",
1429-
opt_start_time=datetime.datetime(1970, 1, 1, 1, 1, 1, microsecond=123456),
1433+
opt_start_time=datetime.datetime(
1434+
1970, 1, 1, 1, 1, 1, microsecond=123456
1435+
),
14301436
deliver_policy=api.DeliverPolicy.BY_START_TIME,
14311437
)
14321438
assert isinstance(con.created, datetime.datetime)
14331439
assert con.config.opt_start_time == datetime.datetime(
1434-
1970, 1, 1, 1, 1, 1, microsecond=123456, tzinfo=datetime.timezone.utc
1440+
1970,
1441+
1,
1442+
1,
1443+
1,
1444+
1,
1445+
1,
1446+
microsecond=123456,
1447+
tzinfo=datetime.timezone.utc
14351448
)
14361449
await nc.close()
14371450

@@ -1443,11 +1456,15 @@ async def test_consumer_with_opt_start_time_date_tz(self):
14431456
await jsm.add_stream(name="ctests", subjects=["a", "b", "c.>"])
14441457
con = await jsm.add_consumer(
14451458
"ctests",
1446-
opt_start_time=datetime.datetime(1970, 1, 1, tzinfo=pytz.timezone("Europe/Paris")),
1459+
opt_start_time=datetime.datetime(
1460+
1970, 1, 1, tzinfo=pytz.timezone("Europe/Paris")
1461+
),
14471462
deliver_policy=api.DeliverPolicy.BY_START_TIME,
14481463
)
14491464
assert isinstance(con.created, datetime.datetime)
1450-
assert con.config.opt_start_time == datetime.datetime(1970, 1, 1, tzinfo=pytz.timezone("Europe/Paris"))
1465+
assert con.config.opt_start_time == datetime.datetime(
1466+
1970, 1, 1, tzinfo=pytz.timezone("Europe/Paris")
1467+
)
14511468
await nc.close()
14521469

14531470
@async_test
@@ -1458,11 +1475,15 @@ async def test_consumer_with_opt_start_time_timestamp_tz(self):
14581475
await jsm.add_stream(name="ctests", subjects=["a", "b", "c.>"])
14591476
con = await jsm.add_consumer(
14601477
"ctests",
1461-
opt_start_time=datetime.datetime(1970, 1, 1, 1, 1, 1, tzinfo=pytz.timezone("Europe/Paris")),
1478+
opt_start_time=datetime.datetime(
1479+
1970, 1, 1, 1, 1, 1, tzinfo=pytz.timezone("Europe/Paris")
1480+
),
14621481
deliver_policy=api.DeliverPolicy.BY_START_TIME,
14631482
)
14641483
assert isinstance(con.created, datetime.datetime)
1465-
assert con.config.opt_start_time == datetime.datetime(1970, 1, 1, 1, 1, 1, tzinfo=pytz.timezone("Europe/Paris"))
1484+
assert con.config.opt_start_time == datetime.datetime(
1485+
1970, 1, 1, 1, 1, 1, tzinfo=pytz.timezone("Europe/Paris")
1486+
)
14661487
await nc.close()
14671488

14681489
@async_test
@@ -1474,30 +1495,44 @@ async def test_consumer_with_opt_start_time_microseconds_tz(self):
14741495
con = await jsm.add_consumer(
14751496
"ctests",
14761497
opt_start_time=datetime.datetime(
1477-
1970, 1, 1, 1, 1, 1, microsecond=123456, tzinfo=pytz.timezone("Europe/Paris")
1498+
1970,
1499+
1,
1500+
1,
1501+
1,
1502+
1,
1503+
1,
1504+
microsecond=123456,
1505+
tzinfo=pytz.timezone("Europe/Paris")
14781506
),
14791507
deliver_policy=api.DeliverPolicy.BY_START_TIME,
14801508
)
14811509
assert isinstance(con.created, datetime.datetime)
14821510
assert con.config.opt_start_time == datetime.datetime(
1483-
1970, 1, 1, 1, 1, 1, microsecond=123456, tzinfo=pytz.timezone("Europe/Paris")
1511+
1970,
1512+
1,
1513+
1,
1514+
1,
1515+
1,
1516+
1,
1517+
microsecond=123456,
1518+
tzinfo=pytz.timezone("Europe/Paris")
14841519
)
14851520
await nc.close()
14861521

14871522
def test_parser_consumer_info_with_created_timestamp(self):
14881523
for created in [
1489-
"1970-01-01T01:02:03Z",
1490-
"1970-01-01T02:02:03+01:00",
1491-
"1970-01-01T01:02:03.0Z",
1492-
"1970-01-01T01:02:03.00Z",
1493-
"1970-01-01T01:02:03.000Z",
1494-
"1970-01-01T01:02:03.0000Z",
1495-
"1970-01-01T01:02:03.00000Z",
1496-
"1970-01-01T01:02:03.000000Z",
1497-
"1970-01-01T01:02:03.0000000Z",
1498-
"1970-01-01T01:02:03.00000000Z",
1499-
"1970-01-01T01:02:03.000000000Z",
1500-
"1970-01-01T02:02:03.000000000Z+01:00",
1524+
"1970-01-01T01:02:03Z",
1525+
"1970-01-01T02:02:03+01:00",
1526+
"1970-01-01T01:02:03.0Z",
1527+
"1970-01-01T01:02:03.00Z",
1528+
"1970-01-01T01:02:03.000Z",
1529+
"1970-01-01T01:02:03.0000Z",
1530+
"1970-01-01T01:02:03.00000Z",
1531+
"1970-01-01T01:02:03.000000Z",
1532+
"1970-01-01T01:02:03.0000000Z",
1533+
"1970-01-01T01:02:03.00000000Z",
1534+
"1970-01-01T01:02:03.000000000Z",
1535+
"1970-01-01T02:02:03.000000000Z+01:00",
15011536
]:
15021537
info = api.ConsumerInfo.from_response({
15031538
"name": "test",
@@ -1510,21 +1545,21 @@ def test_parser_consumer_info_with_created_timestamp(self):
15101545
1970, 1, 1, 1, 2, 3, tzinfo=datetime.timezone.utc
15111546
)
15121547
for created in [
1513-
"1970-01-01T01:02:03.4Z",
1514-
"1970-01-01T01:02:03.4+00:00",
1515-
"1970-01-01T01:02:03.40Z",
1516-
"1970-01-01T02:02:03.40+01:00",
1517-
"1970-01-01T01:02:03.400Z",
1518-
"1970-01-01T04:02:03.400+03:00",
1519-
"1970-01-01T01:02:03.4000Z",
1520-
"1970-01-01T07:22:03.4000+06:20",
1521-
"1970-01-01T01:02:03.40000Z",
1522-
"1970-01-01T00:02:03.400000-01:00",
1523-
"1970-01-01T01:02:03.400000Z",
1524-
"1970-01-01T01:02:03.4000000Z",
1525-
"1970-01-01T01:02:03.40000000Z",
1526-
"1970-01-01T01:02:03.400000000Z",
1527-
"1970-01-01T02:02:03.400000000Z+01:00",
1548+
"1970-01-01T01:02:03.4Z",
1549+
"1970-01-01T01:02:03.4+00:00",
1550+
"1970-01-01T01:02:03.40Z",
1551+
"1970-01-01T02:02:03.40+01:00",
1552+
"1970-01-01T01:02:03.400Z",
1553+
"1970-01-01T04:02:03.400+03:00",
1554+
"1970-01-01T01:02:03.4000Z",
1555+
"1970-01-01T07:22:03.4000+06:20",
1556+
"1970-01-01T01:02:03.40000Z",
1557+
"1970-01-01T00:02:03.400000-01:00",
1558+
"1970-01-01T01:02:03.400000Z",
1559+
"1970-01-01T01:02:03.4000000Z",
1560+
"1970-01-01T01:02:03.40000000Z",
1561+
"1970-01-01T01:02:03.400000000Z",
1562+
"1970-01-01T02:02:03.400000000Z+01:00",
15281563
]:
15291564
info = api.ConsumerInfo.from_response({
15301565
"name": "test",

0 commit comments

Comments
 (0)