Skip to content

Commit

Permalink
Merge branch '2.3.x' into 3.0.x
Browse files Browse the repository at this point in the history
  • Loading branch information
davidism committed Nov 11, 2023
2 parents d30ef25 + ac6859f commit 6eafc0e
Show file tree
Hide file tree
Showing 24 changed files with 102 additions and 142 deletions.
29 changes: 0 additions & 29 deletions .flake8

This file was deleted.

31 changes: 8 additions & 23 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,26 +1,11 @@
MANIFEST
build
dist
/src/Werkzeug.egg-info
*.pyc
*.pyo
.venv
.DS_Store
docs/_build
bench/a
bench/b
.tox
.idea/
.vscode/
__pycache__/
.pytest_cache/
.tox/
.coverage
.coverage.*
coverage_out
htmlcov
.cache
.xprocess
.hypothesis
test_uwsgi_failed
.idea
.pytest_cache/
htmlcov/
docs/_build/
dist/
venv/
.vscode
.mypy_cache/
.dmypy.json
40 changes: 7 additions & 33 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,42 +1,16 @@
ci:
autoupdate_branch: "2.3.x"
autoupdate_schedule: monthly
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v3.10.1
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.5
hooks:
- id: pyupgrade
args: ["--py38-plus"]
- repo: https://github.com/asottile/reorder-python-imports
rev: v3.10.0
hooks:
- id: reorder-python-imports
name: Reorder Python imports (src, tests)
files: "^(?!examples/)"
args: ["--application-directories", ".:src"]
- id: reorder-python-imports
name: Reorder Python imports (examples)
files: "^examples/"
args: ["--application-directories", "examples"]
- repo: https://github.com/psf/black
rev: 23.7.0
hooks:
- id: black
- repo: https://github.com/PyCQA/flake8
rev: 6.1.0
hooks:
- id: flake8
additional_dependencies:
- flake8-bugbear
- flake8-implicit-str-concat
- repo: https://github.com/peterdemin/pip-compile-multi
rev: v2.6.3
hooks:
- id: pip-compile-multi-verify
- id: ruff
- id: ruff-format
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: check-merge-conflict
- id: debug-statements
- id: fix-byte-order-marker
- id: trailing-whitespace
- id: end-of-file-fixer
exclude: "^tests/.*.http$"
25 changes: 25 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,28 @@ module = [
"xprocess.*",
]
ignore_missing_imports = true

[tool.ruff]
extend-exclude = ["examples/"]
src = ["src"]
fix = false
show-fixes = true
show-source = true

[tool.ruff.lint]
select = [
"B", # flake8-bugbear
"E", # pycodestyle error
"F", # pyflakes
#"I", # isort
"UP", # pyupgrade
"W", # pycodestyle warning
]
ignore = [
"E402" # allow circular imports at end of file
]
ignore-init-module-imports = true

[tool.ruff.lint.isort]
force-single-line = true
order-by-type = false
2 changes: 1 addition & 1 deletion src/werkzeug/datastructures/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def to_header(self) -> str:
if self.type == "basic":
value = base64.b64encode(
f"{self.username}:{self.password}".encode()
).decode("utf8")
).decode("ascii")
return f"Basic {value}"

if self.token is not None:
Expand Down
2 changes: 1 addition & 1 deletion src/werkzeug/datastructures/mixins.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class ImmutableListMixin(list[V]):
_hash_cache: int | None
def __hash__(self) -> int: ... # type: ignore
def __delitem__(self, key: SupportsIndex | slice) -> NoReturn: ...
def __iadd__(self, other: t.Any) -> NoReturn: ... # type: ignore
def __iadd__(self, other: Any) -> NoReturn: ... # type: ignore
def __imul__(self, other: SupportsIndex) -> NoReturn: ...
def __setitem__(self, key: int | slice, value: V) -> NoReturn: ... # type: ignore
def append(self, value: V) -> NoReturn: ...
Expand Down
2 changes: 1 addition & 1 deletion src/werkzeug/datastructures/structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class MultiDict(TypeConversionDict):

def __init__(self, mapping=None):
if isinstance(mapping, MultiDict):
dict.__init__(self, ((k, l[:]) for k, l in mapping.lists()))
dict.__init__(self, ((k, vs[:]) for k, vs in mapping.lists()))
elif isinstance(mapping, dict):
tmp = {}
for key, value in mapping.items():
Expand Down
4 changes: 2 additions & 2 deletions src/werkzeug/debug/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def _generate() -> str | bytes | None:
guid, guid_type = winreg.QueryValueEx(rk, "MachineGuid")

if guid_type == winreg.REG_SZ:
return guid.encode("utf-8")
return guid.encode()

return guid
except OSError:
Expand Down Expand Up @@ -193,7 +193,7 @@ def get_pin_and_cookie_name(
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode("utf-8")
bit = bit.encode()
h.update(bit)
h.update(b"cookiesalt")

Expand Down
6 changes: 2 additions & 4 deletions src/werkzeug/debug/repr.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,7 @@ def __call__(self, topic: t.Any | None = None) -> None:
helper = _Helper()


def _add_subclass_info(
inner: str, obj: object, base: t.Type | tuple[t.Type, ...]
) -> str:
def _add_subclass_info(inner: str, obj: object, base: type | tuple[type, ...]) -> str:
if isinstance(base, tuple):
for cls in base:
if type(obj) is cls:
Expand All @@ -96,7 +94,7 @@ def _add_subclass_info(


def _sequence_repr_maker(
left: str, right: str, base: t.Type, limit: int = 8
left: str, right: str, base: type, limit: int = 8
) -> t.Callable[[DebugReprGenerator, t.Iterable, bool], str]:
def proxy(self: DebugReprGenerator, obj: t.Iterable, recursive: bool) -> str:
if recursive:
Expand Down
4 changes: 3 additions & 1 deletion src/werkzeug/debug/tbtools.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@ def all_tracebacks(
@cached_property
def all_frames(self) -> list[DebugFrameSummary]:
return [
f for _, te in self.all_tracebacks for f in te.stack # type: ignore[misc]
f # type: ignore[misc]
for _, te in self.all_tracebacks
for f in te.stack
]

def render_traceback_text(self) -> str:
Expand Down
4 changes: 1 addition & 3 deletions src/werkzeug/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,9 +556,7 @@ def _get_current_object() -> T:
# __weakref__ (__getattr__)
# __init_subclass__ (proxying metaclass not supported)
# __prepare__ (metaclass)
__class__ = _ProxyLookup(
fallback=lambda self: type(self), is_attr=True
) # type: ignore
__class__ = _ProxyLookup(fallback=lambda self: type(self), is_attr=True) # type: ignore[assignment]
__instancecheck__ = _ProxyLookup(lambda self, other: isinstance(other, self))
__subclasscheck__ = _ProxyLookup(lambda self, other: issubclass(other, self))
# __class_getitem__ triggered through __getitem__
Expand Down
38 changes: 28 additions & 10 deletions src/werkzeug/middleware/lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class HTTPWarning(Warning):
"""Warning class for HTTP warnings."""


def check_type(context: str, obj: object, need: t.Type = str) -> None:
def check_type(context: str, obj: object, need: type = str) -> None:
if type(obj) is not need:
warn(
f"{context!r} requires {need.__name__!r}, got {type(obj).__name__!r}.",
Expand Down Expand Up @@ -180,30 +180,44 @@ def close(self) -> None:
key
):
warn(
f"Entity header {key!r} found in 304 response.", HTTPWarning
f"Entity header {key!r} found in 304 response.",
HTTPWarning,
stacklevel=2,
)
if bytes_sent:
warn("304 responses must not have a body.", HTTPWarning)
warn(
"304 responses must not have a body.",
HTTPWarning,
stacklevel=2,
)
elif 100 <= status_code < 200 or status_code == 204:
if content_length != 0:
warn(
f"{status_code} responses must have an empty content length.",
HTTPWarning,
stacklevel=2,
)
if bytes_sent:
warn(f"{status_code} responses must not have a body.", HTTPWarning)
warn(
f"{status_code} responses must not have a body.",
HTTPWarning,
stacklevel=2,
)
elif content_length is not None and content_length != bytes_sent:
warn(
"Content-Length and the number of bytes sent to the"
" client do not match.",
WSGIWarning,
stacklevel=2,
)

def __del__(self) -> None:
if not self.closed:
try:
warn(
"Iterator was garbage collected before it was closed.", WSGIWarning
"Iterator was garbage collected before it was closed.",
WSGIWarning,
stacklevel=2,
)
except Exception:
pass
Expand Down Expand Up @@ -236,7 +250,7 @@ def __init__(self, app: WSGIApplication) -> None:
self.app = app

def check_environ(self, environ: WSGIEnvironment) -> None:
if type(environ) is not dict:
if type(environ) is not dict: # noqa: E721
warn(
"WSGI environment is not a standard Python dict.",
WSGIWarning,
Expand Down Expand Up @@ -304,14 +318,14 @@ def check_start_response(
if status_code < 100:
warn("Status code < 100 detected.", WSGIWarning, stacklevel=3)

if type(headers) is not list:
if type(headers) is not list: # noqa: E721
warn("Header list is not a list.", WSGIWarning, stacklevel=3)

for item in headers:
if type(item) is not tuple or len(item) != 2:
warn("Header items must be 2-item tuples.", WSGIWarning, stacklevel=3)
name, value = item
if type(name) is not str or type(value) is not str:
if type(name) is not str or type(value) is not str: # noqa: E721
warn(
"Header keys and values must be strings.", WSGIWarning, stacklevel=3
)
Expand Down Expand Up @@ -402,13 +416,17 @@ def checking_start_response(
)

if kwargs:
warn("'start_response' does not take keyword arguments.", WSGIWarning)
warn(
"'start_response' does not take keyword arguments.",
WSGIWarning,
stacklevel=2,
)

status: str = args[0]
headers: list[tuple[str, str]] = args[1]
exc_info: None | (
tuple[type[BaseException], BaseException, TracebackType]
) = (args[2] if len(args) == 3 else None)
) = args[2] if len(args) == 3 else None

headers_set[:] = self.check_start_response(status, headers, exc_info)
return GuardedWrite(start_response(status, headers, exc_info), chunks)
Expand Down
4 changes: 2 additions & 2 deletions src/werkzeug/routing/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def _pythonize(value: str) -> None | bool | int | float | str:
return str(value)


def parse_converter_args(argstr: str) -> tuple[t.Tuple, dict[str, t.Any]]:
def parse_converter_args(argstr: str) -> tuple[tuple[t.Any, ...], dict[str, t.Any]]:
argstr += ","
args = []
kwargs = {}
Expand Down Expand Up @@ -566,7 +566,7 @@ def get_converter(
self,
variable_name: str,
converter_name: str,
args: t.Tuple,
args: tuple[t.Any, ...],
kwargs: t.Mapping[str, t.Any],
) -> BaseConverter:
"""Looks up the converter for the given parameter.
Expand Down
3 changes: 1 addition & 2 deletions src/werkzeug/sansio/request.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import typing as t
from datetime import datetime
from urllib.parse import parse_qsl

Expand Down Expand Up @@ -91,7 +90,7 @@ class Request:
#: (for example for :attr:`access_list`).
#:
#: .. versionadded:: 0.6
list_storage_class: type[t.List] = ImmutableList
list_storage_class: type[list] = ImmutableList

user_agent_class: type[UserAgent] = UserAgent
"""The class used and returned by the :attr:`user_agent` property to
Expand Down
4 changes: 2 additions & 2 deletions src/werkzeug/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ def gen_salt(length: int) -> str:

def _hash_internal(method: str, salt: str, password: str) -> tuple[str, str]:
method, *args = method.split(":")
salt = salt.encode("utf-8")
password = password.encode("utf-8")
salt = salt.encode()
password = password.encode()

if method == "scrypt":
if not args:
Expand Down
2 changes: 1 addition & 1 deletion src/werkzeug/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ def send_file(
if isinstance(etag, str):
rv.set_etag(etag)
elif etag and path is not None:
check = adler32(path.encode("utf-8")) & 0xFFFFFFFF
check = adler32(path.encode()) & 0xFFFFFFFF
rv.set_etag(f"{mtime}-{size}-{check}")

if conditional:
Expand Down
2 changes: 1 addition & 1 deletion src/werkzeug/wrappers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .request import Request as Request
from .response import Response as Response
from .response import ResponseStream
from .response import ResponseStream as ResponseStream
Loading

0 comments on commit 6eafc0e

Please sign in to comment.