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 .Optional [t .Mapping [object , object ]] = None ,
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 .Optional [t .Mapping [object , object ]] = None ,
85
+ ** kw : object ,
86
+ ) -> T :
87
+ ...
88
+
89
+
90
+ @t .overload
91
+ def field (
92
+ marshmallow_field : marshmallow .fields .Field ,
93
+ * ,
94
+ metadata : t .Optional [t .Mapping [object , object ]] = None ,
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 .Optional [t .Mapping [object , object ]] = None ,
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,61 @@ 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
+ if metadata is None :
118
+ metadata = {}
119
+
120
+ meta : t .Dict [object , object ] = create_metadata (marshmallow_field )
121
+ meta .update (metadata )
122
+
123
+ # call-overload and new_field intermediary:
124
+ # https://github.com/python/typeshed/pull/5823
125
+ new_field : dataclasses .Field [object ] = dataclasses .field (** kw , metadata = meta ) # type: ignore[call-overload]
126
+ return new_field
127
+
128
+
129
+ # These overloads lie about their return type just as both attrs and dataclasses
130
+ # do so as to support the normal usage of `attribute: int = field()`
131
+ @t .overload
132
+ def ib (
133
+ marshmallow_field : marshmallow .fields .Field ,
134
+ * ,
135
+ default : t .Union [T , t .Callable [[], T ]],
136
+ metadata : t .Optional [t .Mapping [object , object ]] = None ,
137
+ ** kw : object ,
138
+ ) -> T :
139
+ ...
140
+
141
+
142
+ @t .overload
143
+ def ib (
144
+ marshmallow_field : marshmallow .fields .Field ,
145
+ * ,
146
+ factory : t .Callable [[], T ],
147
+ metadata : t .Optional [t .Mapping [object , object ]] = None ,
148
+ ** kw : object ,
149
+ ) -> T :
150
+ ...
151
+
152
+
153
+ @t .overload
154
+ def ib (
155
+ marshmallow_field : marshmallow .fields .Field ,
156
+ * ,
157
+ metadata : t .Optional [t .Mapping [object , object ]] = None ,
158
+ ** kw : object ,
159
+ ) -> object :
160
+ ...
161
+
162
+
163
+ # The return type hint of object is certainly a lie but fits a lot better with
164
+ # the normal use of `x: int = desert.ib()`. Both dataclasses and attrs
165
+ # prioritize hinting for this usage as well. Perhaps someday we'll have a
166
+ # plugin that indicates the actual type.
167
+ def ib (
168
+ marshmallow_field : marshmallow .fields .Field ,
169
+ metadata : t .Optional [t .Mapping [object , object ]] = None ,
170
+ ** kw : object ,
171
+ ) -> object :
77
172
"""Specify a marshmallow field in the metadata for an ``attr.dataclass``.
78
173
79
174
.. code-block:: python
@@ -82,9 +177,13 @@ def ib(marshmallow_field: marshmallow.fields.Field, **kw) -> attr._make._Countin
82
177
class A:
83
178
x: int = desert.ib(marshmallow.fields.Int())
84
179
"""
85
- meta = metadata (marshmallow_field )
86
- meta .update (kw .pop ("metadata" , {}))
87
- return attr .ib (** kw , metadata = meta )
180
+ if metadata is None :
181
+ metadata = {}
182
+
183
+ meta : t .Dict [object , object ] = create_metadata (marshmallow_field )
184
+ meta .update (metadata )
185
+ new_field : attr ._make ._CountingAttr = attr .ib (** kw , metadata = meta ) # type: ignore[call-overload]
186
+ return new_field
88
187
89
188
90
189
__version__ = desert ._version .__version__
0 commit comments