diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 596e61c81..c9780a981 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,7 @@ jobs: strategy: matrix: python-version: ["3.12"] - django-version: ["django42"] + django-version: ["django42", "django52"] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 diff --git a/credentials/apps/api/v2/decorators.py b/credentials/apps/api/v2/decorators.py index 97a10aa47..fb63a1439 100644 --- a/credentials/apps/api/v2/decorators.py +++ b/credentials/apps/api/v2/decorators.py @@ -26,7 +26,7 @@ def wrapper(*args, **kwargs): data = request.body logger.info( f"{request.method} request received to endpoint [{request.get_full_path()}] from user " - f"[{request.user.username}] originating from [{request.META.get('HTTP_HOST', 'Unknown')}] " + f"[{request.user.username}] originating from [{request.headers.get('host', 'Unknown')}] " f"with data: [{data}]" ) except Exception as exc: diff --git a/credentials/apps/api/v2/tests/test_serializers.py b/credentials/apps/api/v2/tests/test_serializers.py index b64e82cec..8e87e647f 100644 --- a/credentials/apps/api/v2/tests/test_serializers.py +++ b/credentials/apps/api/v2/tests/test_serializers.py @@ -1,12 +1,11 @@ from collections import namedtuple -from datetime import datetime from logging import WARNING from uuid import uuid4 import ddt -import pytz from django.test import TestCase from django.urls import reverse +from django.utils import timezone from rest_framework.exceptions import ValidationError from rest_framework.settings import api_settings from rest_framework.test import APIRequestFactory @@ -203,8 +202,7 @@ def test_to_representation(self): def test_to_internal_value(self): Request = namedtuple("Request", ["site"]) serializer = UserGradeSerializer(context={"request": Request(site=self.site)}) - updated_at_dt = datetime.now() - updated_at_utc = updated_at_dt.replace(tzinfo=pytz.UTC) + updated_at_utc = timezone.now() data = { "username": "alice", diff --git a/credentials/apps/api/v2/tests/test_views.py b/credentials/apps/api/v2/tests/test_views.py index d39edef38..e8df1226a 100644 --- a/credentials/apps/api/v2/tests/test_views.py +++ b/credentials/apps/api/v2/tests/test_views.py @@ -1,14 +1,13 @@ -import datetime import json from decimal import Decimal from unittest import mock import ddt -import pytz from django.contrib.auth.models import Permission from django.core.exceptions import ObjectDoesNotExist from django.test import TestCase from django.urls import reverse +from django.utils import timezone from rest_framework.renderers import JSONRenderer from rest_framework.test import APIRequestFactory, APITestCase from testfixtures import LogCapture @@ -597,8 +596,7 @@ def test_upgrade_with_lms_last_updated_at_data(self): self.add_user_permission(self.user, "add_usergrade") # simulate updating the existing record with the new field in the data - dt = datetime.datetime.now() - last_updated_at = dt.replace(tzinfo=pytz.UTC) + last_updated_at = timezone.now() data = self.serialize_user_grade(grade) data["lms_last_updated_at"] = last_updated_at response = self.client.post(self.list_path, data=JSONRenderer().render(data), content_type=JSON_CONTENT_TYPE) diff --git a/credentials/apps/badges/admin.py b/credentials/apps/badges/admin.py index 3ee41a2fc..705675881 100644 --- a/credentials/apps/badges/admin.py +++ b/credentials/apps/badges/admin.py @@ -318,6 +318,7 @@ def delete_queryset(self, request, queryset): return super().delete_queryset(request, queryset) + @admin.display(description=_("icon")) def image(self, obj): """ Badge template preview image. @@ -326,8 +327,6 @@ def image(self, obj): return format_html('', obj.icon) return None - image.short_description = _("icon") - def save_model(self, request, obj, form, change): pass @@ -391,6 +390,7 @@ class BadgeRequirementAdmin(admin.ModelAdmin): def has_add_permission(self, request): return False + @admin.display(description=_("badge template")) def template_link(self, instance): """ Interactive link to parent (badge template). @@ -401,8 +401,6 @@ def template_link(self, instance): url = reverse(reverse_name, args=reverse_args) return format_html('{}', url, instance.template) - template_link.short_description = _("badge template") - def response_change(self, request, obj): if "_save" in request.POST: reverse_name = ADMIN_CHANGE_VIEW_REVERSE_NAMES.get(obj.template.origin, "admin:index") @@ -453,6 +451,7 @@ class BadgePenaltyAdmin(admin.ModelAdmin): def has_add_permission(self, request): return False + @admin.display(description=_("badge template")) def template_link(self, instance): """ Interactive link to parent (badge template). @@ -462,8 +461,6 @@ def template_link(self, instance): url = reverse(reverse_name, args=reverse_args) return format_html('{}', url, instance.template) - template_link.short_description = _("badge template") - def formfield_for_manytomany(self, db_field, request, **kwargs): if db_field.name == "requirements": object_id = request.resolver_match.kwargs.get("object_id") diff --git a/credentials/apps/catalog/tests/factories.py b/credentials/apps/catalog/tests/factories.py index a486bc552..57f224dec 100644 --- a/credentials/apps/catalog/tests/factories.py +++ b/credentials/apps/catalog/tests/factories.py @@ -2,12 +2,11 @@ Factories for tests of Credentials. """ -import datetime from uuid import uuid4 import factory +from django.utils.timezone import datetime, timezone from factory.fuzzy import FuzzyDateTime, FuzzyInteger, FuzzyText -from pytz import UTC from slugify import slugify from credentials.apps.catalog.data import PathwayStatus @@ -55,8 +54,8 @@ class Meta: uuid = factory.LazyFunction(uuid4) key = FuzzyText(prefix="course-run-id/", suffix="/fake") title_override = None - start_date = FuzzyDateTime(datetime.datetime(2014, 1, 1, tzinfo=UTC)) - end_date = FuzzyDateTime(datetime.datetime(2014, 1, 1, tzinfo=UTC)).end_dt + start_date = FuzzyDateTime(datetime(2014, 1, 1, tzinfo=timezone.utc)) + end_date = FuzzyDateTime(datetime(2014, 1, 1, tzinfo=timezone.utc)).end_dt class ProgramFactory(factory.django.DjangoModelFactory): diff --git a/credentials/settings/base.py b/credentials/settings/base.py index 620e9b7c1..d95f88cad 100644 --- a/credentials/settings/base.py +++ b/credentials/settings/base.py @@ -230,13 +230,9 @@ TIME_ZONE = "UTC" TIME_ZONE_CLASS = timezone.utc -# https://docs.djangoproject.com/en/4.2/releases/4.0/#zoneinfo-default-timezone-implementation -USE_DEPRECATED_PYTZ = True USE_I18N = True -USE_L10N = True - USE_TZ = True LOCALE_PATHS = (root("conf", "locale"),) diff --git a/credentials/urls.py b/credentials/urls.py index 615e563b5..2906694e6 100644 --- a/credentials/urls.py +++ b/credentials/urls.py @@ -78,7 +78,7 @@ if is_badges_enabled(): urlpatterns += [ - re_path(r"^badges/", include(("credentials.apps.badges.urls", "badges"), namespace="badges")), + path("badges/", include(("credentials.apps.badges.urls", "badges"), namespace="badges")), ] # edx-drf-extensions csrf app diff --git a/tox.ini b/tox.ini index 2b1eb6713..4fbf9e18e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py{3.12}-django{42} +envlist = py{3.12}-django{42,52} skipsdist = true [pytest] @@ -9,6 +9,7 @@ testpaths = credentials/apps [testenv] deps = django42: -r requirements/django.txt + django52: Django>=5.2,<5.3 -r {toxinidir}/requirements/test.txt allowlist_externals: make