Repository: pypa/pip

Issue:
AttributeError: 'NoneType' object has no attribute 'split'
`pip install -r <whatever>` leads to the following error for SOME requirements sets. I cannot tell you which package is the cause, because the installation is rather huge and pip prevents me from debugging by just echoing the error instead of populating the exception to the main method (so no ipython/ipdb).

```
Exception:
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/pip/basecommand.py", line 223, in main
    status = self.run(options, args)
  File "/usr/local/lib/python2.7/site-packages/pip/commands/install.py", line 299, in run
    root=options.root_path,
  File "/usr/local/lib/python2.7/site-packages/pip/req/req_set.py", line 646, in install
    **kwargs
  File "/usr/local/lib/python2.7/site-packages/pip/req/req_install.py", line 813, in install
    self.move_wheel_files(self.source_dir, root=root)
  File "/usr/local/lib/python2.7/site-packages/pip/req/req_install.py", line 1008, in move_wheel_files
    isolated=self.isolated,
  File "/usr/local/lib/python2.7/site-packages/pip/wheel.py", line 479, in move_wheel_files
    maker.make_multiple(['%s = %s' % kv for kv in console.items()])
  File "/usr/local/lib/python2.7/site-packages/pip/_vendor/distlib/scripts.py", line 334, in make_multiple
    filenames.extend(self.make(specification, options))
  File "/usr/local/lib/python2.7/site-packages/pip/_vendor/distlib/scripts.py", line 323, in make
    self._make_script(entry, filenames, options=options)
  File "/usr/local/lib/python2.7/site-packages/pip/_vendor/distlib/scripts.py", line 214, in _make_script
    script = self._get_script_text(entry).encode('utf-8')
  File "/usr/local/lib/python2.7/site-packages/pip/wheel.py", line 396, in _get_script_text
    "import_name": entry.suffix.split(".")[0],
AttributeError: 'NoneType' object has no attribute 'split'
```



Discussion:
Unfortunately, this is not very useful. All we can say is that one of the dependencies has an unusual `console_scripts` entry point declaration.
Could you maybe split your requirement files several times to identify the culprit distribution via dichotomy ?

OK, I'll try that, but it takes some time... Thanks for the `console_scripts` hint.

@xavfernandez The error happens in the following situation:

you have a `setup.py` with the following construction:

```
setup(
...
    entry_points={
        'console_scripts': [
            'mycommand = mypkg.sub.a.b:main'
       ],
...
    },
...
)
```

And the package (`mypkg.sub.a.b`) does not exist. However, the issue is still valid because:
1. The error is misleading and does not help at all.
2. It does not occur on a regular base in case you have an old `setup.pyc` file around (which turned to be the cause in my case). That one is not the fault of pip, but it makes tracking down the issue even harder.

I propose to add an if-check or try-except block at the right place and inform the user that there is something wrong with the `console_script`.

Thanks for taking the time to investigate. But I don't think that's the root cause.

In your case, you seem to have an `entry.suffix` equal to `None`, which would point to an entry point like:
`'mycommand = mypkg.sub.a.b:'` or `'mycommand = mypkg.sub.a.b'` (i.e. without `:something` suffix)

Anyhow, the error message could certainly be improved. A simple raise in https://github.com/pypa/pip/blob/develop/pip/wheel.py#L393-L398 if `entry.suffix is None` could do the trick.


Resolving patch:
diff --git a/pip/wheel.py b/pip/wheel.py
--- a/pip/wheel.py
+++ b/pip/wheel.py
@@ -25,7 +25,8 @@
 
 import pip
 from pip.download import path_to_url, unpack_url
-from pip.exceptions import InvalidWheelFilename, UnsupportedWheel
+from pip.exceptions import (
+    InstallationError, InvalidWheelFilename, UnsupportedWheel)
 from pip.locations import distutils_scheme, PIP_DELETE_MARKER_FILENAME
 from pip import pep425tags
 from pip.utils import (
@@ -390,6 +391,13 @@ def is_entrypoint_wrapper(name):
     # See https://bitbucket.org/pypa/distlib/issue/34/
     # See https://bitbucket.org/pypa/distlib/issue/33/
     def _get_script_text(entry):
+        if entry.suffix is None:
+            raise InstallationError(
+                "Invalid script entry point: %s for req: %s - A callable "
+                "suffix is required. Cf https://packaging.python.org/en/"
+                "latest/distributing.html#console-scripts for more "
+                "information." % (entry, req)
+            )
         return maker.script_template % {
             "module": entry.prefix,
             "import_name": entry.suffix.split(".")[0],


Test patch: