~petersanchez/public-inbox

django-impersonate: Add support for Django 5.0 (pre) v1 NEEDS REVISION

Hugo Rodger-Brown: 1
 Add support for Django 5.0 (pre)

 12 files changed, 65 insertions(+), 31 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.code.netlandish.com/~petersanchez/public-inbox/patches/59/mbox | git am -3
Learn more about email & git

[PATCH django-impersonate] Add support for Django 5.0 (pre) Export this patch

# HG changeset patch
# User Hugo Rodger-Brown
# Date 1681222628 -3600
#      Tue Apr 11 15:17:08 2023 +0100
# Node ID bb4fbfb81186e418ce55d199d60765d473cfe3d5
# Parent  76e93d43501e5304d6b27e7f7072e4d8aab15104
Add support for Django 5.0 (pre)

Adds a compat module that handles the deprecation of timezone.utc
in upcoming versions of Python.

Updates the classifiers to include latest versions of Python and
Django.

Updates the tox configuration to make the python/django support
clearer.

diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -1,15 +1,16 @@
syntax:glob
.*.swp
.coverage
.DS_Store
.idea
.tox
settings_local.py
.*.swp
.venv
*.diff
*.komodoproject
**.pyc
MANIFEST
.idea
settings_local.py

syntax:regexp
^htmlcov$
^env$
syntax: glob
*.komodoproject
.DS_Store
\ No newline at end of file
diff --git a/MANIFEST.in b/MANIFEST.in
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,4 +1,4 @@
include BSD-LICENSE
include LICENSE
include CHANGELOG
include README.rst
recursive-include impersonate/templates *
diff --git a/impersonate/admin.py b/impersonate/admin.py
--- a/impersonate/admin.py
+++ b/impersonate/admin.py
@@ -5,15 +5,11 @@
from django.db.utils import NotSupportedError
from django.utils.html import format_html

from .compat import reverse
from .helpers import User, check_allow_impersonate
from .models import ImpersonationLog
from .settings import settings

try:
    from django.urls import reverse
except ImportError:
    from django.core.urlresolvers import reverse

logger = logging.getLogger(__name__)


diff --git a/impersonate/compat/__init__.py b/impersonate/compat/__init__.py
new file mode 100644
--- /dev/null
+++ b/impersonate/compat/__init__.py
@@ -0,0 +1,4 @@
from .timezone import utc
from .urls import reverse

__all__ = ['reverse', 'utc']
diff --git a/impersonate/compat/timezone.py b/impersonate/compat/timezone.py
new file mode 100644
--- /dev/null
+++ b/impersonate/compat/timezone.py
@@ -0,0 +1,6 @@
# timezone.utc removed in Django 5
try:
    from django.utils.timezone import utc
except ImportError:
    from zoneinfo import ZoneInfo
    utc = ZoneInfo("UTC")
diff --git a/impersonate/compat/urls.py b/impersonate/compat/urls.py
new file mode 100644
--- /dev/null
+++ b/impersonate/compat/urls.py
@@ -0,0 +1,4 @@
try:
    from django.urls import reverse
except ImportError:
    from django.core.urlresolvers import reverse
diff --git a/impersonate/middleware.py b/impersonate/middleware.py
--- a/impersonate/middleware.py
+++ b/impersonate/middleware.py
@@ -2,11 +2,11 @@
from datetime import datetime, timedelta

from django.http import HttpResponseNotAllowed
from django.shortcuts import redirect, reverse
from django.utils import timezone
from django.shortcuts import redirect
from django.utils.deprecation import MiddlewareMixin
from django.utils.functional import SimpleLazyObject

from .compat import reverse, timezone
from .helpers import User, check_allow_for_uri, check_allow_for_user, check_read_only
from .settings import settings

diff --git a/impersonate/tests.py b/impersonate/tests.py
--- a/impersonate/tests.py
+++ b/impersonate/tests.py
@@ -19,7 +19,7 @@
        is_superuser = False
        is_staff = False
'''
from datetime import datetime, timedelta, timezone
from datetime import datetime, timedelta
from distutils.version import LooseVersion
from unittest.mock import PropertyMock, patch
from urllib.parse import urlencode, urlsplit
@@ -35,17 +35,15 @@
from django.utils.duration import duration_string

from .admin import (
    ImpersonationLogAdmin, ImpersonatorFilter, SessionStateFilter,
    ImpersonationLogAdmin,
    ImpersonatorFilter,
    SessionStateFilter,
)
from .compat import reverse, timezone
from .helpers import users_impersonable
from .models import ImpersonationLog
from .signals import session_begin, session_end

try:
    from django.urls import reverse
except ImportError:
    from django.core.urlresolvers import reverse

User = get_user_model()
django_version_loose = LooseVersion(django.get_version())

@@ -725,9 +723,17 @@
        qs = _filter.queryset(None, ImpersonationLog.objects.all())
        self.assertEqual(qs.count(), 2)

        # from 5.0 admin list filter values are multi-valued
        if django_version_loose < "5.0":
            params_complete = {'session': 'complete'}
            params_incomplete = {'session': 'complete'}
        else:
            params_complete = {'session': ['complete']}
            params_incomplete = {'session': ['incomplete']}

        _filter = SessionStateFilter(
            None,
            {'session': 'complete'},
            params_complete,
            ImpersonationLog,
            ImpersonationLogAdmin,
        )
@@ -736,7 +742,7 @@

        _filter = SessionStateFilter(
            None,
            {'session': 'incomplete'},
            params_incomplete,
            ImpersonationLog,
            ImpersonationLogAdmin,
        )
diff --git a/impersonate/views.py b/impersonate/views.py
--- a/impersonate/views.py
+++ b/impersonate/views.py
@@ -5,12 +5,16 @@
from django.db.models import Q
from django.http import Http404
from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone

from .compat import timezone
from .decorators import allowed_user_required
from .helpers import (
    check_allow_for_user, get_paginator, get_redir_arg, get_redir_field,
    get_redir_path, users_impersonable,
    check_allow_for_user,
    get_paginator,
    get_redir_arg,
    get_redir_field,
    get_redir_path,
    users_impersonable,
)
from .settings import User, settings
from .signals import session_begin, session_end
diff --git a/pyproject.toml b/pyproject.toml
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,7 @@
[tool.black]
line-length = 79
skip-string-normalization = true
target-version = ['py37', 'py38']
target-version = ['py37', 'py38', 'py39', 'py310', 'py311']
include = '\.pyi?$'
exclude = '''

diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -48,11 +48,14 @@
        'Framework :: Django :: 2.2',
        'Framework :: Django :: 3.2',
        'Framework :: Django :: 4.0',
        'Framework :: Django :: 4.1',
        'Framework :: Django :: 4.2',
        'Programming Language :: Python',
        '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',
        'Environment :: Web Environment',
    ],
)
diff --git a/tox.ini b/tox.ini
--- a/tox.ini
+++ b/tox.ini
@@ -1,10 +1,20 @@
[tox]
downloadcache = {toxworkdir}/cache/
envlist = py{37,38,39}-django{2.2,3.2},py{38,39}-django{4.0},py310-django{3.2,4.0}
envlist =
	py37-django{22,30,31,32}
	py38-django{22,30,31,32,40,41}
	py39-django{22,30,31,32,40,41}
	py310-django{32,40,41,42,main}
	py311-django{41,42,main}

[testenv]
commands = {envpython} runtests.py
deps =
	django2.2: django>=2.2,<3.0
	django3.2: django>=3.2,<4.0
	django4.0: django>=4.0,<4.1
	django22: django>=2.2,<3.0
	django30: django>=3.0,<3.1
	django31: django>=3.1,<3.2
	django32: django>=3.2,<4.0
	django40: django>=4.0,<4.1
	django41: django>=4.1,<4.2
	django42: django>=4.2,<4.3
	djangomain: https://github.com/django/django/archive/main.tar.gz
Hugo,

Sorry for the delay. Because it affects an unreleased version this patch
hasn't had high priority.

Can you adapt this to be just 1 `compat.py` file versus multiple. Help
keep the footprint as lean as possible.

Thanks,

Peter