Repository: pallets/click
Pull request #1683 (2020-10-07 13:43:33)

swap order of completion instruction
The order was previously `source_{shell}` and `complete_{shell}` because support for other shells was added later. In the new system the shell is always required, there is no longer the assumption of Bash if none is given. Since we've rewritten the system and all existing completion instructions and scripts are invalid anyway, take the opportunity to move the shell first. The order is now `{shell}_source` and `{shell}_complete`.

One potential argument for the old order is that it could be used for autodetection. If the shell was left off the end, detect the shell. However, autodetection isn't particularly useful since the scripts and activation instruction differ between shells anyway. If we do want that later, being explicit with `auto_source` is fine too.

related to #1484 

Checklist:

- [x] Add tests that demonstrate the correct behavior of the change. Tests should fail without the change.
- [x] Add or update relevant docs, in the docs folder and in code.
- [x] Add an entry in `CHANGES.rst` summarizing the change and linking to the issue.
- [x] Add `.. versionchanged::` entries in any relevant code docs.
- [x] Run `pre-commit` hooks and fix any issues.
- [x] Run `pytest` and `tox`, no tests failed.



Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index f7dd405..7429e5e 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -103,6 +103,9 @@ Unreleased
         all values, and must return a list of strings or a list of
         ``ShellComplete``. The old name and behavior is deprecated and
         will be removed in 8.1.
+    -   The env var values used to start completion have changed order.
+        The shell now comes first, such as ``{shell}_source`` rather
+        than ``source_{shell}``, and is always required.
 
 -   Extra context settings (``obj=...``, etc.) are passed on to the
     completion system. :issue:`942`
diff --git a/docs/shell-completion.rst b/docs/shell-completion.rst
index f2c1bb4..699d25d 100644
--- a/docs/shell-completion.rst
+++ b/docs/shell-completion.rst
@@ -31,7 +31,7 @@ a special environment variable will put Click in completion mode.
 In order for completion to be used, the user needs to register a special
 function with their shell. The script is different for every shell, and
 Click will output it when called with ``_{PROG_NAME}_COMPLETE`` set to
-``source_{shell}``. ``{PROG_NAME}`` is the executable name in uppercase
+``{shell}_source``. ``{PROG_NAME}`` is the executable name in uppercase
 with dashes replaced by underscores. The built-in shells are ``bash``,
 ``zsh``, and ``fish``.
 
@@ -46,7 +46,7 @@ program name. This uses ``foo-bar`` as an example.
 
         .. code-block:: bash
 
-            eval "$(_FOO_BAR_COMPLETE=source_bash foo-bar)"
+            eval "$(_FOO_BAR_COMPLETE=bash_source foo-bar)"
 
     .. group-tab:: Zsh
 
@@ -54,7 +54,7 @@ program name. This uses ``foo-bar`` as an example.
 
         .. code-block:: zsh
 
-            eval "$(_FOO_BAR_COMPLETE=source_zsh foo-bar)"
+            eval "$(_FOO_BAR_COMPLETE=zsh_source foo-bar)"
 
     .. group-tab:: Fish
 
@@ -62,7 +62,7 @@ program name. This uses ``foo-bar`` as an example.
 
         .. code-block:: fish
 
-            eval (env _FOO_BAR_COMPLETE=source_fish foo-bar)
+            eval (env _FOO_BAR_COMPLETE=fish_source foo-bar)
 
         This is the same file used for the activation script method
         below. For Fish it's probably always easier to use that method.
@@ -81,7 +81,7 @@ to save your users a step.
 
         .. code-block:: bash
 
-            _FOO_BAR_COMPLETE=source_bash foo-bar > ~/.foo-bar-complete.bash
+            _FOO_BAR_COMPLETE=bash_source foo-bar > ~/.foo-bar-complete.bash
 
         Source the file in ``~/.bashrc``.
 
@@ -95,7 +95,7 @@ to save your users a step.
 
         .. code-block:: bash
 
-            _FOO_BAR_COMPLETE=source_zsh foo-bar > ~/.foo-bar-complete.zsh
+            _FOO_BAR_COMPLETE=zsh_source foo-bar > ~/.foo-bar-complete.zsh
 
         Source the file in ``~/.zshrc``.
 
@@ -109,7 +109,7 @@ to save your users a step.
 
         .. code-block:: fish
 
-            _FOO_BAR_COMPLETE=source_fish foo-bar > ~/.config/fish/completions/foo-bar.fish
+            _FOO_BAR_COMPLETE=fish_source foo-bar > ~/.config/fish/completions/foo-bar.fish
 
 After modifying the shell config, you need to start a new shell in order
 for the changes to be loaded.
@@ -193,7 +193,7 @@ require implementing some smaller parts.
 First, you'll need to figure out how your shell's completion system
 works and write a script to integrate it with Click. It must invoke your
 program with the environment variable ``_{PROG_NAME}_COMPLETE`` set to
-``complete_{shell}`` and pass the complete args and incomplete value.
+``{shell}_complete`` and pass the complete args and incomplete value.
 How it passes those values, and the format of the completion response
 from Click is up to you.
 
@@ -204,7 +204,7 @@ formatting with the following variables:
 -   ``complete_func`` - A safe name for the completion function defined
     in the script.
 -   ``complete_var`` - The environment variable name for passing the
-    ``complete_{shell}`` value.
+    ``{shell}_complete`` instruction.
 -   ``prog_name`` - The name of the executable being completed.
 
 The example code is for a made up shell "My Shell" or "mysh" for short.
@@ -216,7 +216,7 @@ The example code is for a made up shell "My Shell" or "mysh" for short.
 
     _mysh_source = """\
     %(complete_func)s {
-        response=$(%(complete_var)s=complete_mysh %(prog_name)s)
+        response=$(%(complete_var)s=mysh_complete %(prog_name)s)
         # parse response and set completions somehow
     }
     call-on-complete %(prog_name)s %(complete_func)s
@@ -252,12 +252,12 @@ method must return a ``(args, incomplete)`` tuple.
             return args, ""
 
 Finally, implement :meth:`~ShellComplete.format_completion`. This is
-called to format each ``(type, value, help)`` tuples returned by Click
-into a string. For example, the Bash implementation returns
-``f"{type},{value}`` (it doesn't support help strings), and the Zsh
-implementation returns each part separated by a newline, replacing empty
-help with a ``_`` placeholder. This format is entirely up to what you
-parse with your completion script.
+called to format each :class:`CompletionItem` into a string. For
+example, the Bash implementation returns ``f"{item.type},{item.value}``
+(it doesn't support help strings), and the Zsh implementation returns
+each part separated by a newline, replacing empty help with a ``_``
+placeholder. This format is entirely up to what you parse with your
+completion script.
 
 The ``type`` value is usually ``plain``, but it can be another value
 that the completion script can switch on. For example, ``file`` or
@@ -266,15 +266,11 @@ better at that than Click.
 
 .. code-block:: python
 
-    import os
-    from click.parser import split_arg_string
-
     class MyshComplete(ShellComplete):
         ...
 
         def format_completion(self, item):
-            type, value, _ = item
-            return f"{type}\t{value}"
+            return f"{item.type}\t{item.value}"
 
 With those three things implemented, the new shell support is ready. In
 case those weren't sufficient, there are more parts that can be
@@ -286,4 +282,4 @@ the shell somehow.
 
 .. code-block:: text
 
-    _FOO_BAR_COMPLETE=source_mysh foo-bar
+    _FOO_BAR_COMPLETE=mysh_source foo-bar
diff --git a/src/click/shell_completion.py b/src/click/shell_completion.py
index c9664ad..efefba1 100644
--- a/src/click/shell_completion.py
+++ b/src/click/shell_completion.py
@@ -21,7 +21,7 @@ def shell_complete(cli, ctx_args, prog_name, complete_var, instruction):
         instruction and shell, in the form ``instruction_shell``.
     :return: Status code to exit with.
     """
-    instruction, _, shell = instruction.partition("_")
+    shell, _, instruction = instruction.partition("_")
     comp_cls = get_completion_class(shell)
 
     if comp_cls is None:
@@ -78,7 +78,7 @@ _SOURCE_BASH = """\
     local response
 
     response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \
-%(complete_var)s=complete_bash $1)
+%(complete_var)s=bash_complete $1)
 
     for completion in $response; do
         IFS=',' read type value <<< "$completion"
@@ -114,7 +114,7 @@ _SOURCE_ZSH = """\
     (( ! $+commands[%(prog_name)s] )) && return 1
 
     response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \
-%(complete_var)s=complete_zsh %(prog_name)s)}")
+%(complete_var)s=zsh_complete %(prog_name)s)}")
 
     for type key descr in ${response}; do
         if [[ "$type" == "plain" ]]; then
@@ -146,7 +146,7 @@ _SOURCE_FISH = """\
 function %(complete_func)s;
     set -l response;
 
-    for value in (env %(complete_var)s=complete_fish COMP_WORDS=(commandline -cp) \
+    for value in (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \
 COMP_CWORD=(commandline -t) %(prog_name)s);
         set response $response $value;
     end;
@@ -184,8 +184,8 @@ class ShellComplete:
 
     name = None
     """Name to register the shell as with :func:`add_completion_class`.
-    This is used in completion instructions (``source_{name}`` and
-    ``complete_{name}``).
+    This is used in completion instructions (``{name}_source`` and
+    ``{name}_complete``).
     """
     source_template = None
     """Completion script template formatted by :meth:`source`. This must


Test patch:
diff --git a/tests/test_shell_completion.py b/tests/test_shell_completion.py
index 39c0161..5c169a9 100644
--- a/tests/test_shell_completion.py
+++ b/tests/test_shell_completion.py
@@ -254,8 +254,8 @@ def _patch_for_completion(monkeypatch):
 @pytest.mark.usefixtures("_patch_for_completion")
 def test_full_source(runner, shell):
     cli = Group("cli", commands=[Command("a"), Command("b")])
-    result = runner.invoke(cli, env={"_CLI_COMPLETE": f"source_{shell}"})
-    assert f"_CLI_COMPLETE=complete_{shell}" in result.output
+    result = runner.invoke(cli, env={"_CLI_COMPLETE": f"{shell}_source"})
+    assert f"_CLI_COMPLETE={shell}_complete" in result.output
 
 
 @pytest.mark.parametrize(
@@ -272,7 +272,7 @@ def test_full_source(runner, shell):
 @pytest.mark.usefixtures("_patch_for_completion")
 def test_full_complete(runner, shell, env, expect):
     cli = Group("cli", commands=[Command("a"), Command("b", help="bee")])
-    env["_CLI_COMPLETE"] = f"complete_{shell}"
+    env["_CLI_COMPLETE"] = f"{shell}_complete"
     result = runner.invoke(cli, env=env)
     assert result.output == expect
 
@@ -286,6 +286,6 @@ def test_context_settings(runner):
     result = runner.invoke(
         cli,
         obj={"choices": ["a", "b"]},
-        env={"COMP_WORDS": "", "COMP_CWORD": "0", "_CLI_COMPLETE": "complete_bash"},
+        env={"COMP_WORDS": "", "COMP_CWORD": "0", "_CLI_COMPLETE": "bash_complete"},
     )
     assert result.output == "plain,a\nplain,b\n"