Update zipapp.py from 3.13.5 (#6075)

This commit is contained in:
Jack O'Connor authored and GitHub committed 2025-08-06 10:31:55 +09:00
1 parent cac4948afe
commit 93eacdac20
2 files changed
+71 -5

No files matched your search

+47 -4
View File
@@ -9,6 +9,7 @@ import unittest
import zipapp
import zipfile
from test.support import requires_zlib
from test.support import os_helper
from unittest.mock import patch
@@ -54,6 +55,22 @@ class ZipAppTest(unittest.TestCase):
self.assertIn('foo/', z.namelist())
self.assertIn('bar/', z.namelist())
def test_create_sorted_archive(self):
# Test that zipapps order their files by name
source = self.tmpdir / 'source'
source.mkdir()
(source / 'zed.py').touch()
(source / 'bin').mkdir()
(source / 'bin' / 'qux').touch()
(source / 'bin' / 'baz').touch()
(source / '__main__.py').touch()
target = io.BytesIO()
zipapp.create_archive(str(source), target)
target.seek(0)
with zipfile.ZipFile(target, 'r') as zf:
self.assertEqual(zf.namelist(),
["__main__.py", "bin/", "bin/baz", "bin/qux", "zed.py"])
def test_create_archive_with_filter(self):
# Test packing a directory and using filter to specify
# which files to include.
@@ -72,6 +89,30 @@ class ZipAppTest(unittest.TestCase):
self.assertIn('test.py', z.namelist())
self.assertNotIn('test.pyc', z.namelist())
def test_create_archive_self_insertion(self):
# When creating an archive, we shouldn't
# include the archive in the list of files to add.
source = self.tmpdir
(source / '__main__.py').touch()
(source / 'test.py').touch()
target = self.tmpdir / 'target.pyz'
zipapp.create_archive(source, target)
with zipfile.ZipFile(target, 'r') as z:
self.assertEqual(len(z.namelist()), 2)
self.assertIn('__main__.py', z.namelist())
self.assertIn('test.py', z.namelist())
def test_target_overwrites_source_file(self):
# The target cannot be one of the files to add.
source = self.tmpdir
(source / '__main__.py').touch()
target = source / 'target.pyz'
target.touch()
with self.assertRaises(zipapp.ZipAppError):
zipapp.create_archive(source, target)
def test_create_archive_filter_exclude_dir(self):
# Test packing a directory and using a filter to exclude a
# subdirectory (ensures that the path supplied to include
@@ -248,14 +289,15 @@ class ZipAppTest(unittest.TestCase):
zipapp.create_archive(str(target), new_target, interpreter='python2.7')
self.assertTrue(new_target.getvalue().startswith(b'#!python2.7\n'))
def test_read_from_pathobj(self):
# Test that we can copy an archive using a pathlib.Path object
def test_read_from_pathlike_obj(self):
# Test that we can copy an archive using a path-like object
# for the source.
source = self.tmpdir / 'source'
source.mkdir()
(source / '__main__.py').touch()
target1 = self.tmpdir / 'target1.pyz'
target2 = self.tmpdir / 'target2.pyz'
source = os_helper.FakePath(str(source))
target1 = os_helper.FakePath(str(self.tmpdir / 'target1.pyz'))
target2 = os_helper.FakePath(str(self.tmpdir / 'target2.pyz'))
zipapp.create_archive(source, target1, interpreter='python')
zipapp.create_archive(target1, target2, interpreter='python2.7')
self.assertEqual(zipapp.get_interpreter(target2), 'python2.7')
@@ -301,6 +343,7 @@ class ZipAppTest(unittest.TestCase):
# (Unix only) tests that archives with shebang lines are made executable
@unittest.skipIf(sys.platform == 'win32',
'Windows does not support an executable bit')
@os_helper.skip_unless_working_chmod
def test_shebang_is_executable(self):
# Test that an archive with a shebang line is made executable.
source = self.tmpdir / 'source'
+24 -1
View File
@@ -131,12 +131,35 @@ def create_archive(source, target=None, interpreter=None, main=None,
elif not hasattr(target, 'write'):
target = pathlib.Path(target)
# Create the list of files to add to the archive now, in case
# the target is being created in the source directory - we
# don't want the target being added to itself
files_to_add = sorted(source.rglob('*'))
# The target cannot be in the list of files to add. If it were, we'd
# end up overwriting the source file and writing the archive into
# itself, which is an error. We therefore check for that case and
# provide a helpful message for the user.
# Note that we only do a simple path equality check. This won't
# catch every case, but it will catch the common case where the
# source is the CWD and the target is a file in the CWD. More
# thorough checks don't provide enough value to justify the extra
# cost.
# If target is a file-like object, it will simply fail to compare
# equal to any of the entries in files_to_add, so there's no need
# to add a special check for that.
if target in files_to_add:
raise ZipAppError(
f"The target archive {target} overwrites one of the source files.")
with _maybe_open(target, 'wb') as fd:
_write_file_prefix(fd, interpreter)
compression = (zipfile.ZIP_DEFLATED if compressed else
zipfile.ZIP_STORED)
with zipfile.ZipFile(fd, 'w', compression=compression) as z:
for child in source.rglob('*'):
for child in files_to_add:
arcname = child.relative_to(source)
if filter is None or filter(arcname):
z.write(child, arcname.as_posix())