Repository: pypa/pip

Issue:
Protect a few more requests imports
In Debian, we unbundle requests, and further, we unbundled all vendored packages from requests.  This causes pip's vendoring algorithm to fail.  I had to add this patch to the Debian packaging.

```
From 144ba146cde273b815a80859537b09c068fd47e6 Mon Sep 17 00:00:00 2001
From: Barry Warsaw <barry@python.org>
Date: Fri, 29 Jan 2016 16:56:43 -0500
Subject: Debian already unbundles things from requests.

Patch-Name: handle-unbundled-requests.patch

---
 pip/_vendor/__init__.py | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/pip/_vendor/__init__.py b/pip/_vendor/__init__.py
index 1cb35a1..c64896a 100644
--- a/pip/_vendor/__init__.py
+++ b/pip/_vendor/__init__.py
@@ -82,8 +82,12 @@ if DEBUNDLED:
     vendored("requests.packages.urllib3.fields")
     vendored("requests.packages.urllib3.filepost")
     vendored("requests.packages.urllib3.packages")
-    vendored("requests.packages.urllib3.packages.ordered_dict")
-    vendored("requests.packages.urllib3.packages.six")
+    try:
+        vendored("requests.packages.urllib3.packages.ordered_dict")
+        vendored("requests.packages.urllib3.packages.six")
+    except ImportError:
+        # Debian already unbundles these from requests.
+        pass
     vendored("requests.packages.urllib3.packages.ssl_match_hostname")
     vendored("requests.packages.urllib3.packages.ssl_match_hostname."
              "_implementation")
```



Discussion:
I think we can actually just ignore all import errors here. The worst case that happens is one of our libraries doesn't get aliased, at which case I think it will fail when something actually tries to do an import somewhere in pip. Failing here probably just makes things more confusing anyways.


Resolving patch:
diff --git a/pip/_vendor/__init__.py b/pip/_vendor/__init__.py
--- a/pip/_vendor/__init__.py
+++ b/pip/_vendor/__init__.py
@@ -32,10 +32,22 @@ def vendored(modulename):
     try:
         __import__(vendored_name, globals(), locals(), level=0)
     except ImportError:
-        __import__(modulename, globals(), locals(), level=0)
-        sys.modules[vendored_name] = sys.modules[modulename]
-        base, head = vendored_name.rsplit(".", 1)
-        setattr(sys.modules[base], head, sys.modules[modulename])
+        try:
+            __import__(modulename, globals(), locals(), level=0)
+        except ImportError:
+            # We can just silently allow import failures to pass here. If we
+            # got to this point it means that ``import pip._vendor.whatever``
+            # failed and so did ``import whatever``. Since we're importing this
+            # upfront in an attempt to alias imports, not erroring here will
+            # just mean we get a regular import error whenever pip *actually*
+            # tries to import one of these modules to use it, which actually
+            # gives us a better error message than we would have otherwise
+            # gotten.
+            pass
+        else:
+            sys.modules[vendored_name] = sys.modules[modulename]
+            base, head = vendored_name.rsplit(".", 1)
+            setattr(sys.modules[base], head, sys.modules[modulename])
 
 
 # If we're operating in a debundled setup, then we want to go ahead and trigger
@@ -70,14 +82,8 @@ def vendored(modulename):
     vendored("requests.packages.urllib3.connection")
     vendored("requests.packages.urllib3.connectionpool")
     vendored("requests.packages.urllib3.contrib")
-    try:
-        vendored("requests.packages.urllib3.contrib.ntlmpool")
-    except ImportError:
-        pass
-    try:
-        vendored("requests.packages.urllib3.contrib.pyopenssl")
-    except ImportError:
-        pass
+    vendored("requests.packages.urllib3.contrib.ntlmpool")
+    vendored("requests.packages.urllib3.contrib.pyopenssl")
     vendored("requests.packages.urllib3.exceptions")
     vendored("requests.packages.urllib3.fields")
     vendored("requests.packages.urllib3.filepost")


Test patch: