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]

Reply via email to