From 1a57b0d73be32769b681866447ec34fe9b51c3f4 Mon Sep 17 00:00:00 2001 From: Chander Ganesan Date: Thu, 18 Jan 2024 14:00:39 -0500 Subject: [PATCH] Support for Django 5.0 * Update authors * Remove Python 3.7 from the docs test for * Update the cookbook.rst file to store the inlines as a list consistently * switch the docs so we don't have a version issue * exclude python 3.6 for django 5 * Remove CryptPasswordHasher for django versions greater than 4.2 * remove 3.9/django 5 combo * Refactor code to properly use datetime.timezone.utc rather than the deprecated django.utils.timezone.utc * add in compat functionality to monkey-patch timezone to have a utc attribute/alias --- .github/workflows/python-package.yml | 10 ++++++++- AUTHORS | 2 +- README.rst | 2 +- docs/cookbook.rst | 2 +- tastypie/compat.py | 13 ++++++++++- tastypie/fields.py | 2 +- tastypie/utils/timezone.py | 2 +- tests/core/tests/resources.py | 3 ++- tests/settings.py | 9 ++++++-- tox.ini | 33 +++++++++++++++------------- 10 files changed, 53 insertions(+), 25 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 3cd989ff9..5d27b01b6 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -16,7 +16,7 @@ jobs: fail-fast: false matrix: python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] - django-version: ["3.2", "4.0", "4.1", "4.2"] # Todo: add "dev" back + django-version: ["3.2", "4.0", "4.1", "4.2", "5.0"] # Todo: add "dev" back exclude: - python-version: "3.6" django-version: "4.0" @@ -30,6 +30,14 @@ jobs: django-version: "4.2" - python-version: "3.7" django-version: "4.2" + - python-version: "3.6" + django-version: "5.0" + - python-version: "3.7" + django-version: "5.0" + - python-version: "3.8" + django-version: "5.0" + - python-version: "3.9" + django-version: "5.0" # - python-version: "3.6" # django-version: "dev" # - python-version: "3.7" diff --git a/AUTHORS b/AUTHORS index 98a1d989e..466f4dc6b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -105,7 +105,7 @@ Contributors: * Matt Briançon (mattbriancon) for various patches * Blayze Wilhelm (blayzen-w) for a small patch that fixed an issue with saving (PR #1628) * Ryan Young (ryanneilyoung) for removing python 2 code -* Chander Ganesan (chander) for minor patches +* Chander Ganesan (chander) for minor patches, added support for django 4.1 and 5.0 Thanks to Tav for providing validate_jsonp.py, placed in public domain. diff --git a/README.rst b/README.rst index a87cdd7bd..4afc352bf 100644 --- a/README.rst +++ b/README.rst @@ -35,7 +35,7 @@ Core ---- * Python 3.6+, preferably 3.8+ (Whatever is supported by your version of Django) -* Django 4.2, 3.2 (LTS releases), or Django 4.0 / 4.1 (intermediate releases) +* Django 4.2, 3.2 (LTS releases), or Django 4.0, 4.1, and 5.0 (intermediate releases) * dateutil (http://labix.org/python-dateutil) >= 2.1 Format Support diff --git a/docs/cookbook.rst b/docs/cookbook.rst index a7d6c4884..bc3d52078 100644 --- a/docs/cookbook.rst +++ b/docs/cookbook.rst @@ -91,7 +91,7 @@ modifying ``get_object_list``: .. testcode:: - from django.utils import timezone + from tastypie.compat import timezone from myapp.models import MyModel diff --git a/tastypie/compat.py b/tastypie/compat.py index 95e80ba27..6e9bd7cf5 100644 --- a/tastypie/compat.py +++ b/tastypie/compat.py @@ -1,6 +1,7 @@ import django from django.conf import settings from django.contrib.auth import get_user_model # noqa +from django.utils import timezone try: from django.urls import NoReverseMatch, reverse, Resolver404, get_script_prefix # noqa @@ -15,6 +16,17 @@ else: from django.middleware.csrf import _check_token_format +# Django 5.0 eliminated the former datetime_safe function, this provides +# some level of backwards compatability for existing tastypie use cases +if django.VERSION < (5, 0): + from django.utils import datetime_safe # noqa: F401 +else: + import datetime as datetime_safe # noqa: F401 + # Django 5.0 removed this alias - restore it for backwards compatability. + # Django 5.0 essentially completed a lot of the move to zoneinfo, prior to that + # this was an alias that was added in 4.0. + timezone.utc = datetime_safe.timezone.utc + AUTH_USER_MODEL = settings.AUTH_USER_MODEL @@ -74,7 +86,6 @@ def compare_sanitized_tokens(request_csrf_token, csrf_token): return constant_time_compare(_unsalt_cipher_token(request_csrf_token), _unsalt_cipher_token(csrf_token)) - class InvalidTokenFormat(Exception): # noqa pass except ImportError: # pragma: no cover diff --git a/tastypie/fields.py b/tastypie/fields.py index 5711f18a4..cb91d88ed 100644 --- a/tastypie/fields.py +++ b/tastypie/fields.py @@ -12,7 +12,7 @@ except ImportError: from django.db.models.fields.related_descriptors import\ ReverseOneToOneDescriptor -from django.utils import datetime_safe +from tastypie.compat import datetime_safe from tastypie.bundle import Bundle from tastypie.exceptions import ApiFieldError, NotFound diff --git a/tastypie/utils/timezone.py b/tastypie/utils/timezone.py index 81305147f..97a9fb1d8 100644 --- a/tastypie/utils/timezone.py +++ b/tastypie/utils/timezone.py @@ -1,6 +1,6 @@ import datetime +from tastypie.compat import timezone from django.conf import settings -from django.utils import timezone def make_aware(value): diff --git a/tests/core/tests/resources.py b/tests/core/tests/resources.py index 3f81ce5a2..2f9287b49 100644 --- a/tests/core/tests/resources.py +++ b/tests/core/tests/resources.py @@ -24,7 +24,8 @@ from django.http import HttpRequest, QueryDict, Http404 from django.test import TestCase from django.test.utils import override_settings -from django.utils import timezone + +from tastypie.compat import timezone from tastypie.authentication import BasicAuthentication from tastypie.authorization import Authorization diff --git a/tests/settings.py b/tests/settings.py index 68eda5072..b7eaf0728 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -12,6 +12,7 @@ DJANGO_11 = StrictVersion('1.11') DJANGO_19 = StrictVersion('1.9') DJANGO_18 = StrictVersion('1.8') +DJANGO_42 = StrictVersion('4.2') sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) @@ -54,14 +55,18 @@ SECRET_KEY = 'verysecret' # weaker password hashing shoulod allow for faster tests -PASSWORD_HASHERS = ( +PASSWORD_HASHERS = [ 'django.contrib.auth.hashers.CryptPasswordHasher', 'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher', 'django.contrib.auth.hashers.SHA1PasswordHasher', 'django.contrib.auth.hashers.MD5PasswordHasher', -) +] +# Django 5.0 removed this hasher +if DJANGO_VERSION > DJANGO_42: + PASSWORD_HASHERS.remove('django.contrib.auth.hashers.CryptPasswordHasher') + LOGGING = { 'version': 1, diff --git a/tox.ini b/tox.ini index 41cf6f862..6d6f04cbf 100644 --- a/tox.ini +++ b/tox.ini @@ -2,6 +2,7 @@ envlist = py{3.6,3.7,3.8,3.9,3.10}-dj{3.2,} py{3.8,3.9,3.10,3.11}-dj{4.0,4.1,4.2,dev} + py{3.9,3.10,3.11}-dj{5.0} py{3.6,3.7,3.8,3.9,3.10,3.11}-docs, py{3.6,3.7,3.8,3.9,3.10,3.11}-flake8, py{3.8,3.9,3.10,3.11}-flake8-strict @@ -14,20 +15,20 @@ setenv = PYTHONPATH = {toxinidir}:{toxinidir}/tests PYTHONWARNINGS = always TESTEXE = {envbindir}/coverage run --append --source=tastypie,tests {envbindir}/django-admin.py - dj{4.0,4.1,4.2,dev}: TESTEXE = {envbindir}/coverage run --append --source=tastypie,tests {envbindir}/django-admin + dj{4.0,4.1,4.2,5.0,dev}: TESTEXE = {envbindir}/coverage run --append --source=tastypie,tests {envbindir}/django-admin commands = - dj{3.2,4.0,4.1,4.2,dev}: {env:TESTEXE} test -p '*' core.tests --settings=settings_core - dj{3.2,4.0,4.1,4.2,dev}: {env:TESTEXE} test basic.tests --settings=settings_basic - dj{3.2,4.0,4.1,4.2,dev}: {env:TESTEXE} test related_resource.tests --settings=settings_related - dj{3.2,4.0,4.1,4.2,dev}: {env:TESTEXE} test alphanumeric.tests --settings=settings_alphanumeric - dj{3.2,4.0,4.1,4.2,dev}: {env:TESTEXE} test authorization.tests --settings=settings_authorization - dj{3.2,4.0,4.1,4.2,dev}: {env:TESTEXE} test content_gfk.tests --settings=settings_content_gfk - dj{3.2,4.0,4.1,4.2,dev}: {env:TESTEXE} test customuser.tests --settings=settings_customuser - dj{3.2,4.0,4.1,4.2,dev}: {env:TESTEXE} test namespaced.tests --settings=settings_namespaced - dj{3.2,4.0,4.1,4.2,dev}: {env:TESTEXE} test slashless.tests --settings=settings_slashless - dj{3.2,4.0,4.1,4.2,dev}: {env:TESTEXE} test validation.tests --settings=settings_validation - dj{3.2,4.0,4.1,4.2,dev}: {env:TESTEXE} test gis.tests --settings=settings_gis_spatialite + dj{3.2,4.0,4.1,4.2,5.0,dev}: {env:TESTEXE} test -p '*' core.tests --settings=settings_core + dj{3.2,4.0,4.1,4.2,5.0,dev}: {env:TESTEXE} test basic.tests --settings=settings_basic + dj{3.2,4.0,4.1,4.2,5.0,dev}: {env:TESTEXE} test related_resource.tests --settings=settings_related + dj{3.2,4.0,4.1,4.2,5.0,dev}: {env:TESTEXE} test alphanumeric.tests --settings=settings_alphanumeric + dj{3.2,4.0,4.1,4.2,5.0,dev}: {env:TESTEXE} test authorization.tests --settings=settings_authorization + dj{3.2,4.0,4.1,4.2,5.0,dev}: {env:TESTEXE} test content_gfk.tests --settings=settings_content_gfk + dj{3.2,4.0,4.1,4.2,5.0,dev}: {env:TESTEXE} test customuser.tests --settings=settings_customuser + dj{3.2,4.0,4.1,4.2,5.0,dev}: {env:TESTEXE} test namespaced.tests --settings=settings_namespaced + dj{3.2,4.0,4.1,4.2,5.0,dev}: {env:TESTEXE} test slashless.tests --settings=settings_slashless + dj{3.2,4.0,4.1,4.2,5.0,dev}: {env:TESTEXE} test validation.tests --settings=settings_validation + dj{3.2,4.0,4.1,4.2,5.0,dev}: {env:TESTEXE} test gis.tests --settings=settings_gis_spatialite docs: sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html docs: sphinx-build -W -b doctest -d {envtmpdir}/doctrees . {envtmpdir}/html @@ -47,14 +48,16 @@ deps = dj4.0: Django>=4.0,<4.1 dj4.1: Django>=4.1,<4.2 dj4.2: Django>=4.2,<4.3 + dj5.0: Django>=5.0,<5.1 djdev: https://github.com/django/django/archive/refs/heads/main.zip dj{3.2,4.0,4.1,4.2,dev}: python3-digest>=1.8b4 - dj{3.2,4.0,4.1,4.2,dev}: -r{toxinidir}/tests/requirements.txt - dj{3.2,4.0,4.1,4.2,dev}: -r{toxinidir}/requirements.txt + dj{3.2,4.0,4.1,4.2,5.0,dev}: -r{toxinidir}/tests/requirements.txt + dj{3.2,4.0,4.1,4.2,5.0,dev}: -r{toxinidir}/requirements.txt py{3.6,3.7}-docs: Django~=3.2 - py{3.8,3.9,3.10,3.11}-docs: Django<4.3 + py{3.8,3.9}-docs: Django<4.3 + py{3.10,3.11}-docs: Django~=5.0 docs: Sphinx docs: mock docs: sphinx_rtd_theme