Skip to content

dataclasses.replace() should raise TypeError for all invalid or missed required keyword arguments #110273

Closed
@serhiy-storchaka

Description

@serhiy-storchaka

Bug report

When you call a function with incorrect key arguments or missing a required argument, you get a TypeError. But it is not always so with dataclasses.replace(). It raises a ValueError if a keyword argument for an InitVar field is missed or if a keyword argument for a field declared with init=False is specified.

>>> from dataclasses import *
>>> @dataclass
... class C:
...     x: int
...     y: InitVar[int]
...     z: int = field(init=False, default=100)
... 
>>> c = C(x=11, y=22)
>>> replace(c, x=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/serhiy/py/cpython3.12/Lib/dataclasses.py", line 1570, in replace
    raise ValueError(f"InitVar {f.name!r} "
ValueError: InitVar 'y' must be specified with replace()
>>> replace(c, x=1, y=2, z=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/serhiy/py/cpython3.12/Lib/dataclasses.py", line 1563, in replace
    raise ValueError(f'field {f.name} is declared with '
ValueError: field z is declared with init=False, it cannot be specified with replace()

It is not even consistent with constructors:

>>> C(x=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: C.__init__() missing 1 required positional argument: 'y'
>>> C(x=1, y=2, z=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: C.__init__() got an unexpected keyword argument 'z'

And it raises a TypeError for unexpected keyword arguments.

>>> replace(c, x=1, y=2, t=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/serhiy/py/cpython3.12/Lib/dataclasses.py", line 1579, in replace
    return obj.__class__(**changes)
           ^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: C.__init__() got an unexpected keyword argument 't'

I think that dataclasses.replace() should raise TypeError in all these cases.

Linked PRs

Metadata

Metadata

Assignees

Labels

type-bugAn unexpected behavior, bug, or error

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions