Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop support for Django 2.2 #1551

Merged
merged 1 commit into from
Dec 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ In addition to the built-in panels, a number of third-party panels are
contributed by the community.

The current stable version of the Debug Toolbar is 3.2.4. It works on
Django ≥ 2.2.
Django ≥ 3.2.

Documentation, including installation and configuration instructions, is
available at https://django-debug-toolbar.readthedocs.io/.
Expand Down
5 changes: 0 additions & 5 deletions debug_toolbar/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import django

from debug_toolbar.urls import app_name

__all__ = ["VERSION"]
Expand All @@ -12,6 +10,3 @@
# Code that discovers files or modules in INSTALLED_APPS imports this module.

urls = "debug_toolbar.urls", app_name

if django.VERSION < (3, 2):
default_app_config = "debug_toolbar.apps.DebugToolbarConfig"
3 changes: 1 addition & 2 deletions debug_toolbar/management/commands/debugsqlshell.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from time import time

import django
import sqlparse
from django.core.management.commands.shell import Command
from django.db import connection

if connection.vendor == "postgresql" and django.VERSION >= (3, 0, 0):
if connection.vendor == "postgresql":
from django.db.backends.postgresql import base as base_module
else:
from django.db.backends import utils as base_module
Expand Down
75 changes: 23 additions & 52 deletions debug_toolbar/panels/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,9 @@
except ImportError:
ConnectionProxy = None

import django
from django.conf import settings
from django.core import cache
from django.core.cache import (
DEFAULT_CACHE_ALIAS,
CacheHandler,
cache as original_cache,
caches as original_caches,
)
from django.core.cache import DEFAULT_CACHE_ALIAS, CacheHandler
from django.core.cache.backends.base import BaseCache
from django.dispatch import Signal
from django.middleware import cache as middleware_cache
Expand Down Expand Up @@ -141,26 +135,17 @@ def decr_version(self, *args, **kwargs):
return self.cache.decr_version(*args, **kwargs)


if django.VERSION < (3, 2):
class CacheHandlerPatch(CacheHandler):
def __init__(self, settings=None):
self._djdt_wrap = True
super().__init__(settings=settings)

class CacheHandlerPatch(CacheHandler):
def __getitem__(self, alias):
actual_cache = super().__getitem__(alias)
def create_connection(self, alias):
actual_cache = super().create_connection(alias)
if self._djdt_wrap:
return CacheStatTracker(actual_cache)

else:

class CacheHandlerPatch(CacheHandler):
def __init__(self, settings=None):
self._djdt_wrap = True
super().__init__(settings=settings)

def create_connection(self, alias):
actual_cache = super().create_connection(alias)
if self._djdt_wrap:
return CacheStatTracker(actual_cache)
else:
return actual_cache
else:
return actual_cache


middleware_cache.caches = CacheHandlerPatch()
Expand Down Expand Up @@ -268,40 +253,26 @@ def title(self):
)

def enable_instrumentation(self):
if django.VERSION < (3, 2):
if isinstance(middleware_cache.caches, CacheHandlerPatch):
cache.caches = middleware_cache.caches
else:
cache.caches = CacheHandlerPatch()
else:
for alias in cache.caches:
if not isinstance(cache.caches[alias], CacheStatTracker):
cache.caches[alias] = CacheStatTracker(cache.caches[alias])
for alias in cache.caches:
if not isinstance(cache.caches[alias], CacheStatTracker):
cache.caches[alias] = CacheStatTracker(cache.caches[alias])

if not isinstance(middleware_cache.caches, CacheHandlerPatch):
middleware_cache.caches = cache.caches
if not isinstance(middleware_cache.caches, CacheHandlerPatch):
middleware_cache.caches = cache.caches

# Wrap the patched cache inside Django's ConnectionProxy
if ConnectionProxy:
cache.cache = ConnectionProxy(cache.caches, DEFAULT_CACHE_ALIAS)

def disable_instrumentation(self):
if django.VERSION < (3, 2):
cache.caches = original_caches
cache.cache = original_cache
# While it can be restored to the original, any views that were
# wrapped with the cache_page decorator will continue to use a
# monkey patched cache.
middleware_cache.caches = original_caches
else:
for alias in cache.caches:
if isinstance(cache.caches[alias], CacheStatTracker):
cache.caches[alias] = cache.caches[alias].cache
if ConnectionProxy:
cache.cache = ConnectionProxy(cache.caches, DEFAULT_CACHE_ALIAS)
# While it can be restored to the original, any views that were
# wrapped with the cache_page decorator will continue to use a
# monkey patched cache.
for alias in cache.caches:
if isinstance(cache.caches[alias], CacheStatTracker):
cache.caches[alias] = cache.caches[alias].cache
if ConnectionProxy:
cache.cache = ConnectionProxy(cache.caches, DEFAULT_CACHE_ALIAS)
# While it can be restored to the original, any views that were
# wrapped with the cache_page decorator will continue to use a
# monkey patched cache.

def generate_stats(self, request, response):
self.record_stats(
Expand Down
9 changes: 2 additions & 7 deletions debug_toolbar/panels/settings.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
from collections import OrderedDict

import django
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from django.views.debug import get_default_exception_reporter_filter

from debug_toolbar.panels import Panel

if django.VERSION >= (3, 1):
from django.views.debug import get_default_exception_reporter_filter

get_safe_settings = get_default_exception_reporter_filter().get_safe_settings
else:
from django.views.debug import get_safe_settings
get_safe_settings = get_default_exception_reporter_filter().get_safe_settings


class SettingsPanel(Panel):
Expand Down
2 changes: 1 addition & 1 deletion docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Change log
Next version
------------

* Removed support for Django 3.1.
* Removed support for Django < 3.2.

3.2.4 (2021-12-15)
------------------
Expand Down
3 changes: 1 addition & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ classifiers =
Development Status :: 5 - Production/Stable
Environment :: Web Environment
Framework :: Django
Framework :: Django :: 2.2
Framework :: Django :: 3.2
Framework :: Django :: 4.0
Intended Audience :: Developers
Expand All @@ -33,7 +32,7 @@ classifiers =
[options]
python_requires = >=3.6
install_requires =
Django >= 2.2
Django >= 3.2
sqlparse >= 0.2.0
packages = find:
include_package_data = true
Expand Down
3 changes: 1 addition & 2 deletions tests/commands/test_debugsqlshell.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import io
import sys

import django
from django.contrib.auth.models import User
from django.core import management
from django.db import connection
from django.test import TestCase
from django.test.utils import override_settings

if connection.vendor == "postgresql" and django.VERSION >= (3, 0, 0):
if connection.vendor == "postgresql":
from django.db.backends.postgresql import base as base_module
else:
from django.db.backends import utils as base_module
Expand Down
16 changes: 3 additions & 13 deletions tests/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.conf import settings
from django.db import models
from django.db.models import JSONField


class NonAsciiRepr:
Expand All @@ -11,19 +12,8 @@ class Binary(models.Model):
field = models.BinaryField()


try:
from django.db.models import JSONField
except ImportError: # Django<3.1
try:
from django.contrib.postgres.fields import JSONField
except ImportError: # psycopg2 not installed
JSONField = None


if JSONField:

class PostgresJSON(models.Model):
field = JSONField()
class PostgresJSON(models.Model):
field = JSONField()


if settings.USE_GIS:
Expand Down
27 changes: 5 additions & 22 deletions tests/panels/test_sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,7 @@
from debug_toolbar import settings as dt_settings

from ..base import BaseTestCase

try:
from psycopg2._json import Json as PostgresJson
except ImportError:
PostgresJson = None

if connection.vendor == "postgresql":
from ..models import PostgresJSON as PostgresJSONModel
else:
PostgresJSONModel = None
from ..models import PostgresJSON


class SQLPanelTestCase(BaseTestCase):
Expand Down Expand Up @@ -138,12 +129,9 @@ def test_param_conversion(self):
# ensure query was logged
self.assertEqual(len(self.panel._queries), 3)

if (
django.VERSION >= (3, 1)
# Django 4.1 started passing true/false back for boolean
# comparisons in MySQL.
and not (django.VERSION >= (4, 1) and connection.vendor == "mysql")
):
# Django 4.1 started passing true/false back for boolean
# comparisons in MySQL.
if not (django.VERSION >= (4, 1) and connection.vendor == "mysql"):
self.assertEqual(
tuple([q[1]["params"] for q in self.panel._queries]),
('["Foo"]', "[10, 1]", '["2017-12-22 16:07:01"]'),
Expand All @@ -160,7 +148,7 @@ def test_param_conversion(self):
def test_json_param_conversion(self):
self.assertEqual(len(self.panel._queries), 0)

list(PostgresJSONModel.objects.filter(field__contains={"foo": "bar"}))
list(PostgresJSON.objects.filter(field__contains={"foo": "bar"}))

response = self.panel.process_request(self.request)
self.panel.generate_stats(self.request, response)
Expand All @@ -171,11 +159,6 @@ def test_json_param_conversion(self):
self.panel._queries[0][1]["params"],
'["{\\"foo\\": \\"bar\\"}"]',
)
if django.VERSION < (3, 1):
self.assertIsInstance(
self.panel._queries[0][1]["raw_params"][0],
PostgresJson,
)

def test_binary_param_force_text(self):
self.assertEqual(len(self.panel._queries), 0)
Expand Down
8 changes: 1 addition & 7 deletions tests/test_forms.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
from datetime import datetime

import django
from django import forms
from django.test import TestCase

from debug_toolbar.forms import SignedDataForm

# Django 3.1 uses sha256 by default.
SIGNATURE = (
"v02QBcJplEET6QXHNWejnRcmSENWlw6_RjxLTR7QG9g"
if django.VERSION >= (3, 1)
else "ukcAFUqYhUUnqT-LupnYoo-KvFg"
)
SIGNATURE = "v02QBcJplEET6QXHNWejnRcmSENWlw6_RjxLTR7QG9g"

DATA = {"value": "foo", "date": datetime(2020, 1, 1)}
SIGNED_DATA = f'{{"date": "2020-01-01 00:00:00", "value": "foo"}}:{SIGNATURE}'
Expand Down
6 changes: 1 addition & 5 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import re
import unittest

import django
import html5lib
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from django.core import signing
Expand Down Expand Up @@ -444,10 +443,7 @@ def test_auth_login_view_without_redirect(self):
self.assertEqual(response.status_code, 200)
# The key None (without quotes) exists in the list of template
# variables.
if django.VERSION < (3, 0):
self.assertIn("None: &#39;&#39;", response.json()["content"])
else:
self.assertIn("None: &#x27;&#x27;", response.json()["content"])
self.assertIn("None: &#x27;&#x27;", response.json()["content"])


@unittest.skipIf(webdriver is None, "selenium isn't installed")
Expand Down
14 changes: 6 additions & 8 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@
envlist =
docs
packaging
py{36,37}-dj{22,32}-{sqlite,postgresql,postgis,mysql}
py{38,39}-dj{22,32,40,main}-{sqlite,postgresql,postgis,mysql}
py{310}-dj{32,40,main}-{sqlite,postgresql,postgis,mysql}
py{36,37}-dj{32}-{sqlite,postgresql,postgis,mysql}
py{38,39,310}-dj{32,40,main}-{sqlite,postgresql,postgis,mysql}

[testenv]
deps =
dj22: django~=2.2.17
dj32: django~=3.2.9
dj40: django~=4.0.0
sqlite: mock
Expand Down Expand Up @@ -42,25 +40,25 @@ whitelist_externals = make
pip_pre = True
commands = make coverage TEST_ARGS='{posargs:tests}'

[testenv:py{36,37,38,39,310}-dj{22,32,40,main}-postgresql]
[testenv:py{36,37,38,39,310}-dj{40,main}-postgresql]
setenv =
{[testenv]setenv}
DB_BACKEND = postgresql
DB_PORT = {env:DB_PORT:5432}

[testenv:py{36,37,38,39,310}-dj{22,32,40,main}-postgis]
[testenv:py{36,37,38,39,310}-dj{32,40,main}-postgis]
setenv =
{[testenv]setenv}
DB_BACKEND = postgis
DB_PORT = {env:DB_PORT:5432}

[testenv:py{36,37,38,39,310}-dj{22,32,40,main}-mysql]
[testenv:py{36,37,38,39,310}-dj{32,40,main}-mysql]
setenv =
{[testenv]setenv}
DB_BACKEND = mysql
DB_PORT = {env:DB_PORT:3306}

[testenv:py{36,37,38,39,310}-dj{22,32,40,main}-sqlite]
[testenv:py{36,37,38,39,310}-dj{32,40,main}-sqlite]
setenv =
{[testenv]setenv}
DB_BACKEND = sqlite3
Expand Down