diff --git a/debug_toolbar/_stubs.py b/debug_toolbar/_stubs.py index 01d0b8637..a27f3d1fe 100644 --- a/debug_toolbar/_stubs.py +++ b/debug_toolbar/_stubs.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import Any, List, NamedTuple, Optional, Tuple from django import template as dj_template diff --git a/debug_toolbar/panels/profiling.py b/debug_toolbar/panels/profiling.py index ffe9b7e37..b946f9f04 100644 --- a/debug_toolbar/panels/profiling.py +++ b/debug_toolbar/panels/profiling.py @@ -59,7 +59,7 @@ def func_std_string(self): # match what old profile produced # special case for built-in functions name = func_name[2] if name.startswith("<") and name.endswith(">"): - return "{%s}" % name[1:-1] + return f"{{{name[1:-1]}}}" else: return name else: diff --git a/debug_toolbar/panels/sql/forms.py b/debug_toolbar/panels/sql/forms.py index bb83155f4..1fa90ace4 100644 --- a/debug_toolbar/panels/sql/forms.py +++ b/debug_toolbar/panels/sql/forms.py @@ -44,7 +44,7 @@ def clean_alias(self): value = self.cleaned_data["alias"] if value not in connections: - raise ValidationError("Database alias '%s' not found" % value) + raise ValidationError(f"Database alias '{value}' not found") return value diff --git a/debug_toolbar/panels/versions.py b/debug_toolbar/panels/versions.py index 2b41377ca..77915e78b 100644 --- a/debug_toolbar/panels/versions.py +++ b/debug_toolbar/panels/versions.py @@ -16,7 +16,7 @@ class VersionsPanel(Panel): @property def nav_subtitle(self): - return "Django %s" % django.get_version() + return f"Django {django.get_version()}" title = _("Versions") diff --git a/debug_toolbar/toolbar.py b/debug_toolbar/toolbar.py index eb8789b7f..5c6b5cb7b 100644 --- a/debug_toolbar/toolbar.py +++ b/debug_toolbar/toolbar.py @@ -218,7 +218,7 @@ def debug_toolbar_urls(prefix="__debug__"): return [] return [ re_path( - r"^%s/" % re.escape(prefix.lstrip("/")), + r"^{}/".format(re.escape(prefix.lstrip("/"))), include("debug_toolbar.urls"), ), ] diff --git a/debug_toolbar/utils.py b/debug_toolbar/utils.py index 1e75cced2..26154a736 100644 --- a/debug_toolbar/utils.py +++ b/debug_toolbar/utils.py @@ -1,10 +1,12 @@ +from __future__ import annotations + import inspect import linecache import os.path import sys import warnings from pprint import PrettyPrinter, pformat -from typing import Any, Dict, List, Optional, Sequence, Tuple, Union +from typing import Any, Sequence from asgiref.local import Local from django.http import QueryDict @@ -17,7 +19,7 @@ _local_data = Local() -def _is_excluded_frame(frame: Any, excluded_modules: Optional[Sequence[str]]) -> bool: +def _is_excluded_frame(frame: Any, excluded_modules: Sequence[str] | None) -> bool: if not excluded_modules: return False frame_module = frame.f_globals.get("__name__") @@ -39,7 +41,7 @@ def _stack_trace_deprecation_warning() -> None: ) -def tidy_stacktrace(stack: List[stubs.InspectStack]) -> stubs.TidyStackTrace: +def tidy_stacktrace(stack: list[stubs.InspectStack]) -> stubs.TidyStackTrace: """ Clean up stacktrace and remove all entries that are excluded by the HIDE_IN_STACKTRACES setting. @@ -99,7 +101,7 @@ def render_stacktrace(trace: stubs.TidyStackTrace) -> SafeString: return mark_safe(html) -def get_template_info() -> Optional[Dict[str, Any]]: +def get_template_info() -> dict[str, Any] | None: template_info = None cur_frame = sys._getframe().f_back try: @@ -129,7 +131,7 @@ def get_template_info() -> Optional[Dict[str, Any]]: def get_template_context( node: Node, context: stubs.RequestContext, context_lines: int = 3 -) -> Dict[str, Any]: +) -> dict[str, Any]: line, source_lines, name = get_template_source_from_exception_info(node, context) debug_context = [] start = max(1, line - context_lines) @@ -146,7 +148,7 @@ def get_template_context( def get_template_source_from_exception_info( node: Node, context: stubs.RequestContext -) -> Tuple[int, List[Tuple[int, str]], str]: +) -> tuple[int, list[tuple[int, str]], str]: if context.template.origin == node.origin: exception_info = context.template.get_exception_info( Exception("DDT"), node.token @@ -213,8 +215,8 @@ def getframeinfo(frame: Any, context: int = 1) -> inspect.Traceback: def get_sorted_request_variable( - variable: Union[Dict[str, Any], QueryDict], -) -> Dict[str, Union[List[Tuple[str, Any]], Any]]: + variable: dict[str, Any] | QueryDict, +) -> dict[str, list[tuple[str, Any]] | Any]: """ Get a data structure for showing a sorted list of variables from the request data. @@ -228,7 +230,7 @@ def get_sorted_request_variable( return {"raw": variable} -def get_stack(context=1) -> List[stubs.InspectStack]: +def get_stack(context=1) -> list[stubs.InspectStack]: """ Get a list of records for a frame and all higher (calling) frames. @@ -286,7 +288,7 @@ def get_source_file(self, frame): def get_stack_trace( self, *, - excluded_modules: Optional[Sequence[str]] = None, + excluded_modules: Sequence[str] | None = None, include_locals: bool = False, skip: int = 0, ): diff --git a/debug_toolbar/views.py b/debug_toolbar/views.py index 467d7485c..b9a410db5 100644 --- a/debug_toolbar/views.py +++ b/debug_toolbar/views.py @@ -18,7 +18,7 @@ def render_panel(request): "Data for this panel isn't available anymore. " "Please reload the page and retry." ) - content = "

%s

" % escape(content) + content = f"

{escape(content)}

" scripts = [] else: panel = toolbar.get_panel_by_id(request.GET["panel_id"]) diff --git a/tests/base.py b/tests/base.py index 073fc9f15..3f40261fe 100644 --- a/tests/base.py +++ b/tests/base.py @@ -107,8 +107,8 @@ def assertValidHTML(self, content): msg_parts = ["Invalid HTML:"] lines = content.split("\n") for position, errorcode, datavars in parser.errors: - msg_parts.append(" %s" % html5lib.constants.E[errorcode] % datavars) - msg_parts.append(" %s" % lines[position[0] - 1]) + msg_parts.append(f" {html5lib.constants.E[errorcode]}" % datavars) + msg_parts.append(f" {lines[position[0] - 1]}") raise self.failureException("\n".join(msg_parts)) diff --git a/tests/test_csp_rendering.py b/tests/test_csp_rendering.py index 5e355b15a..a84f958c1 100644 --- a/tests/test_csp_rendering.py +++ b/tests/test_csp_rendering.py @@ -1,4 +1,6 @@ -from typing import Dict, cast +from __future__ import annotations + +from typing import cast from xml.etree.ElementTree import Element from django.conf import settings @@ -12,7 +14,7 @@ from .base import IntegrationTestCase -def get_namespaces(element: Element) -> Dict[str, str]: +def get_namespaces(element: Element) -> dict[str, str]: """ Return the default `xmlns`. See https://docs.python.org/3/library/xml.etree.elementtree.html#parsing-xml-with-namespaces @@ -31,7 +33,7 @@ def setUp(self): self.parser = HTMLParser() def _fail_if_missing( - self, root: Element, path: str, namespaces: Dict[str, str], nonce: str + self, root: Element, path: str, namespaces: dict[str, str], nonce: str ): """ Search elements, fail if a `nonce` attribute is missing on them. @@ -41,7 +43,7 @@ def _fail_if_missing( if item.attrib.get("nonce") != nonce: raise self.failureException(f"{item} has no nonce attribute.") - def _fail_if_found(self, root: Element, path: str, namespaces: Dict[str, str]): + def _fail_if_found(self, root: Element, path: str, namespaces: dict[str, str]): """ Search elements, fail if a `nonce` attribute is found on them. """ @@ -56,8 +58,8 @@ def _fail_on_invalid_html(self, content: bytes, parser: HTMLParser): default_msg = ["Content is invalid HTML:"] lines = content.split(b"\n") for position, error_code, data_vars in parser.errors: - default_msg.append(" %s" % E[error_code] % data_vars) - default_msg.append(" %r" % lines[position[0] - 1]) + default_msg.append(f" {E[error_code]}" % data_vars) + default_msg.append(f" {lines[position[0] - 1]!r}") msg = self._formatMessage(None, "\n".join(default_msg)) raise self.failureException(msg) diff --git a/tests/test_integration.py b/tests/test_integration.py index d1d439c72..3cc0b1420 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -324,8 +324,8 @@ def test_html5_validation(self): default_msg = ["Content is invalid HTML:"] lines = content.split(b"\n") for position, errorcode, datavars in parser.errors: - default_msg.append(" %s" % html5lib.constants.E[errorcode] % datavars) - default_msg.append(" %r" % lines[position[0] - 1]) + default_msg.append(f" {html5lib.constants.E[errorcode]}" % datavars) + default_msg.append(f" {lines[position[0] - 1]!r}") msg = self._formatMessage(None, "\n".join(default_msg)) raise self.failureException(msg) diff --git a/tests/test_integration_async.py b/tests/test_integration_async.py index 9386bdaf4..64e8f5a0d 100644 --- a/tests/test_integration_async.py +++ b/tests/test_integration_async.py @@ -247,8 +247,8 @@ async def test_html5_validation(self): default_msg = ["Content is invalid HTML:"] lines = content.split(b"\n") for position, errorcode, datavars in parser.errors: - default_msg.append(" %s" % html5lib.constants.E[errorcode] % datavars) - default_msg.append(" %r" % lines[position[0] - 1]) + default_msg.append(f" {html5lib.constants.E[errorcode]}" % datavars) + default_msg.append(f" {lines[position[0] - 1]!r}") msg = self._formatMessage(None, "\n".join(default_msg)) raise self.failureException(msg)