Repository: conda/conda

Issue:
conda 4.4 + zsh: conda:shift:1: shift count must be <= $#
With conda 4.4.0rc1 and zsh, calling the new conda shell function with no arguments results in
```
$ conda
conda:shift:1: shift count must be <= $#
usage: conda [-h] [-V] command ...
conda: error: argument command: invalid choice: '' (choose from 'clean', 'config', 'create', 'help', 'info', 'install', 'list', 'package', 'remove', 'uninstall', 'search', 'update', 'upgrade')
```
It's mostly an esthetic point but it would be nice if the shell error message (shift count) was not shown.


Discussion:
Thanks for the report!

Sent from my iPhone

> On Sep 30, 2017, at 12:06 AM, Antony Lee <notifications@github.com> wrote:
> 
> With conda 4.4.0rc1 and zsh, calling the new conda shell function with no arguments results in
> 
> $ conda
> conda:shift:1: shift count must be <= $#
> usage: conda [-h] [-V] command ...
> conda: error: argument command: invalid choice: '' (choose from 'clean', 'config', 'create', 'help', 'info', 'install', 'list', 'package', 'remove', 'uninstall', 'search', 'update', 'upgrade')
> It's mostly an esthetic point but it would be nice if the shell error message (shift count) was not shown.
> 
> —
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly, view it on GitHub, or mute the thread.
> 

Some related issues:
1. `conda nonexistentcommand` exits with status 1 but does not print any error message.
2. The changelog recommends putting conda.sh in a profile folder but this usually won't work if the user's terminals are not login shells (as is the default on Linux): nonlogin shells do not read the profile folder and do not inherit *functions* (even though the *environment* is inherited.  I just sourced conda.sh in my .zshrc (rather than my .zprofile).

Resolving patch:
diff --git a/conda/cli/conda_argparse.py b/conda/cli/conda_argparse.py
--- a/conda/cli/conda_argparse.py
+++ b/conda/cli/conda_argparse.py
@@ -112,7 +112,6 @@ def _get_action_from_name(self, name):
     def error(self, message):
         import re
         from .find_commands import find_executable
-
         exc = sys.exc_info()[1]
         if exc:
             # this is incredibly lame, but argparse stupidly does not expose
@@ -122,23 +121,27 @@ def error(self, message):
             else:
                 argument = None
             if argument and argument.dest == "cmd":
-                m = re.match(r"invalid choice: u?'(\w+)'", exc.message)
+                m = re.match(r"invalid choice: u?'(\w*?)'", exc.message)
                 if m:
                     cmd = m.group(1)
-                    executable = find_executable('conda-' + cmd)
-                    if not executable:
-                        from ..exceptions import CommandNotFoundError
-                        raise CommandNotFoundError(cmd)
-                    args = [find_executable('conda-' + cmd)]
-                    args.extend(sys.argv[2:])
-                    os.execv(args[0], args)
+                    if not cmd:
+                        self.print_help()
+                        sys.exit(0)
+                    else:
+                        executable = find_executable('conda-' + cmd)
+                        if not executable:
+                            from ..exceptions import CommandNotFoundError
+                            raise CommandNotFoundError(cmd)
+                        args = [find_executable('conda-' + cmd)]
+                        args.extend(sys.argv[2:])
+                        os.execv(args[0], args)
 
         super(ArgumentParser, self).error(message)
 
     def print_help(self):
         super(ArgumentParser, self).print_help()
 
-        if sys.argv[1:] in ([], ['help'], ['-h'], ['--help']):
+        if sys.argv[1:] in ([], [''], ['help'], ['-h'], ['--help']):
             from .find_commands import find_commands
             other_commands = find_commands()
             if other_commands:
diff --git a/conda/exceptions.py b/conda/exceptions.py
--- a/conda/exceptions.py
+++ b/conda/exceptions.py
@@ -200,7 +200,7 @@ def __init__(self, command):
         else:
             from difflib import get_close_matches
             from .cli.find_commands import find_commands
-            message = "Error: No command 'conda %(command)s'."
+            message = "No command 'conda %(command)s'."
             choices = conda_commands | build_commands | set(find_commands())
             close = get_close_matches(command, choices)
             if close:


Test patch:
diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py
--- a/tests/test_exceptions.py
+++ b/tests/test_exceptions.py
@@ -338,7 +338,7 @@ def test_CommandNotFoundError_simple(self):
                 conda_exception_handler(_raise_helper, exc)
 
         assert not c.stdout
-        assert c.stderr.strip() == ("CommandNotFoundError: Error: No command 'conda instate'.\n"
+        assert c.stderr.strip() == ("CommandNotFoundError: No command 'conda instate'.\n"
                                     "Did you mean 'conda install'?")
 
     def test_CommandNotFoundError_conda_build(self):