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?