https://github.com/python/cpython/commit/e75ef6a768a439ee86aa997cd3ecb1ff73e3c3da
commit: e75ef6a768a439ee86aa997cd3ecb1ff73e3c3da
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-08-13T13:12:24+03:00
summary:

gh-155040: Support copy.replace() for tarfile.TarInfo (GH-155046)

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-08-01-19-01-00.gh-issue-155040.Tr1nFo.rst
M Doc/library/tarfile.rst
M Lib/tarfile.py
M Lib/test/test_tarfile.py

diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst
index fc352e901f31dc..f19038d837bb52 100644
--- a/Doc/library/tarfile.rst
+++ b/Doc/library/tarfile.rst
@@ -963,6 +963,11 @@ A ``TarInfo`` object has the following public data 
attributes:
    If *deep* is false, the copy is shallow, i.e. ``pax_headers``
    and any custom attributes are shared with the original ``TarInfo`` object.
 
+   This method is also used by :func:`copy.replace`.
+
+   .. versionchanged:: next
+      Added support for :func:`copy.replace`.
+
 A :class:`TarInfo` object also provides some convenient query methods:
 
 
diff --git a/Lib/tarfile.py b/Lib/tarfile.py
index dc5c3a59744cbc..592c4638c52c9b 100644
--- a/Lib/tarfile.py
+++ b/Lib/tarfile.py
@@ -1036,6 +1036,8 @@ def replace(self, *,
             result.gname = gname
         return result
 
+    __replace__ = replace
+
     def get_info(self):
         """Return the TarInfo's attributes as a dictionary.
         """
diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
index 5fa97e2ac226c4..bd544dfea51da3 100644
--- a/Lib/test/test_tarfile.py
+++ b/Lib/test/test_tarfile.py
@@ -1,3 +1,4 @@
+import copy
 import errno
 import sys
 import os
@@ -3524,6 +3525,16 @@ def test_replace_internal(self):
         with self.assertRaises(TypeError):
             member.replace(offset=123456789)
 
+    def test_copy_replace(self):
+        member = self.tar.getmember('ustar/regtype')
+        replaced = copy.replace(member, name='misc/other', mode=0o644)
+        self.assertEqual(replaced.name, 'misc/other')
+        self.assertEqual(replaced.mode, 0o644)
+        self.assertEqual(replaced.size, member.size)
+        self.assertEqual(member.name, 'ustar/regtype')
+        with self.assertRaises(TypeError):
+            copy.replace(member, offset=123456789)
+
 
 class NoneInfoExtractTests(ReadTest):
     # These mainly check that all kinds of members are extracted successfully
diff --git 
a/Misc/NEWS.d/next/Library/2026-08-01-19-01-00.gh-issue-155040.Tr1nFo.rst 
b/Misc/NEWS.d/next/Library/2026-08-01-19-01-00.gh-issue-155040.Tr1nFo.rst
new file mode 100644
index 00000000000000..d7875404202912
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-08-01-19-01-00.gh-issue-155040.Tr1nFo.rst
@@ -0,0 +1 @@
+:class:`tarfile.TarInfo` objects now support :func:`copy.replace`.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to