Skip to content

Commit

Permalink
Add pyupgrade and fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
robhudson committed Jul 1, 2024
1 parent 71afcf5 commit 83bb99d
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 30 deletions.
8 changes: 4 additions & 4 deletions csp/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pprint
from collections.abc import Sequence
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
from typing import TYPE_CHECKING, Any

from django.conf import settings
from django.core.checks import Error
Expand Down Expand Up @@ -47,9 +47,9 @@
]


def migrate_settings() -> Tuple[Dict[str, Any], bool]:
def migrate_settings() -> tuple[dict[str, Any], bool]:
# This function is used to migrate settings from the old format to the new format.
config: Dict[str, Any] = {
config: dict[str, Any] = {
"DIRECTIVES": {},
}

Expand Down Expand Up @@ -77,7 +77,7 @@ def migrate_settings() -> Tuple[Dict[str, Any], bool]:
return config, REPORT_ONLY


def check_django_csp_lt_4_0(app_configs: Optional[Sequence[AppConfig]], **kwargs: Any) -> List[Error]:
def check_django_csp_lt_4_0(app_configs: Sequence[AppConfig] | None, **kwargs: Any) -> list[Error]:
check_settings = OUTDATED_SETTINGS + ["CSP_REPORT_ONLY", "CSP_EXCLUDE_URL_PREFIXES", "CSP_REPORT_PERCENTAGE"]
if any(hasattr(settings, setting) for setting in check_settings):
# Try to build the new config.
Expand Down
6 changes: 3 additions & 3 deletions csp/context_processors.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Dict, Literal
from typing import TYPE_CHECKING, Literal

if TYPE_CHECKING:
from django.http import HttpRequest


def nonce(request: HttpRequest) -> Dict[Literal["CSP_NONCE"], str]:
nonce = request.csp_nonce if hasattr(request, "csp_nonce") else ""
def nonce(request: HttpRequest) -> dict[Literal["CSP_NONCE"], str]:
nonce = getattr(request, "csp_nonce", "")

return {"CSP_NONCE": nonce}
12 changes: 6 additions & 6 deletions csp/decorators.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from functools import wraps
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional
from typing import TYPE_CHECKING, Any, Callable

if TYPE_CHECKING:
from django.http import HttpRequest, HttpResponseBase
Expand All @@ -11,7 +11,7 @@
_VIEW_DECORATOR_T = Callable[[_VIEW_T], _VIEW_T]


def csp_exempt(REPORT_ONLY: Optional[bool] = None) -> _VIEW_DECORATOR_T:
def csp_exempt(REPORT_ONLY: bool | None = None) -> _VIEW_DECORATOR_T:
if callable(REPORT_ONLY):
raise RuntimeError(
"Incompatible `csp_exempt` decorator usage. This decorator now requires arguments, "
Expand Down Expand Up @@ -42,7 +42,7 @@ def _wrapped(*a: Any, **kw: Any) -> HttpResponseBase:
)


def csp_update(config: Optional[Dict[str, Any]] = None, REPORT_ONLY: bool = False, **kwargs: Any) -> _VIEW_DECORATOR_T:
def csp_update(config: dict[str, Any] | None = None, REPORT_ONLY: bool = False, **kwargs: Any) -> _VIEW_DECORATOR_T:
if config is None and kwargs:
raise RuntimeError(DECORATOR_DEPRECATION_ERROR.format(fname="csp_update"))

Expand All @@ -61,7 +61,7 @@ def _wrapped(*a: Any, **kw: Any) -> HttpResponseBase:
return decorator


def csp_replace(config: Optional[Dict[str, Any]] = None, REPORT_ONLY: bool = False, **kwargs: Any) -> _VIEW_DECORATOR_T:
def csp_replace(config: dict[str, Any] | None = None, REPORT_ONLY: bool = False, **kwargs: Any) -> _VIEW_DECORATOR_T:
if config is None and kwargs:
raise RuntimeError(DECORATOR_DEPRECATION_ERROR.format(fname="csp_replace"))

Expand All @@ -80,12 +80,12 @@ def _wrapped(*a: Any, **kw: Any) -> HttpResponseBase:
return decorator


def csp(config: Optional[Dict[str, Any]] = None, REPORT_ONLY: bool = False, **kwargs: Any) -> _VIEW_DECORATOR_T:
def csp(config: dict[str, Any] | None = None, REPORT_ONLY: bool = False, **kwargs: Any) -> _VIEW_DECORATOR_T:
if config is None and kwargs:
raise RuntimeError(DECORATOR_DEPRECATION_ERROR.format(fname="csp"))

if config is None:
processed_config: Dict[str, List[Any]] = {}
processed_config: dict[str, list[Any]] = {}
else:
processed_config = {k: [v] if isinstance(v, str) else v for k, v in config.items()}

Expand Down
4 changes: 2 additions & 2 deletions csp/templatetags/csp.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING

from django import template
from django.template.base import token_kwargs
Expand Down Expand Up @@ -38,7 +38,7 @@ def __init__(self, nodelist: NodeList, **kwargs: FilterExpression) -> None:
for k, v in kwargs.items():
self.script_attrs[k] = self._get_token_value(v)

def _get_token_value(self, t: FilterExpression) -> Optional[str]:
def _get_token_value(self, t: FilterExpression) -> str | None:
if hasattr(t, "token") and t.token:
return _unquote(t.token)
return None
Expand Down
6 changes: 3 additions & 3 deletions csp/tests/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple
from typing import TYPE_CHECKING, Any, Callable

from django.http import HttpResponse
from django.template import Context, Template, engines
Expand All @@ -14,7 +14,7 @@
from django.http import HttpRequest


def response(*args: Any, headers: Optional[Dict[str, str]] = None, **kwargs: Any) -> Callable[[HttpRequest], HttpResponse]:
def response(*args: Any, headers: dict[str, str] | None = None, **kwargs: Any) -> Callable[[HttpRequest], HttpResponse]:
def get_response(req: HttpRequest) -> HttpResponse:
response = HttpResponse(*args, **kwargs)
if headers:
Expand All @@ -36,7 +36,7 @@ def assert_template_eq(self, tpl1: str, tpl2: str) -> None:
bbb = tpl2.replace("\n", "").replace(" ", "")
assert aaa == bbb, f"{aaa} != {bbb}"

def process_templates(self, tpl: str, expected: str) -> Tuple[str, str]:
def process_templates(self, tpl: str, expected: str) -> tuple[str, str]:
request = rf.get("/")
mw.process_request(request)
nonce = getattr(request, "csp_nonce")
Expand Down
22 changes: 12 additions & 10 deletions csp/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from __future__ import annotations

import copy
import re
from collections import OrderedDict
from itertools import chain
from typing import Any, Callable, Dict, Optional, Union
from typing import Any, Callable

from django.conf import settings
from django.utils.encoding import force_str
Expand Down Expand Up @@ -50,10 +52,10 @@
"block-all-mixed-content": None, # Deprecated.
}

_DIRECTIVES = Dict[str, Any]
_DIRECTIVES = dict[str, Any]


def default_config(csp: Optional[_DIRECTIVES]) -> Optional[_DIRECTIVES]:
def default_config(csp: _DIRECTIVES | None) -> _DIRECTIVES | None:
if csp is None:
return None
# Make a copy of the passed in config to avoid mutating it, and also to drop any unknown keys.
Expand All @@ -64,10 +66,10 @@ def default_config(csp: Optional[_DIRECTIVES]) -> Optional[_DIRECTIVES]:


def build_policy(
config: Optional[_DIRECTIVES] = None,
update: Optional[_DIRECTIVES] = None,
replace: Optional[_DIRECTIVES] = None,
nonce: Optional[str] = None,
config: _DIRECTIVES | None = None,
update: _DIRECTIVES | None = None,
replace: _DIRECTIVES | None = None,
nonce: str | None = None,
report_only: bool = False,
) -> str:
"""Builds the policy as a string from the settings."""
Expand Down Expand Up @@ -151,7 +153,7 @@ def _bool_attr_mapper(attr_name: str, val: bool) -> str:
return ""


def _async_attr_mapper(attr_name: str, val: Union[str, bool]) -> str:
def _async_attr_mapper(attr_name: str, val: str | bool) -> str:
"""The `async` attribute works slightly different than the other bool
attributes. It can be set explicitly to `false` with no surrounding quotes
according to the spec."""
Expand All @@ -164,7 +166,7 @@ def _async_attr_mapper(attr_name: str, val: Union[str, bool]) -> str:


# Allow per-attribute customization of returned string template
SCRIPT_ATTRS: Dict[str, Callable[[str, Any], str]] = OrderedDict()
SCRIPT_ATTRS: dict[str, Callable[[str, Any], str]] = OrderedDict()
SCRIPT_ATTRS["nonce"] = _default_attr_mapper
SCRIPT_ATTRS["id"] = _default_attr_mapper
SCRIPT_ATTRS["src"] = _default_attr_mapper
Expand Down Expand Up @@ -197,7 +199,7 @@ def _unwrap_script(text: str) -> str:
return text


def build_script_tag(content: Optional[str] = None, **kwargs: Any) -> str:
def build_script_tag(content: str | None = None, **kwargs: Any) -> str:
data = {}
# Iterate all possible script attrs instead of kwargs to make
# interpolation as easy as possible below
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ lint.select = [
"I", # import sorting
"Q", # flake8-quotes errors
"T20", # flake8-print errors
"UP", # py-upgrade
"W", # pycodestyle warnings
# "B", # bugbear errors
# "UP", # py-upgrade
# "B", # bugbear errors - incompatible with our use of `gettattr` and `setattr`.
]
# Allow unused variables when underscore-prefixed.
lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
Expand Down

0 comments on commit 83bb99d

Please sign in to comment.