astral-sh / uv

An extremely fast Python package and project manager, written in Rust.
https://docs.astral.sh/uv
Apache License 2.0
24.7k stars 713 forks source link

Provide `pip` -> `uv pip` alias in virtual environments #1331

Closed vitalik closed 8 months ago

vitalik commented 8 months ago

mabye when uv creates virtualenv it should also create "symlink" for pip to uv pip ?

$ uv venv
...

$ uv pip install ...
...

$ source .venv/bin/activate
...

$ pip freeze
uv==0.1.0

# ^ this is a bit unexpected  <---

$ uv pip freeze
annotated-types==0.6.0
asgiref==3.7.2
certifi==2024.2.2
charset-normalizer==3.3.2
django==5.0.2
django-ninja==1.1.0
idna==3.6
pydantic==2.6.1
pydantic-core==2.16.2
requests==2.31.0
sqlparse==0.4.4
typing-extensions==4.9.0
urllib3==2.2.0
$ which pip
/Users/vitaliy/.pyenv/shims/pip #  global (unexpected)

$ which python
/private/tmp/test/.venv/bin/python # from venv (good)
zanieb commented 8 months ago

Hi! That's kind of a fun idea! I'm a little hesitant to step on the pip namespace automatically, but maybe there's something here.

You can seed pip if you want with uv venv --seed but of course we think uv pip is better to use :)

vitalik commented 8 months ago

but this is what default python -m venv does - it creates a bin/pip which looks like this:

#!/path/to/your/.venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
    sys.exit(main())

while uv does not do that - so now if I accidentally run "pip install something" it will be installed globally

zanieb commented 8 months ago

Yeah I that's fair — I think #1330 may address a small part of that concern but I like your idea too.

pfmoore commented 8 months ago

(Pip maintainer here) I'd be strongly against this because pip and uv pip have different command sets and behaviours. It would be far too easy to end up with users reporting issues with pip when they are actually using uv pip.

vitalik commented 8 months ago

@pfmoore @zanieb ok... so maybe --seed should be enabled by default ?

I think it would be the most annoying thing - activating venv and then installing stuff to global with global pip

jgauth commented 8 months ago

+1 that the default behavior is quite confusing/unexpected:

$ uv venv -p 3.11

Using Python 3.11.8 interpreter at /opt/Python3.11.8/bin/python3.11
Creating virtualenv at: .venv

$ uv pip freeze
# no output -- good, no packages have been installed to this venv

$ source .venv/bin/activate

$ pip freeze
# outputs all the packages installed on my system installation, even with venv active
annotated-types==0.6.0
ansible-base==2.10.8
...

$ which pip
/home/jgauthier/.local/bin/pip
# venv doesn't change what `pip` I'm using

compared to what I was expecting, based on how python3 -m venv works:

$ python3.11 -m venv .venv

$ source .venv/bin/activate

$ pip freeze
# no output (no packages installed)

$ which pip
/home/jgauthier/.local/bin/pip
# venv _does_ change what `pip` I'm using

--seed does fix this, but not having it default seems likely to lead to confusion, and possibly even people installing packages to the system, when they think they're installing to the venv e.g.:

$ uv venv -p 3.11
Using Python 3.11.8 interpreter at /opt/Python3.11.8/bin/python3.11
Creating virtualenv at: .venv

$ source .venv/bin/activate

$ pip install redis
# oh no, this installed to system packages

This ^ could be quite destructive if you're unlucky / not careful

woutervh commented 8 months ago

IMHO uv should be symlink into the virtualenv, and operate automatically in that virtualenv

now, I'm stuck if you don't activate the venv (whould should be optional):

> uv venv foo
> cd foo

# this currently fails
> uv pip install pytest
    error: Failed to locate a virtualenv or Conda environment (checked: `VIRTUAL_ENV`, `CONDA_PREFIX`, and `.venv`). Run `uv venv` to create a virtualenv.

# hopefully this works in the future
> bin/uv pip install pytest
pfmoore commented 8 months ago

Maybe the correct approach is to not call the uv subcommand uv pip in the first place? Then the possibility of confusing the two is substantially reduced.

MithicSpirit commented 8 months ago

while uv does not do that - so now if I accidentally run "pip install something" it will be installed globally

I recommend using alias pip='python -m pip' globally (i.e., in your shell's rc file) so that it always uses the pip module from the current python environment (and fails if one does not exist).

pfmoore commented 8 months ago

There's also the zipapp distribution of pip which will get executed by the active Python environment.

The reality here, though, is that pip is designed to be installed in every environment. That's a historical consequence of a number of things, and it's not ideal, but it's really hard to change. And there's never been any real incentive to do so, as there's never been any viable alternative to pip until now. Simply by being an alternative to pip, uv is going to need to address some of the consequences of disrupting the status quo, where it's expected that you can always run an installer via subprocess.run([sys.executable, "-m", "pip", ...]), or /path/to/env/python -m pip. The problem is wider than simply adding a pip shim that runs uv.

There's a discussion at https://discuss.python.org/t/pip-plans-to-introduce-an-alternative-zipapp-deployment-method/17431 which adds some context to all of this.

zanieb commented 8 months ago

There are some very fair concerns about this idea. I think we are unlikely to do it; solving this is going to require more discussion and consideration.

HarlanHeilman commented 8 months ago

Perhaps a solution would be a uv init that works similarly to the zoxide init https://github.com/ajeetdsouza/zoxide (If you are unfamiliar, it allows you to map over the cd command). This way the user can choose "at their own risk" to map over pip and venv with uv's implementation.

pfmoore commented 8 months ago

I’m not sure why there is any need to overwrite the pip command at all. In spite of the current name, uv pip and pip are completely separate and independent commands/tools. I don’t think we want uv pip to be constrained to follow pip’s interface, for example - it already has some options pip doesn’t have, and omits some pip functionality that it may never want to add.

woutervh commented 8 months ago

maybe rename "uv pip" to "uv rip" :)

pfmoore commented 8 months ago

All the good names are taken, aren't they? :-)

layday commented 8 months ago

Uh, uv pipish? It's pip...ish 🤯

zanieb commented 8 months ago

I do not think we're going to do this.

See instead: