Skip to content

Commit

Permalink
Replace pytz with zoneinfo / datetime.timezone (#622)
Browse files Browse the repository at this point in the history
* Replace pytz with zoneinfo / datetime.timezone

* Remove tzlocal from test requirements since it is unsued, add backports.zoneinfo for python 3.8

* Fix formatting
  • Loading branch information
foarsitter authored Nov 28, 2024
1 parent f1eeaa0 commit dbd6f0d
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 75 deletions.
1 change: 0 additions & 1 deletion examples/zoo_app/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ Jinja2==2.11.3
jsonschema==3.2.0
MarkupSafe==2.0.1
pyrsistent==0.17.3
pytz==2021.1
six==1.16.0
Werkzeug==2.2.3

23 changes: 11 additions & 12 deletions flask_restx/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,15 @@ def my_type(value):
import re
import socket

from datetime import datetime, time, timedelta
from datetime import datetime, time, timedelta, timezone
from email.utils import parsedate_tz, mktime_tz
from urllib.parse import urlparse

import aniso8601
import pytz

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


netloc_regex = re.compile(
Expand Down Expand Up @@ -338,11 +337,11 @@ def _normalize_interval(start, end, value):
end = datetime.combine(end, START_OF_DAY)

if start.tzinfo is None:
start = pytz.UTC.localize(start)
end = pytz.UTC.localize(end)
start = start.replace(tzinfo=timezone.utc)
end = end.replace(tzinfo=timezone.utc)
else:
start = start.astimezone(pytz.UTC)
end = end.astimezone(pytz.UTC)
start = start.astimezone(timezone.utc)
end = end.astimezone(timezone.utc)

return start, end

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

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

except ValueError:
except ValueError as e:
msg = (
"Invalid {arg}: {value}. {arg} must be a valid ISO8601 date/time interval."
)
raise ValueError(msg.format(arg=argument, value=value))
raise ValueError(msg.format(arg=argument, value=value)) from e

return start, end

Expand Down Expand Up @@ -559,9 +558,9 @@ def datetime_from_rfc822(value):
timetuple = parsedate_tz(value)
timestamp = mktime_tz(timetuple)
if timetuple[-1] is None:
return datetime.fromtimestamp(timestamp).replace(tzinfo=pytz.utc)
return datetime.fromtimestamp(timestamp).replace(tzinfo=timezone.utc)
else:
return datetime.fromtimestamp(timestamp, pytz.utc)
return datetime.fromtimestamp(timestamp, timezone.utc)
except Exception:
raise ValueError('Invalid date literal "{0}"'.format(raw))

Expand Down
1 change: 0 additions & 1 deletion requirements/install.pip
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ aniso8601>=0.82
jsonschema
Flask>=0.8, !=2.0.0
werkzeug!=2.0.0
pytz
importlib_resources
2 changes: 1 addition & 1 deletion requirements/test.pip
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pytest-cov==4.0.0
pytest-flask==1.3.0
pytest-mock==3.6.1
pytest-profiling==1.7.0
tzlocal
invoke==2.2.0
twine==3.8.0
setuptools
backports.zoneinfo;python_version<"3.9"
24 changes: 14 additions & 10 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
try:
import zoneinfo
except ImportError:
from backports import zoneinfo

from collections import OrderedDict
from datetime import date, datetime
from datetime import date, datetime, timezone
from decimal import Decimal
from functools import partial

import pytz
import pytest

from flask import Blueprint
Expand Down Expand Up @@ -538,11 +542,11 @@ def test_max_exclusive(self):
(datetime(2011, 1, 1), "Sat, 01 Jan 2011 00:00:00 -0000"),
(datetime(2011, 1, 1, 23, 59, 59), "Sat, 01 Jan 2011 23:59:59 -0000"),
(
datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.utc),
datetime(2011, 1, 1, 23, 59, 59, tzinfo=timezone.utc),
"Sat, 01 Jan 2011 23:59:59 -0000",
),
(
datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.timezone("CET")),
datetime(2011, 1, 1, 23, 59, 59, tzinfo=zoneinfo.ZoneInfo("CET")),
"Sat, 01 Jan 2011 22:59:59 -0000",
),
],
Expand All @@ -558,15 +562,15 @@ def test_rfc822_value(self, value, expected):
(datetime(2011, 1, 1, 23, 59, 59), "2011-01-01T23:59:59"),
(datetime(2011, 1, 1, 23, 59, 59, 1000), "2011-01-01T23:59:59.001000"),
(
datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.utc),
datetime(2011, 1, 1, 23, 59, 59, tzinfo=timezone.utc),
"2011-01-01T23:59:59+00:00",
),
(
datetime(2011, 1, 1, 23, 59, 59, 1000, tzinfo=pytz.utc),
datetime(2011, 1, 1, 23, 59, 59, 1000, tzinfo=timezone.utc),
"2011-01-01T23:59:59.001000+00:00",
),
(
datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.timezone("CET")),
datetime(2011, 1, 1, 23, 59, 59, tzinfo=zoneinfo.ZoneInfo("CET")),
"2011-01-01T23:59:59+01:00",
),
],
Expand Down Expand Up @@ -673,10 +677,10 @@ def test_max_exclusive(self):
(datetime(2011, 1, 1), "2011-01-01"),
(datetime(2011, 1, 1, 23, 59, 59), "2011-01-01"),
(datetime(2011, 1, 1, 23, 59, 59, 1000), "2011-01-01"),
(datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.utc), "2011-01-01"),
(datetime(2011, 1, 1, 23, 59, 59, 1000, tzinfo=pytz.utc), "2011-01-01"),
(datetime(2011, 1, 1, 23, 59, 59, tzinfo=timezone.utc), "2011-01-01"),
(datetime(2011, 1, 1, 23, 59, 59, 1000, tzinfo=timezone.utc), "2011-01-01"),
(
datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.timezone("CET")),
datetime(2011, 1, 1, 23, 59, 59, tzinfo=zoneinfo.ZoneInfo("CET")),
"2011-01-01",
),
],
Expand Down
105 changes: 55 additions & 50 deletions tests/test_inputs.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import re
import pytz
import pytest

from datetime import date, datetime
from datetime import date, datetime, timezone

from flask_restx import inputs

Expand Down Expand Up @@ -37,18 +36,18 @@ class Iso8601DatetimeTest(object):
"value,expected",
[
("2011-01-01", datetime(2011, 1, 1)),
("2011-01-01T00:00:00+00:00", datetime(2011, 1, 1, tzinfo=pytz.utc)),
("2011-01-01T00:00:00+00:00", datetime(2011, 1, 1, tzinfo=timezone.utc)),
(
"2011-01-01T23:59:59+00:00",
datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.utc),
datetime(2011, 1, 1, 23, 59, 59, tzinfo=timezone.utc),
),
(
"2011-01-01T23:59:59.001000+00:00",
datetime(2011, 1, 1, 23, 59, 59, 1000, tzinfo=pytz.utc),
datetime(2011, 1, 1, 23, 59, 59, 1000, tzinfo=timezone.utc),
),
(
"2011-01-01T23:59:59+02:00",
datetime(2011, 1, 1, 21, 59, 59, tzinfo=pytz.utc),
datetime(2011, 1, 1, 21, 59, 59, tzinfo=timezone.utc),
),
],
)
Expand All @@ -70,22 +69,28 @@ class Rfc822DatetimeTest(object):
@pytest.mark.parametrize(
"value,expected",
[
("Sat, 01 Jan 2011", datetime(2011, 1, 1, tzinfo=pytz.utc)),
("Sat, 01 Jan 2011 00:00", datetime(2011, 1, 1, tzinfo=pytz.utc)),
("Sat, 01 Jan 2011 00:00:00", datetime(2011, 1, 1, tzinfo=pytz.utc)),
("Sat, 01 Jan 2011 00:00:00 +0000", datetime(2011, 1, 1, tzinfo=pytz.utc)),
("Sat, 01 Jan 2011 00:00:00 -0000", datetime(2011, 1, 1, tzinfo=pytz.utc)),
("Sat, 01 Jan 2011", datetime(2011, 1, 1, tzinfo=timezone.utc)),
("Sat, 01 Jan 2011 00:00", datetime(2011, 1, 1, tzinfo=timezone.utc)),
("Sat, 01 Jan 2011 00:00:00", datetime(2011, 1, 1, tzinfo=timezone.utc)),
(
"Sat, 01 Jan 2011 00:00:00 +0000",
datetime(2011, 1, 1, tzinfo=timezone.utc),
),
(
"Sat, 01 Jan 2011 00:00:00 -0000",
datetime(2011, 1, 1, tzinfo=timezone.utc),
),
(
"Sat, 01 Jan 2011 23:59:59 -0000",
datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.utc),
datetime(2011, 1, 1, 23, 59, 59, tzinfo=timezone.utc),
),
(
"Sat, 01 Jan 2011 21:00:00 +0200",
datetime(2011, 1, 1, 19, 0, 0, tzinfo=pytz.utc),
datetime(2011, 1, 1, 19, 0, 0, tzinfo=timezone.utc),
),
(
"Sat, 01 Jan 2011 21:00:00 -0200",
datetime(2011, 1, 1, 23, 0, 0, tzinfo=pytz.utc),
datetime(2011, 1, 1, 23, 0, 0, tzinfo=timezone.utc),
),
],
)
Expand Down Expand Up @@ -985,145 +990,145 @@ def test_schema(self):
# Full precision with explicit UTC.
"2013-01-01T12:30:00Z/P1Y2M3DT4H5M6S",
(
datetime(2013, 1, 1, 12, 30, 0, tzinfo=pytz.utc),
datetime(2014, 3, 5, 16, 35, 6, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, 30, 0, tzinfo=timezone.utc),
datetime(2014, 3, 5, 16, 35, 6, tzinfo=timezone.utc),
),
),
(
# Full precision with alternate UTC indication
"2013-01-01T12:30+00:00/P2D",
(
datetime(2013, 1, 1, 12, 30, 0, tzinfo=pytz.utc),
datetime(2013, 1, 3, 12, 30, 0, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, 30, 0, tzinfo=timezone.utc),
datetime(2013, 1, 3, 12, 30, 0, tzinfo=timezone.utc),
),
),
(
# Implicit UTC with time
"2013-01-01T15:00/P1M",
(
datetime(2013, 1, 1, 15, 0, 0, tzinfo=pytz.utc),
datetime(2013, 1, 31, 15, 0, 0, tzinfo=pytz.utc),
datetime(2013, 1, 1, 15, 0, 0, tzinfo=timezone.utc),
datetime(2013, 1, 31, 15, 0, 0, tzinfo=timezone.utc),
),
),
(
# TZ conversion
"2013-01-01T17:00-05:00/P2W",
(
datetime(2013, 1, 1, 22, 0, 0, tzinfo=pytz.utc),
datetime(2013, 1, 15, 22, 0, 0, tzinfo=pytz.utc),
datetime(2013, 1, 1, 22, 0, 0, tzinfo=timezone.utc),
datetime(2013, 1, 15, 22, 0, 0, tzinfo=timezone.utc),
),
),
(
# Date upgrade to midnight-midnight period
"2013-01-01/P3D",
(
datetime(2013, 1, 1, 0, 0, 0, tzinfo=pytz.utc),
datetime(2013, 1, 4, 0, 0, 0, 0, tzinfo=pytz.utc),
datetime(2013, 1, 1, 0, 0, 0, tzinfo=timezone.utc),
datetime(2013, 1, 4, 0, 0, 0, 0, tzinfo=timezone.utc),
),
),
(
# Start/end with UTC
"2013-01-01T12:00:00Z/2013-02-01T12:00:00Z",
(
datetime(2013, 1, 1, 12, 0, 0, tzinfo=pytz.utc),
datetime(2013, 2, 1, 12, 0, 0, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, 0, 0, tzinfo=timezone.utc),
datetime(2013, 2, 1, 12, 0, 0, tzinfo=timezone.utc),
),
),
(
# Start/end with time upgrade
"2013-01-01/2013-06-30",
(
datetime(2013, 1, 1, tzinfo=pytz.utc),
datetime(2013, 6, 30, tzinfo=pytz.utc),
datetime(2013, 1, 1, tzinfo=timezone.utc),
datetime(2013, 6, 30, tzinfo=timezone.utc),
),
),
(
# Start/end with TZ conversion
"2013-02-17T12:00:00-07:00/2013-02-28T15:00:00-07:00",
(
datetime(2013, 2, 17, 19, 0, 0, tzinfo=pytz.utc),
datetime(2013, 2, 28, 22, 0, 0, tzinfo=pytz.utc),
datetime(2013, 2, 17, 19, 0, 0, tzinfo=timezone.utc),
datetime(2013, 2, 28, 22, 0, 0, tzinfo=timezone.utc),
),
),
( # Resolution expansion for single date(time)
# Second with UTC
"2013-01-01T12:30:45Z",
(
datetime(2013, 1, 1, 12, 30, 45, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, 30, 46, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, 30, 45, tzinfo=timezone.utc),
datetime(2013, 1, 1, 12, 30, 46, tzinfo=timezone.utc),
),
),
(
# Second with tz conversion
"2013-01-01T12:30:45+02:00",
(
datetime(2013, 1, 1, 10, 30, 45, tzinfo=pytz.utc),
datetime(2013, 1, 1, 10, 30, 46, tzinfo=pytz.utc),
datetime(2013, 1, 1, 10, 30, 45, tzinfo=timezone.utc),
datetime(2013, 1, 1, 10, 30, 46, tzinfo=timezone.utc),
),
),
(
# Second with implicit UTC
"2013-01-01T12:30:45",
(
datetime(2013, 1, 1, 12, 30, 45, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, 30, 46, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, 30, 45, tzinfo=timezone.utc),
datetime(2013, 1, 1, 12, 30, 46, tzinfo=timezone.utc),
),
),
(
# Minute with UTC
"2013-01-01T12:30+00:00",
(
datetime(2013, 1, 1, 12, 30, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, 31, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, 30, tzinfo=timezone.utc),
datetime(2013, 1, 1, 12, 31, tzinfo=timezone.utc),
),
),
(
# Minute with conversion
"2013-01-01T12:30+04:00",
(
datetime(2013, 1, 1, 8, 30, tzinfo=pytz.utc),
datetime(2013, 1, 1, 8, 31, tzinfo=pytz.utc),
datetime(2013, 1, 1, 8, 30, tzinfo=timezone.utc),
datetime(2013, 1, 1, 8, 31, tzinfo=timezone.utc),
),
),
(
# Minute with implicit UTC
"2013-01-01T12:30",
(
datetime(2013, 1, 1, 12, 30, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, 31, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, 30, tzinfo=timezone.utc),
datetime(2013, 1, 1, 12, 31, tzinfo=timezone.utc),
),
),
(
# Hour, explicit UTC
"2013-01-01T12Z",
(
datetime(2013, 1, 1, 12, tzinfo=pytz.utc),
datetime(2013, 1, 1, 13, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, tzinfo=timezone.utc),
datetime(2013, 1, 1, 13, tzinfo=timezone.utc),
),
),
(
# Hour with offset
"2013-01-01T12-07:00",
(
datetime(2013, 1, 1, 19, tzinfo=pytz.utc),
datetime(2013, 1, 1, 20, tzinfo=pytz.utc),
datetime(2013, 1, 1, 19, tzinfo=timezone.utc),
datetime(2013, 1, 1, 20, tzinfo=timezone.utc),
),
),
(
# Hour with implicit UTC
"2013-01-01T12",
(
datetime(2013, 1, 1, 12, tzinfo=pytz.utc),
datetime(2013, 1, 1, 13, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, tzinfo=timezone.utc),
datetime(2013, 1, 1, 13, tzinfo=timezone.utc),
),
),
(
# Interval with trailing zero fractional seconds should
# be accepted.
"2013-01-01T12:00:00.0/2013-01-01T12:30:00.000000",
(
datetime(2013, 1, 1, 12, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, 30, tzinfo=pytz.utc),
datetime(2013, 1, 1, 12, tzinfo=timezone.utc),
datetime(2013, 1, 1, 12, 30, tzinfo=timezone.utc),
),
),
]
Expand Down

0 comments on commit dbd6f0d

Please sign in to comment.