Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions Doc/library/shutil.rst
Original file line number Diff line number Diff line change
Expand Up @@ -619,22 +619,23 @@ 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 the :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
:mod:`zlib` module is available), "bztar" (if the :mod:`bz2` module is
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 the :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 the :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.

Expand Down Expand Up @@ -669,6 +670,9 @@ 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:: 3.15
Accepts a :term:`path-like object` for *base_name*.

.. function:: get_archive_formats()

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

>>> from pathlib import Path
>>> from shutil import make_archive
>>> import os
>>> archive_name = os.path.expanduser(os.path.join('~', 'myarchive'))
>>> root_dir = os.path.expanduser(os.path.join('~', '.ssh'))
>>> archive_name = Path.home() / 'myarchive'
>>> root_dir = Path.home() / '.ssh'
>>> make_archive(archive_name, 'gztar', root_dir)
'/Users/tarek/myarchive.tar.gz'

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

>>> from pathlib import Path
>>> from shutil import make_archive
>>> import os
>>> archive_name = os.path.expanduser(os.path.join('~', 'myarchive'))
>>> archive_name = Path.home() / 'myarchive'
>>> make_archive(
... archive_name,
... 'tar',
Expand Down
4 changes: 2 additions & 2 deletions Lib/shutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,8 @@ 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

Expand All @@ -1223,8 +1225,6 @@ def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
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()
Expand Down
18 changes: 18 additions & 0 deletions Lib/test/test_shutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -2042,6 +2042,24 @@ def test_make_zipfile_in_curdir(self):
self.assertEqual(make_archive('test', 'zip'), 'test.zip')
self.assertTrue(os.path.isfile('test.zip'))

@support.requires_zlib()
def test_make_archive_accepts_pathlike(self):
tmpdir = self.mkdtemp()
with os_helper.change_cwd(tmpdir), no_chdir:
# Test path-like base_name without root_dir and base_dir
base_name = FakePath(os.path.join(tmpdir, 'archive'))
res = make_archive(base_name, 'zip')
self.assertEqual(res, os.path.join(tmpdir, 'archive.zip'))
self.assertTrue(os.path.isfile(res))

# Test with path-like base_name, root_dir, and base_dir
root_dir, base_dir = self._create_files()
base_name = FakePath(os.path.join(tmpdir, 'archive2'))
res = make_archive(
base_name, 'zip', FakePath(root_dir), FakePath(base_dir))
self.assertEqual(res, os.path.join(tmpdir, 'archive2.zip'))
self.assertTrue(os.path.isfile(res))

def test_register_archive_format(self):

self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Added ``pathlib.Path`` support for :func:`shutil.make_archive` with updated
documentation and lightweight tests.
Loading