https://github.com/python/cpython/commit/12828e5f98a47864e3f6d25fdd99c062fae28b1c
commit: 12828e5f98a47864e3f6d25fdd99c062fae28b1c
branch: main
author: Tadej Magajna <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-02-25T16:44:17+02:00
summary:
gh-85809: Ensure shutil.make_archive accepts path-like objects in all cases
(GH-143668)
files:
A Misc/NEWS.d/next/Library/2026-01-10-22-58-30.gh-issue-85809.0eW4wt.rst
M Doc/library/shutil.rst
M Lib/shutil.py
M Lib/test/test_shutil.py
diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst
index 22444c4d804265..0666fcfde61e61 100644
--- a/Doc/library/shutil.rst
+++ b/Doc/library/shutil.rst
@@ -618,8 +618,8 @@ provided. They rely on the :mod:`zipfile` and
:mod:`tarfile` modules.
Create an archive file (such as zip or tar) and return its name.
- *base_name* is the name of the file to create, including the path, minus
- any format-specific extension.
+ *base_name* is a string or :term:`path-like object` specifying the name of
+ the file to create, including the path, minus any format-specific extension.
*format* is the archive format: one of
"zip" (if the :mod:`zlib` module is available), "tar", "gztar" (if the
@@ -627,13 +627,14 @@ provided. They rely on the :mod:`zipfile` and
:mod:`tarfile` modules.
available), "xztar" (if the :mod:`lzma` module is available), or "zstdtar"
(if the :mod:`compression.zstd` module is available).
- *root_dir* is a directory that will be the root directory of the
- archive, all paths in the archive will be relative to it; for example,
- we typically chdir into *root_dir* before creating the archive.
+ *root_dir* is a string or :term:`path-like object` specifying a directory
+ that will be the root directory of the archive, all paths in the archive
+ will be relative to it; for example, we typically chdir into *root_dir*
+ before creating the archive.
- *base_dir* is the directory where we start archiving from;
- i.e. *base_dir* will be the common prefix of all files and
- directories in the archive. *base_dir* must be given relative
+ *base_dir* is a string or :term:`path-like object` specifying a directory
+ where we start archiving from; i.e. *base_dir* will be the common prefix of
+ all files and directories in the archive. *base_dir* must be given relative
to *root_dir*. See :ref:`shutil-archiving-example-with-basedir` for how to
use *base_dir* and *root_dir* together.
@@ -668,6 +669,10 @@ provided. They rely on the :mod:`zipfile` and
:mod:`tarfile` modules.
This function is now made thread-safe during creation of standard
``.zip`` and tar archives.
+ .. versionchanged:: next
+ Accepts a :term:`path-like object` for *base_name*, *root_dir* and
+ *base_dir*.
+
.. function:: get_archive_formats()
Return a list of supported formats for archiving.
diff --git a/Lib/shutil.py b/Lib/shutil.py
index 8d8fe145567822..44ccdbb503d4fb 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -1212,19 +1212,22 @@ def make_archive(base_name, format, root_dir=None,
base_dir=None, verbose=0,
for arg, val in format_info[1]:
kwargs[arg] = val
+ base_name = os.fspath(base_name)
+
if base_dir is None:
base_dir = os.curdir
+ else:
+ base_dir = os.fspath(base_dir)
supports_root_dir = getattr(func, 'supports_root_dir', False)
save_cwd = None
if root_dir is not None:
+ root_dir = os.fspath(root_dir)
stmd = os.stat(root_dir).st_mode
if not stat.S_ISDIR(stmd):
raise NotADirectoryError(errno.ENOTDIR, 'Not a directory',
root_dir)
if supports_root_dir:
- # Support path-like base_name here for backwards-compatibility.
- base_name = os.fspath(base_name)
kwargs['root_dir'] = root_dir
else:
save_cwd = os.getcwd()
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index ebb6cf88336249..a4bd113bc7f1fc 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -2042,6 +2042,32 @@ def test_make_zipfile_in_curdir(self):
self.assertEqual(make_archive('test', 'zip'), 'test.zip')
self.assertTrue(os.path.isfile('test.zip'))
+ def test_make_archive_pathlike_cwd_default(self):
+ called_args = []
+ def archiver(base_name, base_dir, **kw):
+ called_args.append((base_name, kw.get('root_dir')))
+
+ register_archive_format('xxx', archiver, [], 'xxx file')
+ self.addCleanup(unregister_archive_format, 'xxx')
+ with no_chdir:
+ make_archive(FakePath('basename'), 'xxx')
+ self.assertEqual(called_args, [('basename', None)])
+
+ def test_make_archive_pathlike_cwd_supports_root_dir(self):
+ root_dir = self.mkdtemp()
+ called_args = []
+ def archiver(base_name, base_dir, **kw):
+ called_args.append((base_name, base_dir, kw.get('root_dir')))
+ archiver.supports_root_dir = True
+
+ register_archive_format('xxx', archiver, [], 'xxx file')
+ self.addCleanup(unregister_archive_format, 'xxx')
+ with no_chdir:
+ make_archive(FakePath('basename'), 'xxx',
+ root_dir=FakePath(root_dir),
+ base_dir=FakePath('basedir'))
+ self.assertEqual(called_args, [('basename', 'basedir', root_dir)])
+
def test_register_archive_format(self):
self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
diff --git
a/Misc/NEWS.d/next/Library/2026-01-10-22-58-30.gh-issue-85809.0eW4wt.rst
b/Misc/NEWS.d/next/Library/2026-01-10-22-58-30.gh-issue-85809.0eW4wt.rst
new file mode 100644
index 00000000000000..3993c7a91da138
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-01-10-22-58-30.gh-issue-85809.0eW4wt.rst
@@ -0,0 +1 @@
+Added :term:`path-like object` support for :func:`shutil.make_archive`.
_______________________________________________
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]