Skip to content

Commit dbd6f0d

Browse files
authored
Replace pytz with zoneinfo / datetime.timezone (#622)
* Replace pytz with zoneinfo / datetime.timezone * Remove tzlocal from test requirements since it is unsued, add backports.zoneinfo for python 3.8 * Fix formatting
1 parent f1eeaa0 commit dbd6f0d

File tree

6 files changed

+81
-75
lines changed

6 files changed

+81
-75
lines changed

examples/zoo_app/requirements.txt

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ Jinja2==2.11.3
88
jsonschema==3.2.0
99
MarkupSafe==2.0.1
1010
pyrsistent==0.17.3
11-
pytz==2021.1
1211
six==1.16.0
1312
Werkzeug==2.2.3
1413

flask_restx/inputs.py

+11-12
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,15 @@ def my_type(value):
1919
import re
2020
import socket
2121

22-
from datetime import datetime, time, timedelta
22+
from datetime import datetime, time, timedelta, timezone
2323
from email.utils import parsedate_tz, mktime_tz
2424
from urllib.parse import urlparse
2525

2626
import aniso8601
27-
import pytz
2827

2928
# Constants for upgrading date-based intervals to full datetimes.
30-
START_OF_DAY = time(0, 0, 0, tzinfo=pytz.UTC)
31-
END_OF_DAY = time(23, 59, 59, 999999, tzinfo=pytz.UTC)
29+
START_OF_DAY = time(0, 0, 0, tzinfo=timezone.utc)
30+
END_OF_DAY = time(23, 59, 59, 999999, tzinfo=timezone.utc)
3231

3332

3433
netloc_regex = re.compile(
@@ -338,11 +337,11 @@ def _normalize_interval(start, end, value):
338337
end = datetime.combine(end, START_OF_DAY)
339338

340339
if start.tzinfo is None:
341-
start = pytz.UTC.localize(start)
342-
end = pytz.UTC.localize(end)
340+
start = start.replace(tzinfo=timezone.utc)
341+
end = end.replace(tzinfo=timezone.utc)
343342
else:
344-
start = start.astimezone(pytz.UTC)
345-
end = end.astimezone(pytz.UTC)
343+
start = start.astimezone(timezone.utc)
344+
end = end.astimezone(timezone.utc)
346345

347346
return start, end
348347

@@ -424,11 +423,11 @@ def iso8601interval(value, argument="argument"):
424423

425424
start, end = _normalize_interval(start, end, value)
426425

427-
except ValueError:
426+
except ValueError as e:
428427
msg = (
429428
"Invalid {arg}: {value}. {arg} must be a valid ISO8601 date/time interval."
430429
)
431-
raise ValueError(msg.format(arg=argument, value=value))
430+
raise ValueError(msg.format(arg=argument, value=value)) from e
432431

433432
return start, end
434433

@@ -559,9 +558,9 @@ def datetime_from_rfc822(value):
559558
timetuple = parsedate_tz(value)
560559
timestamp = mktime_tz(timetuple)
561560
if timetuple[-1] is None:
562-
return datetime.fromtimestamp(timestamp).replace(tzinfo=pytz.utc)
561+
return datetime.fromtimestamp(timestamp).replace(tzinfo=timezone.utc)
563562
else:
564-
return datetime.fromtimestamp(timestamp, pytz.utc)
563+
return datetime.fromtimestamp(timestamp, timezone.utc)
565564
except Exception:
566565
raise ValueError('Invalid date literal "{0}"'.format(raw))
567566

requirements/install.pip

-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@ aniso8601>=0.82
22
jsonschema
33
Flask>=0.8, !=2.0.0
44
werkzeug!=2.0.0
5-
pytz
65
importlib_resources

requirements/test.pip

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pytest-cov==4.0.0
77
pytest-flask==1.3.0
88
pytest-mock==3.6.1
99
pytest-profiling==1.7.0
10-
tzlocal
1110
invoke==2.2.0
1211
twine==3.8.0
1312
setuptools
13+
backports.zoneinfo;python_version<"3.9"

tests/test_fields.py

+14-10
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
try:
2+
import zoneinfo
3+
except ImportError:
4+
from backports import zoneinfo
5+
16
from collections import OrderedDict
2-
from datetime import date, datetime
7+
from datetime import date, datetime, timezone
38
from decimal import Decimal
49
from functools import partial
510

6-
import pytz
711
import pytest
812

913
from flask import Blueprint
@@ -538,11 +542,11 @@ def test_max_exclusive(self):
538542
(datetime(2011, 1, 1), "Sat, 01 Jan 2011 00:00:00 -0000"),
539543
(datetime(2011, 1, 1, 23, 59, 59), "Sat, 01 Jan 2011 23:59:59 -0000"),
540544
(
541-
datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.utc),
545+
datetime(2011, 1, 1, 23, 59, 59, tzinfo=timezone.utc),
542546
"Sat, 01 Jan 2011 23:59:59 -0000",
543547
),
544548
(
545-
datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.timezone("CET")),
549+
datetime(2011, 1, 1, 23, 59, 59, tzinfo=zoneinfo.ZoneInfo("CET")),
546550
"Sat, 01 Jan 2011 22:59:59 -0000",
547551
),
548552
],
@@ -558,15 +562,15 @@ def test_rfc822_value(self, value, expected):
558562
(datetime(2011, 1, 1, 23, 59, 59), "2011-01-01T23:59:59"),
559563
(datetime(2011, 1, 1, 23, 59, 59, 1000), "2011-01-01T23:59:59.001000"),
560564
(
561-
datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.utc),
565+
datetime(2011, 1, 1, 23, 59, 59, tzinfo=timezone.utc),
562566
"2011-01-01T23:59:59+00:00",
563567
),
564568
(
565-
datetime(2011, 1, 1, 23, 59, 59, 1000, tzinfo=pytz.utc),
569+
datetime(2011, 1, 1, 23, 59, 59, 1000, tzinfo=timezone.utc),
566570
"2011-01-01T23:59:59.001000+00:00",
567571
),
568572
(
569-
datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.timezone("CET")),
573+
datetime(2011, 1, 1, 23, 59, 59, tzinfo=zoneinfo.ZoneInfo("CET")),
570574
"2011-01-01T23:59:59+01:00",
571575
),
572576
],
@@ -673,10 +677,10 @@ def test_max_exclusive(self):
673677
(datetime(2011, 1, 1), "2011-01-01"),
674678
(datetime(2011, 1, 1, 23, 59, 59), "2011-01-01"),
675679
(datetime(2011, 1, 1, 23, 59, 59, 1000), "2011-01-01"),
676-
(datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.utc), "2011-01-01"),
677-
(datetime(2011, 1, 1, 23, 59, 59, 1000, tzinfo=pytz.utc), "2011-01-01"),
680+
(datetime(2011, 1, 1, 23, 59, 59, tzinfo=timezone.utc), "2011-01-01"),
681+
(datetime(2011, 1, 1, 23, 59, 59, 1000, tzinfo=timezone.utc), "2011-01-01"),
678682
(
679-
datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.timezone("CET")),
683+
datetime(2011, 1, 1, 23, 59, 59, tzinfo=zoneinfo.ZoneInfo("CET")),
680684
"2011-01-01",
681685
),
682686
],

tests/test_inputs.py

+55-50
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import re
2-
import pytz
32
import pytest
43

5-
from datetime import date, datetime
4+
from datetime import date, datetime, timezone
65

76
from flask_restx import inputs
87

@@ -37,18 +36,18 @@ class Iso8601DatetimeTest(object):
3736
"value,expected",
3837
[
3938
("2011-01-01", datetime(2011, 1, 1)),
40-
("2011-01-01T00:00:00+00:00", datetime(2011, 1, 1, tzinfo=pytz.utc)),
39+
("2011-01-01T00:00:00+00:00", datetime(2011, 1, 1, tzinfo=timezone.utc)),
4140
(
4241
"2011-01-01T23:59:59+00:00",
43-
datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.utc),
42+
datetime(2011, 1, 1, 23, 59, 59, tzinfo=timezone.utc),
4443
),
4544
(
4645
"2011-01-01T23:59:59.001000+00:00",
47-
datetime(2011, 1, 1, 23, 59, 59, 1000, tzinfo=pytz.utc),
46+
datetime(2011, 1, 1, 23, 59, 59, 1000, tzinfo=timezone.utc),
4847
),
4948
(
5049
"2011-01-01T23:59:59+02:00",
51-
datetime(2011, 1, 1, 21, 59, 59, tzinfo=pytz.utc),
50+
datetime(2011, 1, 1, 21, 59, 59, tzinfo=timezone.utc),
5251
),
5352
],
5453
)
@@ -70,22 +69,28 @@ class Rfc822DatetimeTest(object):
7069
@pytest.mark.parametrize(
7170
"value,expected",
7271
[
73-
("Sat, 01 Jan 2011", datetime(2011, 1, 1, tzinfo=pytz.utc)),
74-
("Sat, 01 Jan 2011 00:00", datetime(2011, 1, 1, tzinfo=pytz.utc)),
75-
("Sat, 01 Jan 2011 00:00:00", datetime(2011, 1, 1, tzinfo=pytz.utc)),
76-
("Sat, 01 Jan 2011 00:00:00 +0000", datetime(2011, 1, 1, tzinfo=pytz.utc)),
77-
("Sat, 01 Jan 2011 00:00:00 -0000", datetime(2011, 1, 1, tzinfo=pytz.utc)),
72+
("Sat, 01 Jan 2011", datetime(2011, 1, 1, tzinfo=timezone.utc)),
73+
("Sat, 01 Jan 2011 00:00", datetime(2011, 1, 1, tzinfo=timezone.utc)),
74+
("Sat, 01 Jan 2011 00:00:00", datetime(2011, 1, 1, tzinfo=timezone.utc)),
75+
(
76+
"Sat, 01 Jan 2011 00:00:00 +0000",
77+
datetime(2011, 1, 1, tzinfo=timezone.utc),
78+
),
79+
(
80+
"Sat, 01 Jan 2011 00:00:00 -0000",
81+
datetime(2011, 1, 1, tzinfo=timezone.utc),
82+
),
7883
(
7984
"Sat, 01 Jan 2011 23:59:59 -0000",
80-
datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.utc),
85+
datetime(2011, 1, 1, 23, 59, 59, tzinfo=timezone.utc),
8186
),
8287
(
8388
"Sat, 01 Jan 2011 21:00:00 +0200",
84-
datetime(2011, 1, 1, 19, 0, 0, tzinfo=pytz.utc),
89+
datetime(2011, 1, 1, 19, 0, 0, tzinfo=timezone.utc),
8590
),
8691
(
8792
"Sat, 01 Jan 2011 21:00:00 -0200",
88-
datetime(2011, 1, 1, 23, 0, 0, tzinfo=pytz.utc),
93+
datetime(2011, 1, 1, 23, 0, 0, tzinfo=timezone.utc),
8994
),
9095
],
9196
)
@@ -985,145 +990,145 @@ def test_schema(self):
985990
# Full precision with explicit UTC.
986991
"2013-01-01T12:30:00Z/P1Y2M3DT4H5M6S",
987992
(
988-
datetime(2013, 1, 1, 12, 30, 0, tzinfo=pytz.utc),
989-
datetime(2014, 3, 5, 16, 35, 6, tzinfo=pytz.utc),
993+
datetime(2013, 1, 1, 12, 30, 0, tzinfo=timezone.utc),
994+
datetime(2014, 3, 5, 16, 35, 6, tzinfo=timezone.utc),
990995
),
991996
),
992997
(
993998
# Full precision with alternate UTC indication
994999
"2013-01-01T12:30+00:00/P2D",
9951000
(
996-
datetime(2013, 1, 1, 12, 30, 0, tzinfo=pytz.utc),
997-
datetime(2013, 1, 3, 12, 30, 0, tzinfo=pytz.utc),
1001+
datetime(2013, 1, 1, 12, 30, 0, tzinfo=timezone.utc),
1002+
datetime(2013, 1, 3, 12, 30, 0, tzinfo=timezone.utc),
9981003
),
9991004
),
10001005
(
10011006
# Implicit UTC with time
10021007
"2013-01-01T15:00/P1M",
10031008
(
1004-
datetime(2013, 1, 1, 15, 0, 0, tzinfo=pytz.utc),
1005-
datetime(2013, 1, 31, 15, 0, 0, tzinfo=pytz.utc),
1009+
datetime(2013, 1, 1, 15, 0, 0, tzinfo=timezone.utc),
1010+
datetime(2013, 1, 31, 15, 0, 0, tzinfo=timezone.utc),
10061011
),
10071012
),
10081013
(
10091014
# TZ conversion
10101015
"2013-01-01T17:00-05:00/P2W",
10111016
(
1012-
datetime(2013, 1, 1, 22, 0, 0, tzinfo=pytz.utc),
1013-
datetime(2013, 1, 15, 22, 0, 0, tzinfo=pytz.utc),
1017+
datetime(2013, 1, 1, 22, 0, 0, tzinfo=timezone.utc),
1018+
datetime(2013, 1, 15, 22, 0, 0, tzinfo=timezone.utc),
10141019
),
10151020
),
10161021
(
10171022
# Date upgrade to midnight-midnight period
10181023
"2013-01-01/P3D",
10191024
(
1020-
datetime(2013, 1, 1, 0, 0, 0, tzinfo=pytz.utc),
1021-
datetime(2013, 1, 4, 0, 0, 0, 0, tzinfo=pytz.utc),
1025+
datetime(2013, 1, 1, 0, 0, 0, tzinfo=timezone.utc),
1026+
datetime(2013, 1, 4, 0, 0, 0, 0, tzinfo=timezone.utc),
10221027
),
10231028
),
10241029
(
10251030
# Start/end with UTC
10261031
"2013-01-01T12:00:00Z/2013-02-01T12:00:00Z",
10271032
(
1028-
datetime(2013, 1, 1, 12, 0, 0, tzinfo=pytz.utc),
1029-
datetime(2013, 2, 1, 12, 0, 0, tzinfo=pytz.utc),
1033+
datetime(2013, 1, 1, 12, 0, 0, tzinfo=timezone.utc),
1034+
datetime(2013, 2, 1, 12, 0, 0, tzinfo=timezone.utc),
10301035
),
10311036
),
10321037
(
10331038
# Start/end with time upgrade
10341039
"2013-01-01/2013-06-30",
10351040
(
1036-
datetime(2013, 1, 1, tzinfo=pytz.utc),
1037-
datetime(2013, 6, 30, tzinfo=pytz.utc),
1041+
datetime(2013, 1, 1, tzinfo=timezone.utc),
1042+
datetime(2013, 6, 30, tzinfo=timezone.utc),
10381043
),
10391044
),
10401045
(
10411046
# Start/end with TZ conversion
10421047
"2013-02-17T12:00:00-07:00/2013-02-28T15:00:00-07:00",
10431048
(
1044-
datetime(2013, 2, 17, 19, 0, 0, tzinfo=pytz.utc),
1045-
datetime(2013, 2, 28, 22, 0, 0, tzinfo=pytz.utc),
1049+
datetime(2013, 2, 17, 19, 0, 0, tzinfo=timezone.utc),
1050+
datetime(2013, 2, 28, 22, 0, 0, tzinfo=timezone.utc),
10461051
),
10471052
),
10481053
( # Resolution expansion for single date(time)
10491054
# Second with UTC
10501055
"2013-01-01T12:30:45Z",
10511056
(
1052-
datetime(2013, 1, 1, 12, 30, 45, tzinfo=pytz.utc),
1053-
datetime(2013, 1, 1, 12, 30, 46, tzinfo=pytz.utc),
1057+
datetime(2013, 1, 1, 12, 30, 45, tzinfo=timezone.utc),
1058+
datetime(2013, 1, 1, 12, 30, 46, tzinfo=timezone.utc),
10541059
),
10551060
),
10561061
(
10571062
# Second with tz conversion
10581063
"2013-01-01T12:30:45+02:00",
10591064
(
1060-
datetime(2013, 1, 1, 10, 30, 45, tzinfo=pytz.utc),
1061-
datetime(2013, 1, 1, 10, 30, 46, tzinfo=pytz.utc),
1065+
datetime(2013, 1, 1, 10, 30, 45, tzinfo=timezone.utc),
1066+
datetime(2013, 1, 1, 10, 30, 46, tzinfo=timezone.utc),
10621067
),
10631068
),
10641069
(
10651070
# Second with implicit UTC
10661071
"2013-01-01T12:30:45",
10671072
(
1068-
datetime(2013, 1, 1, 12, 30, 45, tzinfo=pytz.utc),
1069-
datetime(2013, 1, 1, 12, 30, 46, tzinfo=pytz.utc),
1073+
datetime(2013, 1, 1, 12, 30, 45, tzinfo=timezone.utc),
1074+
datetime(2013, 1, 1, 12, 30, 46, tzinfo=timezone.utc),
10701075
),
10711076
),
10721077
(
10731078
# Minute with UTC
10741079
"2013-01-01T12:30+00:00",
10751080
(
1076-
datetime(2013, 1, 1, 12, 30, tzinfo=pytz.utc),
1077-
datetime(2013, 1, 1, 12, 31, tzinfo=pytz.utc),
1081+
datetime(2013, 1, 1, 12, 30, tzinfo=timezone.utc),
1082+
datetime(2013, 1, 1, 12, 31, tzinfo=timezone.utc),
10781083
),
10791084
),
10801085
(
10811086
# Minute with conversion
10821087
"2013-01-01T12:30+04:00",
10831088
(
1084-
datetime(2013, 1, 1, 8, 30, tzinfo=pytz.utc),
1085-
datetime(2013, 1, 1, 8, 31, tzinfo=pytz.utc),
1089+
datetime(2013, 1, 1, 8, 30, tzinfo=timezone.utc),
1090+
datetime(2013, 1, 1, 8, 31, tzinfo=timezone.utc),
10861091
),
10871092
),
10881093
(
10891094
# Minute with implicit UTC
10901095
"2013-01-01T12:30",
10911096
(
1092-
datetime(2013, 1, 1, 12, 30, tzinfo=pytz.utc),
1093-
datetime(2013, 1, 1, 12, 31, tzinfo=pytz.utc),
1097+
datetime(2013, 1, 1, 12, 30, tzinfo=timezone.utc),
1098+
datetime(2013, 1, 1, 12, 31, tzinfo=timezone.utc),
10941099
),
10951100
),
10961101
(
10971102
# Hour, explicit UTC
10981103
"2013-01-01T12Z",
10991104
(
1100-
datetime(2013, 1, 1, 12, tzinfo=pytz.utc),
1101-
datetime(2013, 1, 1, 13, tzinfo=pytz.utc),
1105+
datetime(2013, 1, 1, 12, tzinfo=timezone.utc),
1106+
datetime(2013, 1, 1, 13, tzinfo=timezone.utc),
11021107
),
11031108
),
11041109
(
11051110
# Hour with offset
11061111
"2013-01-01T12-07:00",
11071112
(
1108-
datetime(2013, 1, 1, 19, tzinfo=pytz.utc),
1109-
datetime(2013, 1, 1, 20, tzinfo=pytz.utc),
1113+
datetime(2013, 1, 1, 19, tzinfo=timezone.utc),
1114+
datetime(2013, 1, 1, 20, tzinfo=timezone.utc),
11101115
),
11111116
),
11121117
(
11131118
# Hour with implicit UTC
11141119
"2013-01-01T12",
11151120
(
1116-
datetime(2013, 1, 1, 12, tzinfo=pytz.utc),
1117-
datetime(2013, 1, 1, 13, tzinfo=pytz.utc),
1121+
datetime(2013, 1, 1, 12, tzinfo=timezone.utc),
1122+
datetime(2013, 1, 1, 13, tzinfo=timezone.utc),
11181123
),
11191124
),
11201125
(
11211126
# Interval with trailing zero fractional seconds should
11221127
# be accepted.
11231128
"2013-01-01T12:00:00.0/2013-01-01T12:30:00.000000",
11241129
(
1125-
datetime(2013, 1, 1, 12, tzinfo=pytz.utc),
1126-
datetime(2013, 1, 1, 12, 30, tzinfo=pytz.utc),
1130+
datetime(2013, 1, 1, 12, tzinfo=timezone.utc),
1131+
datetime(2013, 1, 1, 12, 30, tzinfo=timezone.utc),
11271132
),
11281133
),
11291134
]

0 commit comments

Comments
 (0)