Skip to content

Replace pytz with zoneinfo / datetime.timezone #622

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading