Repository navigation
Add function signature hooks for dataclasses functions: replace, asdict, astuple #5152
Description
Activity
- addedtopic-pluginsThe plugin API and ideas for new pluginsThe plugin API and ideas for new plugins
on Jun 5, 2018 - added 2 commits that reference this issue
on Aug 18, 2020 How would one go about to fix the type signature for
replace? In TypeScript it is possible to give a replace function this type:function replace<X extends Record<string, any>>(base: X, changes: Partial<X>): X { return {...base, ...changes} }
It's not a 100% correspondence, I'm using TS'
Recordtype instead ofdataclassand just one singlechangesargument instead of a**changeskeyword argument. But in essence it's the type I want to givereplacefrom thedataclassesmodule.This hole is allowing errors to leak through in some of my production code. Lacking a 'typeof' operator as well, it's difficult to ensure the types are correct.
Reacted by OlegAlexander and Misha Bergal- added and removedtopic-pluginsThe plugin API and ideas for new pluginsThe plugin API and ideas for new plugins
on Mar 25, 2022 Hello and thank you for creating mypy!!
If I may, I'd like to make a case for this issue.
dataclasses.replace()is equivalent to thewithkeyword in F#. For anyone wishing to do typed functional programming in Python, havingreplace()checked at compile time is critical. This issue was opened 5 years ago and even the mypy documentation says:Some functions in the dataclasses module, such as replace() and asdict(), have imprecise (too permissive) types. This will be fixed in future releases.
I can only assume that this isn't a trivial issue to fix.
It seems I haven't made a strong case for this issue after all--I've only managed to express my frustration 😢. It's just that the next time someone asks me if it's possible to do typed functional programming in Python, I'd love to say "Yes!" instead of "Almost!"
With
asdictreturning an anonymous TypedDict (as planned in #8583), would this bring us any closer to closing this issue?If the
TypedDictwas not anonymous, and better yet if it was part of dataclasses (e.g. if a dataclass would have__TYPED_DICT__and in particular__PARTIAL_TYPED_DICT__that'stotal=False) then this could perhaps be done in the type definition a'ladef replace(obj: _T, **changes: _T.__PARTIAL_TYPED_DICT__) -> _T: ...
Otherwise we could try something like #14526 where we determine the signature in a function sig hook. Curiously while in
attrs.evolvewe can take the__init__signature and mutate it to be all-ARG_NAMED_OPT, forreplacewe must makeinit=TrueargumentsARG_NAMEDsince they must be explicitly re-specified duringreplace.FWIW I remember I thought #8583 was an OK solution. But we also need to support other methods:
astuple()andreplace(). They should be quite straightforward to implement, it is just a matter of spending time on carefully writing the code.- added a commit that references this issue
on Jun 17, 2023 dataclasses.replaceworks properly since mypy 1.5.0. Thank you for fixing this!!Reacted by Ilya Priven and Giuliano Macedo
Currently, the plugin only supports dataclass creation (i.e. generation of dunder methods with correct types, including
__init__). However, some functions in thedataclassmodules have quite broad types in typeshed, for example:so that arbitrary arguments can be give for
changes, etc. The plugin should be able to give more precise type for these functions. In particular,asdictcould return aTypedDict.