From 94521d2b86745b7f0b768cdaad67f0b70aebb3c1 Mon Sep 17 00:00:00 2001 From: jo Date: Tue, 28 Mar 2023 20:13:28 +0200 Subject: [PATCH] feat(api): replace pytz with zoneinfo Part-of: --- api/funkwhale_api/audio/serializers.py | 9 ++++- api/funkwhale_api/federation/signing.py | 9 ++++- api/funkwhale_api/users/factories.py | 10 ++++- api/poetry.lock | 37 +++++++++++++++++-- api/pyproject.toml | 2 +- api/tests/audio/test_serializers.py | 13 +++++-- .../api-replace-pytz-zoneinfo.enhancement | 1 + 7 files changed, 66 insertions(+), 15 deletions(-) create mode 100644 changes/changelog.d/api-replace-pytz-zoneinfo.enhancement diff --git a/api/funkwhale_api/audio/serializers.py b/api/funkwhale_api/audio/serializers.py index 212d4ab78..3c830fd80 100644 --- a/api/funkwhale_api/audio/serializers.py +++ b/api/funkwhale_api/audio/serializers.py @@ -1,10 +1,10 @@ import datetime import logging +import sys import time import uuid import feedparser -import pytz import requests from django.conf import settings from django.db import transaction @@ -33,6 +33,11 @@ from funkwhale_api.users import serializers as users_serializers from . import categories, models +if sys.version_info < (3, 9): + from backports.zoneinfo import ZoneInfo +else: + from zoneinfo import ZoneInfo + logger = logging.getLogger(__name__) @@ -769,7 +774,7 @@ class RssFeedItemSerializer(serializers.Serializer): if "published_parsed" in validated_data: track_defaults["creation_date"] = datetime.datetime.fromtimestamp( time.mktime(validated_data["published_parsed"]) - ).replace(tzinfo=pytz.utc) + ).replace(tzinfo=ZoneInfo("UTC")) upload_defaults = { "source": validated_data["links"]["audio"]["source"], diff --git a/api/funkwhale_api/federation/signing.py b/api/funkwhale_api/federation/signing.py index ccac03045..1706e5215 100644 --- a/api/funkwhale_api/federation/signing.py +++ b/api/funkwhale_api/federation/signing.py @@ -1,8 +1,8 @@ import datetime import logging +import sys import cryptography.exceptions -import pytz import requests import requests_http_message_signatures from django import forms @@ -11,6 +11,11 @@ from django.utils.http import parse_http_date from . import exceptions, utils +if sys.version_info < (3, 9): + from backports.zoneinfo import ZoneInfo +else: + from zoneinfo import ZoneInfo + logger = logging.getLogger(__name__) # the request Date should be between now - 30s and now + 30s @@ -26,7 +31,7 @@ def verify_date(raw_date): except ValueError as e: raise forms.ValidationError(str(e)) dt = datetime.datetime.utcfromtimestamp(ts) - dt = dt.replace(tzinfo=pytz.utc) + dt = dt.replace(tzinfo=ZoneInfo("UTC")) delta = datetime.timedelta(seconds=DATE_HEADER_VALID_FOR) now = timezone.now() if dt < now - delta or dt > now + delta: diff --git a/api/funkwhale_api/users/factories.py b/api/funkwhale_api/users/factories.py index e8b785bb5..aa1ab4ca5 100644 --- a/api/funkwhale_api/users/factories.py +++ b/api/funkwhale_api/users/factories.py @@ -1,5 +1,6 @@ +import sys + import factory -import pytz from django.contrib.auth.models import Permission from django.utils import timezone @@ -7,6 +8,11 @@ from funkwhale_api.factories import ManyToManyFromList, NoUpdateOnCreate, regist from . import models +if sys.version_info < (3, 9): + from backports.zoneinfo import ZoneInfo +else: + from zoneinfo import ZoneInfo + @registry.register class GroupFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory): @@ -159,7 +165,7 @@ class GrantFactory(factory.django.DjangoModelFactory): class AccessTokenFactory(factory.django.DjangoModelFactory): application = factory.SubFactory(ApplicationFactory) user = factory.SubFactory(UserFactory) - expires = factory.Faker("future_datetime", tzinfo=pytz.UTC) + expires = factory.Faker("future_datetime", tzinfo=ZoneInfo("UTC")) token = factory.Faker("uuid4") scope = "read" diff --git a/api/poetry.lock b/api/poetry.lock index 6bfe98f47..627c34bed 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -339,6 +339,35 @@ files = [ {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, ] +[[package]] +name = "backports-zoneinfo" +version = "0.2.1" +description = "Backport of the standard library zoneinfo module" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, + {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, +] + +[package.extras] +tzdata = ["tzdata"] + [[package]] name = "billiard" version = "3.6.4.0" @@ -2960,14 +2989,14 @@ postgresql = ["psycopg2"] [[package]] name = "pytz" -version = "2022.7.1" +version = "2023.2" description = "World timezone definitions, modern and historical" category = "main" optional = false python-versions = "*" files = [ - {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"}, - {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"}, + {file = "pytz-2023.2-py2.py3-none-any.whl", hash = "sha256:8a8baaf1e237175b02f5c751eea67168043a749c843989e2b3015aa1ad9db68b"}, + {file = "pytz-2023.2.tar.gz", hash = "sha256:a27dcf612c05d2ebde626f7d506555f10dfc815b3eddccfaadfc7d99b11c9a07"}, ] [[package]] @@ -3958,4 +3987,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "6578026fa272d13314b955b48dd4c68b23dabff14071396b48204fbd94262cc8" +content-hash = "6ec584e732f6c471c47086a5a8605610f9a52986bc3b0591fa1f3122c7ad1f7d" diff --git a/api/pyproject.toml b/api/pyproject.toml index 764f848f3..9f78e6602 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -68,6 +68,7 @@ uvicorn = { version = "==0.20.0", extras = ["standard"] } # Libs aiohttp = "==3.8.4" arrow = "==1.2.3" +backports-zoneinfo = { version = "==0.2.1", python = "<3.9" } bleach = "==5.0.1" boto3 = "==1.26.99" click = "==8.1.3" @@ -79,7 +80,6 @@ pillow = "==9.3.0" pydub = "==0.25.1" pyld = "==2.0.3" python-magic = "==0.4.27" -pytz = "==2022.7.1" requests = "==2.28.2" requests-http-message-signatures = "==0.3.1" sentry-sdk = "==1.12.1" diff --git a/api/tests/audio/test_serializers.py b/api/tests/audio/test_serializers.py index 9101e60b3..cdd3a3226 100644 --- a/api/tests/audio/test_serializers.py +++ b/api/tests/audio/test_serializers.py @@ -1,9 +1,9 @@ import datetime +import sys import uuid import feedparser import pytest -import pytz from django.templatetags.static import static from django.urls import reverse @@ -14,6 +14,11 @@ from funkwhale_api.federation import actors from funkwhale_api.federation import serializers as federation_serializers from funkwhale_api.federation import utils as federation_utils +if sys.version_info < (3, 9): + from backports.zoneinfo import ZoneInfo +else: + from zoneinfo import ZoneInfo + def test_channel_serializer_create(factories, mocker): attributed_to = factories["federation.Actor"](local=True) @@ -456,7 +461,7 @@ def test_rss_duration(seconds, expected): "dt, expected", [ ( - datetime.datetime(2020, 1, 30, 6, 0, 49, tzinfo=pytz.UTC), + datetime.datetime(2020, 1, 30, 6, 0, 49, tzinfo=ZoneInfo("UTC")), "Thu, 30 Jan 2020 06:00:49 +0000", ), ], @@ -678,7 +683,7 @@ def test_rss_feed_item_serializer_create(factories): assert upload.track.position == 33 assert upload.track.disc_number == 2 assert upload.track.creation_date == datetime.datetime(2020, 3, 11, 16).replace( - tzinfo=pytz.utc + tzinfo=ZoneInfo("UTC") ) assert upload.track.get_tags() == ["pop", "rock"] assert upload.track.attachment_cover.url == "https://image.url/" @@ -748,7 +753,7 @@ def test_rss_feed_item_serializer_update(factories): assert upload.track.position == 33 assert upload.track.disc_number == 2 assert upload.track.creation_date == datetime.datetime(2020, 3, 11, 16).replace( - tzinfo=pytz.utc + tzinfo=ZoneInfo("UTC") ) assert upload.track.get_tags() == ["pop", "rock"] assert upload.track.attachment_cover.url == "https://image.url/" diff --git a/changes/changelog.d/api-replace-pytz-zoneinfo.enhancement b/changes/changelog.d/api-replace-pytz-zoneinfo.enhancement new file mode 100644 index 000000000..1a02d809f --- /dev/null +++ b/changes/changelog.d/api-replace-pytz-zoneinfo.enhancement @@ -0,0 +1 @@ +Replace pytz with zoneinfo in the API