Skip to content

Commit 5d9f20a

Browse files
miss-islington6t8k
andauthored
[3.12] gh-99203: shutil.make_archive(): restore select CPython <= 3.10.5 behavior (GH-99802) (#107998)
gh-99203: shutil.make_archive(): restore select CPython <= 3.10.5 behavior (GH-99802) Restore following CPython <= 3.10.5 behavior of shutil.make_archive() that went away as part of gh-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>
1 parent 4421c65 commit 5d9f20a

File tree

3 files changed

+52
-0
lines changed

3 files changed

+52
-0
lines changed

Lib/shutil.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,10 @@ def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
11561156
supports_root_dir = getattr(func, 'supports_root_dir', False)
11571157
save_cwd = None
11581158
if root_dir is not None:
1159+
stmd = os.stat(root_dir).st_mode
1160+
if not stat.S_ISDIR(stmd):
1161+
raise NotADirectoryError(errno.ENOTDIR, 'Not a directory', root_dir)
1162+
11591163
if supports_root_dir:
11601164
# Support path-like base_name here for backwards-compatibility.
11611165
base_name = os.fspath(base_name)

Lib/test/test_shutil.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1840,6 +1840,49 @@ def test_register_archive_format(self):
18401840
formats = [name for name, params in get_archive_formats()]
18411841
self.assertNotIn('xxx', formats)
18421842

1843+
def test_make_tarfile_rootdir_nodir(self):
1844+
# GH-99203
1845+
self.addCleanup(os_helper.unlink, f'{TESTFN}.tar')
1846+
for dry_run in (False, True):
1847+
with self.subTest(dry_run=dry_run):
1848+
tmp_dir = self.mkdtemp()
1849+
nonexisting_file = os.path.join(tmp_dir, 'nonexisting')
1850+
with self.assertRaises(FileNotFoundError) as cm:
1851+
make_archive(TESTFN, 'tar', nonexisting_file, dry_run=dry_run)
1852+
self.assertEqual(cm.exception.errno, errno.ENOENT)
1853+
self.assertEqual(cm.exception.filename, nonexisting_file)
1854+
self.assertFalse(os.path.exists(f'{TESTFN}.tar'))
1855+
1856+
tmp_fd, tmp_file = tempfile.mkstemp(dir=tmp_dir)
1857+
os.close(tmp_fd)
1858+
with self.assertRaises(NotADirectoryError) as cm:
1859+
make_archive(TESTFN, 'tar', tmp_file, dry_run=dry_run)
1860+
self.assertEqual(cm.exception.errno, errno.ENOTDIR)
1861+
self.assertEqual(cm.exception.filename, tmp_file)
1862+
self.assertFalse(os.path.exists(f'{TESTFN}.tar'))
1863+
1864+
@support.requires_zlib()
1865+
def test_make_zipfile_rootdir_nodir(self):
1866+
# GH-99203
1867+
self.addCleanup(os_helper.unlink, f'{TESTFN}.zip')
1868+
for dry_run in (False, True):
1869+
with self.subTest(dry_run=dry_run):
1870+
tmp_dir = self.mkdtemp()
1871+
nonexisting_file = os.path.join(tmp_dir, 'nonexisting')
1872+
with self.assertRaises(FileNotFoundError) as cm:
1873+
make_archive(TESTFN, 'zip', nonexisting_file, dry_run=dry_run)
1874+
self.assertEqual(cm.exception.errno, errno.ENOENT)
1875+
self.assertEqual(cm.exception.filename, nonexisting_file)
1876+
self.assertFalse(os.path.exists(f'{TESTFN}.zip'))
1877+
1878+
tmp_fd, tmp_file = tempfile.mkstemp(dir=tmp_dir)
1879+
os.close(tmp_fd)
1880+
with self.assertRaises(NotADirectoryError) as cm:
1881+
make_archive(TESTFN, 'zip', tmp_file, dry_run=dry_run)
1882+
self.assertEqual(cm.exception.errno, errno.ENOTDIR)
1883+
self.assertEqual(cm.exception.filename, tmp_file)
1884+
self.assertFalse(os.path.exists(f'{TESTFN}.zip'))
1885+
18431886
### shutil.unpack_archive
18441887

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

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy