Skip to content

Commit

Permalink
prevent PermissionError when using venv creator on some systems (#2543)
Browse files Browse the repository at this point in the history
  • Loading branch information
kulikjak committed Apr 27, 2023
1 parent ba1cb8b commit 0597a2f
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 0 deletions.
2 changes: 2 additions & 0 deletions docs/changelog/2543.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Prevent ``PermissionError`` when using venv creator on systems that deliver files without user write
permission - by :user:`kulikjak`.
4 changes: 4 additions & 0 deletions src/virtualenv/activation/via_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ def _generate(self, replacements, templates, to_folder, creator):
for template in templates:
text = self.instantiate_template(replacements, template, creator)
dest = to_folder / self.as_name(template)
# remove the file if it already exists - this prevents permission
# errors when the dest is not writable
if dest.exists():
dest.unlink()
# use write_bytes to avoid platform specific line normalization (\n -> \r\n)
dest.write_bytes(text.encode("utf-8"))
generated.append(dest)
Expand Down
22 changes: 22 additions & 0 deletions tests/unit/create/test_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,3 +611,25 @@ def _get_sys_path(flag=None):
assert non_python_path == [i for i in base if i not in extra_as_python_path]
else:
assert base == extra_all


# Make sure that the venv creator works on systems where vendor-delivered files
# (specifically venv scripts delivered with Python itself) are not writable.
#
# https://github.com/pypa/virtualenv/issues/2419
@pytest.mark.skipif("venv" not in CURRENT_CREATORS, reason="test needs venv creator")
def test_venv_creator_without_write_perms(tmp_path, mocker):
from virtualenv.run.session import Session

prev = Session._create

def func(self):
prev(self)
scripts_dir = self.creator.dest / "bin"
for script in scripts_dir.glob("*ctivate*"):
script.chmod(stat.S_IREAD | stat.S_IRGRP | stat.S_IROTH)

mocker.patch("virtualenv.run.session.Session._create", side_effect=func, autospec=True)

cmd = [str(tmp_path), "--seeder", "app-data", "--without-pip", "--creator", "venv"]
cli_run(cmd)

0 comments on commit 0597a2f

Please sign in to comment.