Repository: xonsh/xonsh

Issue:
for abs_name, from_where in matches: TypeError: cannot unpack non-iterable NoneType object
After updating to v16.0.0, some command completions produce an exception to break the shell.


### Traceback (if applicable)

```
Traceback (most recent call last):
  File "/Users/user/Library/Application Support/pipx/venvs/xonsh/lib/python3.11/site-packages/xonsh/procs/proxies.py", line 523, in run
    r = self.f(self.args, sp_stdin, sp_stdout, sp_stderr, spec, spec.stack)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/user/Library/Application Support/pipx/venvs/xonsh/lib/python3.11/site-packages/xonsh/procs/proxies.py", line 319, in proxy_five
    return f(args, stdin, stdout, stderr, spec)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/user/Library/Application Support/pipx/venvs/xonsh/lib/python3.11/site-packages/xonsh/xoreutils/which.py", line 165, in which
    for abs_name, from_where in matches:
        ^^^^^^^^^^^^^^^^^^^^
TypeError: cannot unpack non-iterable NoneType object
```

## Steps to Reproduce

- Define the following alias:

```python
def _plshow(filename: str, uncolored=False):
    """
    display a plist file

    Parameters
    ----------
    uncolored : -u, --uncolored
        remove colors
    """
    with open(filename, 'rb') as f:
        return _pretty_json(plistlib.load(f), colored=(not uncolored))

aliases['plshow'] = ArgParserAlias(prog='plshow', has_args=True, func=_plshow)
```

- From shell, type `plshow <TAB><TAB>`

## For community
⬇️  **Please click the 👍 reaction instead of leaving a `+1` or 👍  comment**



Discussion:
The issue seems to be with the code from `which.py` . I am not able to recreate the issue with following code 

```py
# plshow.py
from xonsh.cli_utils import ArgParserAlias
from xonsh.built_ins import XSH

def _plshow(filename: str, uncolored=False):
    """
    display a plist file

    Parameters
    ----------
    uncolored : -u, --uncolored
        remove colors
    """
    with open(filename, 'rb') as f:
        print("called")
        # return _pretty_json(plistlib.load(f), colored=(not uncolored))

XSH.aliases['plshow'] = ArgParserAlias(prog='plshow', has_args=True, func=_plshow)
```
and sourcing it to bring it to the scope. The completions work fine. It would be good if you can post the rest of the code enough to recreate the issue.
I'm sorry, but I don't know what is the root cause. Probably not something specific to this alias. Almost all completions completely break my shell. I reverted to v0.15.1 and this error stopped. 
You can debug this issue with this `completer` command and by turning on `` and ``

```
$XONSH_DEBUG=1
$XONSH_TRACE_COMPLETIONS=1
completer complete 'plshow '
```
```
user@users-MacBook-Pro ~/.pymobiledevice3 @ $XONSH_SHOW_TRACEBACK = True
                                            $XONSH_DEBUG=1
                                            $XONSH_TRACE_COMPLETIONS=1
                                            completer complete 'plshow '


<stdin>:4:10 - completer complete 'plshow '
<stdin>:4:10 + ![completer complete 'plshow ']
CompletionContext(command=CommandContext(args=(CommandArg(value='plshow', opening_quote='', closing_quote='', is_io_redir=False),), arg_index=1, prefix='', suffix='', opening_quote='', closing_quote='', is_after_closing_quote=False, subcmd_opening=''), python=PythonContext('plshow ', 7, is_sub_expression=False))

TRACE COMPLETIONS: Getting completions with context:
xonsh: To log full traceback to a file set: $XONSH_TRACEBACK_LOGFILE = <filename>
Traceback (most recent call last):
  File "/Users/user/Library/Application Support/pipx/venvs/xonsh/lib/python3.11/site-packages/xonsh/procs/proxies.py", line 523, in run
    r = self.f(self.args, sp_stdin, sp_stdout, sp_stderr, spec, spec.stack)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/user/Library/Application Support/pipx/venvs/xonsh/lib/python3.11/site-packages/xonsh/procs/proxies.py", line 319, in proxy_five
    return f(args, stdin, stdout, stderr, spec)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/user/Library/Application Support/pipx/venvs/xonsh/lib/python3.11/site-packages/xonsh/xoreutils/which.py", line 165, in which
    for abs_name, from_where in matches:
        ^^^^^^^^^^^^^^^^^^^^
TypeError: cannot unpack non-iterable NoneType object

[(RichCompletion('remote_D4B520FA-6DFF-4E6A-9DC3-C5F10784552B.plist ', prefix_len=0, append_closing_quote=False),
  0),
 (RichCompletion('00008120-000114DC219B401E.plist ', prefix_len=0, append_closing_quote=False),
  0),
 (RichCompletion('remote_00008020-001574E01E81002E.plist ', prefix_len=0, append_closing_quote=False),
  0),
 (RichCompletion('00008020-001574E01E81002E.plist ', prefix_len=0, append_closing_quote=False),
  0)]
TRACE COMPLETIONS: Got 4 results from exclusive completer 'path':
Prefix Length: 0
RichCompletion('00008020-001574E01E81002E.plist ', prefix_len=0, append_closing_quote=False)
RichCompletion('00008120-000114DC219B401E.plist ', prefix_len=0, append_closing_quote=False)
RichCompletion('remote_00008020-001574E01E81002E.plist ', prefix_len=0, append_closing_quote=False)
RichCompletion('remote_D4B520FA-6DFF-4E6A-9DC3-C5F10784552B.plist ', prefix_len=0, append_closing_quote=False)
user@users-MacBook-Pro ~/.pymobiledevice3 @
```
I have the same issue with any command completion

```
 » $XONSH_DEBUG=1                                                                                                                                                                       ~
 » $XONSH_TRACE_COMPLETIONS=1                                                                                                                                                           ~
 » fc-cache -frv                                                                                                                                                                        ~
TRACE COMPLETIONS: Getting completions with context:
Traceback (Most recent call last):
523 /gnu/store/5xkaq8w25y6mmb0c3ss0qwp74y39q4yp-xonsh-next-0.16.0/lib/python3.10/site-packages/xonsh/procs/proxies.py run --> r = self.f(self.args, sp_stdin, sp_stdout, sp_stderr, spec, spec.stack)
319 /gnu/store/5xkaq8w25y6mmb0c3ss0qwp74y39q4yp-xonsh-next-0.16.0/lib/python3.10/site-packages/xonsh/procs/proxies.py proxy_five --> return f(args, stdin, stdout, stderr, spec)
165 /gnu/store/5xkaq8w25y6mmb0c3ss0qwp74y39q4yp-xonsh-next-0.16.0/lib/python3.10/site-packages/xonsh/xoreutils/which.py which --> for abs_name, from_where in matches:
TypeError: cannot unpack non-iterable NoneType object
TRACE COMPLETIONS: Got 77 results from exclusive completer 'base':
CompletionContext(command=CommandContext(args=(), arg_index=0, prefix='f', suffix='', opening_quote='', closing_quote='', is_after_closing_quote=False, subcmd_opening=''), python=PythonContext('f', 1, is_sub_expression=False))
[(RichCompletion('for ', prefix_len=1, append_space=True), 1),
 (RichCompletion('float', prefix_len=1), 1),
 (RichCompletion('frozenset', prefix_len=1), 1),
 (RichCompletion('finally:', prefix_len=1), 1),
 (RichCompletion('format', prefix_len=1), 1),
 (RichCompletion('from ', prefix_len=1, append_space=True), 1),
 (RichCompletion('filter', prefix_len=1), 1),
 (RichCompletion('fr.handbrake.ghb ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fdisk ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fstrim ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fsck.ext3 ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fsfreeze ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fsck.msdos ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fsck.minix ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fsck.ext2 ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fsck.vfat ', prefix_len=1, append_space=True), 1),
 (RichCompletion('findfs ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fsck.ext4 ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fsck ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fsck.xfs ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fatlabel ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fsck.cramfs ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fsck.fat ', prefix_len=1, append_space=True), 1),
 (RichCompletion('filefrag ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fmt ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fgconsole ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fuser ', prefix_len=1, append_space=True), 1),
 (RichCompletion('false ', prefix_len=1, append_space=True), 1),
 (RichCompletion('findmnt ', prefix_len=1, append_space=True), 1),
 (RichCompletion('flock ', prefix_len=1, append_space=True), 1),
 (RichCompletion('factor ', prefix_len=1, append_space=True), 1),
 (RichCompletion('find ', prefix_len=1, append_space=True), 1),
 (RichCompletion('free ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fgrep ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fincore ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fallocate ', prefix_len=1, append_space=True), 1),
 (RichCompletion('faillog ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fold ', prefix_len=1, append_space=True), 1),
 (RichCompletion('ftp ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fusermount ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fusermount3 ', prefix_len=1, append_space=True), 1),
 (RichCompletion('f2py3.8 ', prefix_len=1, append_space=True), 1),
 (RichCompletion('f2py3 ', prefix_len=1, append_space=True), 1),
 (RichCompletion('f2py ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fc-cache ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fc-scan ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fzf ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fc-pattern ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fc-cat ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fc-query ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fontforge ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fc-validate ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fax2tiff ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fribidi ', prefix_len=1, append_space=True), 1),
 (RichCompletion('flameshot ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fc-match ', prefix_len=1, append_space=True), 1),
 (RichCompletion('freetype-config ', prefix_len=1, append_space=True), 1),
 (RichCompletion('file ', prefix_len=1, append_space=True), 1),
 (RichCompletion('feh ', prefix_len=1, append_space=True), 1),
 (RichCompletion('flake8 ', prefix_len=1, append_space=True), 1),
 (RichCompletion('flatpak-bisect ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fd ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fastboot ', prefix_len=1, append_space=True), 1),
 (RichCompletion('flatpak ', prefix_len=1, append_space=True), 1),
 (RichCompletion('firefox ', prefix_len=1, append_space=True), 1),
 (RichCompletion('flatpak-coredumpctl ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fontimage ', prefix_len=1, append_space=True), 1),
 (RichCompletion('ffmpeg ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fc-conflist ', prefix_len=1, append_space=True), 1),
 (RichCompletion('ffprobe ', prefix_len=1, append_space=True), 1),
 (RichCompletion('funzip ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fax2ps ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fc-list ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fontlint ', prefix_len=1, append_space=True), 1),
 (RichCompletion('ffplay ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fancontrol ', prefix_len=1, append_space=True), 1),
 (RichCompletion('fg ', prefix_len=1, append_space=True), 1)]
```
this is strange. It should not try to execute any other aliases. 
1. What is the value of `aliases` ? 
2. inside the which file, could you print the full traceback to debug?
At this point I wonder if the better solution is to just validate if `matches is None`, instead of understanding the root cause, since this bug makes the latest xonsh version practically unusable. On every workstation I manually use:

```shell
pipx install 'xonsh[full]<0.16.0'
```
A PR is welcome with the None check until we figure out the root cause. 

Resolving patch:
diff --git a/xonsh/xoreutils/which.py b/xonsh/xoreutils/which.py
--- a/xonsh/xoreutils/which.py
+++ b/xonsh/xoreutils/which.py
@@ -162,7 +162,10 @@ def which(args, stdin=None, stdout=None, stderr=None, spec=None):
         original_os_path = xp.os_environ["PATH"]
         xp.os_environ["PATH"] = XSH.env.detype()["PATH"]
         matches = _which.whichgen(arg, exts=exts, verbose=verbose)
-        for abs_name, from_where in matches:
+        for match in matches:
+            if match is None:
+                continue
+            abs_name, from_where = match
             print_path(abs_name, from_where, stdout, verbose, captured)
             nmatches += 1
             if not pargs.all:


Test patch: