Received: from mail.netlandish.com (mail.netlandish.com [174.136.98.166])
	by code.netlandish.com (Postfix) with ESMTP id B900A81385
	for <~petersanchez/public-inbox@lists.code.netlandish.com>; Fri, 20 Oct 2023 14:45:10 +0000 (UTC)
Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.218.54; helo=mail-ej1-f54.google.com; envelope-from=hugo@yunojuno.com; receiver=<UNKNOWN> 
Authentication-Results: mail.netlandish.com;
	dkim=pass (2048-bit key; unprotected) header.d=yunojuno-com.20230601.gappssmtp.com header.i=@yunojuno-com.20230601.gappssmtp.com header.b=h1ofrBdE
Received: from mail-ej1-f54.google.com (mail-ej1-f54.google.com [209.85.218.54])
	by mail.netlandish.com (Postfix) with ESMTP id 43065152E8A
	for <~petersanchez/public-inbox@lists.code.netlandish.com>; Fri, 20 Oct 2023 14:45:08 +0000 (UTC)
Received: by mail-ej1-f54.google.com with SMTP id a640c23a62f3a-9c773ac9b15so80233166b.2
        for <~petersanchez/public-inbox@lists.code.netlandish.com>; Fri, 20 Oct 2023 07:45:08 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=yunojuno-com.20230601.gappssmtp.com; s=20230601; t=1697813107; x=1698417907; darn=lists.code.netlandish.com;
        h=to:from:date:user-agent:message-id:subject:mime-version:from:to:cc
         :subject:date:message-id:reply-to;
        bh=wewrUfRtUoJUiX7a05bJcifXTWn9J2GuFu45a41U4sE=;
        b=h1ofrBdEaBKj881nwgr64EwNKP/RkucxmMU4VI03AczjSYch0ct4Ou14q1kNpp1Pk+
         N0VsqwfyUl0xywQ7x3ikx+6PT6nSs64Or94pvY0gU9GBGOBEkviq0ioJD6s3HegURXpN
         kil54RwOTHnglvebHb4jPEJcFU3J0kgBTZHmvoFydd+T5oPLRYS1qCM6EJhaicwDTAzZ
         ZAsp3fIj19DrE58cMuDTNgU6zg2QmkTyuMnGAxMeVNR844gZ11MJRz6NXi4Wybw5Gj+E
         Zghgvhlonj2gddep4rmIOWk/wFmMmrSk/vfcvSDmghqbKTjYD1jICwELxukNppclLHAJ
         Xsvw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20230601; t=1697813107; x=1698417907;
        h=to:from:date:user-agent:message-id:subject:mime-version
         :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;
        bh=wewrUfRtUoJUiX7a05bJcifXTWn9J2GuFu45a41U4sE=;
        b=ZQSGIpIMdDqvG+UmD8FfHEpFy6F43YbU7MMuB0+zLumUyceDB6LSmqNQ9FURnyb2+1
         1qoJhKQ1Lm/kKrIu82s9RNphYKwfcsJpg9fmzOFIEpJAa0j13ZAOMKrnWAVX/gakPdWI
         wFvR/tJCXztqGPoup9UPOTiZVwf3Ef4n9cB2AIplWub4U/vhss2q1PkvSOINANTRUHiw
         zT93pUpzZGgiUjQ4O6oYTqo3N/aWZWJIXnXO2/UFm/Gep84Dnha/Q2qicy/4hyksnp0m
         xoPw0ALlfxoH0wGluPTTM+5NEjC9SoUceolB52pPQUNKhKaoOxbE8rTwUkZenxIAumJt
         uk8w==
X-Gm-Message-State: AOJu0YxScWd2QVbAPuSdTtrlRrOMMloY1eOMgRADmXG+/plB3rgSZ8AO
	coMLJ4qwezidvual6+2ggtIPHeRmS/Gghs5JiQSMA9Xo/92tyUwPqYyfyh3C1d+o6riGNdFr/0P
	nR1eHaQtsUvUO/svyPCGB166hKgcMG5DyGHBTpCQ1P2wEr6Cf4pfSIoRKABPmVQ==
X-Google-Smtp-Source: AGHT+IGg37XY6R1o4h1VG4O8NbJbu+DeVK0y1YWeoFDvrFBcIRDwvlpTzlCCSDPTgS4mFRkVg8ihUw==
X-Received: by 2002:a17:907:97d4:b0:9be:7b67:1673 with SMTP id js20-20020a17090797d400b009be7b671673mr1491675ejc.1.1697813107035;
        Fri, 20 Oct 2023 07:45:07 -0700 (PDT)
Received: from h12h5hdzq6x8.lan ([5.80.29.162])
        by smtp.gmail.com with ESMTPSA id u17-20020a17090657d100b009c5c5c2c59csm1688536ejr.149.2023.10.20.07.45.06
        for <~petersanchez/public-inbox@lists.code.netlandish.com>
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Fri, 20 Oct 2023 07:45:06 -0700 (PDT)
MIME-Version: 1.0
Subject: [PATCH django-impersonate] Add Django 5.0 compatibility (reverse
 function)
X-Mercurial-Node: 20fc6981d0031925058fe71500e92a0728fd1425
X-Mercurial-Series-Index: 1
X-Mercurial-Series-Total: 1
Message-Id: <20fc6981d0031925058f.1697813105@h12h5hdzq6x8.lan>
X-Mercurial-Series-Id: <20fc6981d0031925058f.1697813105@h12h5hdzq6x8.lan>
User-Agent: Mercurial-patchbomb/6.5.1
Date: Fri, 20 Oct 2023 15:45:05 +0100
From: =?iso-8859-1?q?Hugo_Rodger-Brown?= <hugo@yunojuno.com>
To: ~petersanchez/public-inbox@lists.code.netlandish.com
Content-Type: text/plain; charset="US-ASCII"

# HG changeset patch
# User Hugo Rodger-Brown <hugo@yunojuno.com>
# Date 1697812487 -3600
#      Fri Oct 20 15:34:47 2023 +0100
# Node ID 20fc6981d0031925058fe71500e92a0728fd1425
# Parent  c0672089c42607eda5f423483cdc79092c9d1efa
Add Django 5.0 compatibility (reverse function)

I have added a `compat` module to handle the migration of the `reverse`
function from django.core.urlresolvers to django.urls.

I have updated the tests to handle the change in 4.2 to 5.0 where request
params passed to a SimpleListFilter are passed as list of values, not just
one.

I have updated the build matrix to include Django5.0 and the main branch, as
well as Python 3.12.

diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -6,10 +6,12 @@
 **.pyc
 MANIFEST
 .idea
+.venv
+*.egg-info
 
 syntax:regexp
 ^htmlcov$
 ^env$
 syntax: glob
 *.komodoproject
-.DS_Store
\ No newline at end of file
+.DS_Store
diff --git a/MANIFEST.in b/MANIFEST.in
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,4 +1,4 @@
-include BSD-LICENSE
 include CHANGELOG
+include LICENSE
 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__)
 
 
@@ -44,6 +40,7 @@
         )
 
     def queryset(self, request, queryset):
+        print(f"self.value(): {self.value()}")
         if self.value() == 'incomplete':
             return queryset.filter(session_ended_at__isnull=True)
         if self.value() == 'complete':
diff --git a/impersonate/compat.py b/impersonate/compat.py
new file mode 100644
--- /dev/null
+++ b/impersonate/compat.py
@@ -0,0 +1,7 @@
+# compatibility module for handling Django upgrade namespace changes
+try:
+    from django.urls import reverse
+except ImportError:
+    from django.core.urlresolvers import reverse
+
+__all__ = ["reverse"]
diff --git a/impersonate/middleware.py b/impersonate/middleware.py
--- a/impersonate/middleware.py
+++ b/impersonate/middleware.py
@@ -2,10 +2,11 @@
 from datetime import datetime, timedelta, timezone
 
 from django.http import HttpResponseNotAllowed
-from django.shortcuts import redirect, reverse
+from django.shortcuts import redirect
 from django.utils.deprecation import MiddlewareMixin
 from django.utils.functional import SimpleLazyObject
 
+from .compat import reverse
 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
@@ -35,17 +35,15 @@
 from django.utils.duration import duration_string
 
 from .admin import (
-    ImpersonationLogAdmin, ImpersonatorFilter, SessionStateFilter,
+    ImpersonationLogAdmin,
+    ImpersonatorFilter,
+    SessionStateFilter,
 )
+from .compat import reverse
 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,16 @@
         qs = _filter.queryset(None, ImpersonationLog.objects.all())
         self.assertEqual(qs.count(), 2)
 
+        def _format_params(val):
+            # Django 5.x returns request querystring params as a list
+            # https://github.com/django/django/commit/d03dc63177ad3ba6e685e314eed45d6a8ec5cb0c
+            if django_version_loose >= '5.0':
+                return {'session': [val]}
+            return {'session': val}
+
         _filter = SessionStateFilter(
             None,
-            {'session': 'complete'},
+            _format_params('complete'),
             ImpersonationLog,
             ImpersonationLogAdmin,
         )
@@ -736,7 +741,7 @@
 
         _filter = SessionStateFilter(
             None,
-            {'session': 'incomplete'},
+            _format_params('incomplete'),
             ImpersonationLog,
             ImpersonationLogAdmin,
         )
diff --git a/impersonate/views.py b/impersonate/views.py
--- a/impersonate/views.py
+++ b/impersonate/views.py
@@ -8,8 +8,12 @@
 
 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', 'py312']
 include = '\.pyi?$'
 exclude = '''
 
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -48,11 +48,16 @@
         'Framework :: Django :: 2.2',
         'Framework :: Django :: 3.2',
         'Framework :: Django :: 4.0',
+        'Framework :: Django :: 4.1',
+        'Framework :: Django :: 4.2',
+        'Framework :: Django :: 5.0',
         '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',
+        'Programming Language :: Python :: 3.12',
         'Environment :: Web Environment',
     ],
 )
diff --git a/tox.ini b/tox.ini
--- a/tox.ini
+++ b/tox.ini
@@ -1,10 +1,28 @@
 [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}
+; https://docs.djangoproject.com/en/2.2/faq/install/
+; https://docs.djangoproject.com/en/5.0/faq/install/
+envlist =
+	py{37,38,39}-django2.2
+	; Django 3.0 / 3.1 not included in PyPI classifiers
+	; py{37,38,39}-django3.0
+	; py{37,38,39}-django3.1
+	py{37,38,39,310}-django3.2
+	py{38,39,310}-django4.0
+	py{38,39,310}-django4.1
+	py{38,39,310,311}-django4.1
+	py{38,39,310,311}-django4.2
+	py{310,311,312}-django{5.0,main}
 
 [testenv]
 commands = {envpython} runtests.py
 deps =
 	django2.2: django>=2.2,<3.0
-	django3.2: django>=3.2,<4.0
+	django3.0: django>=3.0,<3.1
+	django3.1: django>=3.1,<3.2
+	django3.2: django>=3.2,<3.3
 	django4.0: django>=4.0,<4.1
+	django4.1: django>=4.1,<4.2
+	django4.2: django>=4.2,<4.3
+	django5.0: https://github.com/django/django/archive/stable/5.0.x.tar.gz
+	djangomain: https://github.com/django/django/archive/main.tar.gz


-- 
Disclaimer: This email and any files transmitted with it are confidential 
and intended solely for the use of the individual or entity to whom they 
are addressed. This message contains confidential information and is 
intended only for the individual named. If you are not the named addressee, 
you should not disseminate, distribute or copy this email. Please notify 
the sender immediately by email if you have received this email by mistake 
and delete this email from your system. If you are not the intended 
recipient, you are notified that disclosing, copying, distributing or 
taking any action in reliance on the contents of this information is 
strictly prohibited.  YunoJuno is 100% compliant with the GDPR data 
protection regulation. Visit our privacy policy to learn how we collect, 
keep, and process your private information in accordance with these laws at 
www.yunojuno.com <http://www.yunojuno.com/>.