Skip to content

Commit 6000e80

Browse files
committed
address mypy strict findings
1 parent 5a48a0f commit 6000e80

24 files changed

+346
-234
lines changed

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Unreleased
88
- Session data is untagged without relying on the built-in ``json.loads``
99
``object_hook``. This allows other JSON providers that don't implement that.
1010
:issue:`5381`
11+
- Address more type findings when using mypy strict mode. :pr:`5383`
1112

1213

1314
Version 3.0.0

pyproject.toml

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -82,21 +82,7 @@ python_version = "3.8"
8282
files = ["src/flask", "tests/typing"]
8383
show_error_codes = true
8484
pretty = true
85-
#strict = true
86-
allow_redefinition = true
87-
disallow_subclassing_any = true
88-
#disallow_untyped_calls = true
89-
#disallow_untyped_defs = true
90-
#disallow_incomplete_defs = true
91-
no_implicit_optional = true
92-
local_partial_types = true
93-
#no_implicit_reexport = true
94-
strict_equality = true
95-
warn_redundant_casts = true
96-
warn_unused_configs = true
97-
warn_unused_ignores = true
98-
#warn_return_any = true
99-
#warn_unreachable = true
85+
strict = true
10086

10187
[[tool.mypy.overrides]]
10288
module = [

requirements/typing.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
mypy
22
types-contextvars
33
types-dataclasses
4+
asgiref
45
cryptography
6+
python-dotenv

requirements/typing.txt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,23 @@
44
#
55
# pip-compile typing.in
66
#
7+
asgiref==3.7.2
8+
# via -r typing.in
79
cffi==1.16.0
810
# via cryptography
9-
cryptography==41.0.5
11+
cryptography==41.0.7
1012
# via -r typing.in
11-
mypy==1.6.1
13+
mypy==1.8.0
1214
# via -r typing.in
1315
mypy-extensions==1.0.0
1416
# via mypy
1517
pycparser==2.21
1618
# via cffi
19+
python-dotenv==1.0.0
20+
# via -r typing.in
1721
types-contextvars==2.4.7.3
1822
# via -r typing.in
1923
types-dataclasses==0.6.6
2024
# via -r typing.in
21-
typing-extensions==4.8.0
25+
typing-extensions==4.9.0
2226
# via mypy

src/flask/app.py

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from __future__ import annotations
22

3+
import collections.abc as cabc
34
import os
45
import sys
56
import typing as t
67
import weakref
7-
from collections.abc import Iterator as _abc_Iterator
88
from datetime import timedelta
99
from inspect import iscoroutinefunction
1010
from itertools import chain
@@ -54,6 +54,9 @@
5454
from .wrappers import Response
5555

5656
if t.TYPE_CHECKING: # pragma: no cover
57+
from _typeshed.wsgi import StartResponse
58+
from _typeshed.wsgi import WSGIEnvironment
59+
5760
from .testing import FlaskClient
5861
from .testing import FlaskCliRunner
5962

@@ -200,11 +203,11 @@ class Flask(App):
200203

201204
#: The class that is used for request objects. See :class:`~flask.Request`
202205
#: for more information.
203-
request_class = Request
206+
request_class: type[Request] = Request
204207

205208
#: The class that is used for response objects. See
206209
#: :class:`~flask.Response` for more information.
207-
response_class = Response
210+
response_class: type[Response] = Response
208211

209212
#: the session interface to use. By default an instance of
210213
#: :class:`~flask.sessions.SecureCookieSessionInterface` is used here.
@@ -216,11 +219,11 @@ def __init__(
216219
self,
217220
import_name: str,
218221
static_url_path: str | None = None,
219-
static_folder: str | os.PathLike | None = "static",
222+
static_folder: str | os.PathLike[str] | None = "static",
220223
static_host: str | None = None,
221224
host_matching: bool = False,
222225
subdomain_matching: bool = False,
223-
template_folder: str | os.PathLike | None = "templates",
226+
template_folder: str | os.PathLike[str] | None = "templates",
224227
instance_path: str | None = None,
225228
instance_relative_config: bool = False,
226229
root_path: str | None = None,
@@ -282,7 +285,7 @@ def get_send_file_max_age(self, filename: str | None) -> int | None:
282285
if isinstance(value, timedelta):
283286
return int(value.total_seconds())
284287

285-
return value
288+
return value # type: ignore[no-any-return]
286289

287290
def send_static_file(self, filename: str) -> Response:
288291
"""The view function used to serve files from
@@ -447,13 +450,13 @@ def raise_routing_exception(self, request: Request) -> t.NoReturn:
447450
or request.routing_exception.code in {307, 308}
448451
or request.method in {"GET", "HEAD", "OPTIONS"}
449452
):
450-
raise request.routing_exception # type: ignore
453+
raise request.routing_exception # type: ignore[misc]
451454

452455
from .debughelpers import FormDataRoutingRedirect
453456

454457
raise FormDataRoutingRedirect(request)
455458

456-
def update_template_context(self, context: dict) -> None:
459+
def update_template_context(self, context: dict[str, t.Any]) -> None:
457460
"""Update the template context with some commonly used variables.
458461
This injects request, session, config and g into the template
459462
context as well as everything template context processors want
@@ -481,7 +484,7 @@ def update_template_context(self, context: dict) -> None:
481484

482485
context.update(orig_ctx)
483486

484-
def make_shell_context(self) -> dict:
487+
def make_shell_context(self) -> dict[str, t.Any]:
485488
"""Returns the shell context for an interactive shell for this
486489
application. This runs all the registered shell context
487490
processors.
@@ -724,7 +727,7 @@ def handle_http_exception(
724727
handler = self._find_error_handler(e, request.blueprints)
725728
if handler is None:
726729
return e
727-
return self.ensure_sync(handler)(e)
730+
return self.ensure_sync(handler)(e) # type: ignore[no-any-return]
728731

729732
def handle_user_exception(
730733
self, e: Exception
@@ -756,7 +759,7 @@ def handle_user_exception(
756759
if handler is None:
757760
raise
758761

759-
return self.ensure_sync(handler)(e)
762+
return self.ensure_sync(handler)(e) # type: ignore[no-any-return]
760763

761764
def handle_exception(self, e: Exception) -> Response:
762765
"""Handle an exception that did not have an error handler
@@ -849,7 +852,7 @@ def dispatch_request(self) -> ft.ResponseReturnValue:
849852
return self.make_default_options_response()
850853
# otherwise dispatch to the handler for that endpoint
851854
view_args: dict[str, t.Any] = req.view_args # type: ignore[assignment]
852-
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
855+
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
853856

854857
def full_dispatch_request(self) -> Response:
855858
"""Dispatches the request and on top of that performs request
@@ -913,7 +916,7 @@ def make_default_options_response(self) -> Response:
913916
rv.allow.update(methods)
914917
return rv
915918

916-
def ensure_sync(self, func: t.Callable) -> t.Callable:
919+
def ensure_sync(self, func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:
917920
"""Ensure that the function is synchronous for WSGI workers.
918921
Plain ``def`` functions are returned as-is. ``async def``
919922
functions are wrapped to run and wait for the response.
@@ -928,7 +931,7 @@ def ensure_sync(self, func: t.Callable) -> t.Callable:
928931
return func
929932

930933
def async_to_sync(
931-
self, func: t.Callable[..., t.Coroutine]
934+
self, func: t.Callable[..., t.Coroutine[t.Any, t.Any, t.Any]]
932935
) -> t.Callable[..., t.Any]:
933936
"""Return a sync function that will run the coroutine function.
934937
@@ -1166,7 +1169,7 @@ def make_response(self, rv: ft.ResponseReturnValue) -> Response:
11661169

11671170
# make sure the body is an instance of the response class
11681171
if not isinstance(rv, self.response_class):
1169-
if isinstance(rv, (str, bytes, bytearray)) or isinstance(rv, _abc_Iterator):
1172+
if isinstance(rv, (str, bytes, bytearray)) or isinstance(rv, cabc.Iterator):
11701173
# let the response class set the status and headers instead of
11711174
# waiting to do it manually, so that the class can handle any
11721175
# special logic
@@ -1240,7 +1243,7 @@ def preprocess_request(self) -> ft.ResponseReturnValue | None:
12401243
rv = self.ensure_sync(before_func)()
12411244

12421245
if rv is not None:
1243-
return rv
1246+
return rv # type: ignore[no-any-return]
12441247

12451248
return None
12461249

@@ -1353,7 +1356,7 @@ def app_context(self) -> AppContext:
13531356
"""
13541357
return AppContext(self)
13551358

1356-
def request_context(self, environ: dict) -> RequestContext:
1359+
def request_context(self, environ: WSGIEnvironment) -> RequestContext:
13571360
"""Create a :class:`~flask.ctx.RequestContext` representing a
13581361
WSGI environment. Use a ``with`` block to push the context,
13591362
which will make :data:`request` point at this request.
@@ -1425,7 +1428,9 @@ def test_request_context(self, *args: t.Any, **kwargs: t.Any) -> RequestContext:
14251428
finally:
14261429
builder.close()
14271430

1428-
def wsgi_app(self, environ: dict, start_response: t.Callable) -> t.Any:
1431+
def wsgi_app(
1432+
self, environ: WSGIEnvironment, start_response: StartResponse
1433+
) -> cabc.Iterable[bytes]:
14291434
"""The actual WSGI application. This is not implemented in
14301435
:meth:`__call__` so that middlewares can be applied without
14311436
losing a reference to the app object. Instead of doing this::
@@ -1473,7 +1478,9 @@ def wsgi_app(self, environ: dict, start_response: t.Callable) -> t.Any:
14731478

14741479
ctx.pop(error)
14751480

1476-
def __call__(self, environ: dict, start_response: t.Callable) -> t.Any:
1481+
def __call__(
1482+
self, environ: WSGIEnvironment, start_response: StartResponse
1483+
) -> cabc.Iterable[bytes]:
14771484
"""The WSGI server calls the Flask application object as the
14781485
WSGI application. This calls :meth:`wsgi_app`, which can be
14791486
wrapped to apply middleware.

src/flask/blueprints.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def get_send_file_max_age(self, filename: str | None) -> int | None:
3939
if isinstance(value, timedelta):
4040
return int(value.total_seconds())
4141

42-
return value
42+
return value # type: ignore[no-any-return]
4343

4444
def send_static_file(self, filename: str) -> Response:
4545
"""The view function used to serve files from

0 commit comments

Comments
 (0)