]> granicus.if.org Git - python/commitdiff
bpo-37163: Deprecate passing argument obj of dataclasses.replace() by keyword. (GH...
authorSerhiy Storchaka <storchaka@gmail.com>
Wed, 19 Jun 2019 07:33:27 +0000 (10:33 +0300)
committerGitHub <noreply@github.com>
Wed, 19 Jun 2019 07:33:27 +0000 (10:33 +0300)
Lib/dataclasses.py
Lib/test/test_dataclasses.py
Misc/NEWS.d/next/Library/2019-06-07-08-18-05.bpo-37163.36JkUh.rst [new file with mode: 0644]

index b035cbb809f848a29e3d82bcb879e89f1b23c1c2..18713722a764ad59726e4ece6a8ddcd2fc344a7c 100644 (file)
@@ -1206,7 +1206,7 @@ def make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True,
                      unsafe_hash=unsafe_hash, frozen=frozen)
 
 
-def replace(obj, **changes):
+def replace(*args, **changes):
     """Return a new object replacing specified fields with new values.
 
     This is especially useful for frozen classes.  Example usage:
@@ -1220,6 +1220,17 @@ def replace(obj, **changes):
       c1 = replace(c, x=3)
       assert c1.x == 3 and c1.y == 2
       """
+    if len(args) > 1:
+        raise TypeError(f'replace() takes 1 positional argument but {len(args)} were given')
+    if args:
+        obj, = args
+    elif 'obj' in changes:
+        obj = changes.pop('obj')
+        import warnings
+        warnings.warn("Passing 'obj' as keyword argument is deprecated",
+                      DeprecationWarning, stacklevel=2)
+    else:
+        raise TypeError("replace() missing 1 required positional argument: 'obj'")
 
     # We're going to mutate 'changes', but that's okay because it's a
     # new dict, even if called with 'replace(obj, **my_changes)'.
@@ -1255,3 +1266,4 @@ def replace(obj, **changes):
     # changes that aren't fields, this will correctly raise a
     # TypeError.
     return obj.__class__(**changes)
+replace.__text_signature__ = '(obj, /, **kwargs)'
index 53e8443c2adf17f1b461704a5e3a25759cf62e16..cb0e18c242d100f8122faf7c62fa7740a46c66a4 100755 (executable)
@@ -3075,6 +3075,13 @@ class TestReplace(unittest.TestCase):
         self.assertEqual(c1.x, 3)
         self.assertEqual(c1.y, 2)
 
+        self.assertRaises(TypeError, replace)
+        self.assertRaises(TypeError, replace, c, c)
+        with self.assertWarns(DeprecationWarning):
+            c1 = replace(obj=c, x=3)
+        self.assertEqual(c1.x, 3)
+        self.assertEqual(c1.y, 2)
+
     def test_frozen(self):
         @dataclass(frozen=True)
         class C:
diff --git a/Misc/NEWS.d/next/Library/2019-06-07-08-18-05.bpo-37163.36JkUh.rst b/Misc/NEWS.d/next/Library/2019-06-07-08-18-05.bpo-37163.36JkUh.rst
new file mode 100644 (file)
index 0000000..04cf61d
--- /dev/null
@@ -0,0 +1,2 @@
+Deprecated passing ``obj`` argument of :func:`dataclasses.replace` as
+keyword argument.