Repository: pypa/pip

Issue:
Struggling with "setuptools must be installed to install from a source distribution"
I create a virtualenv using the latest release (13.0.3), but then I cannot install this package from source using pip: https://pypi.python.org/pypi/kevinarpe-rambutan3/1.7.1

I get the dreaded "setuptools must be installed to install from a source distribution".  I've googled high and low on this issue and I am clueless.  I saw some bug reports in this project, but none of the tips / solutions worked for me.

I tired upgrading setuptools in the virtualenv to latest, but still no luck.  I also tried upgrading pip, but my virtualenv already has the latest.

I am a Python3.4.3 user on Linux.

Any ideas?

Apologies if this issue seems vague.  I am truly baffled.  I can provide more debug info if you need it.



Discussion:
This is related to "import setuptools" from pip/req/req_install.py (~line 334).  I tried manually on the python3 in my virtualenv.  Due to bad linking (my fault) when building my python3 binary, the _ctypes module did not build correctly.  As a result, setuptools cannot be imported.  What a crazy red herring.  Clearly not the fault of pip!

However, is it possible to provide the reason from ImportError in the InstallationError exception raised?  It may be helpful in the future.

A colleague just got bitten by this one and the `setuptools must be installed to install from a source distribution` error message did not help.

The traceback when running `import setuptools` was:

```
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "/home/user/dev/venvs/some_venv/lib/python3.4/site-packages/setuptools/__init__.py", line 12, in <module>
   from setuptools.extension import Extension
 File "/home/user/dev/venvs/some_venv/lib/python3.4/site-packages/setuptools/extension.py", line 8, in <module>
   from .dist import _get_unpatched
 File "/home/user/dev/venvs/some_venv/lib/python3.4/site-packages/setuptools/dist.py", line 18, in <module>
   from setuptools import windows_support
 File "/home/user/dev/venvs/some_venv/lib/python3.4/site-packages/setuptools/windows_support.py", line 2, in <module>
   import ctypes
 File "/usr/lib/python3.4/ctypes/__init__.py", line 7, in <module>
   from _ctypes import Union, Structure, Array
ImportError: /home/user/dev/venvs/some_venv/lib/python3.4/lib-dynload/_ctypes.cpython-34m-x86_64-linux-gnu.so: undefined symbol: _PyTraceback_Add
```

As @kevinarpe suggested, I think we should improve the error message and include the exception.


Resolving patch:
diff --git a/pip/req/req_install.py b/pip/req/req_install.py
--- a/pip/req/req_install.py
+++ b/pip/req/req_install.py
@@ -6,6 +6,7 @@
 import shutil
 import sys
 import tempfile
+import traceback
 import zipfile
 
 from distutils.util import change_root
@@ -343,11 +344,15 @@ def setup_py(self):
         assert self.source_dir, "No source dir for %s" % self
         try:
             import setuptools  # noqa
-        except ImportError:
+        except ImportError as e:
+            if get_installed_version('setuptools') is None:
+                add_msg = "Please install setuptools."
+            else:
+                add_msg = traceback.format_exc(e)
             # Setuptools is not available
             raise InstallationError(
-                "setuptools must be installed to install from a source "
-                "distribution"
+                "Could not import setuptools which is required to "
+                "install from a source distribution.\n%s" % add_msg
             )
 
         setup_file = 'setup.py'


Test patch:
diff --git a/tests/functional/test_install.py b/tests/functional/test_install.py
--- a/tests/functional/test_install.py
+++ b/tests/functional/test_install.py
@@ -26,7 +26,8 @@ def test_without_setuptools(script, data):
         expect_error=True,
     )
     assert (
-        "setuptools must be installed to install from a source distribution"
+        "Could not import setuptools which is required to install from a "
+        "source distribution."
         in result.stderr
     )