dataclass allow_missing option
Hi all, Dataclasses provide a unique way of creating parameter bags with decent typing and validation options. However, they currently lack a meaningful way of detecting a missing value as a dataclass interface consumer. Current behavior allows us to specify defaults per property, but defining a default value has consequences for the reusability of the dataclass, especially when it comes to inheritance patterns. Aside from this effect, littering the code with `str_field: str = MISSING_STR` does not really provide a clean and readable interface. Therefore, I would like to propose an extra option on both the dataclasses.dataclass decorator as well as a dataclasses.field boolean argument called `allow_missing`. Example: @dataclass(allow_missing=True) class UserBag: user_id: UUID bag = UserBag() # no exception with regards to missing args bag.user_id # type: Missing[UUID] ? if not bag.user_id: # sentinel value evaluates to false ... if dataclasses.ismissing(bag.user_id): # or more explicit ... Alternatively, as api on a per-field-basis: @dataclass class UserBag: user_id: UUID = field(allow_missing=True) As a bonus, one would imagine the `asdict` method has an argument to convert a dataclass instance to a dictionary without the missing properties (example: `asdict(d, exclude_missing=True)`). Generation of code could stay largely the same as it currently is, with only minor differences: - type hinting of constructor args should provide a sentinel default value that adheres to the typing of the original field, something along the lines of `__init__(self, arg = Missing[str])` - exception currently raised if a Missing[T] value is detected after construction should be silenced if the field is marked as missable. - current sentinel MISSING value evaluates to True when cast as boolean I would love to have your feedback on this. Best, Eelke van den Bos
I really like this idea! I have very often had to create my own MISSING global in modules where None might actually be a legitimate value for the dataclass member. And additionally when I am doing thorough type hinting, I haved at times ended up not only have to do the MISSING object, but a MissingType to go with it. Having both of these already present and handled appropriately in the dataclasses library would be a big win, IMO. --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler On Thu, Dec 17, 2020 at 11:56 AM Eelke van den Bos <eelkevdbos@gmail.com> wrote:
Hi all,
Dataclasses provide a unique way of creating parameter bags with decent typing and validation options. However, they currently lack a meaningful way of detecting a missing value as a dataclass interface consumer.
Current behavior allows us to specify defaults per property, but defining a default value has consequences for the reusability of the dataclass, especially when it comes to inheritance patterns. Aside from this effect, littering the code with `str_field: str = MISSING_STR` does not really provide a clean and readable interface.
Therefore, I would like to propose an extra option on both the dataclasses.dataclass decorator as well as a dataclasses.field boolean argument called `allow_missing`.
Example:
@dataclass(allow_missing=True) class UserBag: user_id: UUID
bag = UserBag() # no exception with regards to missing args bag.user_id # type: Missing[UUID] ?
if not bag.user_id: # sentinel value evaluates to false ... if dataclasses.ismissing(bag.user_id): # or more explicit ...
Alternatively, as api on a per-field-basis:
@dataclass class UserBag: user_id: UUID = field(allow_missing=True)
As a bonus, one would imagine the `asdict` method has an argument to convert a dataclass instance to a dictionary without the missing properties (example: `asdict(d, exclude_missing=True)`).
Generation of code could stay largely the same as it currently is, with only minor differences: - type hinting of constructor args should provide a sentinel default value that adheres to the typing of the original field, something along the lines of `__init__(self, arg = Missing[str])` - exception currently raised if a Missing[T] value is detected after construction should be silenced if the field is marked as missable. - current sentinel MISSING value evaluates to True when cast as boolean
I would love to have your feedback on this.
Best,
Eelke van den Bos _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/LG4OXW... Code of Conduct: http://python.org/psf/codeofconduct/
On Thu, Dec 17, 2020 at 12:26:21PM -0500, Ricky Teachey wrote:
I really like this idea!
I have very often had to create my own MISSING global in modules where None might actually be a legitimate value for the dataclass member.
I'm sorry Ricky, perhaps I'm missing something here, but I can't see how your comment about a "MISSING" sentinel relates to Eelke's suggestion. Can you give a simplified but concrete example? -- Steve
participants (3)
-
Eelke van den Bos
-
Ricky Teachey
-
Steven D'Aprano