uv icon indicating copy to clipboard operation
uv copied to clipboard

Add `pyenv-virtualenv` compatybility

Open Czaki opened this issue 1 year ago • 18 comments

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.

Czaki avatar Oct 04 '24 21:10 Czaki

Hi! Does pyenv-virtualenv not set VIRTUAL_ENV?

zanieb avatar Oct 04 '24 21:10 zanieb

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

zanieb avatar Oct 04 '24 21:10 zanieb

Hi! Does pyenv-virtualenv not set VIRTUAL_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

Czaki avatar Oct 04 '24 21:10 Czaki

I see. The .python-version file shouldn't contain the name of an environment for use with uv — does pyenv support that?

zanieb avatar Oct 04 '24 21:10 zanieb

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.

Czaki avatar Oct 04 '24 21:10 Czaki

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.

zanieb avatar Oct 04 '24 21:10 zanieb

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).

Czaki avatar Oct 04 '24 22:10 Czaki

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.

zanieb avatar Oct 04 '24 23:10 zanieb

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.

Czaki avatar Oct 05 '24 06:10 Czaki

I see, thanks. It sounds like this is an extension of .python-version files as defined by pyvenv specifically for pyvenv-virtualenv?

zanieb avatar Oct 05 '24 14:10 zanieb

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.

Czaki avatar Oct 05 '24 20:10 Czaki

I see, thanks. It sounds like this is an extension of .python-version files as defined by pyvenv specifically for pyvenv-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 ..

>$ 

samypr100 avatar Oct 06 '24 19:10 samypr100

I do not understand why tests fail. Could you hint me?

Czaki avatar Oct 06 '24 21:10 Czaki

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.

zanieb avatar Oct 06 '24 22:10 zanieb

Hm. Maybe I should change to use PYENV_ROOT environment variable and check $PYENV_ROOT/versiosn/{value} directory if exists?

Czaki avatar Oct 16 '24 16:10 Czaki

What should I update/motivate here?

Czaki avatar Oct 21 '24 18:10 Czaki

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.

zanieb avatar Oct 21 '24 18:10 zanieb

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.

Czaki avatar Oct 21 '24 18:10 Czaki

I believe https://github.com/astral-sh/uv/pull/12909 should cover the use-case you have here, without encoding knowledge of pyenv-virtualenv.

zanieb avatar Apr 19 '25 16:04 zanieb