Skip to content

Commit de8e204

Browse files
committed
gh-85809: Ensure shutil.make_archive supports path-like objects
Support for path-like objects such as `Pathlib.path` in `shutil.make_archive`. The change ensures path-like support for all parameters regardless of input. Added lightweight tests and updated documentation including examples.
1 parent aa8578d commit de8e204

File tree

4 files changed

+39
-15
lines changed

4 files changed

+39
-15
lines changed

Doc/library/shutil.rst

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -619,22 +619,23 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules.
619619

620620
Create an archive file (such as zip or tar) and return its name.
621621

622-
*base_name* is the name of the file to create, including the path, minus
623-
any format-specific extension.
622+
*base_name* is the :term:`path-like object` specifying the name of the file
623+
to create, including the path, minus any format-specific extension.
624624

625625
*format* is the archive format: one of
626626
"zip" (if the :mod:`zlib` module is available), "tar", "gztar" (if the
627627
:mod:`zlib` module is available), "bztar" (if the :mod:`bz2` module is
628628
available), "xztar" (if the :mod:`lzma` module is available), or "zstdtar"
629629
(if the :mod:`compression.zstd` module is available).
630630

631-
*root_dir* is a directory that will be the root directory of the
632-
archive, all paths in the archive will be relative to it; for example,
633-
we typically chdir into *root_dir* before creating the archive.
631+
*root_dir* is the :term:`path-like object` specifying a directory that will
632+
be the root directory of the archive, all paths in the archive will be
633+
relative to it; for example, we typically chdir into *root_dir* before
634+
creating the archive.
634635

635-
*base_dir* is the directory where we start archiving from;
636-
i.e. *base_dir* will be the common prefix of all files and
637-
directories in the archive. *base_dir* must be given relative
636+
*base_dir* is the :term:`path-like object` specifying a directory where we
637+
start archiving from; i.e. *base_dir* will be the common prefix of all files
638+
and directories in the archive. *base_dir* must be given relative
638639
to *root_dir*. See :ref:`shutil-archiving-example-with-basedir` for how to
639640
use *base_dir* and *root_dir* together.
640641

@@ -669,6 +670,9 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules.
669670
This function is now made thread-safe during creation of standard
670671
``.zip`` and tar archives.
671672

673+
.. versionchanged:: 3.15
674+
Accepts a :term:`path-like object` for *base_name*.
675+
672676
.. function:: get_archive_formats()
673677

674678
Return a list of supported formats for archiving.
@@ -814,10 +818,10 @@ Archiving example
814818
In this example, we create a gzip'ed tar-file archive containing all files
815819
found in the :file:`.ssh` directory of the user::
816820

821+
>>> from pathlib import Path
817822
>>> from shutil import make_archive
818-
>>> import os
819-
>>> archive_name = os.path.expanduser(os.path.join('~', 'myarchive'))
820-
>>> root_dir = os.path.expanduser(os.path.join('~', '.ssh'))
823+
>>> archive_name = Path.home() / 'myarchive'
824+
>>> root_dir = Path.home() / '.ssh'
821825
>>> make_archive(archive_name, 'gztar', root_dir)
822826
'/Users/tarek/myarchive.tar.gz'
823827

@@ -858,9 +862,9 @@ we show how to use :func:`make_archive`, but this time with the usage of
858862
In the final archive, :file:`please_add.txt` should be included, but
859863
:file:`do_not_add.txt` should not. Therefore we use the following::
860864

865+
>>> from pathlib import Path
861866
>>> from shutil import make_archive
862-
>>> import os
863-
>>> archive_name = os.path.expanduser(os.path.join('~', 'myarchive'))
867+
>>> archive_name = Path.home() / 'myarchive'
864868
>>> make_archive(
865869
... archive_name,
866870
... 'tar',

Lib/shutil.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,8 @@ def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
12121212
for arg, val in format_info[1]:
12131213
kwargs[arg] = val
12141214

1215+
base_name = os.fspath(base_name)
1216+
12151217
if base_dir is None:
12161218
base_dir = os.curdir
12171219

@@ -1223,8 +1225,6 @@ def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
12231225
raise NotADirectoryError(errno.ENOTDIR, 'Not a directory', root_dir)
12241226

12251227
if supports_root_dir:
1226-
# Support path-like base_name here for backwards-compatibility.
1227-
base_name = os.fspath(base_name)
12281228
kwargs['root_dir'] = root_dir
12291229
else:
12301230
save_cwd = os.getcwd()

Lib/test/test_shutil.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,6 +2042,24 @@ def test_make_zipfile_in_curdir(self):
20422042
self.assertEqual(make_archive('test', 'zip'), 'test.zip')
20432043
self.assertTrue(os.path.isfile('test.zip'))
20442044

2045+
@support.requires_zlib()
2046+
def test_make_archive_accepts_pathlike(self):
2047+
tmpdir = self.mkdtemp()
2048+
with os_helper.change_cwd(tmpdir), no_chdir:
2049+
# Test path-like base_name without root_dir and base_dir
2050+
base_name = FakePath(os.path.join(tmpdir, 'archive'))
2051+
res = make_archive(base_name, 'zip')
2052+
self.assertEqual(res, os.path.join(tmpdir, 'archive.zip'))
2053+
self.assertTrue(os.path.isfile(res))
2054+
2055+
# Test with path-like base_name, root_dir, and base_dir
2056+
root_dir, base_dir = self._create_files()
2057+
base_name = FakePath(os.path.join(tmpdir, 'archive2'))
2058+
res = make_archive(
2059+
base_name, 'zip', FakePath(root_dir), FakePath(base_dir))
2060+
self.assertEqual(res, os.path.join(tmpdir, 'archive2.zip'))
2061+
self.assertTrue(os.path.isfile(res))
2062+
20452063
def test_register_archive_format(self):
20462064

20472065
self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Added ``pathlib.Path`` support for :func:`shutil.make_archive` with updated
2+
documentation and lightweight tests.

0 commit comments

Comments
 (0)