1212 import attr ._make
1313
1414
15+ T = t .TypeVar ("T" )
16+
17+
1518def schema (
16- cls : t . Type , many : bool = False , meta : t .Dict [str , t .Any ] = {}
19+ cls : type , many : bool = False , meta : t .Dict [str , t .Any ] = {}
1720) -> marshmallow .Schema :
1821 """Build a marshmallow schema *instance* for the class.
1922
@@ -29,7 +32,7 @@ def schema(
2932
3033
3134def schema_class (
32- cls : t . Type , meta : t .Dict [str , t .Any ] = {}
35+ cls : type , meta : t .Dict [str , t .Any ] = {}
3336) -> t .Type [marshmallow .Schema ]:
3437 """Build a marshmallow schema *class* for the class.
3538
@@ -46,7 +49,7 @@ def schema_class(
4649
4750def metadata (
4851 field : marshmallow .fields .Field ,
49- ) -> t .Dict ["desert._make._DesertSentinel" , t . Dict [ t . Any , marshmallow . fields . Field ] ]:
52+ ) -> t .Dict [object , object ]:
5053 """Specify a marshmallow field in the field metadata.
5154
5255 .. code-block:: python
@@ -56,7 +59,53 @@ def metadata(
5659 return {desert ._make ._DESERT_SENTINEL : {"marshmallow_field" : field }}
5760
5861
59- def field (marshmallow_field : marshmallow .fields .Field , ** kw ) -> dataclasses .Field :
62+ # TODO: maybe deprecate and rename metadata()
63+ create_metadata = metadata
64+
65+
66+ # These overloads lie about their return type just as both attrs and dataclasses
67+ # do so as to support the normal usage of `attribute: int = field()`
68+ @t .overload
69+ def field (
70+ marshmallow_field : marshmallow .fields .Field ,
71+ * ,
72+ default : T ,
73+ metadata : t .Mapping [object , object ] = {},
74+ ** kw : object ,
75+ ) -> T :
76+ ...
77+
78+
79+ @t .overload
80+ def field (
81+ marshmallow_field : marshmallow .fields .Field ,
82+ * ,
83+ default_factory : t .Callable [[], T ],
84+ metadata : t .Mapping [object , object ] = {},
85+ ** kw : object ,
86+ ) -> T :
87+ ...
88+
89+
90+ @t .overload
91+ def field (
92+ marshmallow_field : marshmallow .fields .Field ,
93+ * ,
94+ metadata : t .Mapping [object , object ] = {},
95+ ** kw : object ,
96+ ) -> object :
97+ ...
98+
99+
100+ # The return type hint of object is certainly a lie but fits a lot better with
101+ # the normal use of `x: int = desert.field()`. Both dataclasses and attrs
102+ # prioritize hinting for this usage as well. Perhaps someday we'll have a
103+ # plugin that indicates the actual type.
104+ def field (
105+ marshmallow_field : marshmallow .fields .Field ,
106+ metadata : t .Mapping [object , object ] = {},
107+ ** kw : object ,
108+ ) -> object :
60109 """Specify a marshmallow field in the metadata for a ``dataclasses.dataclass``.
61110
62111 .. code-block:: python
@@ -65,15 +114,58 @@ def field(marshmallow_field: marshmallow.fields.Field, **kw) -> dataclasses.Fiel
65114 class A:
66115 x: int = desert.field(marshmallow.fields.Int())
67116 """
68- meta = metadata (marshmallow_field )
69- meta .update (kw .pop ("metadata" , {}))
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]
74-
75-
76- def ib (marshmallow_field : marshmallow .fields .Field , ** kw ) -> attr ._make ._CountingAttr :
117+ meta : t .Dict [object , object ] = create_metadata (marshmallow_field )
118+ meta .update (metadata )
119+
120+ # call-overload and new_field intermediary:
121+ # https://github.com/python/typeshed/pull/5823
122+ new_field : dataclasses .Field [object ] = dataclasses .field (** kw , metadata = meta ) # type: ignore[call-overload]
123+ return new_field
124+
125+
126+ # These overloads lie about their return type just as both attrs and dataclasses
127+ # do so as to support the normal usage of `attribute: int = field()`
128+ @t .overload
129+ def ib (
130+ marshmallow_field : marshmallow .fields .Field ,
131+ * ,
132+ default : t .Union [T , t .Callable [[], T ]],
133+ metadata : t .Mapping [object , object ] = {},
134+ ** kw : object ,
135+ ) -> T :
136+ ...
137+
138+
139+ @t .overload
140+ def ib (
141+ marshmallow_field : marshmallow .fields .Field ,
142+ * ,
143+ factory : t .Callable [[], T ],
144+ metadata : t .Mapping [object , object ] = {},
145+ ** kw : object ,
146+ ) -> T :
147+ ...
148+
149+
150+ @t .overload
151+ def ib (
152+ marshmallow_field : marshmallow .fields .Field ,
153+ * ,
154+ metadata : t .Mapping [object , object ] = {},
155+ ** kw : object ,
156+ ) -> object :
157+ ...
158+
159+
160+ # The return type hint of object is certainly a lie but fits a lot better with
161+ # the normal use of `x: int = desert.ib()`. Both dataclasses and attrs
162+ # prioritize hinting for this usage as well. Perhaps someday we'll have a
163+ # plugin that indicates the actual type.
164+ def ib (
165+ marshmallow_field : marshmallow .fields .Field ,
166+ metadata : t .Mapping [object , object ] = {},
167+ ** kw : object ,
168+ ) -> object :
77169 """Specify a marshmallow field in the metadata for an ``attr.dataclass``.
78170
79171 .. code-block:: python
@@ -82,9 +174,10 @@ def ib(marshmallow_field: marshmallow.fields.Field, **kw) -> attr._make._Countin
82174 class A:
83175 x: int = desert.ib(marshmallow.fields.Int())
84176 """
85- meta = metadata (marshmallow_field )
86- meta .update (kw .pop ("metadata" , {}))
87- return attr .ib (** kw , metadata = meta )
177+ meta : t .Dict [object , object ] = create_metadata (marshmallow_field )
178+ meta .update (metadata )
179+ new_field : attr ._make ._CountingAttr = attr .ib (** kw , metadata = meta ) # type: ignore[call-overload]
180+ return new_field
88181
89182
90183__version__ = desert ._version .__version__
0 commit comments