Repository: jazzband/django-oauth-toolkit (language: python)

Issue:
Test on Django 4.2
## Description of the Change

Test with the new Django! 🎉

## Checklist

- [x] PR only contains one change (considered splitting up PR)
- [x] unit-test added
- [x] documentation updated
- [x] `CHANGELOG.md` updated (only for user relevant changes)
- [x] author name in `AUTHORS`



Discussion / hints:
## [Codecov](https://codecov.io/gh/jazzband/django-oauth-toolkit/pull/1264?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jazzband) Report
> Merging [#1264](https://codecov.io/gh/jazzband/django-oauth-toolkit/pull/1264?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jazzband) (a8af6bb) into [master](https://codecov.io/gh/jazzband/django-oauth-toolkit/commit/edc47bf44fa89ba673d50f476cf37e765b209dbe?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jazzband) (edc47bf) will **not change** coverage.
> The diff coverage is `n/a`.

```diff
@@           Coverage Diff           @@
##           master    #1264   +/-   ##
=======================================
  Coverage   96.97%   96.97%           
=======================================
  Files          31       31           
  Lines        1821     1821           
=======================================
  Hits         1766     1766           
  Misses         55       55           
```



:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jazzband)


Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dddfe00e5..6b4275a6c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,13 +25,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 * #1285 Add post_logout_redirect_uris field in application views.
 * #1311 Add option to disable client_secret hashing to allow verifying JWTs' signatures.
 * #1337 Gracefully handle expired or deleted refresh tokens, in `validate_user`.
+* #1350 Support Python 3.12 and Django 5.0
 
-- ### Fixed
+### Fixed
 * #1322 Instructions in documentation on how to create a code challenge and code verifier
 * #1284 Allow to logout with no id_token_hint even if the browser session already expired
 * #1296 Added reverse function in migration 0006_alter_application_client_secret
 * #1336 Fix encapsulation for Redirect URI scheme validation
 
+### Removed
+* #1350 Remove support for Python 3.7 and Django 2.2
+
 ## [2.3.0] 2023-05-31
 
 ### WARNING
diff --git a/README.rst b/README.rst
index 15ff04f7b..cbeedf1b4 100644
--- a/README.rst
+++ b/README.rst
@@ -43,8 +43,8 @@ Please report any security issues to the JazzBand security team at <security@jaz
 Requirements
 ------------
 
-* Python 3.7+
-* Django 2.2, 3.2, 4.0 (4.0.1+ due to a regression), 4.1, or 4.2
+* Python 3.8+
+* Django 3.2, 4.0 (4.0.1+ due to a regression), 4.1, 4.2, or 5.0
 * oauthlib 3.1+
 
 Installation
diff --git a/oauth2_provider/__init__.py b/oauth2_provider/__init__.py
index ebd93203d..55e470907 100644
--- a/oauth2_provider/__init__.py
+++ b/oauth2_provider/__init__.py
@@ -1,7 +1,1 @@
-import django
-
-
 __version__ = "2.3.0"
-
-if django.VERSION < (3, 2):
-    default_app_config = "oauth2_provider.apps.DOTConfig"
diff --git a/setup.cfg b/setup.cfg
index 8acc93c9a..453126c28 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -12,30 +12,31 @@ classifiers =
 	Development Status :: 5 - Production/Stable
 	Environment :: Web Environment
 	Framework :: Django
-	Framework :: Django :: 2.2
 	Framework :: Django :: 3.2
 	Framework :: Django :: 4.0
 	Framework :: Django :: 4.1
 	Framework :: Django :: 4.2
+	Framework :: Django :: 5.0
 	Intended Audience :: Developers
 	License :: OSI Approved :: BSD License
 	Operating System :: OS Independent
 	Programming Language :: Python :: 3
-	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
+	Programming Language :: Python :: 3.12
 	Topic :: Internet :: WWW/HTTP
 
 [options]
 packages = find:
 include_package_data = True
 zip_safe = False
+python_requires = >=3.8
 # jwcrypto has a direct dependency on six, but does not list it yet in a release
 # Previously, cryptography also depended on six, so this was unnoticed
 install_requires =
-	django >= 2.2, != 4.0.0
+	django >= 3.2, != 4.0.0
 	requests >= 2.13.0
 	oauthlib >= 3.1.0
 	jwcrypto >= 0.8.0
diff --git a/tox.ini b/tox.ini
index cf9390b32..61b983b5b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -5,20 +5,20 @@ envlist =
     migrate_swapped,
     docs,
     sphinxlint,
-    py{37,38,39}-dj22,
-    py{37,38,39,310}-dj32,
+    py{38,39,310}-dj32,
     py{38,39,310}-dj40,
     py{38,39,310,311}-dj41,
-    py{38,39,310,311}-dj42,
-    py{310,311}-djmain,
+    py{38,39,310,311,312}-dj42,
+    py{310,311,312}-dj50,
+    py{310,311,312}-djmain,
 
 [gh-actions]
 python =
-    3.7: py37
     3.8: py38, docs, flake8, migrations, migrate_swapped, sphinxlint
     3.9: py39
     3.10: py310
     3.11: py311
+    3.12: py312
 
 [gh-actions:env]
 DJANGO =
@@ -27,6 +27,7 @@ DJANGO =
     4.0: dj40
     4.1: dj41
     4.2: dj42
+    5.0: dj50
     main: djmain
 
 [pytest]
@@ -54,6 +55,7 @@ deps =
     dj40: Django>=4.0.0,<4.1
     dj41: Django>=4.1,<4.2
     dj42: Django>=4.2,<4.3
+    dj50: Django>=5.0b1,<5.1
     djmain: https://github.com/django/django/archive/main.tar.gz
     djangorestframework
     oauthlib>=3.1.0
@@ -68,7 +70,7 @@ deps =
 passenv =
     PYTEST_ADDOPTS
 
-[testenv:py{38,39,310}-djmain]
+[testenv:py{310,311,312}-djmain]
 ignore_errors = true
 ignore_outcome = true
 


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 84bfe64ed..86a21bc27 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -9,31 +9,42 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
-        django-version: ['2.2', '3.2', '4.0', '4.1', '4.2', 'main']
+        python-version:
+        - '3.8'
+        - '3.9'
+        - '3.10'
+        - '3.11'
+        - '3.12'
+        django-version:
+        - '3.2'
+        - '4.0'
+        - '4.1'
+        - '4.2'
+        - '5.0'
+        - 'main'
         exclude:
           # https://docs.djangoproject.com/en/dev/faq/install/#what-python-version-can-i-use-with-django
 
-          # Python 3.10+ is not supported by Django 2.2
-          - python-version: '3.10'
-            django-version: '2.2'
-
-          # Python 3.7 is not supported by Django 4.0+
-          - python-version: '3.7'
-            django-version: '4.0'
-          - python-version: '3.7'
-            django-version: '4.1'
-          - python-version: '3.7'
-            django-version: '4.2'
-          - python-version: '3.7'
-            django-version: 'main'
-
           # < Python 3.10 is not supported by Django 5.0+
+          - python-version: '3.8'
+            django-version: '5.0'
+          - python-version: '3.9'
+            django-version: '5.0'
           - python-version: '3.8'
             django-version: 'main'
           - python-version: '3.9'
             django-version: 'main'
 
+          # Python 3.12 is not supported by Django < 5.0
+          - python-version: '3.12'
+            django-version: '3.2'
+          - python-version: '3.12'
+            django-version: '4.0'
+          - python-version: '3.12'
+            django-version: '4.1'
+          - python-version: '3.12'
+            django-version: '4.2'
+
     steps:
     - uses: actions/checkout@v4
 
diff --git a/tests/test_application_views.py b/tests/test_application_views.py
index 560c68cdb..9b277bc71 100644
--- a/tests/test_application_views.py
+++ b/tests/test_application_views.py
@@ -57,13 +57,13 @@ def test_application_registration_user(self):
         app = get_application_model().objects.get(name="Foo app")
         self.assertEqual(app.user.username, "foo_user")
         app = Application.objects.get()
-        self.assertEquals(app.name, form_data["name"])
-        self.assertEquals(app.client_id, form_data["client_id"])
-        self.assertEquals(app.redirect_uris, form_data["redirect_uris"])
-        self.assertEquals(app.post_logout_redirect_uris, form_data["post_logout_redirect_uris"])
-        self.assertEquals(app.client_type, form_data["client_type"])
-        self.assertEquals(app.authorization_grant_type, form_data["authorization_grant_type"])
-        self.assertEquals(app.algorithm, form_data["algorithm"])
+        self.assertEqual(app.name, form_data["name"])
+        self.assertEqual(app.client_id, form_data["client_id"])
+        self.assertEqual(app.redirect_uris, form_data["redirect_uris"])
+        self.assertEqual(app.post_logout_redirect_uris, form_data["post_logout_redirect_uris"])
+        self.assertEqual(app.client_type, form_data["client_type"])
+        self.assertEqual(app.authorization_grant_type, form_data["authorization_grant_type"])
+        self.assertEqual(app.algorithm, form_data["algorithm"])
 
 
 class TestApplicationViews(BaseTest):
@@ -115,7 +115,7 @@ def test_application_detail_not_owner(self):
         response = self.client.get(reverse("oauth2_provider:detail", args=(self.app_bar_1.pk,)))
         self.assertEqual(response.status_code, 404)
 
-    def test_application_udpate(self):
+    def test_application_update(self):
         self.client.login(username="foo_user", password="123456")
 
         form_data = {
@@ -132,8 +132,8 @@ def test_application_udpate(self):
         self.assertRedirects(response, reverse("oauth2_provider:detail", args=(self.app_foo_1.pk,)))
 
         self.app_foo_1.refresh_from_db()
-        self.assertEquals(self.app_foo_1.client_id, form_data["client_id"])
-        self.assertEquals(self.app_foo_1.redirect_uris, form_data["redirect_uris"])
-        self.assertEquals(self.app_foo_1.post_logout_redirect_uris, form_data["post_logout_redirect_uris"])
-        self.assertEquals(self.app_foo_1.client_type, form_data["client_type"])
-        self.assertEquals(self.app_foo_1.authorization_grant_type, form_data["authorization_grant_type"])
+        self.assertEqual(self.app_foo_1.client_id, form_data["client_id"])
+        self.assertEqual(self.app_foo_1.redirect_uris, form_data["redirect_uris"])
+        self.assertEqual(self.app_foo_1.post_logout_redirect_uris, form_data["post_logout_redirect_uris"])
+        self.assertEqual(self.app_foo_1.client_type, form_data["client_type"])
+        self.assertEqual(self.app_foo_1.authorization_grant_type, form_data["authorization_grant_type"])