Skip to content

Commit 23855f9

Browse files
committed
fix types, check with 3.9
1 parent abdbea6 commit 23855f9

File tree

1 file changed

+75
-79
lines changed

1 file changed

+75
-79
lines changed

marshmallow_dataclass/__init__.py

Lines changed: 75 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -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

153185
else:
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

Comments
 (0)