diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 143caa1..cb93e81 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,10 +6,13 @@ jobs: strategy: matrix: python-version: ['3.8', '3.9', '3.10', '3.11'] - django-version: ['3.2', '4.0', '4.1'] + django-version: ['3.2', '4.1', '4.2'] include: - python-version: 3.7 django-version: 3.2 + exclude: + - python-version: 3.11 + django-version: 3.2 fail-fast: false steps: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index adb8393..a37d6dc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: end-of-file-fixer - id: trailing-whitespace @@ -12,13 +12,13 @@ repos: args: ["--profile", "black"] - repo: https://github.com/psf/black - rev: 23.1.0 + rev: 23.9.1 hooks: - id: black args: [--target-version=py310] - repo: https://github.com/pycqa/flake8 - rev: '6.0.0' + rev: '6.1.0' hooks: - id: flake8 additional_dependencies: diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 98eba14..8a77ee1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,8 @@ Changelog ========= +* Unreleased + * Use ``Image.Resampling.LANCZOS`` instead of ``Image.LANCZOS`` that was removed in Pillow 10.0.0 + * 7.1.1 (February 23, 2023) * Switch to setuptools for building diff --git a/avatar/admin.py b/avatar/admin.py index 55ad544..9425ef3 100644 --- a/avatar/admin.py +++ b/avatar/admin.py @@ -17,14 +17,12 @@ class AvatarAdmin(admin.ModelAdmin): list_per_page = 50 def get_avatar(self, avatar_in): - context = dict( - { - "user": avatar_in.user, - "url": avatar_in.avatar.url, - "alt": str(avatar_in.user), - "size": 80, - } - ) + context = { + "user": avatar_in.user, + "url": avatar_in.avatar.url, + "alt": str(avatar_in.user), + "size": 80, + } return render_to_string("avatar/avatar_tag.html", context) get_avatar.short_description = _("Avatar") diff --git a/avatar/conf.py b/avatar/conf.py index caf3da9..a29cec6 100644 --- a/avatar/conf.py +++ b/avatar/conf.py @@ -5,7 +5,7 @@ from PIL import Image class AvatarConf(AppConf): DEFAULT_SIZE = 80 - RESIZE_METHOD = Image.LANCZOS + RESIZE_METHOD = Image.Resampling.LANCZOS STORAGE_DIR = "avatars" PATH_HANDLER = "avatar.models.avatar_path_handler" GRAVATAR_BASE_URL = "https://www.gravatar.com/avatar/" diff --git a/avatar/templates/avatar/add.html b/avatar/templates/avatar/add.html index 9b4fed6..b5214fa 100644 --- a/avatar/templates/avatar/add.html +++ b/avatar/templates/avatar/add.html @@ -7,7 +7,7 @@ {% if not avatars %}

{% trans "You haven't uploaded an avatar yet. Please upload one now." %}

{% endif %} -
+ {{ upload_avatar_form.as_p }}

{% csrf_token %}

diff --git a/avatar/templates/avatar/change.html b/avatar/templates/avatar/change.html index 8d27359..444015a 100644 --- a/avatar/templates/avatar/change.html +++ b/avatar/templates/avatar/change.html @@ -7,14 +7,14 @@ {% if not avatars %}

{% trans "You haven't uploaded an avatar yet. Please upload one now." %}

{% else %} -
+

{% csrf_token %}

{% endif %} -
+ {{ upload_avatar_form.as_p }}

{% csrf_token %}

diff --git a/avatar/templates/avatar/confirm_delete.html b/avatar/templates/avatar/confirm_delete.html index aad11a9..dfb4626 100644 --- a/avatar/templates/avatar/confirm_delete.html +++ b/avatar/templates/avatar/confirm_delete.html @@ -7,7 +7,7 @@

{% blocktrans %}You have no avatars to delete. Please upload one now.{% endblocktrans %}

{% else %}

{% trans "Please select the avatars that you would like to delete." %}

-
+ diff --git a/avatar/templatetags/avatar_tags.py b/avatar/templatetags/avatar_tags.py index 59b4b8b..2c7e392 100644 --- a/avatar/templatetags/avatar_tags.py +++ b/avatar/templatetags/avatar_tags.py @@ -94,7 +94,7 @@ def primary_avatar(user, width=settings.AVATAR_DEFAULT_SIZE, height=None): else: kwargs["height"] = height - url = reverse("avatar_render_primary", kwargs=kwargs) + url = reverse("avatar:render_primary", kwargs=kwargs) return """%s""" % ( url, width, diff --git a/avatar/urls.py b/avatar/urls.py index 9a043f8..12f7472 100644 --- a/avatar/urls.py +++ b/avatar/urls.py @@ -1,19 +1,24 @@ -from django.urls import re_path +from django.urls import path from avatar import views +# For reversing namespaced urls +# https://docs.djangoproject.com/en/4.1/topics/http/urls/#reversing-namespaced-urls +app_name = "avatar" + urlpatterns = [ - re_path(r"^add/$", views.add, name="avatar_add"), - re_path(r"^change/$", views.change, name="avatar_change"), - re_path(r"^delete/$", views.delete, name="avatar_delete"), - re_path( - r"^render_primary/(?P[\w\d\@\.\-_]+)/(?P[\d]+)/$", + path("add/", views.add, name="add"), + path("change/", views.change, name="change"), + path("delete/", views.delete, name="delete"), + # https://docs.djangoproject.com/en/4.1/topics/http/urls/#path-converters + path( + "render_primary///", views.render_primary, - name="avatar_render_primary", + name="render_primary", ), - re_path( - r"^render_primary/(?P[\w\d\@\.\-_]+)/(?P[\d]+)/(?P[\d]+)/$", + path( + "render_primary////", views.render_primary, - name="avatar_render_primary", + name="render_primary", ), ] diff --git a/docs/index.txt b/docs/index.txt index 4309714..3de6484 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -211,7 +211,7 @@ appear on the site. Listed below are those settings: .. py:data:: AVATAR_RESIZE_METHOD The method to use when resizing images, based on the options available in - Pillow. Defaults to ``Image.LANCZOS``. + Pillow. Defaults to ``Image.Resampling.LANCZOS``. .. py:data:: AVATAR_STORAGE_DIR diff --git a/pyproject.toml b/pyproject.toml index 66bcc54..4a34c61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,16 +17,16 @@ classifiers=[ "Intended Audience :: Developers", "Framework :: Django", "Framework :: Django :: 3.2", - "Framework :: Django :: 4.0", "Framework :: Django :: 4.1", + "Framework :: Django :: 4.2", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", ] dynamic = ["version", "dependencies"] diff --git a/requirements.txt b/requirements.txt index ff2aef2..9752ac4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -Pillow>=8.4.0 +Pillow>=9.3.0 django-appconf>=1.0.5 dnspython>=2.3.0 diff --git a/tests/requirements.txt b/tests/requirements.txt index c326a12..f13bf22 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,3 +1,3 @@ -coverage==7.1.0 +coverage~=7.1.0 django python-magic diff --git a/tests/tests.py b/tests/tests.py index 79d6874..742e816 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -43,7 +43,7 @@ class AssertSignal: def upload_helper(o, filename): f = open(os.path.join(o.testdatapath, filename), "rb") response = o.client.post( - reverse("avatar_add"), + reverse("avatar:add"), { "avatar": f, }, @@ -165,7 +165,7 @@ class AvatarTests(TestCase): def test_default_url(self): response = self.client.get( reverse( - "avatar_render_primary", + "avatar:render_primary", kwargs={ "user": self.user.username, "width": 80, @@ -196,7 +196,7 @@ class AvatarTests(TestCase): receiver = AssertSignal() avatar_deleted.connect(receiver) response = self.client.post( - reverse("avatar_delete"), + reverse("avatar:delete"), { "choices": [avatar[0].id], }, @@ -216,7 +216,7 @@ class AvatarTests(TestCase): primary = get_primary_avatar(self.user) oid = primary.id self.client.post( - reverse("avatar_delete"), + reverse("avatar:delete"), { "choices": [oid], }, @@ -229,7 +229,7 @@ class AvatarTests(TestCase): def test_change_avatar_get(self): self.test_normal_image_upload() - response = self.client.get(reverse("avatar_change")) + response = self.client.get(reverse("avatar:change")) self.assertEqual(response.status_code, 200) self.assertIsNotNone(response.context["avatar"]) @@ -239,7 +239,7 @@ class AvatarTests(TestCase): old_primary = Avatar.objects.get(user=self.user, primary=True) choice = Avatar.objects.filter(user=self.user, primary=False)[0] response = self.client.post( - reverse("avatar_change"), + reverse("avatar:change"), { "choice": choice.pk, },