Received: from mail.netlandish.com (mail.netlandish.com [174.136.98.166])
	by code.netlandish.com (Postfix) with ESMTP id 34FD183384
	for <~petersanchez/public-inbox@lists.code.netlandish.com>; Wed, 28 Jun 2023 10:24:39 +0000 (UTC)
Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.128.52; helo=mail-wm1-f52.google.com; envelope-from=hugo@yunojuno.com; receiver=<UNKNOWN> 
Authentication-Results: mail.netlandish.com;
	dkim=pass (2048-bit key; unprotected) header.d=yunojuno-com.20221208.gappssmtp.com header.i=@yunojuno-com.20221208.gappssmtp.com header.b=IDti93Wt
Received: from mail-wm1-f52.google.com (mail-wm1-f52.google.com [209.85.128.52])
	by mail.netlandish.com (Postfix) with ESMTP id 825D4152E8A
	for <~petersanchez/public-inbox@lists.code.netlandish.com>; Wed, 28 Jun 2023 10:24:35 +0000 (UTC)
Received: by mail-wm1-f52.google.com with SMTP id 5b1f17b1804b1-3fba66f3e1dso16709955e9.3
        for <~petersanchez/public-inbox@lists.code.netlandish.com>; Wed, 28 Jun 2023 03:24:35 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=yunojuno-com.20221208.gappssmtp.com; s=20221208; t=1687947874; x=1690539874;
        h=to:from:date:user-agent:message-id:subject
         :content-transfer-encoding:mime-version:from:to:cc:subject:date
         :message-id:reply-to;
        bh=BRc5aHbUmV1MFdRcShXjOuyGAn/vtq5svS6tF5Qcroc=;
        b=IDti93WtrBHYEzKvZKlSX5bbA78lbai7SBKJaRKtiNmcdrk1OOKMdD8bzVxe8MKaeN
         21sylGJxiJVtCYtWIoJv99X0y/yn6t8K4pUegPK/+EiTb0jmyDy9fpE6xHr2j7khQWJS
         1iwTVHAdXsj/0ksuLrvVr3QGmUx8C1ZYpHoGjIa0jgu6e2SKr+Cj3BHtBxsDvFj31nqz
         iBxq3Aw9U7o9bh+hkBUreZP/K8SO36t7mbtSAKHEiqYkwEJVagnwS8KEy/l/braflPTj
         KmfWD/59ERrbZZCnRvApSiDIq+6aIHO0PwcArpZ0pCpgi+qrewSq8K26VkqGu+kCNgKn
         MIfw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20221208; t=1687947874; x=1690539874;
        h=to:from:date:user-agent:message-id:subject
         :content-transfer-encoding:mime-version:x-gm-message-state:from:to
         :cc:subject:date:message-id:reply-to;
        bh=BRc5aHbUmV1MFdRcShXjOuyGAn/vtq5svS6tF5Qcroc=;
        b=lOBUtjwh7a70MMvCaZFFt6SbvhX7thw1cfsSaXsBZaUN3GKyUl8jkBaFuxzCxLTu0g
         KvYaXJ1mCL8ugO8TpVAKcOwUO03bE06ldQHneZw0KEhrblobnStesnsrjphVRCQdsrhk
         qj4WsHeZfd0lWswQBmtosd1t764HR8n+lax8ubOFcZ/DpzXMVtqT5MA8RWgsC93SEHK5
         Y5hxNLt8WVpCiQfeLg4z/d9twEnIVfbGojpAUWkVYFNycKQUBnwlm4KKCjU/+j1NuQNj
         J/pD6TbKSXNSr8dI5YRv8f3KXaurYAW0jcFtlP/jhcsz3ZXHc8oNWteDHnfH498US7Iu
         BBug==
X-Gm-Message-State: AC+VfDzK8FnP4cgSavbXY7s7UA3xW17mCRIuZz7J48IpmSdrDmSCp8Ft
	cgU3vCf7de517xlplO5q3mrerhHd2o+ZN02yjYA=
X-Google-Smtp-Source: ACHHUZ64A5qocEmP8gDls+N1UMrKeehc9RWaObzcTRvbQe8g3p0qlnBDOuqpGMjikMEGSOG8U5uIfw==
X-Received: by 2002:a05:600c:215:b0:3fa:99d6:47a4 with SMTP id 21-20020a05600c021500b003fa99d647a4mr5849860wmi.22.1687947874354;
        Wed, 28 Jun 2023 03:24:34 -0700 (PDT)
Received: from [127.0.0.1] ([217.138.15.147])
        by smtp.gmail.com with ESMTPSA id m13-20020a7bcb8d000000b003fba97b1252sm3407343wmi.1.2023.06.28.03.24.33
        for <~petersanchez/public-inbox@lists.code.netlandish.com>
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Wed, 28 Jun 2023 03:24:33 -0700 (PDT)
MIME-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Subject: [PATCH django-impersonate] Add support for Django 5.0 (pre)
X-Mercurial-Node: 4abfc208f5ac1289c52f7d2b2ace9abddd1bb46c
X-Mercurial-Series-Index: 1
X-Mercurial-Series-Total: 1
Message-Id: <4abfc208f5ac1289c52f.1687947872@C17FQ18CQ6L4>
X-Mercurial-Series-Id: <4abfc208f5ac1289c52f.1687947872@C17FQ18CQ6L4>
User-Agent: Mercurial-patchbomb/6.4rc0
Date: Wed, 28 Jun 2023 11:24:32 +0100
From: =?iso-8859-1?q?Hugo_Rodger-Brown?= <hugo@yunojuno.com>
To: ~petersanchez/public-inbox@lists.code.netlandish.com

# HG changeset patch
# User Hugo Rodger-Brown
# Date 1681222628 -3600
#      Tue Apr 11 15:17:08 2023 +0100
# Node ID 4abfc208f5ac1289c52f7d2b2ace9abddd1bb46c
# 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.py b/impersonate/compat.py
new file mode 100644
--- /dev/null
+++ b/impersonate/compat.py
@@ -0,0 +1,12 @@
+try:
+    from django.urls import reverse
+except ImportError:
+    from django.core.urlresolvers import reverse
+
+
+# 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/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