Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 4 additions & 0 deletions Lib/shutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,10 @@ def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
supports_root_dir = getattr(func, 'supports_root_dir', False)
save_cwd = None
if root_dir is not None:
stmd = os.stat(root_dir).st_mode
if not stat.S_ISDIR(stmd):
raise NotADirectoryError(root_dir)
Comment thread
6t8k marked this conversation as resolved.
Outdated

if supports_root_dir:
# Support path-like base_name here for backwards-compatibility.
base_name = os.fspath(base_name)
Expand Down
43 changes: 43 additions & 0 deletions Lib/test/test_shutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -1665,6 +1665,49 @@ def test_register_archive_format(self):
formats = [name for name, params in get_archive_formats()]
self.assertNotIn('xxx', formats)

def _unlink_existing_file(self, path):
Comment thread
6t8k marked this conversation as resolved.
Outdated
try:
os.unlink(path)
except FileNotFoundError:
pass

def test_make_tarfile_rootdir_nodir(self):
# GH-99203
self.addCleanup(self._unlink_existing_file, f'{TESTFN}.tar')
for dry_run in (0, True):
Comment thread
6t8k marked this conversation as resolved.
Outdated
with self.subTest(dry_run=dry_run):
tmp_fd, tmp_file = tempfile.mkstemp(dir=self.mkdtemp())
Comment thread
6t8k marked this conversation as resolved.
Outdated
os.close(tmp_fd)
with self.assertRaises(NotADirectoryError):
make_archive(TESTFN, 'tar', tmp_file, dry_run=dry_run)
self.assertFalse(os.path.exists(f'{TESTFN}.tar'))

tmp_fd, tmp_file = tempfile.mkstemp(dir=self.mkdtemp())
os.close(tmp_fd)
os.unlink(tmp_file)
with self.assertRaises(FileNotFoundError):
make_archive(TESTFN, 'tar', tmp_file, dry_run=dry_run)
self.assertFalse(os.path.exists(f'{TESTFN}.tar'))

@support.requires_zlib()
def test_make_zipfile_rootdir_nodir(self):
# GH-99203
self.addCleanup(self._unlink_existing_file, f'{TESTFN}.zip')
for dry_run in (0, True):
with self.subTest(dry_run=dry_run):
tmp_fd, tmp_file = tempfile.mkstemp(dir=self.mkdtemp())
os.close(tmp_fd)
with self.assertRaises(NotADirectoryError):
make_archive(TESTFN, 'zip', tmp_file, dry_run=dry_run)
self.assertFalse(os.path.exists(f'{TESTFN}.zip'))

tmp_fd, tmp_file = tempfile.mkstemp(dir=self.mkdtemp())
os.close(tmp_fd)
os.unlink(tmp_file)
with self.assertRaises(FileNotFoundError):
make_archive(TESTFN, 'zip', tmp_file, dry_run=dry_run)
self.assertFalse(os.path.exists(f'{TESTFN}.zip'))

### shutil.unpack_archive

def check_unpack_archive(self, format):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Restore following CPython <= 3.10.5 behavior of :func:`shutil.make_archive`:
do not create an empty archive if ``root_dir`` is not a directory, and, in that
case, raise :class:`FileNotFoundError` or :class:`NotADirectoryError`
regardless of ``format`` choice. Beyond the brought-back behavior, the function
may now also raise these exceptions in ``dry_run`` mode.