Repository: pypa/pip

Issue:
AttributeError on tab completion of `pip install -U ...`
**Environment**

* pip version: 18.0
* Python version: 3.7.0
* OS: macOS High Sierra

Using iTerm2 3.1.7 or Terminal.app.

<!-- Feel free to add more information about your environment here -->

**Description**
<!-- A clear and concise description of what the bug is. -->

Attempt `pip install -U projectname` with tab completion.


**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->

Tab completion works, or at least no error.

**How to Reproduce**
<!-- Describe the steps to reproduce this bug. -->

1. Type `pip install -U` or `pip install --upgrade` then a few letters of a project name (eg. just `p` below), then press the tab key.
3. An error occurs:

**Output**

```console
$ pip install --upgrade pTraceback (most recent call last):
  File "/usr/local/bin/pip3", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.7/site-packages/pip/_internal/__init__.py", line 293, in main
    autocomplete()
  File "/usr/local/lib/python3.7/site-packages/pip/_internal/__init__.py", line 121, in autocomplete
    cwords, cword, subcommand.parser.option_list_all,
  File "/usr/local/lib/python3.7/site-packages/pip/_internal/__init__.py", line 170, in get_path_completion_type
    for x in opt.metavar.split('/')):
AttributeError: 'NoneType' object has no attribute 'split'
```

**Notes**

* When omitting `-U` or `--upgrade`, pressing tab doesn't complete anything but more importantly there's no error.

* No error with pip 18.0 on Python 2.7.15. Pressing tab suggests files/directories in current dir (with and without `-U`).


Discussion:
I am getting similar with the following:
```
$ pip freeze --user Traceback (most recent call last):
  File "/opt/local/bin/pip", line 11, in <module>
    load_entry_point('pip==18.0', 'console_scripts', 'pip')()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pip/_internal/__init__.py", line 293, in main
    autocomplete()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pip/_internal/__init__.py", line 121, in autocomplete
    cwords, cword, subcommand.parser.option_list_all,
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pip/_internal/__init__.py", line 170, in get_path_completion_type
    for x in opt.metavar.split('/')):
AttributeError: 'NoneType' object has no attribute 'split'
```
Thanks for filing this @hugovk!

This was a minor oversight; should be a simple fix.

---

This issue is a good starting point for anyone who wants to help out with pip's development -- it's simple and the process of fixing this should be a good introduction to pip's development workflow.

The relavent function here is in the pip._internal.cli.autocomplete. The change would be to handle the case where option.metavar is None and the relevant test case added to test_autocomplete.py or test_completion.py.

Feel free to mention me if someone wants to take this up. :)
Is expected behaviour for autocomplete after `pip3 install`, `pip3 wheel`, `pip3 download` and `pip3 hash` to simply autocomplete optional arguments, and not paths? The tests indicate only optional arguments, but before autocomplete was implemented, paths were included in the autocomplete.

When including paths and options to the autocomplete, autocompleting on `pip3 install` would often produce more than 100 items, which prompts the user if they want to see all 100 items. This is inconvenient

Resolving patch:
diff --git a/src/pip/_internal/cli/autocompletion.py b/src/pip/_internal/cli/autocompletion.py
--- a/src/pip/_internal/cli/autocompletion.py
+++ b/src/pip/_internal/cli/autocompletion.py
@@ -116,7 +116,8 @@ def get_path_completion_type(cwords, cword, opts):
             continue
         for o in str(opt).split('/'):
             if cwords[cword - 2].split('=')[0] == o:
-                if any(x in ('path', 'file', 'dir')
+                if not opt.metavar or any(
+                        x in ('path', 'file', 'dir')
                         for x in opt.metavar.split('/')):
                     return opt.metavar
 


Test patch:
diff --git a/tests/functional/test_completion.py b/tests/functional/test_completion.py
--- a/tests/functional/test_completion.py
+++ b/tests/functional/test_completion.py
@@ -204,6 +204,30 @@ def test_completion_not_files_after_option(script, data):
     )
 
 
+@pytest.mark.parametrize("cl_opts", ["-U", "--user", "-h"])
+def test_completion_not_files_after_nonexpecting_option(script, data, cl_opts):
+    """
+    Test not getting completion files after options which not applicable
+    (e.g. ``pip install``)
+    """
+    res, env = setup_completion(
+        script=script,
+        words=('pip install %s r' % cl_opts),
+        cword='2',
+        cwd=data.completion_paths,
+    )
+    assert not any(out in res.stdout for out in
+                   ('requirements.txt', 'readme.txt',)), (
+        "autocomplete function completed <file> when "
+        "it should not complete"
+    )
+    assert not any(os.path.join(out, '') in res.stdout
+                   for out in ('replay', 'resources')), (
+        "autocomplete function completed <dir> when "
+        "it should not complete"
+    )
+
+
 def test_completion_directories_after_option(script, data):
     """
     Test getting completion <dir> after options in command