Skip to content

Commit 528381b

Browse files
committed
check and fixup for mypy
1 parent 1fc8466 commit 528381b

File tree

3 files changed

+35
-17
lines changed

3 files changed

+35
-17
lines changed

src/desert/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
import desert._version
99

1010

11+
if t.TYPE_CHECKING:
12+
import attr._make
13+
14+
1115
def schema(
1216
cls: t.Type, many: bool = False, meta: t.Dict[str, t.Any] = {}
1317
) -> marshmallow.Schema:
@@ -63,7 +67,10 @@ class A:
6367
"""
6468
meta = metadata(marshmallow_field)
6569
meta.update(kw.pop("metadata", {}))
66-
return dataclasses.field(**kw, metadata=meta)
70+
# typeshed hints it as Mapping[str, Any] without any obvious reason
71+
# https://github.com/python/typeshed/blob/95a45eb4abd0c25849268983cb614e3bf6b9b264/stdlib/dataclasses.pyi#L81
72+
# https://github.com/python/typeshed/pull/5823
73+
return dataclasses.field(**kw, metadata=meta) # type: ignore[arg-type]
6774

6875

6976
def ib(marshmallow_field: marshmallow.fields.Field, **kw) -> attr._make._CountingAttr:

src/desert/_make.py

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ class User:
5454
Schema: t.ClassVar[Type[Schema]] = Schema # For the type checker
5555
"""
5656

57-
__all__ = ("schema_class", "schema")
58-
5957
import dataclasses
6058
import datetime
6159
import decimal
@@ -99,7 +97,7 @@ def class_schema(
9997
``marshmallow_field`` key in the metadata dictionary.
10098
"""
10199

102-
fields: t.Union[t.Tuple[dataclasses.Field], t.Tuple[attr.Attribute]]
100+
fields: t.Union[t.Tuple[dataclasses.Field, ...], t.Tuple[attr.Attribute, ...]]
103101

104102
if not isinstance(clazz, type):
105103
raise desert.exceptions.UnknownType(
@@ -119,9 +117,9 @@ def class_schema(
119117
raise desert.exceptions.NotAnAttrsClassOrDataclass(clazz)
120118

121119
# Copy all public fields of the dataclass to the schema
122-
attributes = {
123-
field.name: field for field in fields if not field.name.startswith("_")
124-
}
120+
attributes: t.Dict[
121+
str, t.Union[dataclasses.Field, attr.Attribute, marshmallow.fields.Field]
122+
] = {field.name: field for field in fields if not field.name.startswith("_")}
125123

126124
# Update the schema members to contain marshmallow fields instead of dataclass fields.
127125
hints = t.get_type_hints(clazz)
@@ -133,16 +131,23 @@ def class_schema(
133131
field.metadata,
134132
)
135133

134+
class_attributes: t.Dict[str, t.Any] = {
135+
**attributes,
136+
"Meta": type("Meta", (), meta),
137+
}
138+
136139
cls_schema = type(
137140
clazz.__name__,
138141
(_base_schema(clazz),),
139-
{**attributes, "Meta": type("Meta", (), meta)},
142+
class_attributes,
140143
)
141144

142145
return t.cast(t.Type[marshmallow.Schema], cls_schema)
143146

144147

145-
_native_to_marshmallow: t.Dict[type, t.Type[marshmallow.fields.Field]] = {
148+
_native_to_marshmallow: t.Dict[
149+
t.Union[type, t.Any], t.Type[marshmallow.fields.Field]
150+
] = {
146151
int: marshmallow.fields.Integer,
147152
float: marshmallow.fields.Float,
148153
str: marshmallow.fields.String,
@@ -171,7 +176,7 @@ def only(items: t.Iterable[T]) -> T:
171176

172177

173178
def field_for_schema(
174-
typ: type, default=marshmallow.missing, metadata: t.Mapping[str, t.Any] = None
179+
typ: type, default=marshmallow.missing, metadata: t.Mapping[t.Any, t.Any] = None
175180
) -> marshmallow.fields.Field:
176181
"""
177182
Get a marshmallow Field corresponding to the given python type.
@@ -319,25 +324,30 @@ def _get_field_default(field: t.Union[dataclasses.Field, attr.Attribute]):
319324
<marshmallow.missing>
320325
"""
321326
if isinstance(field, dataclasses.Field):
322-
if field.default_factory != dataclasses.MISSING:
327+
# https://github.com/python/mypy/issues/10750
328+
if field.default_factory != dataclasses.MISSING: # type: ignore[misc]
323329
return dataclasses.MISSING
324330
if field.default is dataclasses.MISSING:
325331
return marshmallow.missing
326332
return field.default
327333
elif isinstance(field, attr.Attribute):
328334
if field.default == attr.NOTHING:
329335
return marshmallow.missing
330-
if isinstance(field.default, attr.Factory):
331-
if field.default.takes_self:
336+
if isinstance(field.default, attr.Factory): # type: ignore[arg-type]
337+
# attrs specifically doesn't support this so as to support the
338+
# primary use case.
339+
# https://github.com/python-attrs/attrs/blob/38580632ceac1cd6e477db71e1d190a4130beed4/src/attr/__init__.pyi#L63-L65
340+
if field.default.takes_self: # type: ignore[union-attr]
332341
return attr.NOTHING
333-
return field.default.factory
342+
return field.default.factory # type: ignore[union-attr]
334343
return field.default
335344
else:
336345
raise TypeError(field)
337346

338347

339-
def sentinel(name):
340-
return attr.make_class(name, [], frozen=True)()
348+
@attr.frozen
349+
class _DesertSentinel:
350+
pass
341351

342352

343-
_DESERT_SENTINEL = sentinel("_DesertSentinel")
353+
_DESERT_SENTINEL = _DesertSentinel()

tox.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ commands =
4242
check-manifest {toxinidir}
4343
black --check {toxinidir}
4444
isort --verbose --check-only --diff --recursive src tests setup.py
45+
mypy src/desert/
4546

4647
[testenv:spell]
4748
setenv =

0 commit comments

Comments
 (0)