Replies: 2 comments 7 replies
-
|
A few thoughts:
|
Beta Was this translation helpful? Give feedback.
-
... so this might work, although not quite "no changes to third-party libraries". Also, if we go down this route, I think it'll be prudent to document it in somewhere, either in cpython's typing.rst or in python/typing's docs, or in each type checker's docs, but certainly not solely in this discussion 🙏 . IMO the first is preferable, since it's the main and only documentation on the Also, given that libs would have to make some updates anyway, this would be clearly the more complex syntax (vs. bool param), and I wonder to what advantage (fewer params? some future flexibility? some merit in avoiding special-casing dataclass more than it already is?). Footnotes |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Exposé
In PEP-681, Data Class Transforms were conceived as "a way for third-party libraries to indicate that certain decorator functions, classes, and metaclasses provide behaviors similar to dataclasses". Let's call this 📖 the intended use. The PEP was successful in that, e.g. in pydantic, but over time another use emerged — let's call it 🎁 the bonus use - where
@dataclass_transformis used for decorators which don't merely return something with similar to, but actual dataclasses. The motivation for the latter is to make custom decorators seen as equivalent to@dataclasses.dataclassby type-checkers and IDEs:Real-world examples1:
So,
@dataclass_transformis useful in more than one way, and that's great. Meanwhile, type checkers are also improving their understanding ofdataclassesmodule's utility functions:dataclasses.is_dataclassdataclasses.fieldsobjargtuple[Field[int], Field[str], ...])dataclasses.as_dictobjargTypedDict?)dataclasses.as_tupleobjargtuple(42, 'spam'))dataclasses.replaceobjargchangesargThe problem we're solving
For the purposes of the improved checks above, we should not treat any Data Class Transform'd class as a "true" dataclass, e.g. pydantic models do not function as dataclasses (i.e.
is_dataclass(some_pydantic_model) is False). Straight reading of PEP-681 also does not suggest that. Meanwhile, some type checkers (mypy, pyright) are currently doing just that, and that's where we run into a conundrum:TypeGuardfordataclasses.is_dataclass(); refineasdict(),astuple(),fields(),replace()typeshed#9362, then we (a) lose type safety forobj, and (b) we keep inconsistent behavior in type-checkers whenever we have special treatment of dataclasses utility functions.Proposal
PEP-681 foresaw the need to add more parameters:
I'm suggesting adding a
returns_dataclassparameter todataclass_transform:def dataclass_transform( *, eq_default: bool = True, order_default: bool = False, kw_only_default: bool = False, + returns_dataclass: bool = <...>, field_specifiers: tuple[type | Callable[..., Any], ...] = (), **kwargs: Any, ) -> Callable[[_T], _T]: ...I'm not sure whether it should default to
TrueorFalse. My unscientific exploration of uses in the wild suggests more 🎁 bonus uses than 📖 intended uses, which would tip the scale in favor ofTrue. Meanwhile, adherence to PEP-681 contract would tip the scale in favor ofFalse. But most importantly we'll gain a way to express this property of the returned class.Footnotes
can probably find more if it makes the case stronger ↩
Beta Was this translation helpful? Give feedback.
All reactions