Skip to content

Commit cde0077

Browse files
committed
disallow_untyped_calls = true
1 parent 739b771 commit cde0077

71 files changed

Lines changed: 1754 additions & 852 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

flask_admin/_backwards.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def get_property(obj: t.Any, name: str, old_name: str, default: t.Any = None) ->
3636

3737

3838
class ObsoleteAttr:
39-
def __init__(self, new_name: str, old_name: str, default: t.Any):
39+
def __init__(self, new_name: str, old_name: str, default: t.Any) -> None:
4040
self.new_name = new_name
4141
self.old_name = old_name
4242
self.cache = "_cache_" + new_name
@@ -69,7 +69,7 @@ def __set__(self, obj: t.Any, value: t.Any) -> None:
6969

7070

7171
class ImportRedirect:
72-
def __init__(self, prefix: str, target: str):
72+
def __init__(self, prefix: str, target: str) -> None:
7373
self.prefix = prefix
7474
self.target = target
7575

flask_admin/_types.py

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,48 +13,43 @@
1313
from wtforms.widgets import Input
1414

1515
if sys.version_info >= (3, 11):
16-
from typing import NotRequired # noqa
16+
from typing import NotRequired
1717
else:
18-
from typing_extensions import NotRequired # noqa
18+
from typing_extensions import NotRequired
1919

2020
if t.TYPE_CHECKING:
21-
from flask_admin.base import BaseView as T_VIEW # noqa
21+
# optional dependencies
22+
from arrow import Arrow as T_ARROW # noqa
23+
from flask_babel import LazyString as T_LAZY_STRING
24+
from flask_sqlalchemy import Model as T_SQLALCHEMY_LEGACY_MODEL
25+
from sqlalchemy.orm import DeclarativeBase as T_DECLARATIVE_BASE
26+
27+
from flask_admin.base import BaseView as T_VIEW
2228
from flask_admin.contrib.sqla.validators import InputRequired as T_INPUT_REQUIRED
2329
from flask_admin.contrib.sqla.validators import (
2430
TimeZoneValidator as T_TIMEZONE_VALIDATOR,
2531
)
2632
from flask_admin.contrib.sqla.validators import Unique as T_UNIQUE
27-
from flask_admin.form import FormOpts as T_FORM_OPTS # noqa
28-
from flask_admin.form.rules import (
29-
FieldSet as T_FIELD_SET,
30-
BaseRule as T_BASE_RULE,
31-
Header as T_HEADER,
32-
Field as T_FLASK_ADMIN_FIELD,
33-
Macro as T_MACRO,
34-
)
33+
from flask_admin.form import FormOpts as T_FORM_OPTS
34+
from flask_admin.form.rules import BaseRule as T_BASE_RULE
35+
from flask_admin.form.rules import Field as T_FLASK_ADMIN_FIELD
36+
from flask_admin.form.rules import FieldSet as T_FIELD_SET
37+
from flask_admin.form.rules import Header as T_HEADER
38+
from flask_admin.form.rules import Macro as T_MACRO
3539
from flask_admin.model import BaseModelView as T_MODEL_VIEW
36-
from flask_admin.model.ajax import AjaxModelLoader as T_AJAX_MODEL_LOADER # noqa
37-
from flask_admin.model.fields import AjaxSelectField as T_AJAX_SELECT_FIELD # noqa
38-
from flask_admin.model.form import ( # noqa
39-
InlineBaseFormAdmin as T_INLINE_BASE_FORM_ADMIN,
40-
)
40+
from flask_admin.model.ajax import AjaxModelLoader as T_AJAX_MODEL_LOADER
41+
from flask_admin.model.fields import AjaxSelectField as T_AJAX_SELECT_FIELD
42+
from flask_admin.model.form import InlineBaseFormAdmin as T_INLINE_BASE_FORM_ADMIN
4143
from flask_admin.model.form import InlineFormAdmin as T_INLINE_FORM_ADMIN
4244
from flask_admin.model.widgets import (
43-
InlineFieldListWidget as T_INLINE_FIELD_LIST_WIDGET,
45+
AjaxSelect2Widget as T_INLINE_AJAX_SELECT2_WIDGET,
4446
)
45-
from flask_admin.model.widgets import InlineFormWidget as T_INLINE_FORM_WIDGET
4647
from flask_admin.model.widgets import (
47-
AjaxSelect2Widget as T_INLINE_AJAX_SELECT2_WIDGET,
48+
InlineFieldListWidget as T_INLINE_FIELD_LIST_WIDGET,
4849
)
50+
from flask_admin.model.widgets import InlineFormWidget as T_INLINE_FORM_WIDGET
4951
from flask_admin.model.widgets import XEditableWidget as T_INLINE_X_EDITABLE_WIDGET
5052

51-
# optional dependencies
52-
from arrow import Arrow as T_ARROW # noqa
53-
from flask_babel import LazyString as T_LAZY_STRING # noqa
54-
55-
from flask_sqlalchemy import Model as T_SQLALCHEMY_LEGACY_MODEL
56-
from sqlalchemy.orm import DeclarativeBase as T_DECLARATIVE_BASE
57-
5853
T_SQLALCHEMY_MODEL: t.TypeAlias = t.Union[
5954
T_SQLALCHEMY_LEGACY_MODEL, T_DECLARATIVE_BASE
6055
]
@@ -82,14 +77,15 @@
8277
T_SQLALCHEMY_COLUMN = Column # type: ignore[misc]
8378

8479
T_MONGO_CLIENT = MongoClient[t.Any]
85-
from redis import Redis as T_REDIS # noqa
80+
from PIL.Image import Image as T_PIL_IMAGE
81+
from redis import Redis as T_REDIS
82+
8683
from flask_admin.contrib.peewee.ajax import (
8784
QueryAjaxModelLoader as T_PEEWEE_QUERY_AJAX_MODEL_LOADER,
88-
) # noqa
85+
)
8986
from flask_admin.contrib.sqla.ajax import (
9087
QueryAjaxModelLoader as T_SQLA_QUERY_AJAX_MODEL_LOADER,
91-
) # noqa
92-
from PIL.Image import Image as T_PIL_IMAGE # noqa
88+
)
9389

9490
T_ORM_MODEL: t.TypeAlias = t.Union[
9591
T_SQLALCHEMY_LEGACY_MODEL,
@@ -278,3 +274,9 @@ def __contains__(self, key: t.Any, /) -> bool: ...
278274

279275
class _MultiDictLikeWithGetlist(_MultiDictLikeBase, t.Protocol):
280276
def getlist(self, key: str, /) -> list[t.Any]: ...
277+
278+
279+
class _T_MONGOENGINE_FIELD_PROTOCOL(t.Protocol):
280+
id: t.Any
281+
data: t.Any
282+
name: str

flask_admin/actions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ def get_actions_list(self) -> tuple[list[t.Any], dict[t.Any, t.Any]]:
8989
"""
9090
Return a list and a dictionary of allowed actions.
9191
"""
92-
actions = []
93-
actions_confirmation = {}
92+
actions: list[tuple[str, str]] = []
93+
actions_confirmation: dict[str, str] = {}
9494

9595
for act in self._actions:
9696
name, text = act

flask_admin/base.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from flask import g
1010
from flask import render_template
1111
from flask import url_for
12+
from flask.typing import ResponseReturnValue
1213
from flask.views import MethodView
1314
from flask.views import View
1415
from markupsafe import Markup
@@ -21,11 +22,11 @@
2122
# For compatibility reasons import MenuLink
2223
from flask_admin.blueprints import _BlueprintWithHostSupport as Blueprint
2324
from flask_admin.consts import ADMIN_ROUTES_HOST_VARIABLE
24-
from flask_admin.menu import BaseMenu # noqa: F401
25-
from flask_admin.menu import MenuCategory # noqa: F401
26-
from flask_admin.menu import MenuLink # noqa: F401
27-
from flask_admin.menu import MenuView # noqa: F401
28-
from flask_admin.menu import SubMenuCategory # noqa: F401
25+
from flask_admin.menu import BaseMenu
26+
from flask_admin.menu import MenuCategory
27+
from flask_admin.menu import MenuLink
28+
from flask_admin.menu import MenuView
29+
from flask_admin.menu import SubMenuCategory
2930
from flask_admin.theme import Bootstrap4Theme
3031
from flask_admin.theme import Theme
3132

@@ -405,7 +406,7 @@ def is_accessible(self) -> bool:
405406
"""
406407
return True
407408

408-
def _handle_view(self, name: str, **kwargs: dict[str, t.Any]) -> t.Any:
409+
def _handle_view(self, name: str, **kwargs: t.Any) -> ResponseReturnValue | None:
409410
"""
410411
This method will be executed before calling any view method.
411412
@@ -420,6 +421,7 @@ def _handle_view(self, name: str, **kwargs: dict[str, t.Any]) -> t.Any:
420421
# abort(403)
421422
if not self.is_accessible():
422423
return self.inaccessible_callback(name, **kwargs) or abort(403)
424+
return None
423425

424426
def _run_view(
425427
self, fn: t.Callable[..., t.Any], *args: t.Any, **kwargs: t.Any
@@ -440,7 +442,9 @@ def _run_view(
440442
except TypeError:
441443
return fn(cls=self, **kwargs)
442444

443-
def inaccessible_callback(self, name: t.Any, **kwargs: t.Any) -> t.Any:
445+
def inaccessible_callback(
446+
self, name: t.Any, **kwargs: t.Any
447+
) -> ResponseReturnValue:
444448
"""
445449
Handle the response to inaccessible views.
446450

flask_admin/contrib/fileadmin/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def __init__(self, on_windows: bool) -> None:
5858
"""
5959
self.on_windows = on_windows
6060

61-
def normpath(self, path):
61+
def normpath(self, path: str) -> str:
6262
"""
6363
returns the correct normalized path based on the platform of the storage.
6464
@@ -122,7 +122,7 @@ def get_files(
122122
the relative path, a flag signifying if it is a directory, the file
123123
size in bytes and the time last modified in seconds since the epoch
124124
"""
125-
items = []
125+
items: list[tuple[str, str, bool, int, float]] = []
126126
for f in os.listdir(directory):
127127
fp = op.join(directory, f)
128128
rel_path = op.join(path, f)
@@ -645,7 +645,7 @@ def is_in_folder(self, base_path: str, directory: T_PATH_LIKE) -> bool:
645645
:param directory:
646646
Directory path to check
647647
"""
648-
return self.normpath(directory).startswith(base_path)
648+
return self.normpath(directory).startswith(base_path) # type: ignore[arg-type]
649649

650650
def save_file(self, path: str, file_data: FileStorage) -> None:
651651
"""
@@ -874,7 +874,7 @@ def _save_form_files(self, directory: str, path: str, form: t.Any) -> None:
874874
self.save_file(filename, form.upload.data)
875875
self.on_file_upload(directory, path, filename)
876876

877-
def normpath(self, path):
877+
def normpath(self, path: str) -> str:
878878
return self.storage.normpath(path) # type: ignore[union-attr]
879879

880880
@property
@@ -886,8 +886,8 @@ def _get_breadcrumbs(self, path: str) -> list[tuple[str, str]]:
886886
Returns a list of tuples with each tuple containing the folder and
887887
the tree up to that folder when traversing down the `path`
888888
"""
889-
accumulator = []
890-
breadcrumbs = []
889+
accumulator: list[str] = []
890+
breadcrumbs: list[tuple[str, str]] = []
891891

892892
for n in path.split(self._separator):
893893
accumulator.append(n)

flask_admin/contrib/fileadmin/azure.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def __init__(
5151
blob_service_client: BlobServiceClient,
5252
container_name: str,
5353
on_windows: bool = False,
54-
):
54+
) -> None:
5555
"""
5656
Constructor
5757
@@ -106,7 +106,7 @@ def get_files(
106106
num_path_parts = len(path_parts)
107107

108108
folders = set()
109-
files = []
109+
files: list[tuple[str, str, bool, int, float]] = []
110110

111111
container_client = self._client.get_container_client(self._container_name)
112112

@@ -168,8 +168,8 @@ def get_base_path(self) -> str:
168168
def get_breadcrumbs(self, path: str | None) -> list[tuple[str, str]]:
169169
path = self._ensure_blob_path(path)
170170

171-
accumulator = []
172-
breadcrumbs = []
171+
accumulator: list[str] = []
172+
breadcrumbs: list[tuple[str, str]] = []
173173
if path is not None:
174174
for folder in path.split(self.separator):
175175
accumulator.append(folder)
@@ -181,7 +181,7 @@ def send_file(self, file_path: str) -> flask.Response:
181181
if path is None:
182182
raise ValueError("No path provided")
183183
blob = self._container_client.get_blob_client(path).download_blob()
184-
if not blob.properties or not blob.properties.has_key("content_settings"):
184+
if not blob.properties or not blob.properties.has_key("content_settings"): # type: ignore[no-untyped-call]
185185
raise ValueError("Blob has no properties")
186186
mime_type = blob.properties["content_settings"]["content_type"]
187187
blob_file = io.BytesIO()

flask_admin/contrib/fileadmin/s3.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ def _remove_trailing_slash(name: str) -> str:
9797
return name[:-1]
9898

9999
files = []
100-
directories = []
100+
directories: list[tuple[str, str, bool, int, int]] = []
101101
if path and not path.endswith(self.separator):
102102
path += self.separator
103103

@@ -173,8 +173,8 @@ def get_base_path(self) -> str:
173173

174174
@_strip_leading_slash_from("path")
175175
def get_breadcrumbs(self, path: str) -> list[tuple[str, str]]:
176-
accumulator = []
177-
breadcrumbs = []
176+
accumulator: list[str] = []
177+
breadcrumbs: list[tuple[str, str]] = []
178178
for n in path.split(self.separator):
179179
accumulator.append(n)
180180
breadcrumbs.append((n, self.separator.join(accumulator)))

flask_admin/contrib/geoa/fields.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def _value(self):
5454
else:
5555
return ""
5656

57-
def process_formdata(self, valuelist):
57+
def process_formdata(self, valuelist: t.Sequence[str] | None) -> None:
5858
super().process_formdata(valuelist)
5959
if str(self.data) == "":
6060
self.data = None

flask_admin/contrib/geoa/form.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1+
import typing as t
2+
13
from flask_admin.contrib.sqla.form import AdminModelConverter as SQLAAdminConverter
24
from flask_admin.model.form import converts
35

6+
from ..._types import T_COL_NO_STR
47
from .fields import GeoJSONField
58

69

710
class AdminModelConverter(SQLAAdminConverter):
811
@converts("Geography", "Geometry")
9-
def convert_geom(self, column, field_args, **extra):
10-
field_args["geometry_type"] = column.type.geometry_type
11-
field_args["srid"] = column.type.srid
12+
def convert_geom(
13+
self, column: T_COL_NO_STR, field_args: dict[str, t.Any], **extra: t.Any
14+
) -> GeoJSONField:
15+
field_args["geometry_type"] = column.type.geometry_type # type: ignore[union-attr]
16+
field_args["srid"] = column.type.srid # type: ignore[union-attr]
1217
field_args["session"] = self.session
1318
field_args["tile_layer_url"] = self.view.tile_layer_url # type: ignore[attr-defined]
1419
field_args["tile_layer_attribution"] = self.view.tile_layer_attribution # type: ignore[attr-defined]

0 commit comments

Comments
 (0)