Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Lib/test/test_zipapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,20 @@ def test_shebang_is_executable(self):
zipapp.create_archive(str(source), str(target), interpreter='python')
self.assertTrue(target.stat().st_mode & stat.S_IEXEC)

@unittest.skipIf(sys.platform == 'win32',
'Windows does not support an executable bit')
@os_helper.skip_unless_working_chmod
def test_copied_archive_with_pathlike_target_is_executable(self):
# Test that copying an archive to a PathLike target makes it executable.
source = self.tmpdir / 'source'
source.mkdir()
(source / '__main__.py').touch()
target = self.tmpdir / 'source.pyz'
zipapp.create_archive(source, target, interpreter='python')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a comment explaining why we are creating the zipapp twice. Something like:

Copying an archive uses a different code path than creating one from scratch. Ensure that the executable bit is set even if the target is a path-like object.

Maybe also add a reference to the bug report.

In theory we should have checks for both the str and the os.PathLike cases, but that feels like overkill.

new_target = self.tmpdir / 'changed.pyz'
zipapp.create_archive(target, new_target, interpreter='python')
self.assertTrue(new_target.stat().st_mode & stat.S_IEXEC)

@unittest.skipIf(sys.platform == 'win32',
'Windows does not support an executable bit')
def test_no_shebang_is_not_executable(self):
Expand Down
2 changes: 1 addition & 1 deletion Lib/zipapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def _copy_archive(archive, new_archive, interpreter=None):
dst.write(first_2)
shutil.copyfileobj(src, dst)

if interpreter and isinstance(new_archive, str):
if interpreter and isinstance(new_archive, (str, os.PathLike)):
os.chmod(new_archive, os.stat(new_archive).st_mode | stat.S_IEXEC)


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:func:`zipapp.create_archive` now correctly sets the executable bit on the
target archive when the target is a path-like object.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
target archive when the target is a path-like object.
target archive when copying a zipapp where the target is a path-like object.

Loading