Add `pyenv-virtualenv` compatybility
Summary
I'm using pyenv with pyenv-virtualenv for my daily workflow.
Currently, uv pip nice works as a replacement of pip, however, try to use uvx or uv build it ends with error message
error: No interpreter found for executable name `partsegcore` in virtual environments, managed installations, or system path
Where partsegcore is the name of virtualenv.
This PR is fixing this
Test Plan
I tested it locally.
Hi! Does pyenv-virtualenv not set VIRTUAL_ENV?
I'm not sure if we'll accept this functionality yet, but I think you'd want to add it at https://github.com/astral-sh/uv/blob/bf3286cd2d22f775107b807ac2e15d636bc334b7/crates/uv-python/src/discovery.rs#L225-L242
Hi! Does
pyenv-virtualenvnot setVIRTUAL_ENV?
Yes. It set. I put a comment in meantime.
I'm not sure if we'll accept this functionality yet, but I think you'd want to add it at
Based on my tries, this code is not reached if the .python-version file is present. uv fails when cannot find an executable with the name same as the provided virtualenv name in the .python-version
I see. The .python-version file shouldn't contain the name of an environment for use with uv — does pyenv support that?
I see. The .python-version file shouldn't contain the name of an environment for use with uv — does pyenv support that?
No. This is default location where pyenv store which python use:
https://github.com/pyenv/pyenv/blob/master/COMMANDS.md#pyenv-local
Seting python version using pyenv cli will be put in this file.
In the same way we let you put versions in that file, but not the name of an environment. It sounds like you put an environment name in there which will break uv as we'll try to find it as an executable name.
In the same way we let you put versions in that file, but not the name of an environment. It sounds like you put an environment name in there which will break uv as we'll try to find it as an executable name.
If I put only Python versions in this file, it will lead to work in a global Python installation, not isolated per context.
As far as I know, the pyenv is a tool that introduced .python-version as a file to save information about used python environment and storing name of any valid pyenv environments is a valid use of this file.
Because of this, it is recommended to not store .python-version in git repository, as it may be machine-specific.
And uv does not fully support .python-version (check only the working directory, without checking parents), and does not allow ignoring it (only --no-config option that means much more).
I don't see using an environment name in the version file in the pyenv documentation. Regardless, I don't think it's a use-case we can support.
Using of named virtualenv is described in documentation of pyenv-virtualenv https://github.com/pyenv/pyenv-virtualenv?tab=readme-ov-file#activate-virtualenv
If eval "$(pyenv virtualenv-init -)" is configured in your shell, pyenv-virtualenv will automatically activate/deactivate virtualenvs on entering/leaving directories which contain a .python-version file that contains the name of a valid virtual environment as shown in the output of pyenv virtualenvs (e.g., venv34 or 3.4.3/envs/venv34 in example above) . .python-version files are used by pyenv to denote local Python versions and can be created and deleted with the pyenv local command.
I see, thanks. It sounds like this is an extension of .python-version files as defined by pyvenv specifically for pyvenv-virtualenv?
I'm pyenv user, not a maintainer.
I think that this part of pyenv documentation is valid part of specyfication:
Locating Pyenv-provided Python installations
Once pyenv has determined which version of Python your application has specified, it passes the command along to the corresponding Python installation.
Each Python version is installed into its own directory under
$(pyenv root)/versions.For example, you might have these versions installed:
$(pyenv root)/versions/2.7.8/ $(pyenv root)/versions/3.4.2/ $(pyenv root)/versions/pypy-2.4.0/As far as Pyenv is concerned, version names are simply directories under
$(pyenv root)/versions.
So pyenv-virtualenv is creating a directory named as virtualenv under $(pyenv root)/versions directory.
I see, thanks. It sounds like this is an extension of
.python-versionfiles as defined bypyvenvspecifically forpyvenv-virtualenv?
This is correct and somewhat the historical use of .python-version by pyenv-virtualenv.
To illustrate, say you have pyenv and pyenv-virtualenv installed with 3.12.7, 3.13.0rc3.
>$ mkdir myproject
>$ cd myproject
myproject>$ echo 'testenv3.12' > .python-version
myproject>$ pyenv virtualenv 3.12.7 testenv3.12
(testenv3.12) myproject>$ python -c 'import sys; print(sys.prefix)'
/home/dev/.pyenv/versions/testenv3.12
(testenv3.12) myproject>$ echo '3.12.7' > .python-version
myproject>$ python --version
Python 3.12.7
myproject>$ python -c 'import sys; print(sys.prefix)'
/home/dev/.pyenv/versions/3.12.7
myproject>$ echo '3.13.0rc3' > .python-version
myproject>$ python --version
Python 3.13.0rc3
myproject>$ python -c 'import sys; print(sys.prefix)'
/home/dev/.pyenv/versions/3.13.0rc3
myproject>$ pyenv virtualenv 3.13.0rc3 testenv3.13
myproject>$ echo 'testenv3.13' > .python-version
(testenv3.13) myproject>$ python -c 'import sys; print(sys.prefix)'
/home/dev/.pyenv/versions/testenv3.13
(testenv3.13) myproject>$ cd ..
>$
I do not understand why tests fail. Could you hint me?
The test is failing because you changed version file parsing to split on within-line whitespace so something such >3.8, <3.11 is parsed as >3.8, which changes the snapshot:
3 │-Updated `.python-version` from `>3.8, <3.11` -> `3.11`
3 │+Updated `.python-version` from `>3.8,` -> `3.11`
I'll repeat that I'm pretty unsure that we'll accept this change though.
Hm.
Maybe I should change to use PYENV_ROOT environment variable and check $PYENV_ROOT/versiosn/{value} directory if exists?
What should I update/motivate here?
I'm still not excited about making this change. It relies on some specific third-party behavior and we generally try not to integrate with third-party Python discovery mechanisms here.
I'm still not excited about making this change. It relies on some specific third-party behavior and we generally try not to integrate with third-party Python discovery mechanisms here.
Maybe some other change, to make uv not crash if someone is using pyenv with pyenv-virtualenv?
When I now call uvx or uv build I currently do not need to use the same python as in the current virtual environment.
I believe https://github.com/astral-sh/uv/pull/12909 should cover the use-case you have here, without encoding knowledge of pyenv-virtualenv.