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
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.
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.
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()
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)
--- /dev/null
+Added :term:`path-like object` support for :func:`shutil.make_archive`.