Repository navigation
🐛 fix(create): reject an empty destination instead of using the working directory - #3491
Open
darrenhuai wants to merge 2 commits into
Open
darrenhuai wants to merge 2 commits into
darrenhuai wants to merge 2 commits into
Conversation
…ng directory
validate_dest accepted an empty destination and resolved it to the
working directory, because Path("") is "." and nothing checked for it.
On Windows a destination made only of spaces did the same, since the
path API drops trailing spaces. The usual way to pass one is an unset
shell variable, as in virtualenv --clear "$VENV". Without --clear that
writes bin, lib, pyvenv.cfg and a catch-all .gitignore into the project
folder. With --clear, Creator.run hands the working directory to
safe_delete and everything in it is gone before the environment is
built.
validate_dest now refuses an empty or whitespace-only destination before
any other check, and the error says to pass . for the current directory,
which still works as before. Whitespace is refused on POSIX too, where a
folder named " " is legal, so the same command behaves the same on every
platform; such a name is far more likely a quoting slip than a choice.
darrenhuai
marked this pull request as ready for review
October 29, 2026 15:07
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
If the destination argument is empty, virtualenv builds the environment in the current directory, and with
--clearit deletes everything there first. The usual way to end up with one is a variable that isn't set. Here it is on Linux with Python 3.12 and main at 861cff7 (run aspython3 -m virtualenvfrom that checkout), in a throwaway folder:IMPORTANT.txtandsrcare gone. The firstls -Aprints nothing because the folder itself was removed and made again under the shell. Without--clearnothing gets deleted, but the same command still writesbin,lib,pyvenv.cfg,CACHEDIR.TAGand, when the folder has none, a.gitignoreholding*straight into the project. On Windows a destination made only of spaces acts like an empty one, because Windows drops trailing spaces and dots from path names. In a Windows probe withsafe_deleteswapped for a recorder,""and" "with--clearboth handed it the working directory.The cause is in
Creator.validate_dest. It buildsPath(raw_value)and thenPath(os.path.abspath(...)).resolve(), and sincePath("")isPath("."), the empty string comes back as the working directory. That directory exists and is writable, so every later check passes, andCreator.runcallssafe_delete(self.dest)when--clearis set. The--clearguard from #3422 only refuses symlink and reparse point destinations, and #3426 only adds the line boundary check for the venv creator, so neither catches this. It is the same problem #3422 went after:--clearremoving a folder the user never named.validate_destnow refuses an empty or whitespace-only destination before its other checks. The same run on this branch, usage lines trimmed:.still works, with or without--clear, so you can create or clear an environment in the current directory when you ask for it.Venv.validate_destcalls the base method, so every creator gets the check. Whitespace-only names are refused on POSIX too, even though" "is a legal folder name there. Refusing them only on Windows would make one command line mean different things per platform, and a name that is nothing but spaces is far more likely a quoting slip than a choice. If you'd rather keep" "working on POSIX I can narrow it.On Windows, names made only of dots and spaces, such as
...or. ., also resolve to the working directory. They aren't blank, though, and refusing them would mean copying Windows' own name normalization, so I kept this PR to empty and whitespace-only values. Stdlibpython -m venv --clear ""has the same problem, but virtualenv already checks the destination more strictly than venv does (#3399, #3426), and this is one more of those checks.test_blank_destination_leaves_working_directoryswapssafe_deletefor a recorder and runscli_runfrom insidetmp_pathon""(alone, with--clearand withVIRTUALENV_CLEAR=1), on" "with--clear, and on"\t". Each case has to exit with code 2, print the new message, never reachsafe_delete, and leave the folder holding only its marker file.test_dot_destination_is_working_directorychecks that. --clearstill resolves to the working directory. All five blank cases fail on main.Thanks for contributing, make sure you address all the checklists (for details on how see development documentation)
ran the linter to address style issues (
tox -e fix). I ran the same hooks throughprekon the changed files; the semgrep hook only looks atactivate.sh.wrote descriptive pull request text
ensured there are test(s) validating the fix
added a
docs/changelog/+short-description.<type>.rstfragment for each user-facing change, or appliedskip newsupdated/extended the documentation (no page covers the destination beyond its help text; I updated the
validate_destdocstring)for changes to activation scripts,
pyvenv.cfg, wheel downloads, app-data or release workflows (none of these change; the fix only refuses a blank destination argument before anything is written)ran tests on Python 3.9 and 3.15 (
tox run -e 3.9,3.15). I rantest_creator.pyon 3.9 and left the full 3.9 and 3.15 runs to CI.linked upstream issues beside any temporary interpreter overrides (none)
kept the PR in draft until CI passes