From 3f4dc49439a42222cb7cbf26ffd583195a8e7f16 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Aug 2026 19:27:39 +0300 Subject: [PATCH 1/2] gh-155040: Support copy.replace() for tarfile.TarInfo Co-Authored-By: Claude Opus 5 (1M context) --- Doc/library/tarfile.rst | 5 +++++ Lib/tarfile.py | 2 ++ Lib/test/test_tarfile.py | 11 +++++++++++ .../2026-08-01-19-01-00.gh-issue-155040.Tr1nFo.rst | 1 + 4 files changed, 19 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-08-01-19-01-00.gh-issue-155040.Tr1nFo.rst diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index fc352e901f31dc7..afe66de83bc3d6d 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 of :func:`copy.replace`. + A :class:`TarInfo` object also provides some convenient query methods: diff --git a/Lib/tarfile.py b/Lib/tarfile.py index d12bd15aa2d2319..0c6ab21682b0c22 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 c86bcb79eb85d89..7bd0424c2e8b42f 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 000000000000000..d7875404202912d --- /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`. From 581951e058d53bdc81b5326274e60153e7a1318c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Aug 2026 21:48:33 +0300 Subject: [PATCH 2/2] Update Doc/library/tarfile.rst Co-authored-by: Stan Ulbrych --- Doc/library/tarfile.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index afe66de83bc3d6d..f19038d837bb526 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -966,7 +966,7 @@ A ``TarInfo`` object has the following public data attributes: This method is also used by :func:`copy.replace`. .. versionchanged:: next - Added support of :func:`copy.replace`. + Added support for :func:`copy.replace`. A :class:`TarInfo` object also provides some convenient query methods: