Repository: pypa/pip

Issue:
Installing pip for Python 3 may overwrite Python 2 scripts
pip installs the unversioned scripts for pip and easy_install unconditionally, even when running in a global Python 3 install on a *nix system with a shared binary directory.

This issue currently affects the ensurepip bundling with CPython: http://bugs.python.org/issue19406

At the very least, we need pip to support an "--altinstall" equivalent that only installs the fully qualified versioned scripts.

It would also be useful to be able to install just pip3 and pip3.4 without installing the unqualified version (we would probably configure ensurepip to do that by default when outside virtual environments on *nix systems).



Discussion:
So the versioned commands are a hack right now that we added until metadata 2.0 has proper support for them. Due to their hackish nature we're loathe to add a "proper" support for them until metadata 2.0 has and figuring out how to handle that case in the general case with flags or what not.

So what i'd like to do, thinking about it. Is a hidden flag or environment variable that `ensurepip` could use to say which scripts it wants installed. This would be undocumented and exist soley for ensurepip. Then when metadata 2.0 gets proper support for this feature we can expose real flags after some discussion about _how_ to do that.

Does that sound reasonable?

Agreed, let's not try to solve this issue "properly" without metadata support.

Is there a list of issues that need to be considered for the entry point / script wrapper support in metadata 2.0? This issue should be captured on that so that it doesn't get forgotten when we do have that debate.

Sounds good - metadata issues can be reported against the PyPA metadata
project on BitBucket.


Resolving patch:
diff --git a/pip/wheel.py b/pip/wheel.py
--- a/pip/wheel.py
+++ b/pip/wheel.py
@@ -272,12 +272,30 @@ def _get_script_text(entry):
     # override the versioned entry points in the wheel and generate the
     # correct ones. This code is purely a short-term measure until Metadat 2.0
     # is available.
+    #
+    # To add the level of hack in this section of code, in order to support
+    # ensurepip this code will look for an ``ENSUREPIP_OPTIONS`` environment
+    # variable which will control which version scripts get installed.
+    #
+    # ENSUREPIP_OPTIONS=altinstall
+    #   - Only pipX.Y and easy_install-X.Y will be generated and installed
+    # ENSUREPIP_OPTIONS=install
+    #   - pipX.Y, pipX, easy_install-X.Y will be generated and installed. Note
+    #     that this option is technically if ENSUREPIP_OPTIONS is set and is
+    #     not altinstall
+    # DEFAULT
+    #   - The default behavior is to install pip, pipX, pipX.Y, easy_install
+    #     and easy_install-X.Y.
     pip_script = console.pop('pip', None)
     if pip_script:
-        spec = 'pip = ' + pip_script
-        generated.extend(maker.make(spec))
-        spec = 'pip%s = %s' % (sys.version[:1], pip_script)
-        generated.extend(maker.make(spec))
+        if "ENSUREPIP_OPTIONS" not in os.environ:
+            spec = 'pip = ' + pip_script
+            generated.extend(maker.make(spec))
+
+        if os.environ.get("ENSUREPIP_OPTIONS", "") != "altinstall":
+            spec = 'pip%s = %s' % (sys.version[:1], pip_script)
+            generated.extend(maker.make(spec))
+
         spec = 'pip%s = %s' % (sys.version[:3], pip_script)
         generated.extend(maker.make(spec))
         # Delete any other versioned pip entry points
@@ -286,8 +304,10 @@ def _get_script_text(entry):
             del console[k]
     easy_install_script = console.pop('easy_install', None)
     if easy_install_script:
-        spec = 'easy_install = ' + easy_install_script
-        generated.extend(maker.make(spec))
+        if "ENSUREPIP_OPTIONS" not in os.environ:
+            spec = 'easy_install = ' + easy_install_script
+            generated.extend(maker.make(spec))
+
         spec = 'easy_install-%s = %s' % (sys.version[:3], easy_install_script)
         generated.extend(maker.make(spec))
         # Delete any other versioned easy_install entry points


Test patch: