Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The pipX.Y console script is set to the Python version used to build the wheel instead of the one used to install the wheel #8010

Closed
sinoroc opened this issue Apr 9, 2020 · 6 comments
Labels
auto-locked Outdated issues that have been locked by automation

Comments

@sinoroc
Copy link
Contributor

sinoroc commented Apr 9, 2020

If I understood right the pipX.Y console script is set to the version of the Python interpreter used to build the pip's wheel, instead of the version of the Python interpreter used to install it.

Found this issue thanks to this question on Stack Overflow:

Looks like the root cause of the issue lies in the setup.py for example here in the latest tagged version:

pip/setup.py

Lines 75 to 83 in 931749f

entry_points={
"console_scripts": [
"pip=pip._internal.cli.main:main",
"pip{}=pip._internal.cli.main:main".format(sys.version_info[0]),
"pip{}.{}=pip._internal.cli.main:main".format(
*sys.version_info[:2]
),
],
},

Looks to me like the actual pipX.Y label is set when the wheel is built. But if it is later installed with a different Python version than the one used to build the wheel, then it is problematic. I would expect that installing from the sdist should not present the issue.

I should have a closer look at it with a clean setup, but it seems like surprisingly it is somehow not an issue at install-time (the right pipX.Y script is created), but it gets confusing at uninstall-time, in that it seems to delete the wrong pipX.Y (the one in entry_points.txt) additionnally to the right one (the one corresponding to the current Python interpreter).

$ lsb_release -d
Description:	Ubuntu 18.04.4 LTS
$ python3.7 --version
Python 3.7.5
$ python3.7 -m venv .
$ cat lib/python3.7/site-packages/pip-9.0.1.dist-info/entry_points.txt 
[console_scripts]
pip = pip:main
pip3 = pip:main
pip3.6 = pip:main
$ ls bin/pip*
bin/pip  bin/pip3  bin/pip3.7
$ bin/python3.7 -m pip uninstall pip
Uninstalling pip-9.0.1:
  /tmp/tmp.mpoe7tpIgR/bin/pip
  /tmp/tmp.mpoe7tpIgR/bin/pip3
  /tmp/tmp.mpoe7tpIgR/bin/pip3.7
  [...]
Proceed (y/n)? n
$ touch bin/pip3.5 bin/pip3.6
$ ls bin/pip*
bin/pip  bin/pip3  bin/pip3.5  bin/pip3.6  bin/pip3.7
$ bin/python3.7 -m pip uninstall pip
Uninstalling pip-9.0.1:
  /tmp/tmp.mpoe7tpIgR/bin/pip
  /tmp/tmp.mpoe7tpIgR/bin/pip3
  /tmp/tmp.mpoe7tpIgR/bin/pip3.6
  /tmp/tmp.mpoe7tpIgR/bin/pip3.7
  [...]
Proceed (y/n)? n
$ bin/python3.7 -m pip download pip
Collecting pip
  Using cached https://files.pythonhosted.org/packages/54/0c/d01aa759fdc501a58f431eb594a17495f15b88da142ce14b5845662c13f3/pip-20.0.2-py2.py3-none-any.whl
  Saved ./pip-20.0.2-py2.py3-none-any.whl
Successfully downloaded pip
$ bin/python3.7 -m zipfile --extract pip-20.0.2-py2.py3-none-any.whl output
$ cat output/pip-20.0.2.dist-info/entry_points.txt 
[console_scripts]
pip = pip._internal.cli.main:main
pip3 = pip._internal.cli.main:main
pip3.8 = pip._internal.cli.main:main
$ bin/python3.7 -m pip install pip-20.0.2-py2.py3-none-any.whl
Processing ./pip-20.0.2-py2.py3-none-any.whl
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 9.0.1
    Uninstalling pip-9.0.1:
      Successfully uninstalled pip-9.0.1
Successfully installed pip-20.0.2
$ ls bin/pip*
bin/pip  bin/pip3  bin/pip3.5  bin/pip3.7

Related issues:

@triage-new-issues triage-new-issues bot added the S: needs triage Issues/PRs that need to be triaged label Apr 9, 2020
@uranusjr
Copy link
Member

uranusjr commented Apr 10, 2020

Your observation is correct. The wheel specification does not allow post-installation hooks, so this is the best pip can do.

pip actually carry special logic in its wheel installation logic, so it will replaces pipX and pipX.Y entry points when used to install itself, which explains the somewhat surprising phenomenom you mentioned.

I’m going to close this since the pip maintainers are aware of the solution, and there really isn’t a way to magically fix this. The best pip can do for this is to remove those entry points entirely (a la #3164), but unfortunately that would make a complete different bunch of people very very angry :-)

@sinoroc
Copy link
Contributor Author

sinoroc commented Apr 10, 2020

Noted.

Still (my initial report is probably too confuse and not clear enough on that aspect), I would like to draw attention on the fact that if indeed there is logic inside pip itself to by-pass the labels for the console scripts at install time there should be a symmetrical one at uninstall time and it doesn't seem to be the case. Or did I somehow miss it?

As for the total removal of pip's console scripts (#3164) it would make me very very happy :)

@uranusjr
Copy link
Member

As forthe total removal of pip's console scripts (#3164) it would make me very very happy :)

Likewise!

pip records what it installs, and the uninstallation simply removes them. So the install-time console-script bypass does not need to be mirrored there; that definition is not consulted at all for uninstallation.

@sinoroc
Copy link
Contributor Author

sinoroc commented Apr 10, 2020

I'm afraid I have to insist, since it doesn't match my experience. Hopefully, I didn't misinterpret your words.

In the following transcript, notice how the manually added bin/pip3.8 file is deleted when pip is uninstalled, although it is not listed in pip's RECORD file:

$ lsb_release -d
Description:	Ubuntu 18.04.4 LTS
$ python3.7 --version
Python 3.7.5
$ python3.7 -m venv .
$ bin/python3.7 -m pip install 'pip==20.0.2'
Collecting pip==20.0.2
  Using cached https://files.pythonhosted.org/packages/54/0c/d01aa759fdc501a58f431eb594a17495f15b88da142ce14b5845662c13f3/pip-20.0.2-py2.py3-none-any.whl
Installing collected packages: pip
  Found existing installation: pip 9.0.1
    Uninstalling pip-9.0.1:
      Successfully uninstalled pip-9.0.1
Successfully installed pip-20.0.2
$ cat lib/python3.7/site-packages/pip-20.0.2.dist-info/entry_points.txt
[console_scripts]
pip = pip._internal.cli.main:main
pip3 = pip._internal.cli.main:main
pip3.8 = pip._internal.cli.main:main
$ cat lib/python3.7/site-packages/pip-20.0.2.dist-info/RECORD | grep 'bin/pip'
../../../bin/pip,sha256=iTk1pTIzZSK3XUIbfuT2o9Bd1JJzKoMTvB9JaSj1a5k,242
../../../bin/pip3,sha256=iTk1pTIzZSK3XUIbfuT2o9Bd1JJzKoMTvB9JaSj1a5k,242
../../../bin/pip3.7,sha256=iTk1pTIzZSK3XUIbfuT2o9Bd1JJzKoMTvB9JaSj1a5k,242
$ ls bin/pip*
bin/pip  bin/pip3  bin/pip3.7
$ touch bin/pip3.6 bin/pip3.8
$ ls bin/pip*
bin/pip  bin/pip3  bin/pip3.6  bin/pip3.7  bin/pip3.8
$ bin/python3.7 -m pip uninstall pip
Found existing installation: pip 20.0.2
Uninstalling pip-20.0.2:
  Would remove:
    /tmp/tmp.rgTTAMfSHc/bin/pip
    /tmp/tmp.rgTTAMfSHc/bin/pip3
    /tmp/tmp.rgTTAMfSHc/bin/pip3.7
    /tmp/tmp.rgTTAMfSHc/bin/pip3.8
    /tmp/tmp.rgTTAMfSHc/lib/python3.7/site-packages/pip-20.0.2.dist-info/*
    /tmp/tmp.rgTTAMfSHc/lib/python3.7/site-packages/pip/*
Proceed (y/n)? y
  Successfully uninstalled pip-20.0.2
$ ls bin/pip*
bin/pip3.6

My assumption is that the file bin/pip3.8 is deleted because it is listed in pip's entry_points.txt file. And indeed, in another test, I removed the pip3.8 line from the entry_points.txt file and the bin/pip3.8 file is left untouched when pip is uninstalled.

@pfmoore
Copy link
Member

pfmoore commented Apr 10, 2020

You are correct - the relevant code seems to be here.

But to be honest, I'm reluctant to add any more complexity to this whole mess. I'd much rather we just removed the console scripts, or at a minimum removed the versioned ones, and bypassed the whole problem. If we can't do that, I think we should just accept the current behaviour is sub-optimal and move on. (I guess we could note somewhere that versioned names pipX.Y are "reserved", and users shouldn't manually create them, but I doubt that's really going to make that much difference).

@sinoroc
Copy link
Contributor Author

sinoroc commented Apr 10, 2020

But to be honest, I'm reluctant to add any more complexity to this whole mess. I'd much rather we just removed the console scripts, or at a minimum removed the versioned ones, and bypassed the whole problem. If we can't do that, I think we should just accept the current behaviour is sub-optimal and move on.

Agreed. It's not obvious that it's worth fixing.

I guess we could note somewhere that versioned names pipX.Y are "reserved", and users shouldn't manually create them, but I doubt that's really going to make that much difference

Just to be clear, from what I understood of the case that prompted this investigation, such files were not created manually, but were the result of installing and upgrading pip globally for multiple versions of the Python interpreter. As always I'll tell them to use the explicit /path/to/pythonX.Y -m pip instead.

@lock lock bot added the auto-locked Outdated issues that have been locked by automation label May 20, 2020
@triage-new-issues triage-new-issues bot removed the S: needs triage Issues/PRs that need to be triaged label May 20, 2020
@lock lock bot locked as resolved and limited conversation to collaborators May 20, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
auto-locked Outdated issues that have been locked by automation
Projects
None yet
Development

No branches or pull requests

3 participants