Repository: django-cms/djangocms-video (language: python)

Issue:
Django 4.2/DjangoCMS 3.11 support
If I ran `python manage.py makemigrations` after updating to Django 4.2/DjangoCMS 3.11, new migrations will be generated.


Discussion / hints:
Would be best with updates based on https://github.com/django-cms/djangocms-audio/pull/32

Fix patch:
diff --git a/.coveragerc b/.coveragerc
index 0cbbcaa..fd922ca 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,4 +1,5 @@
 [run]
+parallel = True
 branch = True
 source = djangocms_video
 omit =
diff --git a/.github/workflows/lint-pr.yml b/.github/workflows/lint-pr.yml
new file mode 100644
index 0000000..fb4e16d
--- /dev/null
+++ b/.github/workflows/lint-pr.yml
@@ -0,0 +1,20 @@
+name: "Lint PR"
+
+# Validates PR titles against the conventional commit spec
+# https://github.com/commitizen/conventional-commit-types
+
+on:
+  pull_request_target:
+    types:
+      - opened
+      - edited
+      - synchronize
+
+jobs:
+  conventional-commits:
+    name: Validate PR title
+    runs-on: ubuntu-latest
+    steps:
+      - uses: amannn/action-semantic-pull-request@v4
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 6110948..62fbcdc 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -2,37 +2,26 @@ name: Lint
 
 on: [push, pull_request]
 
-jobs:
-  flake8:
-    name: flake8
-    runs-on: ubuntu-latest
-    steps:
-      - name: Checkout
-        uses: actions/checkout@v2
-      - name: Set up Python
-        uses: actions/setup-python@v2
-        with:
-          python-version: 3.9
-      - name: Install flake8
-        run: pip install --upgrade flake8
-      - name: Run flake8
-        uses: liskin/gh-problem-matcher-wrap@v1
-        with:
-          linters: flake8
-          run: flake8
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
 
-  isort:
+jobs:
+  ruff:
+    name: ruff
     runs-on: ubuntu-latest
     steps:
       - name: Checkout
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
       - name: Set up Python
-        uses: actions/setup-python@v2
-        with:
-          python-version: 3.9
-      - run: python -m pip install isort
-      - name: isort
-        uses: liskin/gh-problem-matcher-wrap@v1
+        uses: actions/setup-python@v4
         with:
-          linters: isort
-          run: isort -c -rc -df djangocms_video
\ No newline at end of file
+          python-version: '3.11'
+          allow-prereleases: true
+          cache: pip
+      - run: |
+          python -m pip install --upgrade pip
+          pip install ruff
+      - name: Run Ruff
+        run: |
+          ruff djangocms_video
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..d00ab37
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,50 @@
+ci:
+    autofix_commit_msg: |
+        ci: auto fixes from pre-commit hooks
+
+        for more information, see https://pre-commit.ci
+    autofix_prs: false
+    autoupdate_commit_msg: 'ci: pre-commit autoupdate'
+    autoupdate_schedule: monthly
+
+repos:
+  - repo: https://github.com/asottile/pyupgrade
+    rev: v3.7.0
+    hooks:
+      - id: pyupgrade
+        args: ["--py38-plus"]
+
+  - repo: https://github.com/adamchainz/django-upgrade
+    rev: '1.14.0'
+    hooks:
+      - id: django-upgrade
+        args: [--target-version, "3.2"]
+
+  - repo: https://github.com/astral-sh/ruff-pre-commit
+    rev: v0.0.275
+    hooks:
+      - id: ruff
+        args: [--fix, --exit-non-zero-on-fix]
+
+  - repo: https://github.com/asottile/yesqa
+    rev: v1.5.0
+    hooks:
+      - id: yesqa
+
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v4.4.0
+    hooks:
+      - id: check-merge-conflict
+      - id: debug-statements
+      - id: mixed-line-ending
+      - id: trailing-whitespace
+
+  - repo: https://github.com/pycqa/isort
+    rev: 5.12.0
+    hooks:
+      - id: isort
+
+  - repo: https://github.com/codespell-project/codespell
+    rev: v2.2.5
+    hooks:
+      - id: codespell
diff --git a/djangocms_video/cms_plugins.py b/djangocms_video/cms_plugins.py
index 4663f85..ecc9b2d 100644
--- a/djangocms_video/cms_plugins.py
+++ b/djangocms_video/cms_plugins.py
@@ -1,7 +1,6 @@
-from django.utils.translation import gettext_lazy as _
-
 from cms.plugin_base import CMSPluginBase
 from cms.plugin_pool import plugin_pool
+from django.utils.translation import gettext_lazy as _
 
 from . import forms, models
 
diff --git a/djangocms_video/forms.py b/djangocms_video/forms.py
index babd361..a66e715 100644
--- a/djangocms_video/forms.py
+++ b/djangocms_video/forms.py
@@ -5,7 +5,6 @@
 
 from . import models
 
-
 YOUTUBE_URL_RE = re.compile(r'(?:(?:http://|https://|//)?(?:www\.)?youtu\.?be.*).*')
 # https://stackoverflow.com/a/9102270
 YOUTUBE_VIDEO_ID_RE = re.compile(r'(?:[?&]v=|/embed/|/1/|/v/|https?://(?:www\.)?youtu\.be/)([^&\n?#]+)')
diff --git a/djangocms_video/migrations/0011_alter_videoplayer_cmsplugin_ptr_and_more.py b/djangocms_video/migrations/0011_alter_videoplayer_cmsplugin_ptr_and_more.py
new file mode 100644
index 0000000..f25a733
--- /dev/null
+++ b/djangocms_video/migrations/0011_alter_videoplayer_cmsplugin_ptr_and_more.py
@@ -0,0 +1,30 @@
+# Generated by Django 4.2.4 on 2023-08-02 14:03
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('cms', '0022_auto_20180620_1551'),
+        ('djangocms_video', '0010_videoplayer_parameters'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='videoplayer',
+            name='cmsplugin_ptr',
+            field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, related_name='%(app_label)s_%(class)s', serialize=False, to='cms.cmsplugin'),
+        ),
+        migrations.AlterField(
+            model_name='videosource',
+            name='cmsplugin_ptr',
+            field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, related_name='%(app_label)s_%(class)s', serialize=False, to='cms.cmsplugin'),
+        ),
+        migrations.AlterField(
+            model_name='videotrack',
+            name='cmsplugin_ptr',
+            field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, related_name='%(app_label)s_%(class)s', serialize=False, to='cms.cmsplugin'),
+        ),
+    ]
diff --git a/djangocms_video/models.py b/djangocms_video/models.py
index cda739e..323f0ba 100644
--- a/djangocms_video/models.py
+++ b/djangocms_video/models.py
@@ -5,14 +5,12 @@
 """
 from urllib.parse import parse_qsl, urlencode, urlparse, urlunparse
 
+from cms.models import CMSPlugin
 from django.conf import settings
 from django.core.exceptions import ValidationError
 from django.db import models
 from django.utils.translation import gettext
 from django.utils.translation import gettext_lazy as _
-
-from cms.models import CMSPlugin
-
 from djangocms_attributes_field.fields import AttributesField
 from filer.fields.file import FilerFileField
 from filer.fields.image import FilerImageField
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..64bdc3d
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,19 @@
+[tool.ruff]
+exclude = [
+    ".env",
+    ".venv",
+    "**/migrations/**",
+]
+ignore = [
+    "E501",  # line too long
+    "F403",  # 'from module import *' used; unable to detect undefined names
+    "E701",  # multiple statements on one line (colon)
+    "F401",  # module imported but unused
+]
+line-length = 119
+select = [
+    "I",
+    "E",
+    "F",
+    "W",
+]
diff --git a/setup.py b/setup.py
index 97366dc..e211d7f 100644
--- a/setup.py
+++ b/setup.py
@@ -3,12 +3,10 @@
 
 from djangocms_video import __version__
 
-
 REQUIREMENTS = [
     'django-cms>=3.7',
     'django-filer>=1.7',
     'djangocms-attributes-field>=1',
-    'django-treebeard>=4.3,<4.5',
 ]
 
 
@@ -20,17 +18,22 @@
     'Operating System :: OS Independent',
     'Programming Language :: Python',
     'Programming Language :: Python :: 3',
-    'Programming Language :: Python :: 3.5',
-    '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',
     'Framework :: Django',
-    'Framework :: Django :: 2.2',
-    'Framework :: Django :: 3.0',
-    'Framework :: Django :: 3.1',
+    'Framework :: Django :: 3.2',
+    'Framework :: Django :: 4.0',
+    'Framework :: Django :: 4.1',
+    'Framework :: Django :: 4.2',
     'Framework :: Django CMS',
     'Framework :: Django CMS :: 3.7',
     'Framework :: Django CMS :: 3.8',
+    'Framework :: Django CMS :: 3.9',
+    'Framework :: Django CMS :: 3.10',
+    'Framework :: Django CMS :: 3.11',
+    'Framework :: Django CMS :: 4.1',
     'Topic :: Internet :: WWW/HTTP',
     'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
     'Topic :: Software Development',
diff --git a/tox.ini b/tox.ini
index 6f17d4f..584a12c 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,61 +1,26 @@
 [tox]
+requires =
+    tox>=4.2
 envlist =
-    flake8
-    isort
-    py{35,36,37,38}-dj{22}-cms{37,38}
-    py{36,37,38}-dj{30}-cms{37,38}
-    py{36,37,38}-dj{31}-cms{38}
-
+    ruff
+    py311-django42-cms311
+    py310-django42-cms311
+    py310-django32-cms{38, 39, 310}
+    py39-django32-cms{38, 39, 310}
+    py38-django32-cms{38, 39, 310}
 skip_missing_interpreters=True
 
-[flake8]
-max-line-length = 119
-exclude =
-    *.egg-info,
-    .eggs,
-    .git,
-    .settings,
-    .tox,
-    build,
-    data,
-    dist,
-    docs,
-    *migrations*,
-    requirements,
-    tmp
-
-[isort]
-line_length = 79
-skip = manage.py, *migrations*, .tox, .eggs, data
-include_trailing_comma = true
-multi_line_output = 5
-not_skip = __init__.py
-lines_after_imports = 2
-default_section = THIRDPARTY
-sections = FUTURE, STDLIB, DJANGO, CMS, THIRDPARTY, FIRSTPARTY, LIB, LOCALFOLDER
-known_first_party = djangocms_video
-known_cms = cms, menus
-known_django = django
-
 [testenv]
 deps =
-    -r{toxinidir}/tests/requirements/base.txt
-    dj22: Django>=2.2,<3.0
-    dj30: Django>=3.0,<3.1
-    dj31: Django>=3.1,<3.2
-    cms37: django-cms>=3.7,<3.8
-    cms38: django-cms>=3.8,<3.9
+    -r tests/requirements/{env_name}.txt
 commands =
     {envpython} --version
     {env:COMMAND:coverage} erase
     {env:COMMAND:coverage} run setup.py test
-    {env:COMMAND:coverage} report
-
-[testenv:flake8]
-deps = flake8
-commands = flake8
+    {env:COMMAND:coverage} combine --keep
+    {env:COMMAND:coverage} report --show-missing
 
-[testenv:isort]
-deps = isort
-commands = isort -c -rc -df djangocms_video
+[testenv:ruff]
+deps = ruff
+commands = ruff djangocms_video
 skip_install = true


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index fa7cae5..0f80d38 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -1,39 +1,81 @@
 name: CodeCov
 
-on: [push, pull_request]
+on:
+  push:
+    branches:
+    - master
+  pull_request:
+
+concurrency:
+  group: ${{ github.head_ref || github.run_id }}
+  cancel-in-progress: true
 
 jobs:
-  unit-tests:
-    runs-on: ${{ matrix.os }}
+  tests:
+    name: ${{ matrix.database }} Python ${{ matrix.python-version }}
+    runs-on: ubuntu-22.04
+
     strategy:
       fail-fast: false
       matrix:
-        python-version: [ 3.7, 3.8, 3.9, ]  # latest release minus two
-        requirements-file: [
-          dj22_cms37.txt,
-          dj22_cms38.txt,
-          dj30_cms37.txt,
-          dj30_cms38.txt,
-          dj31_cms38.txt,
-        ]
-        os: [
-          ubuntu-20.04,
-        ]
+        python-version:
+        - '3.8'
+        - '3.9'
+        - '3.10'
+        - '3.11'
 
     steps:
-    - uses: actions/checkout@v1
-    - name: Set up Python ${{ matrix.python-version }}
+    - uses: actions/checkout@v3
 
-      uses: actions/setup-python@v2
+    - uses: actions/setup-python@v4
       with:
         python-version: ${{ matrix.python-version }}
+        allow-prereleases: true
+        cache: pip
+        cache-dependency-path: 'requirements/*.txt'
+
     - name: Install dependencies
       run: |
-        python -m pip install --upgrade pip
-        pip install -r tests/requirements/${{ matrix.requirements-file }}
-        python setup.py install
-    - name: Run coverage
-      run: coverage run setup.py test
-
-    - name: Upload Coverage to Codecov
-      uses: codecov/codecov-action@v1
\ No newline at end of file
+        python -m pip install --upgrade pip setuptools wheel
+        python -m pip install --upgrade 'tox>=4.0.0rc3'
+
+    - name: Run tox targets for ${{ matrix.python-version }}
+      run: tox run -f py$(echo ${{ matrix.python-version }} | tr -d .)
+
+    - name: Upload coverage data
+      uses: actions/upload-artifact@v3
+      with:
+        name: coverage-data
+        path: '.coverage*'
+
+  coverage:
+    name: Coverage
+    runs-on: ubuntu-22.04
+    needs: tests
+    steps:
+      - uses: actions/checkout@v3
+
+      - uses: actions/setup-python@v4
+        with:
+          python-version: '3.11'
+
+      - name: Install dependencies
+        run: python -m pip install --upgrade coverage[toml]
+
+      - name: Download data
+        uses: actions/download-artifact@v3
+        with:
+          name: coverage-data
+
+      - name: Combine coverage and fail if it's <95%
+        run: |
+          python -m coverage combine
+          python -m coverage html --skip-covered --skip-empty
+          python -m coverage report --fail-under=95
+
+      - name: Upload HTML report
+        if: ${{ failure() }}
+        uses: actions/upload-artifact@v3
+        with:
+          name: html-report
+          path: htmlcov
diff --git a/tests/helpers.py b/tests/helpers.py
index af7cbc3..57b2a45 100644
--- a/tests/helpers.py
+++ b/tests/helpers.py
@@ -2,7 +2,6 @@
 from tempfile import mkdtemp
 
 from django.core.files import File
-
 from filer.models.filemodels import File as FilerFile
 from filer.models.foldermodels import Folder as FilerFolder
 from filer.models.imagemodels import Image as FilerImage
diff --git a/tests/requirements/compile.py b/tests/requirements/compile.py
new file mode 100755
index 0000000..f4a7064
--- /dev/null
+++ b/tests/requirements/compile.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+#
+# This script requries multiple python versions to be installed.
+# You can use pyenv for that.
+#
+# See: https://github.com/pyenv/pyenv#installation
+# For example:
+# curl https://pyenv.run | bash
+#
+# Then setup pyenv shell environment like described here:
+# https://github.com/pyenv/pyenv#set-up-your-shell-environment-for-pyenv
+#
+# Install requirements for building python versions:
+# https://github.com/pyenv/pyenv/wiki#suggested-build-environment
+#
+# Now install python versions:
+# pyenv install 3.8 3.9 3.10 3.11
+#
+# Then activate them globaly with the systems default to be still default:
+# pyenv global system 3.11 3.10 3.9 3.8
+#
+# Also pip-tools must be installed for every version of python.
+# pip3.8 install pip-tools
+# pip3.9 install pip-tools
+# pip3.10 install pip-tools
+# pip3.11 install pip-tools
+
+from __future__ import annotations
+
+import sys
+from os import chdir, environ
+from pathlib import Path
+from subprocess import run
+
+CONFIG_MATRIX = [
+    ["python3.8", "Django>=3.2a1,<3.3", "django-cms>=3.8,<3.9", "py38-django32-cms38.txt",],
+    ["python3.8", "Django>=3.2a1,<3.3", "django-cms>=3.9,<3.10", "py38-django32-cms39.txt",],
+    ["python3.8", "Django>=3.2a1,<3.3", "django-cms>=3.10,<3.11", "py38-django32-cms310.txt",],
+
+    ["python3.9", "Django>=3.2a1,<3.3", "django-cms>=3.8,<3.9", "py39-django32-cms38.txt",],
+    ["python3.9", "Django>=3.2a1,<3.3", "django-cms>=3.9,<3.10", "py39-django32-cms39.txt",],
+    ["python3.9", "Django>=3.2a1,<3.3", "django-cms>=3.10,<3.11", "py39-django32-cms310.txt",],
+
+    ["python3.10", "Django>=3.2a1,<3.3", "django-cms>=3.8,<3.9", "py310-django32-cms38.txt",],
+    ["python3.10", "Django>=3.2a1,<3.3", "django-cms>=3.9,<3.10", "py310-django32-cms39.txt",],
+    ["python3.10", "Django>=3.2a1,<3.3", "django-cms>=3.10,<3.11", "py310-django32-cms310.txt",],
+    ["python3.10", "Django>=4.2a1,<5.0", "django-cms>=3.11,<4.0", "py310-django42-cms311.txt",],
+
+    ["python3.11", "Django>=4.2a1,<5.0", "django-cms>=3.11,<4.0", "py311-django42-cms311.txt",],
+]
+
+if __name__ == "__main__":
+    chdir(Path(__file__).parent)
+    environ["CUSTOM_COMPILE_COMMAND"] = "requirements/compile.py"
+    environ["PIP_REQUIRE_VIRTUALENV"] = "0"
+    common_args = [
+        "-m",
+        "piptools",
+        "compile",
+        "--generate-hashes",
+        "--allow-unsafe",
+    ] + sys.argv[1:]
+    # mysqlclient requirements found on each version's "Databases" documentation page:
+    # https://docs.djangoproject.com/en/3.0/ref/databases/#mysql-db-api-drivers
+
+    for req in CONFIG_MATRIX:
+        cmd = [
+            req[0],
+            *common_args,
+            "--upgrade-package",
+            req[1],
+            "--upgrade-package",
+            req[2],
+            "--output-file",
+            req[3],
+        ]
+        print(" ".join(cmd))
+        output = run(
+            cmd,
+            # check=True,
+            capture_output=True,
+        )
+        print(output.stderr.decode('utf-8'))
diff --git a/tests/requirements/dj22_cms37.txt b/tests/requirements/dj22_cms37.txt
deleted file mode 100644
index 6b96a10..0000000
--- a/tests/requirements/dj22_cms37.txt
+++ /dev/null
@@ -1,4 +0,0 @@
--r base.txt
-
-Django>=2.2,<3.0
-django-cms>=3.7,<3.8
diff --git a/tests/requirements/dj22_cms38.txt b/tests/requirements/dj22_cms38.txt
deleted file mode 100644
index 22c4fef..0000000
--- a/tests/requirements/dj22_cms38.txt
+++ /dev/null
@@ -1,4 +0,0 @@
--r base.txt
-
-Django>=2.2,<3.0
-django-cms>=3.8,<3.9
diff --git a/tests/requirements/dj30_cms37.txt b/tests/requirements/dj30_cms37.txt
deleted file mode 100644
index edcfd45..0000000
--- a/tests/requirements/dj30_cms37.txt
+++ /dev/null
@@ -1,4 +0,0 @@
--r base.txt
-
-Django>=3.0,<3.1
-django-cms>=3.7,<3.8
diff --git a/tests/requirements/dj30_cms38.txt b/tests/requirements/dj30_cms38.txt
deleted file mode 100644
index 7bc3c0b..0000000
--- a/tests/requirements/dj30_cms38.txt
+++ /dev/null
@@ -1,4 +0,0 @@
--r base.txt
-
-Django>=3.0,<3.1
-django-cms>=3.8,<3.9
diff --git a/tests/requirements/dj31_cms38.txt b/tests/requirements/dj31_cms38.txt
deleted file mode 100644
index d17fdb4..0000000
--- a/tests/requirements/dj31_cms38.txt
+++ /dev/null
@@ -1,4 +0,0 @@
--r base.txt
-
-Django>=3.1,<3.2
-django-cms>=3.8,<3.9
diff --git a/tests/requirements/py310-django32-cms310.txt b/tests/requirements/py310-django32-cms310.txt
new file mode 100644
index 0000000..25e40a3
--- /dev/null
+++ b/tests/requirements/py310-django32-cms310.txt
@@ -0,0 +1,164 @@
+#
+# This file is autogenerated by pip-compile with Python 3.10
+# by the following command:
+#
+#    requirements/compile.py
+#
+asgiref==3.7.2 \
+    --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \
+    --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed
+    # via django
+cachetools==5.3.1 \
+    --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \
+    --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b
+    # via tox
+chardet==5.2.0 \
+    --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \
+    --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
+    # via tox
+colorama==0.4.6 \
+    --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+    --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+    # via tox
+coverage==7.3.0 \
+    --hash=sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34 \
+    --hash=sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e \
+    --hash=sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7 \
+    --hash=sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b \
+    --hash=sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3 \
+    --hash=sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985 \
+    --hash=sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95 \
+    --hash=sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2 \
+    --hash=sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a \
+    --hash=sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74 \
+    --hash=sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd \
+    --hash=sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af \
+    --hash=sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54 \
+    --hash=sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865 \
+    --hash=sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214 \
+    --hash=sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54 \
+    --hash=sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe \
+    --hash=sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0 \
+    --hash=sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321 \
+    --hash=sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446 \
+    --hash=sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e \
+    --hash=sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527 \
+    --hash=sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12 \
+    --hash=sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f \
+    --hash=sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f \
+    --hash=sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84 \
+    --hash=sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479 \
+    --hash=sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e \
+    --hash=sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873 \
+    --hash=sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70 \
+    --hash=sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0 \
+    --hash=sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977 \
+    --hash=sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51 \
+    --hash=sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28 \
+    --hash=sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1 \
+    --hash=sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254 \
+    --hash=sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1 \
+    --hash=sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd \
+    --hash=sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689 \
+    --hash=sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d \
+    --hash=sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543 \
+    --hash=sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9 \
+    --hash=sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637 \
+    --hash=sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071 \
+    --hash=sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482 \
+    --hash=sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1 \
+    --hash=sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b \
+    --hash=sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5 \
+    --hash=sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a \
+    --hash=sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393 \
+    --hash=sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a \
+    --hash=sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba
+    # via -r requirements.in
+distlib==0.3.7 \
+    --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \
+    --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8
+    # via virtualenv
+dj-database-url==2.1.0 \
+    --hash=sha256:04bc34b248d4c21aaa13e4ab419ae6575ef5f10f3df735ce7da97722caa356e0 \
+    --hash=sha256:f2042cefe1086e539c9da39fad5ad7f61173bf79665e69bf7e4de55fa88b135f
+    # via django-app-helper
+django==3.2.20 \
+    --hash=sha256:a477ab326ae7d8807dc25c186b951ab8c7648a3a23f9497763c37307a2b5ef87 \
+    --hash=sha256:dec2a116787b8e14962014bf78e120bba454135108e1af9e9b91ade7b2964c40
+    # via
+    #   -r requirements.in
+    #   dj-database-url
+    #   django-js-asset
+django-app-helper==3.3.1 \
+    --hash=sha256:6d5fdd0d247817aff4412d9854c434c577ae6aaa28198e3568e3e13bd749b3d1 \
+    --hash=sha256:a2573fcdfe272b5978c52675fe75c40a9e518c4ff93efbd3940280093b25d378
+    # via -r requirements.in
+django-js-asset==2.1.0 \
+    --hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \
+    --hash=sha256:be6f69ae5c4865617aa7726c48eddb64089a1e7d4ea7d22a35a3beb8282020f6
+    # via django-mptt
+django-mptt==0.14.0 \
+    --hash=sha256:2c92a2b1614c53086278795ccf50580cf1f9b8564f3ff03055dd62bab5987711 \
+    --hash=sha256:d9a87433ab0e4f35247c6f6d5a93ace6990860a4ba8796f815d185f773b9acfc
+    # via -r requirements.in
+docopt==0.6.2 \
+    --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491
+    # via django-app-helper
+filelock==3.12.2 \
+    --hash=sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81 \
+    --hash=sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec
+    # via
+    #   tox
+    #   virtualenv
+packaging==23.1 \
+    --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \
+    --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f
+    # via
+    #   pyproject-api
+    #   tox
+platformdirs==3.10.0 \
+    --hash=sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d \
+    --hash=sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d
+    # via
+    #   tox
+    #   virtualenv
+pluggy==1.2.0 \
+    --hash=sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849 \
+    --hash=sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3
+    # via tox
+pyproject-api==1.5.4 \
+    --hash=sha256:8d41f3f0c04f0f6a830c27b1c425fa66699715ae06d8a054a1c5eeaaf8bfb145 \
+    --hash=sha256:ca462d457880340ceada078678a296ac500061cef77a040e1143004470ab0046
+    # via tox
+pytz==2023.3 \
+    --hash=sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588 \
+    --hash=sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb
+    # via django
+six==1.16.0 \
+    --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+    --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+    # via django-app-helper
+sqlparse==0.4.4 \
+    --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \
+    --hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c
+    # via django
+tomli==2.0.1 \
+    --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
+    --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
+    # via
+    #   pyproject-api
+    #   tox
+tox==4.9.0 \
+    --hash=sha256:9b6d38fe422599d084afd89375b4803f4bc1f8f16573c77c8fd8ffcc6938f1ff \
+    --hash=sha256:c80de60fe26f9a009b0a763888bf2099ccfbef50a0279a6b9f6de40eb4eb7457
+    # via -r requirements.in
+typing-extensions==4.7.1 \
+    --hash=sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36 \
+    --hash=sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2
+    # via
+    #   asgiref
+    #   dj-database-url
+virtualenv==20.24.3 \
+    --hash=sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02 \
+    --hash=sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc
+    # via tox
diff --git a/tests/requirements/py310-django32-cms38.txt b/tests/requirements/py310-django32-cms38.txt
new file mode 100644
index 0000000..25e40a3
--- /dev/null
+++ b/tests/requirements/py310-django32-cms38.txt
@@ -0,0 +1,164 @@
+#
+# This file is autogenerated by pip-compile with Python 3.10
+# by the following command:
+#
+#    requirements/compile.py
+#
+asgiref==3.7.2 \
+    --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \
+    --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed
+    # via django
+cachetools==5.3.1 \
+    --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \
+    --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b
+    # via tox
+chardet==5.2.0 \
+    --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \
+    --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
+    # via tox
+colorama==0.4.6 \
+    --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+    --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+    # via tox
+coverage==7.3.0 \
+    --hash=sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34 \
+    --hash=sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e \
+    --hash=sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7 \
+    --hash=sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b \
+    --hash=sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3 \
+    --hash=sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985 \
+    --hash=sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95 \
+    --hash=sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2 \
+    --hash=sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a \
+    --hash=sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74 \
+    --hash=sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd \
+    --hash=sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af \
+    --hash=sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54 \
+    --hash=sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865 \
+    --hash=sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214 \
+    --hash=sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54 \
+    --hash=sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe \
+    --hash=sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0 \
+    --hash=sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321 \
+    --hash=sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446 \
+    --hash=sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e \
+    --hash=sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527 \
+    --hash=sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12 \
+    --hash=sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f \
+    --hash=sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f \
+    --hash=sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84 \
+    --hash=sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479 \
+    --hash=sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e \
+    --hash=sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873 \
+    --hash=sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70 \
+    --hash=sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0 \
+    --hash=sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977 \
+    --hash=sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51 \
+    --hash=sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28 \
+    --hash=sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1 \
+    --hash=sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254 \
+    --hash=sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1 \
+    --hash=sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd \
+    --hash=sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689 \
+    --hash=sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d \
+    --hash=sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543 \
+    --hash=sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9 \
+    --hash=sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637 \
+    --hash=sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071 \
+    --hash=sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482 \
+    --hash=sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1 \
+    --hash=sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b \
+    --hash=sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5 \
+    --hash=sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a \
+    --hash=sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393 \
+    --hash=sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a \
+    --hash=sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba
+    # via -r requirements.in
+distlib==0.3.7 \
+    --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \
+    --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8
+    # via virtualenv
+dj-database-url==2.1.0 \
+    --hash=sha256:04bc34b248d4c21aaa13e4ab419ae6575ef5f10f3df735ce7da97722caa356e0 \
+    --hash=sha256:f2042cefe1086e539c9da39fad5ad7f61173bf79665e69bf7e4de55fa88b135f
+    # via django-app-helper
+django==3.2.20 \
+    --hash=sha256:a477ab326ae7d8807dc25c186b951ab8c7648a3a23f9497763c37307a2b5ef87 \
+    --hash=sha256:dec2a116787b8e14962014bf78e120bba454135108e1af9e9b91ade7b2964c40
+    # via
+    #   -r requirements.in
+    #   dj-database-url
+    #   django-js-asset
+django-app-helper==3.3.1 \
+    --hash=sha256:6d5fdd0d247817aff4412d9854c434c577ae6aaa28198e3568e3e13bd749b3d1 \
+    --hash=sha256:a2573fcdfe272b5978c52675fe75c40a9e518c4ff93efbd3940280093b25d378
+    # via -r requirements.in
+django-js-asset==2.1.0 \
+    --hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \
+    --hash=sha256:be6f69ae5c4865617aa7726c48eddb64089a1e7d4ea7d22a35a3beb8282020f6
+    # via django-mptt
+django-mptt==0.14.0 \
+    --hash=sha256:2c92a2b1614c53086278795ccf50580cf1f9b8564f3ff03055dd62bab5987711 \
+    --hash=sha256:d9a87433ab0e4f35247c6f6d5a93ace6990860a4ba8796f815d185f773b9acfc
+    # via -r requirements.in
+docopt==0.6.2 \
+    --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491
+    # via django-app-helper
+filelock==3.12.2 \
+    --hash=sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81 \
+    --hash=sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec
+    # via
+    #   tox
+    #   virtualenv
+packaging==23.1 \
+    --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \
+    --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f
+    # via
+    #   pyproject-api
+    #   tox
+platformdirs==3.10.0 \
+    --hash=sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d \
+    --hash=sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d
+    # via
+    #   tox
+    #   virtualenv
+pluggy==1.2.0 \
+    --hash=sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849 \
+    --hash=sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3
+    # via tox
+pyproject-api==1.5.4 \
+    --hash=sha256:8d41f3f0c04f0f6a830c27b1c425fa66699715ae06d8a054a1c5eeaaf8bfb145 \
+    --hash=sha256:ca462d457880340ceada078678a296ac500061cef77a040e1143004470ab0046
+    # via tox
+pytz==2023.3 \
+    --hash=sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588 \
+    --hash=sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb
+    # via django
+six==1.16.0 \
+    --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+    --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+    # via django-app-helper
+sqlparse==0.4.4 \
+    --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \
+    --hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c
+    # via django
+tomli==2.0.1 \
+    --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
+    --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
+    # via
+    #   pyproject-api
+    #   tox
+tox==4.9.0 \
+    --hash=sha256:9b6d38fe422599d084afd89375b4803f4bc1f8f16573c77c8fd8ffcc6938f1ff \
+    --hash=sha256:c80de60fe26f9a009b0a763888bf2099ccfbef50a0279a6b9f6de40eb4eb7457
+    # via -r requirements.in
+typing-extensions==4.7.1 \
+    --hash=sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36 \
+    --hash=sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2
+    # via
+    #   asgiref
+    #   dj-database-url
+virtualenv==20.24.3 \
+    --hash=sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02 \
+    --hash=sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc
+    # via tox
diff --git a/tests/requirements/py310-django32-cms39.txt b/tests/requirements/py310-django32-cms39.txt
new file mode 100644
index 0000000..25e40a3
--- /dev/null
+++ b/tests/requirements/py310-django32-cms39.txt
@@ -0,0 +1,164 @@
+#
+# This file is autogenerated by pip-compile with Python 3.10
+# by the following command:
+#
+#    requirements/compile.py
+#
+asgiref==3.7.2 \
+    --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \
+    --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed
+    # via django
+cachetools==5.3.1 \
+    --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \
+    --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b
+    # via tox
+chardet==5.2.0 \
+    --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \
+    --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
+    # via tox
+colorama==0.4.6 \
+    --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+    --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+    # via tox
+coverage==7.3.0 \
+    --hash=sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34 \
+    --hash=sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e \
+    --hash=sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7 \
+    --hash=sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b \
+    --hash=sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3 \
+    --hash=sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985 \
+    --hash=sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95 \
+    --hash=sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2 \
+    --hash=sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a \
+    --hash=sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74 \
+    --hash=sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd \
+    --hash=sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af \
+    --hash=sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54 \
+    --hash=sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865 \
+    --hash=sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214 \
+    --hash=sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54 \
+    --hash=sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe \
+    --hash=sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0 \
+    --hash=sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321 \
+    --hash=sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446 \
+    --hash=sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e \
+    --hash=sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527 \
+    --hash=sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12 \
+    --hash=sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f \
+    --hash=sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f \
+    --hash=sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84 \
+    --hash=sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479 \
+    --hash=sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e \
+    --hash=sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873 \
+    --hash=sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70 \
+    --hash=sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0 \
+    --hash=sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977 \
+    --hash=sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51 \
+    --hash=sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28 \
+    --hash=sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1 \
+    --hash=sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254 \
+    --hash=sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1 \
+    --hash=sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd \
+    --hash=sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689 \
+    --hash=sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d \
+    --hash=sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543 \
+    --hash=sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9 \
+    --hash=sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637 \
+    --hash=sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071 \
+    --hash=sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482 \
+    --hash=sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1 \
+    --hash=sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b \
+    --hash=sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5 \
+    --hash=sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a \
+    --hash=sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393 \
+    --hash=sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a \
+    --hash=sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba
+    # via -r requirements.in
+distlib==0.3.7 \
+    --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \
+    --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8
+    # via virtualenv
+dj-database-url==2.1.0 \
+    --hash=sha256:04bc34b248d4c21aaa13e4ab419ae6575ef5f10f3df735ce7da97722caa356e0 \
+    --hash=sha256:f2042cefe1086e539c9da39fad5ad7f61173bf79665e69bf7e4de55fa88b135f
+    # via django-app-helper
+django==3.2.20 \
+    --hash=sha256:a477ab326ae7d8807dc25c186b951ab8c7648a3a23f9497763c37307a2b5ef87 \
+    --hash=sha256:dec2a116787b8e14962014bf78e120bba454135108e1af9e9b91ade7b2964c40
+    # via
+    #   -r requirements.in
+    #   dj-database-url
+    #   django-js-asset
+django-app-helper==3.3.1 \
+    --hash=sha256:6d5fdd0d247817aff4412d9854c434c577ae6aaa28198e3568e3e13bd749b3d1 \
+    --hash=sha256:a2573fcdfe272b5978c52675fe75c40a9e518c4ff93efbd3940280093b25d378
+    # via -r requirements.in
+django-js-asset==2.1.0 \
+    --hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \
+    --hash=sha256:be6f69ae5c4865617aa7726c48eddb64089a1e7d4ea7d22a35a3beb8282020f6
+    # via django-mptt
+django-mptt==0.14.0 \
+    --hash=sha256:2c92a2b1614c53086278795ccf50580cf1f9b8564f3ff03055dd62bab5987711 \
+    --hash=sha256:d9a87433ab0e4f35247c6f6d5a93ace6990860a4ba8796f815d185f773b9acfc
+    # via -r requirements.in
+docopt==0.6.2 \
+    --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491
+    # via django-app-helper
+filelock==3.12.2 \
+    --hash=sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81 \
+    --hash=sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec
+    # via
+    #   tox
+    #   virtualenv
+packaging==23.1 \
+    --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \
+    --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f
+    # via
+    #   pyproject-api
+    #   tox
+platformdirs==3.10.0 \
+    --hash=sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d \
+    --hash=sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d
+    # via
+    #   tox
+    #   virtualenv
+pluggy==1.2.0 \
+    --hash=sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849 \
+    --hash=sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3
+    # via tox
+pyproject-api==1.5.4 \
+    --hash=sha256:8d41f3f0c04f0f6a830c27b1c425fa66699715ae06d8a054a1c5eeaaf8bfb145 \
+    --hash=sha256:ca462d457880340ceada078678a296ac500061cef77a040e1143004470ab0046
+    # via tox
+pytz==2023.3 \
+    --hash=sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588 \
+    --hash=sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb
+    # via django
+six==1.16.0 \
+    --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+    --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+    # via django-app-helper
+sqlparse==0.4.4 \
+    --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \
+    --hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c
+    # via django
+tomli==2.0.1 \
+    --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
+    --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
+    # via
+    #   pyproject-api
+    #   tox
+tox==4.9.0 \
+    --hash=sha256:9b6d38fe422599d084afd89375b4803f4bc1f8f16573c77c8fd8ffcc6938f1ff \
+    --hash=sha256:c80de60fe26f9a009b0a763888bf2099ccfbef50a0279a6b9f6de40eb4eb7457
+    # via -r requirements.in
+typing-extensions==4.7.1 \
+    --hash=sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36 \
+    --hash=sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2
+    # via
+    #   asgiref
+    #   dj-database-url
+virtualenv==20.24.3 \
+    --hash=sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02 \
+    --hash=sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc
+    # via tox
diff --git a/tests/requirements/py310-django42-cms311.txt b/tests/requirements/py310-django42-cms311.txt
new file mode 100644
index 0000000..e709ac1
--- /dev/null
+++ b/tests/requirements/py310-django42-cms311.txt
@@ -0,0 +1,160 @@
+#
+# This file is autogenerated by pip-compile with Python 3.10
+# by the following command:
+#
+#    requirements/compile.py
+#
+asgiref==3.7.2 \
+    --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \
+    --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed
+    # via django
+cachetools==5.3.1 \
+    --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \
+    --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b
+    # via tox
+chardet==5.2.0 \
+    --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \
+    --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
+    # via tox
+colorama==0.4.6 \
+    --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+    --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+    # via tox
+coverage==7.3.0 \
+    --hash=sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34 \
+    --hash=sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e \
+    --hash=sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7 \
+    --hash=sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b \
+    --hash=sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3 \
+    --hash=sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985 \
+    --hash=sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95 \
+    --hash=sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2 \
+    --hash=sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a \
+    --hash=sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74 \
+    --hash=sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd \
+    --hash=sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af \
+    --hash=sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54 \
+    --hash=sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865 \
+    --hash=sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214 \
+    --hash=sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54 \
+    --hash=sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe \
+    --hash=sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0 \
+    --hash=sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321 \
+    --hash=sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446 \
+    --hash=sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e \
+    --hash=sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527 \
+    --hash=sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12 \
+    --hash=sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f \
+    --hash=sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f \
+    --hash=sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84 \
+    --hash=sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479 \
+    --hash=sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e \
+    --hash=sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873 \
+    --hash=sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70 \
+    --hash=sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0 \
+    --hash=sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977 \
+    --hash=sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51 \
+    --hash=sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28 \
+    --hash=sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1 \
+    --hash=sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254 \
+    --hash=sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1 \
+    --hash=sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd \
+    --hash=sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689 \
+    --hash=sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d \
+    --hash=sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543 \
+    --hash=sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9 \
+    --hash=sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637 \
+    --hash=sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071 \
+    --hash=sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482 \
+    --hash=sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1 \
+    --hash=sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b \
+    --hash=sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5 \
+    --hash=sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a \
+    --hash=sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393 \
+    --hash=sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a \
+    --hash=sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba
+    # via -r requirements.in
+distlib==0.3.7 \
+    --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \
+    --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8
+    # via virtualenv
+dj-database-url==2.1.0 \
+    --hash=sha256:04bc34b248d4c21aaa13e4ab419ae6575ef5f10f3df735ce7da97722caa356e0 \
+    --hash=sha256:f2042cefe1086e539c9da39fad5ad7f61173bf79665e69bf7e4de55fa88b135f
+    # via django-app-helper
+django==4.2.4 \
+    --hash=sha256:7e4225ec065e0f354ccf7349a22d209de09cc1c074832be9eb84c51c1799c432 \
+    --hash=sha256:860ae6a138a238fc4f22c99b52f3ead982bb4b1aad8c0122bcd8c8a3a02e409d
+    # via
+    #   -r requirements.in
+    #   dj-database-url
+    #   django-js-asset
+django-app-helper==3.3.1 \
+    --hash=sha256:6d5fdd0d247817aff4412d9854c434c577ae6aaa28198e3568e3e13bd749b3d1 \
+    --hash=sha256:a2573fcdfe272b5978c52675fe75c40a9e518c4ff93efbd3940280093b25d378
+    # via -r requirements.in
+django-js-asset==2.1.0 \
+    --hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \
+    --hash=sha256:be6f69ae5c4865617aa7726c48eddb64089a1e7d4ea7d22a35a3beb8282020f6
+    # via django-mptt
+django-mptt==0.14.0 \
+    --hash=sha256:2c92a2b1614c53086278795ccf50580cf1f9b8564f3ff03055dd62bab5987711 \
+    --hash=sha256:d9a87433ab0e4f35247c6f6d5a93ace6990860a4ba8796f815d185f773b9acfc
+    # via -r requirements.in
+docopt==0.6.2 \
+    --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491
+    # via django-app-helper
+filelock==3.12.2 \
+    --hash=sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81 \
+    --hash=sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec
+    # via
+    #   tox
+    #   virtualenv
+packaging==23.1 \
+    --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \
+    --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f
+    # via
+    #   pyproject-api
+    #   tox
+platformdirs==3.10.0 \
+    --hash=sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d \
+    --hash=sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d
+    # via
+    #   tox
+    #   virtualenv
+pluggy==1.2.0 \
+    --hash=sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849 \
+    --hash=sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3
+    # via tox
+pyproject-api==1.5.4 \
+    --hash=sha256:8d41f3f0c04f0f6a830c27b1c425fa66699715ae06d8a054a1c5eeaaf8bfb145 \
+    --hash=sha256:ca462d457880340ceada078678a296ac500061cef77a040e1143004470ab0046
+    # via tox
+six==1.16.0 \
+    --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+    --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+    # via django-app-helper
+sqlparse==0.4.4 \
+    --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \
+    --hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c
+    # via django
+tomli==2.0.1 \
+    --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
+    --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
+    # via
+    #   pyproject-api
+    #   tox
+tox==4.9.0 \
+    --hash=sha256:9b6d38fe422599d084afd89375b4803f4bc1f8f16573c77c8fd8ffcc6938f1ff \
+    --hash=sha256:c80de60fe26f9a009b0a763888bf2099ccfbef50a0279a6b9f6de40eb4eb7457
+    # via -r requirements.in
+typing-extensions==4.7.1 \
+    --hash=sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36 \
+    --hash=sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2
+    # via
+    #   asgiref
+    #   dj-database-url
+virtualenv==20.24.3 \
+    --hash=sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02 \
+    --hash=sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc
+    # via tox
diff --git a/tests/requirements/py311-django42-cms311.txt b/tests/requirements/py311-django42-cms311.txt
new file mode 100644
index 0000000..9e8f328
--- /dev/null
+++ b/tests/requirements/py311-django42-cms311.txt
@@ -0,0 +1,152 @@
+#
+# This file is autogenerated by pip-compile with Python 3.11
+# by the following command:
+#
+#    requirements/compile.py
+#
+asgiref==3.7.2 \
+    --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \
+    --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed
+    # via django
+cachetools==5.3.1 \
+    --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \
+    --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b
+    # via tox
+chardet==5.2.0 \
+    --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \
+    --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
+    # via tox
+colorama==0.4.6 \
+    --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+    --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+    # via tox
+coverage==7.3.0 \
+    --hash=sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34 \
+    --hash=sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e \
+    --hash=sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7 \
+    --hash=sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b \
+    --hash=sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3 \
+    --hash=sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985 \
+    --hash=sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95 \
+    --hash=sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2 \
+    --hash=sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a \
+    --hash=sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74 \
+    --hash=sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd \
+    --hash=sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af \
+    --hash=sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54 \
+    --hash=sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865 \
+    --hash=sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214 \
+    --hash=sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54 \
+    --hash=sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe \
+    --hash=sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0 \
+    --hash=sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321 \
+    --hash=sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446 \
+    --hash=sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e \
+    --hash=sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527 \
+    --hash=sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12 \
+    --hash=sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f \
+    --hash=sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f \
+    --hash=sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84 \
+    --hash=sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479 \
+    --hash=sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e \
+    --hash=sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873 \
+    --hash=sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70 \
+    --hash=sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0 \
+    --hash=sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977 \
+    --hash=sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51 \
+    --hash=sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28 \
+    --hash=sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1 \
+    --hash=sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254 \
+    --hash=sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1 \
+    --hash=sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd \
+    --hash=sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689 \
+    --hash=sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d \
+    --hash=sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543 \
+    --hash=sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9 \
+    --hash=sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637 \
+    --hash=sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071 \
+    --hash=sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482 \
+    --hash=sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1 \
+    --hash=sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b \
+    --hash=sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5 \
+    --hash=sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a \
+    --hash=sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393 \
+    --hash=sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a \
+    --hash=sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba
+    # via -r requirements.in
+distlib==0.3.7 \
+    --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \
+    --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8
+    # via virtualenv
+dj-database-url==2.1.0 \
+    --hash=sha256:04bc34b248d4c21aaa13e4ab419ae6575ef5f10f3df735ce7da97722caa356e0 \
+    --hash=sha256:f2042cefe1086e539c9da39fad5ad7f61173bf79665e69bf7e4de55fa88b135f
+    # via django-app-helper
+django==4.2.4 \
+    --hash=sha256:7e4225ec065e0f354ccf7349a22d209de09cc1c074832be9eb84c51c1799c432 \
+    --hash=sha256:860ae6a138a238fc4f22c99b52f3ead982bb4b1aad8c0122bcd8c8a3a02e409d
+    # via
+    #   -r requirements.in
+    #   dj-database-url
+    #   django-js-asset
+django-app-helper==3.3.1 \
+    --hash=sha256:6d5fdd0d247817aff4412d9854c434c577ae6aaa28198e3568e3e13bd749b3d1 \
+    --hash=sha256:a2573fcdfe272b5978c52675fe75c40a9e518c4ff93efbd3940280093b25d378
+    # via -r requirements.in
+django-js-asset==2.1.0 \
+    --hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \
+    --hash=sha256:be6f69ae5c4865617aa7726c48eddb64089a1e7d4ea7d22a35a3beb8282020f6
+    # via django-mptt
+django-mptt==0.14.0 \
+    --hash=sha256:2c92a2b1614c53086278795ccf50580cf1f9b8564f3ff03055dd62bab5987711 \
+    --hash=sha256:d9a87433ab0e4f35247c6f6d5a93ace6990860a4ba8796f815d185f773b9acfc
+    # via -r requirements.in
+docopt==0.6.2 \
+    --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491
+    # via django-app-helper
+filelock==3.12.2 \
+    --hash=sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81 \
+    --hash=sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec
+    # via
+    #   tox
+    #   virtualenv
+packaging==23.1 \
+    --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \
+    --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f
+    # via
+    #   pyproject-api
+    #   tox
+platformdirs==3.10.0 \
+    --hash=sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d \
+    --hash=sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d
+    # via
+    #   tox
+    #   virtualenv
+pluggy==1.2.0 \
+    --hash=sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849 \
+    --hash=sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3
+    # via tox
+pyproject-api==1.5.4 \
+    --hash=sha256:8d41f3f0c04f0f6a830c27b1c425fa66699715ae06d8a054a1c5eeaaf8bfb145 \
+    --hash=sha256:ca462d457880340ceada078678a296ac500061cef77a040e1143004470ab0046
+    # via tox
+six==1.16.0 \
+    --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+    --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+    # via django-app-helper
+sqlparse==0.4.4 \
+    --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \
+    --hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c
+    # via django
+tox==4.9.0 \
+    --hash=sha256:9b6d38fe422599d084afd89375b4803f4bc1f8f16573c77c8fd8ffcc6938f1ff \
+    --hash=sha256:c80de60fe26f9a009b0a763888bf2099ccfbef50a0279a6b9f6de40eb4eb7457
+    # via -r requirements.in
+typing-extensions==4.7.1 \
+    --hash=sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36 \
+    --hash=sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2
+    # via dj-database-url
+virtualenv==20.24.3 \
+    --hash=sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02 \
+    --hash=sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc
+    # via tox
diff --git a/tests/requirements/py38-django32-cms310.txt b/tests/requirements/py38-django32-cms310.txt
new file mode 100644
index 0000000..27611e3
--- /dev/null
+++ b/tests/requirements/py38-django32-cms310.txt
@@ -0,0 +1,164 @@
+#
+# This file is autogenerated by pip-compile with Python 3.8
+# by the following command:
+#
+#    requirements/compile.py
+#
+asgiref==3.7.2 \
+    --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \
+    --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed
+    # via django
+cachetools==5.3.1 \
+    --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \
+    --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b
+    # via tox
+chardet==5.2.0 \
+    --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \
+    --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
+    # via tox
+colorama==0.4.6 \
+    --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+    --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+    # via tox
+coverage==7.3.0 \
+    --hash=sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34 \
+    --hash=sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e \
+    --hash=sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7 \
+    --hash=sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b \
+    --hash=sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3 \
+    --hash=sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985 \
+    --hash=sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95 \
+    --hash=sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2 \
+    --hash=sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a \
+    --hash=sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74 \
+    --hash=sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd \
+    --hash=sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af \
+    --hash=sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54 \
+    --hash=sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865 \
+    --hash=sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214 \
+    --hash=sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54 \
+    --hash=sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe \
+    --hash=sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0 \
+    --hash=sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321 \
+    --hash=sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446 \
+    --hash=sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e \
+    --hash=sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527 \
+    --hash=sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12 \
+    --hash=sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f \
+    --hash=sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f \
+    --hash=sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84 \
+    --hash=sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479 \
+    --hash=sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e \
+    --hash=sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873 \
+    --hash=sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70 \
+    --hash=sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0 \
+    --hash=sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977 \
+    --hash=sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51 \
+    --hash=sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28 \
+    --hash=sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1 \
+    --hash=sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254 \
+    --hash=sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1 \
+    --hash=sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd \
+    --hash=sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689 \
+    --hash=sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d \
+    --hash=sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543 \
+    --hash=sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9 \
+    --hash=sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637 \
+    --hash=sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071 \
+    --hash=sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482 \
+    --hash=sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1 \
+    --hash=sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b \
+    --hash=sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5 \
+    --hash=sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a \
+    --hash=sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393 \
+    --hash=sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a \
+    --hash=sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba
+    # via -r requirements.in
+distlib==0.3.7 \
+    --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \
+    --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8
+    # via virtualenv
+dj-database-url==2.1.0 \
+    --hash=sha256:04bc34b248d4c21aaa13e4ab419ae6575ef5f10f3df735ce7da97722caa356e0 \
+    --hash=sha256:f2042cefe1086e539c9da39fad5ad7f61173bf79665e69bf7e4de55fa88b135f
+    # via django-app-helper
+django==3.2.20 \
+    --hash=sha256:a477ab326ae7d8807dc25c186b951ab8c7648a3a23f9497763c37307a2b5ef87 \
+    --hash=sha256:dec2a116787b8e14962014bf78e120bba454135108e1af9e9b91ade7b2964c40
+    # via
+    #   -r requirements.in
+    #   dj-database-url
+    #   django-js-asset
+django-app-helper==3.3.1 \
+    --hash=sha256:6d5fdd0d247817aff4412d9854c434c577ae6aaa28198e3568e3e13bd749b3d1 \
+    --hash=sha256:a2573fcdfe272b5978c52675fe75c40a9e518c4ff93efbd3940280093b25d378
+    # via -r requirements.in
+django-js-asset==2.1.0 \
+    --hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \
+    --hash=sha256:be6f69ae5c4865617aa7726c48eddb64089a1e7d4ea7d22a35a3beb8282020f6
+    # via django-mptt
+django-mptt==0.14.0 \
+    --hash=sha256:2c92a2b1614c53086278795ccf50580cf1f9b8564f3ff03055dd62bab5987711 \
+    --hash=sha256:d9a87433ab0e4f35247c6f6d5a93ace6990860a4ba8796f815d185f773b9acfc
+    # via -r requirements.in
+docopt==0.6.2 \
+    --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491
+    # via django-app-helper
+filelock==3.12.2 \
+    --hash=sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81 \
+    --hash=sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec
+    # via
+    #   tox
+    #   virtualenv
+packaging==23.1 \
+    --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \
+    --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f
+    # via
+    #   pyproject-api
+    #   tox
+platformdirs==3.10.0 \
+    --hash=sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d \
+    --hash=sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d
+    # via
+    #   tox
+    #   virtualenv
+pluggy==1.2.0 \
+    --hash=sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849 \
+    --hash=sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3
+    # via tox
+pyproject-api==1.5.4 \
+    --hash=sha256:8d41f3f0c04f0f6a830c27b1c425fa66699715ae06d8a054a1c5eeaaf8bfb145 \
+    --hash=sha256:ca462d457880340ceada078678a296ac500061cef77a040e1143004470ab0046
+    # via tox
+pytz==2023.3 \
+    --hash=sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588 \
+    --hash=sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb
+    # via django
+six==1.16.0 \
+    --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+    --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+    # via django-app-helper
+sqlparse==0.4.4 \
+    --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \
+    --hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c
+    # via django
+tomli==2.0.1 \
+    --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
+    --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
+    # via
+    #   pyproject-api
+    #   tox
+tox==4.9.0 \
+    --hash=sha256:9b6d38fe422599d084afd89375b4803f4bc1f8f16573c77c8fd8ffcc6938f1ff \
+    --hash=sha256:c80de60fe26f9a009b0a763888bf2099ccfbef50a0279a6b9f6de40eb4eb7457
+    # via -r requirements.in
+typing-extensions==4.7.1 \
+    --hash=sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36 \
+    --hash=sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2
+    # via
+    #   asgiref
+    #   dj-database-url
+virtualenv==20.24.3 \
+    --hash=sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02 \
+    --hash=sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc
+    # via tox
diff --git a/tests/requirements/py38-django32-cms38.txt b/tests/requirements/py38-django32-cms38.txt
new file mode 100644
index 0000000..27611e3
--- /dev/null
+++ b/tests/requirements/py38-django32-cms38.txt
@@ -0,0 +1,164 @@
+#
+# This file is autogenerated by pip-compile with Python 3.8
+# by the following command:
+#
+#    requirements/compile.py
+#
+asgiref==3.7.2 \
+    --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \
+    --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed
+    # via django
+cachetools==5.3.1 \
+    --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \
+    --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b
+    # via tox
+chardet==5.2.0 \
+    --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \
+    --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
+    # via tox
+colorama==0.4.6 \
+    --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+    --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+    # via tox
+coverage==7.3.0 \
+    --hash=sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34 \
+    --hash=sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e \
+    --hash=sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7 \
+    --hash=sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b \
+    --hash=sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3 \
+    --hash=sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985 \
+    --hash=sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95 \
+    --hash=sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2 \
+    --hash=sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a \
+    --hash=sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74 \
+    --hash=sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd \
+    --hash=sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af \
+    --hash=sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54 \
+    --hash=sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865 \
+    --hash=sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214 \
+    --hash=sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54 \
+    --hash=sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe \
+    --hash=sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0 \
+    --hash=sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321 \
+    --hash=sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446 \
+    --hash=sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e \
+    --hash=sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527 \
+    --hash=sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12 \
+    --hash=sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f \
+    --hash=sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f \
+    --hash=sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84 \
+    --hash=sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479 \
+    --hash=sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e \
+    --hash=sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873 \
+    --hash=sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70 \
+    --hash=sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0 \
+    --hash=sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977 \
+    --hash=sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51 \
+    --hash=sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28 \
+    --hash=sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1 \
+    --hash=sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254 \
+    --hash=sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1 \
+    --hash=sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd \
+    --hash=sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689 \
+    --hash=sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d \
+    --hash=sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543 \
+    --hash=sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9 \
+    --hash=sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637 \
+    --hash=sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071 \
+    --hash=sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482 \
+    --hash=sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1 \
+    --hash=sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b \
+    --hash=sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5 \
+    --hash=sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a \
+    --hash=sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393 \
+    --hash=sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a \
+    --hash=sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba
+    # via -r requirements.in
+distlib==0.3.7 \
+    --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \
+    --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8
+    # via virtualenv
+dj-database-url==2.1.0 \
+    --hash=sha256:04bc34b248d4c21aaa13e4ab419ae6575ef5f10f3df735ce7da97722caa356e0 \
+    --hash=sha256:f2042cefe1086e539c9da39fad5ad7f61173bf79665e69bf7e4de55fa88b135f
+    # via django-app-helper
+django==3.2.20 \
+    --hash=sha256:a477ab326ae7d8807dc25c186b951ab8c7648a3a23f9497763c37307a2b5ef87 \
+    --hash=sha256:dec2a116787b8e14962014bf78e120bba454135108e1af9e9b91ade7b2964c40
+    # via
+    #   -r requirements.in
+    #   dj-database-url
+    #   django-js-asset
+django-app-helper==3.3.1 \
+    --hash=sha256:6d5fdd0d247817aff4412d9854c434c577ae6aaa28198e3568e3e13bd749b3d1 \
+    --hash=sha256:a2573fcdfe272b5978c52675fe75c40a9e518c4ff93efbd3940280093b25d378
+    # via -r requirements.in
+django-js-asset==2.1.0 \
+    --hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \
+    --hash=sha256:be6f69ae5c4865617aa7726c48eddb64089a1e7d4ea7d22a35a3beb8282020f6
+    # via django-mptt
+django-mptt==0.14.0 \
+    --hash=sha256:2c92a2b1614c53086278795ccf50580cf1f9b8564f3ff03055dd62bab5987711 \
+    --hash=sha256:d9a87433ab0e4f35247c6f6d5a93ace6990860a4ba8796f815d185f773b9acfc
+    # via -r requirements.in
+docopt==0.6.2 \
+    --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491
+    # via django-app-helper
+filelock==3.12.2 \
+    --hash=sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81 \
+    --hash=sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec
+    # via
+    #   tox
+    #   virtualenv
+packaging==23.1 \
+    --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \
+    --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f
+    # via
+    #   pyproject-api
+    #   tox
+platformdirs==3.10.0 \
+    --hash=sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d \
+    --hash=sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d
+    # via
+    #   tox
+    #   virtualenv
+pluggy==1.2.0 \
+    --hash=sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849 \
+    --hash=sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3
+    # via tox
+pyproject-api==1.5.4 \
+    --hash=sha256:8d41f3f0c04f0f6a830c27b1c425fa66699715ae06d8a054a1c5eeaaf8bfb145 \
+    --hash=sha256:ca462d457880340ceada078678a296ac500061cef77a040e1143004470ab0046
+    # via tox
+pytz==2023.3 \
+    --hash=sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588 \
+    --hash=sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb
+    # via django
+six==1.16.0 \
+    --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+    --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+    # via django-app-helper
+sqlparse==0.4.4 \
+    --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \
+    --hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c
+    # via django
+tomli==2.0.1 \
+    --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
+    --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
+    # via
+    #   pyproject-api
+    #   tox
+tox==4.9.0 \
+    --hash=sha256:9b6d38fe422599d084afd89375b4803f4bc1f8f16573c77c8fd8ffcc6938f1ff \
+    --hash=sha256:c80de60fe26f9a009b0a763888bf2099ccfbef50a0279a6b9f6de40eb4eb7457
+    # via -r requirements.in
+typing-extensions==4.7.1 \
+    --hash=sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36 \
+    --hash=sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2
+    # via
+    #   asgiref
+    #   dj-database-url
+virtualenv==20.24.3 \
+    --hash=sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02 \
+    --hash=sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc
+    # via tox
diff --git a/tests/requirements/py38-django32-cms39.txt b/tests/requirements/py38-django32-cms39.txt
new file mode 100644
index 0000000..27611e3
--- /dev/null
+++ b/tests/requirements/py38-django32-cms39.txt
@@ -0,0 +1,164 @@
+#
+# This file is autogenerated by pip-compile with Python 3.8
+# by the following command:
+#
+#    requirements/compile.py
+#
+asgiref==3.7.2 \
+    --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \
+    --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed
+    # via django
+cachetools==5.3.1 \
+    --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \
+    --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b
+    # via tox
+chardet==5.2.0 \
+    --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \
+    --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
+    # via tox
+colorama==0.4.6 \
+    --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+    --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+    # via tox
+coverage==7.3.0 \
+    --hash=sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34 \
+    --hash=sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e \
+    --hash=sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7 \
+    --hash=sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b \
+    --hash=sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3 \
+    --hash=sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985 \
+    --hash=sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95 \
+    --hash=sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2 \
+    --hash=sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a \
+    --hash=sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74 \
+    --hash=sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd \
+    --hash=sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af \
+    --hash=sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54 \
+    --hash=sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865 \
+    --hash=sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214 \
+    --hash=sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54 \
+    --hash=sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe \
+    --hash=sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0 \
+    --hash=sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321 \
+    --hash=sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446 \
+    --hash=sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e \
+    --hash=sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527 \
+    --hash=sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12 \
+    --hash=sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f \
+    --hash=sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f \
+    --hash=sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84 \
+    --hash=sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479 \
+    --hash=sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e \
+    --hash=sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873 \
+    --hash=sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70 \
+    --hash=sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0 \
+    --hash=sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977 \
+    --hash=sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51 \
+    --hash=sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28 \
+    --hash=sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1 \
+    --hash=sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254 \
+    --hash=sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1 \
+    --hash=sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd \
+    --hash=sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689 \
+    --hash=sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d \
+    --hash=sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543 \
+    --hash=sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9 \
+    --hash=sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637 \
+    --hash=sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071 \
+    --hash=sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482 \
+    --hash=sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1 \
+    --hash=sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b \
+    --hash=sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5 \
+    --hash=sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a \
+    --hash=sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393 \
+    --hash=sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a \
+    --hash=sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba
+    # via -r requirements.in
+distlib==0.3.7 \
+    --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \
+    --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8
+    # via virtualenv
+dj-database-url==2.1.0 \
+    --hash=sha256:04bc34b248d4c21aaa13e4ab419ae6575ef5f10f3df735ce7da97722caa356e0 \
+    --hash=sha256:f2042cefe1086e539c9da39fad5ad7f61173bf79665e69bf7e4de55fa88b135f
+    # via django-app-helper
+django==3.2.20 \
+    --hash=sha256:a477ab326ae7d8807dc25c186b951ab8c7648a3a23f9497763c37307a2b5ef87 \
+    --hash=sha256:dec2a116787b8e14962014bf78e120bba454135108e1af9e9b91ade7b2964c40
+    # via
+    #   -r requirements.in
+    #   dj-database-url
+    #   django-js-asset
+django-app-helper==3.3.1 \
+    --hash=sha256:6d5fdd0d247817aff4412d9854c434c577ae6aaa28198e3568e3e13bd749b3d1 \
+    --hash=sha256:a2573fcdfe272b5978c52675fe75c40a9e518c4ff93efbd3940280093b25d378
+    # via -r requirements.in
+django-js-asset==2.1.0 \
+    --hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \
+    --hash=sha256:be6f69ae5c4865617aa7726c48eddb64089a1e7d4ea7d22a35a3beb8282020f6
+    # via django-mptt
+django-mptt==0.14.0 \
+    --hash=sha256:2c92a2b1614c53086278795ccf50580cf1f9b8564f3ff03055dd62bab5987711 \
+    --hash=sha256:d9a87433ab0e4f35247c6f6d5a93ace6990860a4ba8796f815d185f773b9acfc
+    # via -r requirements.in
+docopt==0.6.2 \
+    --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491
+    # via django-app-helper
+filelock==3.12.2 \
+    --hash=sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81 \
+    --hash=sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec
+    # via
+    #   tox
+    #   virtualenv
+packaging==23.1 \
+    --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \
+    --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f
+    # via
+    #   pyproject-api
+    #   tox
+platformdirs==3.10.0 \
+    --hash=sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d \
+    --hash=sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d
+    # via
+    #   tox
+    #   virtualenv
+pluggy==1.2.0 \
+    --hash=sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849 \
+    --hash=sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3
+    # via tox
+pyproject-api==1.5.4 \
+    --hash=sha256:8d41f3f0c04f0f6a830c27b1c425fa66699715ae06d8a054a1c5eeaaf8bfb145 \
+    --hash=sha256:ca462d457880340ceada078678a296ac500061cef77a040e1143004470ab0046
+    # via tox
+pytz==2023.3 \
+    --hash=sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588 \
+    --hash=sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb
+    # via django
+six==1.16.0 \
+    --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+    --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+    # via django-app-helper
+sqlparse==0.4.4 \
+    --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \
+    --hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c
+    # via django
+tomli==2.0.1 \
+    --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
+    --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
+    # via
+    #   pyproject-api
+    #   tox
+tox==4.9.0 \
+    --hash=sha256:9b6d38fe422599d084afd89375b4803f4bc1f8f16573c77c8fd8ffcc6938f1ff \
+    --hash=sha256:c80de60fe26f9a009b0a763888bf2099ccfbef50a0279a6b9f6de40eb4eb7457
+    # via -r requirements.in
+typing-extensions==4.7.1 \
+    --hash=sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36 \
+    --hash=sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2
+    # via
+    #   asgiref
+    #   dj-database-url
+virtualenv==20.24.3 \
+    --hash=sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02 \
+    --hash=sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc
+    # via tox
diff --git a/tests/requirements/py39-django32-cms310.txt b/tests/requirements/py39-django32-cms310.txt
new file mode 100644
index 0000000..23c1159
--- /dev/null
+++ b/tests/requirements/py39-django32-cms310.txt
@@ -0,0 +1,164 @@
+#
+# This file is autogenerated by pip-compile with Python 3.9
+# by the following command:
+#
+#    requirements/compile.py
+#
+asgiref==3.7.2 \
+    --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \
+    --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed
+    # via django
+cachetools==5.3.1 \
+    --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \
+    --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b
+    # via tox
+chardet==5.2.0 \
+    --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \
+    --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
+    # via tox
+colorama==0.4.6 \
+    --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+    --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+    # via tox
+coverage==7.3.0 \
+    --hash=sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34 \
+    --hash=sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e \
+    --hash=sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7 \
+    --hash=sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b \
+    --hash=sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3 \
+    --hash=sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985 \
+    --hash=sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95 \
+    --hash=sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2 \
+    --hash=sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a \
+    --hash=sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74 \
+    --hash=sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd \
+    --hash=sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af \
+    --hash=sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54 \
+    --hash=sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865 \
+    --hash=sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214 \
+    --hash=sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54 \
+    --hash=sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe \
+    --hash=sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0 \
+    --hash=sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321 \
+    --hash=sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446 \
+    --hash=sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e \
+    --hash=sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527 \
+    --hash=sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12 \
+    --hash=sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f \
+    --hash=sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f \
+    --hash=sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84 \
+    --hash=sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479 \
+    --hash=sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e \
+    --hash=sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873 \
+    --hash=sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70 \
+    --hash=sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0 \
+    --hash=sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977 \
+    --hash=sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51 \
+    --hash=sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28 \
+    --hash=sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1 \
+    --hash=sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254 \
+    --hash=sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1 \
+    --hash=sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd \
+    --hash=sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689 \
+    --hash=sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d \
+    --hash=sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543 \
+    --hash=sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9 \
+    --hash=sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637 \
+    --hash=sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071 \
+    --hash=sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482 \
+    --hash=sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1 \
+    --hash=sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b \
+    --hash=sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5 \
+    --hash=sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a \
+    --hash=sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393 \
+    --hash=sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a \
+    --hash=sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba
+    # via -r requirements.in
+distlib==0.3.7 \
+    --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \
+    --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8
+    # via virtualenv
+dj-database-url==2.1.0 \
+    --hash=sha256:04bc34b248d4c21aaa13e4ab419ae6575ef5f10f3df735ce7da97722caa356e0 \
+    --hash=sha256:f2042cefe1086e539c9da39fad5ad7f61173bf79665e69bf7e4de55fa88b135f
+    # via django-app-helper
+django==3.2.20 \
+    --hash=sha256:a477ab326ae7d8807dc25c186b951ab8c7648a3a23f9497763c37307a2b5ef87 \
+    --hash=sha256:dec2a116787b8e14962014bf78e120bba454135108e1af9e9b91ade7b2964c40
+    # via
+    #   -r requirements.in
+    #   dj-database-url
+    #   django-js-asset
+django-app-helper==3.3.1 \
+    --hash=sha256:6d5fdd0d247817aff4412d9854c434c577ae6aaa28198e3568e3e13bd749b3d1 \
+    --hash=sha256:a2573fcdfe272b5978c52675fe75c40a9e518c4ff93efbd3940280093b25d378
+    # via -r requirements.in
+django-js-asset==2.1.0 \
+    --hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \
+    --hash=sha256:be6f69ae5c4865617aa7726c48eddb64089a1e7d4ea7d22a35a3beb8282020f6
+    # via django-mptt
+django-mptt==0.14.0 \
+    --hash=sha256:2c92a2b1614c53086278795ccf50580cf1f9b8564f3ff03055dd62bab5987711 \
+    --hash=sha256:d9a87433ab0e4f35247c6f6d5a93ace6990860a4ba8796f815d185f773b9acfc
+    # via -r requirements.in
+docopt==0.6.2 \
+    --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491
+    # via django-app-helper
+filelock==3.12.2 \
+    --hash=sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81 \
+    --hash=sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec
+    # via
+    #   tox
+    #   virtualenv
+packaging==23.1 \
+    --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \
+    --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f
+    # via
+    #   pyproject-api
+    #   tox
+platformdirs==3.10.0 \
+    --hash=sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d \
+    --hash=sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d
+    # via
+    #   tox
+    #   virtualenv
+pluggy==1.2.0 \
+    --hash=sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849 \
+    --hash=sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3
+    # via tox
+pyproject-api==1.5.4 \
+    --hash=sha256:8d41f3f0c04f0f6a830c27b1c425fa66699715ae06d8a054a1c5eeaaf8bfb145 \
+    --hash=sha256:ca462d457880340ceada078678a296ac500061cef77a040e1143004470ab0046
+    # via tox
+pytz==2023.3 \
+    --hash=sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588 \
+    --hash=sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb
+    # via django
+six==1.16.0 \
+    --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+    --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+    # via django-app-helper
+sqlparse==0.4.4 \
+    --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \
+    --hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c
+    # via django
+tomli==2.0.1 \
+    --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
+    --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
+    # via
+    #   pyproject-api
+    #   tox
+tox==4.9.0 \
+    --hash=sha256:9b6d38fe422599d084afd89375b4803f4bc1f8f16573c77c8fd8ffcc6938f1ff \
+    --hash=sha256:c80de60fe26f9a009b0a763888bf2099ccfbef50a0279a6b9f6de40eb4eb7457
+    # via -r requirements.in
+typing-extensions==4.7.1 \
+    --hash=sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36 \
+    --hash=sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2
+    # via
+    #   asgiref
+    #   dj-database-url
+virtualenv==20.24.3 \
+    --hash=sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02 \
+    --hash=sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc
+    # via tox
diff --git a/tests/requirements/py39-django32-cms38.txt b/tests/requirements/py39-django32-cms38.txt
new file mode 100644
index 0000000..23c1159
--- /dev/null
+++ b/tests/requirements/py39-django32-cms38.txt
@@ -0,0 +1,164 @@
+#
+# This file is autogenerated by pip-compile with Python 3.9
+# by the following command:
+#
+#    requirements/compile.py
+#
+asgiref==3.7.2 \
+    --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \
+    --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed
+    # via django
+cachetools==5.3.1 \
+    --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \
+    --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b
+    # via tox
+chardet==5.2.0 \
+    --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \
+    --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
+    # via tox
+colorama==0.4.6 \
+    --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+    --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+    # via tox
+coverage==7.3.0 \
+    --hash=sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34 \
+    --hash=sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e \
+    --hash=sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7 \
+    --hash=sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b \
+    --hash=sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3 \
+    --hash=sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985 \
+    --hash=sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95 \
+    --hash=sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2 \
+    --hash=sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a \
+    --hash=sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74 \
+    --hash=sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd \
+    --hash=sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af \
+    --hash=sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54 \
+    --hash=sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865 \
+    --hash=sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214 \
+    --hash=sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54 \
+    --hash=sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe \
+    --hash=sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0 \
+    --hash=sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321 \
+    --hash=sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446 \
+    --hash=sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e \
+    --hash=sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527 \
+    --hash=sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12 \
+    --hash=sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f \
+    --hash=sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f \
+    --hash=sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84 \
+    --hash=sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479 \
+    --hash=sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e \
+    --hash=sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873 \
+    --hash=sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70 \
+    --hash=sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0 \
+    --hash=sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977 \
+    --hash=sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51 \
+    --hash=sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28 \
+    --hash=sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1 \
+    --hash=sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254 \
+    --hash=sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1 \
+    --hash=sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd \
+    --hash=sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689 \
+    --hash=sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d \
+    --hash=sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543 \
+    --hash=sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9 \
+    --hash=sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637 \
+    --hash=sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071 \
+    --hash=sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482 \
+    --hash=sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1 \
+    --hash=sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b \
+    --hash=sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5 \
+    --hash=sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a \
+    --hash=sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393 \
+    --hash=sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a \
+    --hash=sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba
+    # via -r requirements.in
+distlib==0.3.7 \
+    --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \
+    --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8
+    # via virtualenv
+dj-database-url==2.1.0 \
+    --hash=sha256:04bc34b248d4c21aaa13e4ab419ae6575ef5f10f3df735ce7da97722caa356e0 \
+    --hash=sha256:f2042cefe1086e539c9da39fad5ad7f61173bf79665e69bf7e4de55fa88b135f
+    # via django-app-helper
+django==3.2.20 \
+    --hash=sha256:a477ab326ae7d8807dc25c186b951ab8c7648a3a23f9497763c37307a2b5ef87 \
+    --hash=sha256:dec2a116787b8e14962014bf78e120bba454135108e1af9e9b91ade7b2964c40
+    # via
+    #   -r requirements.in
+    #   dj-database-url
+    #   django-js-asset
+django-app-helper==3.3.1 \
+    --hash=sha256:6d5fdd0d247817aff4412d9854c434c577ae6aaa28198e3568e3e13bd749b3d1 \
+    --hash=sha256:a2573fcdfe272b5978c52675fe75c40a9e518c4ff93efbd3940280093b25d378
+    # via -r requirements.in
+django-js-asset==2.1.0 \
+    --hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \
+    --hash=sha256:be6f69ae5c4865617aa7726c48eddb64089a1e7d4ea7d22a35a3beb8282020f6
+    # via django-mptt
+django-mptt==0.14.0 \
+    --hash=sha256:2c92a2b1614c53086278795ccf50580cf1f9b8564f3ff03055dd62bab5987711 \
+    --hash=sha256:d9a87433ab0e4f35247c6f6d5a93ace6990860a4ba8796f815d185f773b9acfc
+    # via -r requirements.in
+docopt==0.6.2 \
+    --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491
+    # via django-app-helper
+filelock==3.12.2 \
+    --hash=sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81 \
+    --hash=sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec
+    # via
+    #   tox
+    #   virtualenv
+packaging==23.1 \
+    --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \
+    --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f
+    # via
+    #   pyproject-api
+    #   tox
+platformdirs==3.10.0 \
+    --hash=sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d \
+    --hash=sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d
+    # via
+    #   tox
+    #   virtualenv
+pluggy==1.2.0 \
+    --hash=sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849 \
+    --hash=sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3
+    # via tox
+pyproject-api==1.5.4 \
+    --hash=sha256:8d41f3f0c04f0f6a830c27b1c425fa66699715ae06d8a054a1c5eeaaf8bfb145 \
+    --hash=sha256:ca462d457880340ceada078678a296ac500061cef77a040e1143004470ab0046
+    # via tox
+pytz==2023.3 \
+    --hash=sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588 \
+    --hash=sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb
+    # via django
+six==1.16.0 \
+    --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+    --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+    # via django-app-helper
+sqlparse==0.4.4 \
+    --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \
+    --hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c
+    # via django
+tomli==2.0.1 \
+    --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
+    --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
+    # via
+    #   pyproject-api
+    #   tox
+tox==4.9.0 \
+    --hash=sha256:9b6d38fe422599d084afd89375b4803f4bc1f8f16573c77c8fd8ffcc6938f1ff \
+    --hash=sha256:c80de60fe26f9a009b0a763888bf2099ccfbef50a0279a6b9f6de40eb4eb7457
+    # via -r requirements.in
+typing-extensions==4.7.1 \
+    --hash=sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36 \
+    --hash=sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2
+    # via
+    #   asgiref
+    #   dj-database-url
+virtualenv==20.24.3 \
+    --hash=sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02 \
+    --hash=sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc
+    # via tox
diff --git a/tests/requirements/py39-django32-cms39.txt b/tests/requirements/py39-django32-cms39.txt
new file mode 100644
index 0000000..23c1159
--- /dev/null
+++ b/tests/requirements/py39-django32-cms39.txt
@@ -0,0 +1,164 @@
+#
+# This file is autogenerated by pip-compile with Python 3.9
+# by the following command:
+#
+#    requirements/compile.py
+#
+asgiref==3.7.2 \
+    --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \
+    --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed
+    # via django
+cachetools==5.3.1 \
+    --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \
+    --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b
+    # via tox
+chardet==5.2.0 \
+    --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \
+    --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
+    # via tox
+colorama==0.4.6 \
+    --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+    --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+    # via tox
+coverage==7.3.0 \
+    --hash=sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34 \
+    --hash=sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e \
+    --hash=sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7 \
+    --hash=sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b \
+    --hash=sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3 \
+    --hash=sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985 \
+    --hash=sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95 \
+    --hash=sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2 \
+    --hash=sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a \
+    --hash=sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74 \
+    --hash=sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd \
+    --hash=sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af \
+    --hash=sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54 \
+    --hash=sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865 \
+    --hash=sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214 \
+    --hash=sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54 \
+    --hash=sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe \
+    --hash=sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0 \
+    --hash=sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321 \
+    --hash=sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446 \
+    --hash=sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e \
+    --hash=sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527 \
+    --hash=sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12 \
+    --hash=sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f \
+    --hash=sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f \
+    --hash=sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84 \
+    --hash=sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479 \
+    --hash=sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e \
+    --hash=sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873 \
+    --hash=sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70 \
+    --hash=sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0 \
+    --hash=sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977 \
+    --hash=sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51 \
+    --hash=sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28 \
+    --hash=sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1 \
+    --hash=sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254 \
+    --hash=sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1 \
+    --hash=sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd \
+    --hash=sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689 \
+    --hash=sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d \
+    --hash=sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543 \
+    --hash=sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9 \
+    --hash=sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637 \
+    --hash=sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071 \
+    --hash=sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482 \
+    --hash=sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1 \
+    --hash=sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b \
+    --hash=sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5 \
+    --hash=sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a \
+    --hash=sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393 \
+    --hash=sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a \
+    --hash=sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba
+    # via -r requirements.in
+distlib==0.3.7 \
+    --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \
+    --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8
+    # via virtualenv
+dj-database-url==2.1.0 \
+    --hash=sha256:04bc34b248d4c21aaa13e4ab419ae6575ef5f10f3df735ce7da97722caa356e0 \
+    --hash=sha256:f2042cefe1086e539c9da39fad5ad7f61173bf79665e69bf7e4de55fa88b135f
+    # via django-app-helper
+django==3.2.20 \
+    --hash=sha256:a477ab326ae7d8807dc25c186b951ab8c7648a3a23f9497763c37307a2b5ef87 \
+    --hash=sha256:dec2a116787b8e14962014bf78e120bba454135108e1af9e9b91ade7b2964c40
+    # via
+    #   -r requirements.in
+    #   dj-database-url
+    #   django-js-asset
+django-app-helper==3.3.1 \
+    --hash=sha256:6d5fdd0d247817aff4412d9854c434c577ae6aaa28198e3568e3e13bd749b3d1 \
+    --hash=sha256:a2573fcdfe272b5978c52675fe75c40a9e518c4ff93efbd3940280093b25d378
+    # via -r requirements.in
+django-js-asset==2.1.0 \
+    --hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \
+    --hash=sha256:be6f69ae5c4865617aa7726c48eddb64089a1e7d4ea7d22a35a3beb8282020f6
+    # via django-mptt
+django-mptt==0.14.0 \
+    --hash=sha256:2c92a2b1614c53086278795ccf50580cf1f9b8564f3ff03055dd62bab5987711 \
+    --hash=sha256:d9a87433ab0e4f35247c6f6d5a93ace6990860a4ba8796f815d185f773b9acfc
+    # via -r requirements.in
+docopt==0.6.2 \
+    --hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491
+    # via django-app-helper
+filelock==3.12.2 \
+    --hash=sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81 \
+    --hash=sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec
+    # via
+    #   tox
+    #   virtualenv
+packaging==23.1 \
+    --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \
+    --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f
+    # via
+    #   pyproject-api
+    #   tox
+platformdirs==3.10.0 \
+    --hash=sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d \
+    --hash=sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d
+    # via
+    #   tox
+    #   virtualenv
+pluggy==1.2.0 \
+    --hash=sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849 \
+    --hash=sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3
+    # via tox
+pyproject-api==1.5.4 \
+    --hash=sha256:8d41f3f0c04f0f6a830c27b1c425fa66699715ae06d8a054a1c5eeaaf8bfb145 \
+    --hash=sha256:ca462d457880340ceada078678a296ac500061cef77a040e1143004470ab0046
+    # via tox
+pytz==2023.3 \
+    --hash=sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588 \
+    --hash=sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb
+    # via django
+six==1.16.0 \
+    --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+    --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+    # via django-app-helper
+sqlparse==0.4.4 \
+    --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \
+    --hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c
+    # via django
+tomli==2.0.1 \
+    --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
+    --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
+    # via
+    #   pyproject-api
+    #   tox
+tox==4.9.0 \
+    --hash=sha256:9b6d38fe422599d084afd89375b4803f4bc1f8f16573c77c8fd8ffcc6938f1ff \
+    --hash=sha256:c80de60fe26f9a009b0a763888bf2099ccfbef50a0279a6b9f6de40eb4eb7457
+    # via -r requirements.in
+typing-extensions==4.7.1 \
+    --hash=sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36 \
+    --hash=sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2
+    # via
+    #   asgiref
+    #   dj-database-url
+virtualenv==20.24.3 \
+    --hash=sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02 \
+    --hash=sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc
+    # via tox
diff --git a/tests/requirements/base.txt b/tests/requirements/requirements.in
similarity index 62%
rename from tests/requirements/base.txt
rename to tests/requirements/requirements.in
index a9cdb8c..5887457 100644
--- a/tests/requirements/base.txt
+++ b/tests/requirements/requirements.in
@@ -1,5 +1,5 @@
-isort
+coverage
+django
 django-app-helper
+django-mptt
 tox
-coverage
-flake8
diff --git a/tests/test_forms.py b/tests/test_forms.py
index 0dcc0ec..bc76b1b 100644
--- a/tests/test_forms.py
+++ b/tests/test_forms.py
@@ -1,7 +1,9 @@
 from django.test import TestCase, override_settings
 
 from djangocms_video.forms import (
-    DEFAULT_YOUTUBE_EMBED_URL, YOUTUBE_URL_RE, VideoPlayerPluginForm,
+    DEFAULT_YOUTUBE_EMBED_URL,
+    YOUTUBE_URL_RE,
+    VideoPlayerPluginForm,
 )
 
 YOUTUBE_NOCOOKIE_EMBED_URL = "//www.youtube-nocookie.com/embed/{}"
diff --git a/tests/test_models.py b/tests/test_models.py
index 1ce25ad..383a7d0 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -3,7 +3,11 @@
 from django.test import TestCase
 
 from djangocms_video.models import (
-    VideoPlayer, VideoSource, VideoTrack, get_extensions, get_templates,
+    VideoPlayer,
+    VideoSource,
+    VideoTrack,
+    get_extensions,
+    get_templates,
 )
 
 from .helpers import get_filer_file, get_filer_image
diff --git a/tests/test_plugins.py b/tests/test_plugins.py
index ce194eb..53a471a 100644
--- a/tests/test_plugins.py
+++ b/tests/test_plugins.py
@@ -2,7 +2,9 @@
 from cms.test_utils.testcases import CMSTestCase
 
 from djangocms_video.cms_plugins import (
-    VideoPlayerPlugin, VideoSourcePlugin, VideoTrackPlugin,
+    VideoPlayerPlugin,
+    VideoSourcePlugin,
+    VideoTrackPlugin,
 )
 
 from .helpers import get_filer_file