Skip to content

Commit c0e1ba1

Browse files
[3.14] gh-156568: Make zipapp archives executable with PathLike targets (gh-156569) (gh-159405)
1 parent 6909287 commit c0e1ba1

3 files changed

Lines changed: 21 additions & 1 deletion

File tree

‎Lib/test/test_zipapp.py‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,24 @@ def test_shebang_is_executable(self):
366366
zipapp.create_archive(str(source), str(target), interpreter='python')
367367
self.assertTrue(target.stat().st_mode & stat.S_IEXEC)
368368

369+
@unittest.skipIf(sys.platform == 'win32',
370+
'Windows does not support an executable bit')
371+
@os_helper.skip_unless_working_chmod
372+
def test_copied_archive_with_pathlike_target_is_executable(self):
373+
# Test that copying an archive to a PathLike target makes it executable.
374+
source = self.tmpdir / 'source'
375+
source.mkdir()
376+
(source / '__main__.py').touch()
377+
target = self.tmpdir / 'source.pyz'
378+
zipapp.create_archive(source, target, interpreter='python')
379+
# Copying an archive uses a different code path than creating
380+
# one from scratch. Ensure that the executable bit is set
381+
# even if the target is a path-like object.
382+
# See https://github.com/python/cpython/issues/156568
383+
new_target = self.tmpdir / 'changed.pyz'
384+
zipapp.create_archive(target, new_target, interpreter='python')
385+
self.assertTrue(new_target.stat().st_mode & stat.S_IEXEC)
386+
369387
@unittest.skipIf(sys.platform == 'win32',
370388
'Windows does not support an executable bit')
371389
def test_no_shebang_is_not_executable(self):

‎Lib/zipapp.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def _copy_archive(archive, new_archive, interpreter=None):
6969
dst.write(first_2)
7070
shutil.copyfileobj(src, dst)
7171

72-
if interpreter and isinstance(new_archive, str):
72+
if interpreter and isinstance(new_archive, (str, os.PathLike)):
7373
os.chmod(new_archive, os.stat(new_archive).st_mode | stat.S_IEXEC)
7474

7575

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:func:`zipapp.create_archive` now correctly sets the executable bit on the
2+
target archive when copying a zipapp where the target is a path-like object.

0 commit comments

Comments
 (0)