Skip to content

Commit

Permalink
[3.11] pythongh-99203: shutil.make_archive(): restore select CPython …
Browse files Browse the repository at this point in the history
…<= 3.10.5 behavior (pythonGH-99802)

Restore following CPython <= 3.10.5 behavior of shutil.make_archive()
that went away as part of pythongh-93160:

Do not create an empty archive if root_dir is not a directory, and, in
that case, raise FileNotFoundError or NotADirectoryError regardless
of format choice. Beyond the brought-back behavior, the function may
now also raise these exceptions in dry_run mode..
(cherry picked from commit a86df29)

Co-authored-by: 6t8k <58048945+6t8k@users.noreply.github.com>
  • Loading branch information
6t8k authored and serhiy-storchaka committed Aug 16, 2023
1 parent 3f7dfb6 commit a716563
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 2 deletions.
8 changes: 6 additions & 2 deletions Lib/shutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -1114,10 +1114,14 @@ def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
if base_dir is None:
base_dir = os.curdir

support_root_dir = format_info[3]
supports_root_dir = format_info[3]
save_cwd = None
if root_dir is not None:
if support_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
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 @@ -1629,6 +1629,49 @@ def test_register_archive_format(self):
formats = [name for name, params in get_archive_formats()]
self.assertNotIn('xxx', formats)

def test_make_tarfile_rootdir_nodir(self):
# GH-99203
self.addCleanup(os_helper.unlink, f'{TESTFN}.tar')
for dry_run in (False, True):
with self.subTest(dry_run=dry_run):
tmp_dir = self.mkdtemp()
nonexisting_file = os.path.join(tmp_dir, 'nonexisting')
with self.assertRaises(FileNotFoundError) as cm:
make_archive(TESTFN, 'tar', nonexisting_file, dry_run=dry_run)
self.assertEqual(cm.exception.errno, errno.ENOENT)
self.assertEqual(cm.exception.filename, nonexisting_file)
self.assertFalse(os.path.exists(f'{TESTFN}.tar'))

tmp_fd, tmp_file = tempfile.mkstemp(dir=tmp_dir)
os.close(tmp_fd)
with self.assertRaises(NotADirectoryError) as cm:
make_archive(TESTFN, 'tar', tmp_file, dry_run=dry_run)
self.assertEqual(cm.exception.errno, errno.ENOTDIR)
self.assertEqual(cm.exception.filename, tmp_file)
self.assertFalse(os.path.exists(f'{TESTFN}.tar'))

@support.requires_zlib()
def test_make_zipfile_rootdir_nodir(self):
# GH-99203
self.addCleanup(os_helper.unlink, f'{TESTFN}.zip')
for dry_run in (False, True):
with self.subTest(dry_run=dry_run):
tmp_dir = self.mkdtemp()
nonexisting_file = os.path.join(tmp_dir, 'nonexisting')
with self.assertRaises(FileNotFoundError) as cm:
make_archive(TESTFN, 'zip', nonexisting_file, dry_run=dry_run)
self.assertEqual(cm.exception.errno, errno.ENOENT)
self.assertEqual(cm.exception.filename, nonexisting_file)
self.assertFalse(os.path.exists(f'{TESTFN}.zip'))

tmp_fd, tmp_file = tempfile.mkstemp(dir=tmp_dir)
os.close(tmp_fd)
with self.assertRaises(NotADirectoryError) as cm:
make_archive(TESTFN, 'zip', tmp_file, dry_run=dry_run)
self.assertEqual(cm.exception.errno, errno.ENOTDIR)
self.assertEqual(cm.exception.filename, tmp_file)
self.assertFalse(os.path.exists(f'{TESTFN}.zip'))

### shutil.unpack_archive

def check_unpack_archive(self, format, **kwargs):
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.

0 comments on commit a716563

Please sign in to comment.