Repository: jazzband/django-dbbackup (language: python)

Issue:
Support Django 4.2
# Feature Request

Add Django 4.2 to the automated CI testing suite.

# Issue

When attempting to add support for Django 4.2, the following error appears within CI:

```
ERROR Error sending data
  Traceback (most recent call last):
    File "/home/runner/work/django-dbbackup/django-dbbackup/.tox/py310-django42/lib/python3.10/site-packages/gnupg.py", line 155, in _copy_data
      outstream.write(data)
  TypeError: a bytes-like object is required, not 'str'
  ....ERROR Exception: Foo
    File "/home/runner/work/django-dbbackup/django-dbbackup/dbbackup/utils.py", line 120, in wrapper
      func(*args, **kwargs)
    File "/home/runner/work/django-dbbackup/django-dbbackup/dbbackup/tests/test_utils.py", line 81, in func
      raise Exception("Foo")
  
  .ERROR Exception: Foo
    File "/home/runner/work/django-dbbackup/django-dbbackup/dbbackup/utils.py", line 120, in wrapper
      func(*args, **kwargs)
    File "/home/runner/work/django-dbbackup/django-dbbackup/dbbackup/tests/test_utils.py", line 91, in func
      raise Exception("Foo")
  
  ..ERROR Error sending data
  Traceback (most recent call last):
    File "/home/runner/work/django-dbbackup/django-dbbackup/.tox/py310-django42/lib/python3.10/site-packages/gnupg.py", line 155, in _copy_data
      outstream.write(data)
  TypeError: a bytes-like object is required, not 'str'
```

https://github.com/jazzband/django-dbbackup/blob/790ec8bd297ef24cddfd2618d18d243abd15437e/dbbackup/tests/utils.py#L120-L122

https://github.com/jazzband/django-dbbackup/blob/790ec8bd297ef24cddfd2618d18d243abd15437e/dbbackup/tests/test_utils.py#L87-L100

### `python-gnupg`

https://github.com/jazzband/django-dbbackup/blob/790ec8bd297ef24cddfd2618d18d243abd15437e/requirements/tests.txt#L9

https://github.com/vsajip/python-gnupg/blob/6081e55ccb513a478a64eaa48e993cb40853851e/gnupg.py#L138


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4115766f..82b8aae2 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -12,7 +12,7 @@ jobs:
         runs-on: ubuntu-latest
         strategy:
             matrix:
-                python-version: ["3.7", "3.8", "3.9", "3.10"]
+                python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
         steps:
             - uses: actions/checkout@v2
             - name: Set up Python ${{ matrix.python-version }}
@@ -24,7 +24,10 @@ jobs:
                   python -m pip install --upgrade pip
                   python -m pip install -r requirements/tests.txt
                   python -m pip install -r requirements.txt
-            - name: Linting
+            # TODO: Remove this conditional when Python 3.7 is dropped and Flake8 executes on
+            # all Python versions in matrix.
+            - if: matrix.python-version == '3.8'
+              name: Linting
               run: flake8
             # Environments are selected using tox-gh-actions configuration in tox.ini.
             - name: Test with tox
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 50944fbd..d79957ab 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -33,7 +33,7 @@ repos:
       hooks:
           - id: yesqa
     - repo: https://github.com/pycqa/isort
-      rev: "5.10.1"
+      rev: "5.12.0"
       hooks:
           - id: isort
             args: ["--profile", "black"]
diff --git a/requirements/build.txt b/requirements/build.txt
index 82e745cf..b1434cfc 100644
--- a/requirements/build.txt
+++ b/requirements/build.txt
@@ -1,5 +1,5 @@
 build
 setuptools
-tox
+tox>=4.0.0
 twine
 wheel
diff --git a/setup.py b/setup.py
index ce7fc362..82ed9e67 100644
--- a/setup.py
+++ b/setup.py
@@ -51,6 +51,8 @@ def get_test_requirements():
         "Framework :: Django :: 2.2",
         "Framework :: Django :: 3.2",
         "Framework :: Django :: 4.0",
+        "Framework :: Django :: 4.1",
+        "Framework :: Django :: 4.2",
         "Intended Audience :: Developers",
         "Intended Audience :: System Administrators",
         "License :: OSI Approved :: BSD License",
@@ -61,6 +63,7 @@ def get_test_requirements():
         "Programming Language :: Python :: 3.8",
         "Programming Language :: Python :: 3.9",
         "Programming Language :: Python :: 3.10",
+        "Programming Language :: Python :: 3.11",
         "Topic :: Database",
         "Topic :: System :: Archiving",
         "Topic :: System :: Archiving :: Backup",
diff --git a/tox.ini b/tox.ini
index da3732f2..68e6b0c7 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = py{37,38,39}-django22,py{37,38,39,310}-django{32,40,master},lint,docs,functional
+envlist = py{37,38,39}-django22,py{37,38,39,310,311}-django{32,40,41,42,master},lint,docs,functional
 
 [testenv]
 passenv = *
@@ -10,6 +10,8 @@ deps =
     django22: django>=2.2,<2.3
     django32: django>=3.2,<3.3
     django40: django>=4.0,<4.1
+    django41: django>=4.1,<4.2
+    django42: django>=4.2,<4.3
     djangomaster: https://github.com/django/django/archive/master.zip
 commands = {posargs:coverage run runtests.py}
 
@@ -17,9 +19,10 @@ commands = {posargs:coverage run runtests.py}
 [gh-actions]
 python =
     3.7: py37-django{22,32},functional
-    3.8: py38-django{22,32,40},functional
-    3.9: py39-django{22,32,40},functional
-    3.10: py310-django{22,32,40},functional
+    3.8: py38-django{22,32,40,41,42},functional
+    3.9: py39-django{22,32,40,41,42},functional
+    3.10: py310-django{22,32,40,41,42},functional
+    3.11: py311-django{40,41,42},functional
 
 [testenv:lint]
 basepython = python
@@ -29,14 +32,14 @@ commands = prospector dbbackup -0
 
 [testenv:docs]
 basepython = python
-whitelist_externals=make
+allowlist_externals=make
 deps = -rrequirements/docs.txt
 commands = make docs
 
 [testenv:functional]
 basepython = python
 passenv = *
-whitelist_externals = bash
+allowlist_externals = bash
 deps =
     -rrequirements/tests.txt
     django
@@ -48,7 +51,7 @@ commands = {posargs:bash -x functional.sh}
 [testenv:functional-mongodb]
 basepython = python
 passenv = *
-whitelist_externals = bash
+allowlist_externals = bash
 deps =
     -rrequirements/tests.txt
     djongo


Test patch:
diff --git a/dbbackup/tests/test_storage.py b/dbbackup/tests/test_storage.py
index e9b38558..e5ba32fb 100644
--- a/dbbackup/tests/test_storage.py
+++ b/dbbackup/tests/test_storage.py
@@ -23,7 +23,11 @@ def test_set_path(self):
     @patch("dbbackup.settings.STORAGE", DEFAULT_STORAGE_PATH)
     def test_set_options(self, *args):
         storage = get_storage(options=STORAGE_OPTIONS)
-        self.assertEqual(storage.storage.__module__, "django.core.files.storage")
+        self.assertIn(
+            storage.storage.__module__,
+            # TODO: Remove "django.core.files.storage" case when dropping support for Django < 4.2.
+            ("django.core.files.storage", "django.core.files.storage.filesystem"),
+        )
 
 
 class StorageTest(TestCase):
diff --git a/requirements/tests.txt b/requirements/tests.txt
index e975d619..a189f4c9 100644
--- a/requirements/tests.txt
+++ b/requirements/tests.txt
@@ -9,5 +9,5 @@ python-dotenv
 python-gnupg>=0.5.0
 pytz
 testfixtures
-tox
+tox>=4.0.0
 tox-gh-actions