diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 96bf6e1df47..ad7bf0f7593 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1173,6 +1173,9 @@ def replace(obj, **changes): continue if f.name not in changes: + if f._field_type is _FIELD_INITVAR: + raise ValueError(f"InitVar {f.name!r} " + 'must be specified with replace()') changes[f.name] = getattr(obj, f.name) # Create the new object, which calls __init__() and diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 929793119d7..d9556c7ff9c 100755 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -3024,6 +3024,22 @@ class TestReplace(unittest.TestCase): replace(c, x=5) + def test_initvar_is_specified(self): + @dataclass + class C: + x: int + y: InitVar[int] + + def __post_init__(self, y): + self.x *= y + + c = C(1, 10) + self.assertEqual(c.x, 10) + with self.assertRaisesRegex(ValueError, r"InitVar 'y' must be " + "specified with replace()"): + replace(c, x=3) + c = replace(c, x=3, y=5) + self.assertEqual(c.x, 15) ## def test_initvar(self): ## @dataclass ## class C: diff --git a/Misc/NEWS.d/next/Library/2018-06-10-15-14-17.bpo-33805.5LAz5a.rst b/Misc/NEWS.d/next/Library/2018-06-10-15-14-17.bpo-33805.5LAz5a.rst new file mode 100644 index 00000000000..74bcf6d7c8c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-06-10-15-14-17.bpo-33805.5LAz5a.rst @@ -0,0 +1 @@ +Improve error message of dataclasses.replace() when an InitVar is not specified