@@ -135,11 +135,34 @@ def dataclass(
135135 base_schema : Optional [Type [marshmallow .Schema ]] = None ,
136136 cls_frame : Optional [types .FrameType ] = None ,
137137 ) -> Union [Type [_U ], Callable [[Type [_U ]], Type [_U ]]]:
138- return _dataclass (
139- _cls = _cls ,
140- base_schema = base_schema ,
141- cls_frame = cls_frame ,
142- # dataclass passthrough
138+ """
139+ This decorator does the same as dataclasses.dataclass, but also applies :func:`add_schema`.
140+ It adds a `.Schema` attribute to the class object
141+
142+ :param base_schema: marshmallow schema used as a base class when deriving dataclass schema
143+ :param cls_frame: frame of cls definition, used to obtain locals with other classes definitions.
144+ If None is passed the caller frame will be treated as cls_frame
145+
146+ >>> @dataclass
147+ ... class Artist:
148+ ... name: str
149+ >>> Artist.Schema
150+ <class 'marshmallow.schema.Artist'>
151+
152+ >>> from typing import ClassVar
153+ >>> from marshmallow import Schema
154+ >>> @dataclass(order=True) # preserve field order
155+ ... class Point:
156+ ... x:float
157+ ... y:float
158+ ... Schema: ClassVar[Type[Schema]] = Schema # For the type checker
159+ ...
160+ >>> Point.Schema().load({'x':0, 'y':0}) # This line can be statically type checked
161+ Point(x=0.0, y=0.0)
162+ """
163+ # dataclass's typing doesn't expect it to be called as a function, so ignore type check
164+ dc = dataclasses .dataclass ( # type: ignore
165+ _cls ,
143166 repr = repr ,
144167 eq = eq ,
145168 order = order ,
@@ -149,8 +172,18 @@ def dataclass(
149172 kw_only = kw_only ,
150173 slots = slots ,
151174 )
175+ if not cls_frame :
176+ current_frame = inspect .currentframe ()
177+ if current_frame :
178+ cls_frame = current_frame .f_back
179+ # Per https://docs.python.org/3/library/inspect.html#the-interpreter-stack
180+ del current_frame
181+ if _cls is None :
182+ return lambda cls : add_schema (dc (cls ), base_schema , cls_frame = cls_frame )
183+ return add_schema (dc , base_schema , cls_frame = cls_frame )
152184
153185else :
186+
154187 @overload
155188 def dataclass (
156189 _cls : Type [_U ],
@@ -192,86 +225,49 @@ def dataclass(
192225 base_schema : Optional [Type [marshmallow .Schema ]] = None ,
193226 cls_frame : Optional [types .FrameType ] = None ,
194227 ) -> Union [Type [_U ], Callable [[Type [_U ]], Type [_U ]]]:
195- return _dataclass (
196- _cls = _cls ,
197- base_schema = base_schema ,
198- cls_frame = cls_frame ,
199- # dataclass passthrough
228+ """
229+ This decorator does the same as dataclasses.dataclass, but also applies :func:`add_schema`.
230+ It adds a `.Schema` attribute to the class object
231+
232+ :param base_schema: marshmallow schema used as a base class when deriving dataclass schema
233+ :param cls_frame: frame of cls definition, used to obtain locals with other classes definitions.
234+ If None is passed the caller frame will be treated as cls_frame
235+
236+ >>> @dataclass
237+ ... class Artist:
238+ ... name: str
239+ >>> Artist.Schema
240+ <class 'marshmallow.schema.Artist'>
241+
242+ >>> from typing import ClassVar
243+ >>> from marshmallow import Schema
244+ >>> @dataclass(order=True) # preserve field order
245+ ... class Point:
246+ ... x:float
247+ ... y:float
248+ ... Schema: ClassVar[Type[Schema]] = Schema # For the type checker
249+ ...
250+ >>> Point.Schema().load({'x':0, 'y':0}) # This line can be statically type checked
251+ Point(x=0.0, y=0.0)
252+ """
253+ # dataclass's typing doesn't expect it to be called as a function, so ignore type check
254+ dc = dataclasses .dataclass ( # type: ignore
255+ _cls ,
200256 repr = repr ,
201257 eq = eq ,
202258 order = order ,
203259 unsafe_hash = unsafe_hash ,
204260 frozen = frozen ,
205261 )
206-
207- @overload
208- def _dataclass (
209- _cls : Type [_U ],
210- * ,
211- base_schema : Optional [Type [marshmallow .Schema ]] = None ,
212- cls_frame : Optional [types .FrameType ] = None ,
213- ** kwargs ,
214- ) -> Type [_U ]:
215- ...
216-
217- @overload
218- def _dataclass (
219- * ,
220- base_schema : Optional [Type [marshmallow .Schema ]] = None ,
221- cls_frame : Optional [types .FrameType ] = None ,
222- ** kwargs ,
223- ) -> Callable [[Type [_U ]], Type [_U ]]:
224- ...
225-
226- # _cls should never be specified by keyword, so start it with an
227- # underscore. The presence of _cls is used to detect if this
228- # decorator is being called with parameters or not.
229- def _dataclass (
230- _cls : Type [_U ] = None ,
231- * ,
232- base_schema : Optional [Type [marshmallow .Schema ]] = None ,
233- cls_frame : Optional [types .FrameType ] = None ,
234- ** kwargs ,
235- ) -> Union [Type [_U ], Callable [[Type [_U ]], Type [_U ]]]:
236- """
237- This decorator does the same as dataclasses.dataclass, but also applies :func:`add_schema`.
238- It adds a `.Schema` attribute to the class object
239-
240- :param base_schema: marshmallow schema used as a base class when deriving dataclass schema
241- :param cls_frame: frame of cls definition, used to obtain locals with other classes definitions.
242- If None is passed the caller frame will be treated as cls_frame
243-
244- >>> @dataclass
245- ... class Artist:
246- ... name: str
247- >>> Artist.Schema
248- <class 'marshmallow.schema.Artist'>
249-
250- >>> from typing import ClassVar
251- >>> from marshmallow import Schema
252- >>> @dataclass(order=True) # preserve field order
253- ... class Point:
254- ... x:float
255- ... y:float
256- ... Schema: ClassVar[Type[Schema]] = Schema # For the type checker
257- ...
258- >>> Point.Schema().load({'x':0, 'y':0}) # This line can be statically type checked
259- Point(x=0.0, y=0.0)
260- """
261- # dataclass's typing doesn't expect it to be called as a function, so ignore type check
262- dc = dataclasses .dataclass ( # type: ignore
263- _cls ,
264- ** kwargs ,
265- )
266- if not cls_frame :
267- current_frame = inspect .currentframe ()
268- if current_frame :
269- cls_frame = current_frame .f_back
270- # Per https://docs.python.org/3/library/inspect.html#the-interpreter-stack
271- del current_frame
272- if _cls is None :
273- return lambda cls : add_schema (dc (cls ), base_schema , cls_frame = cls_frame )
274- return add_schema (dc , base_schema , cls_frame = cls_frame )
262+ if not cls_frame :
263+ current_frame = inspect .currentframe ()
264+ if current_frame :
265+ cls_frame = current_frame .f_back
266+ # Per https://docs.python.org/3/library/inspect.html#the-interpreter-stack
267+ del current_frame
268+ if _cls is None :
269+ return lambda cls : add_schema (dc (cls ), base_schema , cls_frame = cls_frame )
270+ return add_schema (dc , base_schema , cls_frame = cls_frame )
275271
276272
277273@overload
0 commit comments