diff --git a/Lib/shutil.py b/Lib/shutil.py index 8d8fe145567822..ac2f8750272257 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -1358,6 +1358,7 @@ def _unpack_tarfile(filename, extract_dir, *, filter=None): _UNPACK_FORMATS = { 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"), 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file"), + 'whl': (['.whl'], _unpack_zipfile, [], "Wheel file"), } if _ZLIB_SUPPORTED: diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index ebb6cf88336249..0f481a6f8a9c3f 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -2115,12 +2115,13 @@ def check_unpack_archive(self, format, **kwargs): self.check_unpack_archive_with_converter(format, FakePath, **kwargs) def check_unpack_archive_with_converter(self, format, converter, **kwargs): + make_format = kwargs.pop("make_format", format) root_dir, base_dir = self._create_files() expected = rlistdir(root_dir) expected.remove('outer') base_name = os.path.join(self.mkdtemp(), 'archive') - filename = make_archive(base_name, format, root_dir, base_dir) + filename = make_archive(base_name, make_format, root_dir, base_dir) # let's try to unpack it now tmpdir2 = self.mkdtemp() @@ -2168,6 +2169,12 @@ def test_unpack_archive_zip(self): with self.assertRaises(TypeError): self.check_unpack_archive('zip', filter='data') + @support.requires_zlib() + def test_unpack_archive_whl(self): + self.check_unpack_archive('whl', make_format='zip') + with self.assertRaises(TypeError): + self.check_unpack_archive('whl', filter='data', make_format='zip') + def test_unpack_registry(self): formats = get_unpack_formats() diff --git a/Misc/NEWS.d/next/Library/2025-10-20-13-08-04.gh-issue-84027.HjBO0B.rst b/Misc/NEWS.d/next/Library/2025-10-20-13-08-04.gh-issue-84027.HjBO0B.rst new file mode 100644 index 00000000000000..060eeabd903bbb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-10-20-13-08-04.gh-issue-84027.HjBO0B.rst @@ -0,0 +1 @@ +:mod:`shutil` now can unpack wheel packages using the ``whl`` format.