12
12
import attr ._make
13
13
14
14
15
+ T = t .TypeVar ("T" )
16
+
17
+
15
18
def 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 ] = {}
17
20
) -> marshmallow .Schema :
18
21
"""Build a marshmallow schema *instance* for the class.
19
22
@@ -29,7 +32,7 @@ def schema(
29
32
30
33
31
34
def schema_class (
32
- cls : t . Type , meta : t .Dict [str , t .Any ] = {}
35
+ cls : type , meta : t .Dict [str , t .Any ] = {}
33
36
) -> t .Type [marshmallow .Schema ]:
34
37
"""Build a marshmallow schema *class* for the class.
35
38
@@ -46,7 +49,7 @@ def schema_class(
46
49
47
50
def metadata (
48
51
field : marshmallow .fields .Field ,
49
- ) -> t .Dict ["desert._make._DesertSentinel" , t . Dict [ t . Any , marshmallow . fields . Field ] ]:
52
+ ) -> t .Dict [object , object ]:
50
53
"""Specify a marshmallow field in the field metadata.
51
54
52
55
.. code-block:: python
@@ -56,7 +59,53 @@ def metadata(
56
59
return {desert ._make ._DESERT_SENTINEL : {"marshmallow_field" : field }}
57
60
58
61
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 :
60
109
"""Specify a marshmallow field in the metadata for a ``dataclasses.dataclass``.
61
110
62
111
.. code-block:: python
@@ -65,15 +114,58 @@ def field(marshmallow_field: marshmallow.fields.Field, **kw) -> dataclasses.Fiel
65
114
class A:
66
115
x: int = desert.field(marshmallow.fields.Int())
67
116
"""
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 :
77
169
"""Specify a marshmallow field in the metadata for an ``attr.dataclass``.
78
170
79
171
.. code-block:: python
@@ -82,9 +174,10 @@ def ib(marshmallow_field: marshmallow.fields.Field, **kw) -> attr._make._Countin
82
174
class A:
83
175
x: int = desert.ib(marshmallow.fields.Int())
84
176
"""
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
88
181
89
182
90
183
__version__ = desert ._version .__version__
0 commit comments