From 03118f7ae2f9b1244dfad54548ad4f5f206b6fe0 Mon Sep 17 00:00:00 2001 From: Tom Forbes Date: Tue, 14 Nov 2023 13:36:36 +0000 Subject: [PATCH 1/2] Handle missing COMP_WORDS and COMP_CWORD in completion script --- news/12401.bugfix.rst | 1 + src/pip/_internal/cli/autocompletion.py | 4 ++++ tests/functional/test_completion.py | 29 +++++++++++++++++++++---- 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 news/12401.bugfix.rst diff --git a/news/12401.bugfix.rst b/news/12401.bugfix.rst new file mode 100644 index 000000000..371f80011 --- /dev/null +++ b/news/12401.bugfix.rst @@ -0,0 +1 @@ +Fix exception with completions when COMP_CWORD is not set diff --git a/src/pip/_internal/cli/autocompletion.py b/src/pip/_internal/cli/autocompletion.py index e5950b906..f3f70ac85 100644 --- a/src/pip/_internal/cli/autocompletion.py +++ b/src/pip/_internal/cli/autocompletion.py @@ -17,6 +17,10 @@ def autocomplete() -> None: # Don't complete if user hasn't sourced bash_completion file. if "PIP_AUTO_COMPLETE" not in os.environ: return + # Don't complete if autocompletion environment variables + # are not present + if not os.environ.get("COMP_WORDS") or not os.environ.get("COMP_CWORD"): + return cwords = os.environ["COMP_WORDS"].split()[1:] cword = int(os.environ["COMP_CWORD"]) try: diff --git a/tests/functional/test_completion.py b/tests/functional/test_completion.py index 4be033583..66bb89382 100644 --- a/tests/functional/test_completion.py +++ b/tests/functional/test_completion.py @@ -128,7 +128,11 @@ def autocomplete_script( class DoAutocomplete(Protocol): def __call__( - self, words: str, cword: str, cwd: Union[Path, str, None] = None + self, + words: str, + cword: str, + cwd: Union[Path, str, None] = None, + include_env: bool = True, ) -> Tuple[TestPipResult, PipTestEnvironment]: ... @@ -141,10 +145,14 @@ def autocomplete( autocomplete_script.environ["PIP_AUTO_COMPLETE"] = "1" def do_autocomplete( - words: str, cword: str, cwd: Union[Path, str, None] = None + words: str, + cword: str, + cwd: Union[Path, str, None] = None, + include_env: bool = True, ) -> Tuple[TestPipResult, PipTestEnvironment]: - autocomplete_script.environ["COMP_WORDS"] = words - autocomplete_script.environ["COMP_CWORD"] = cword + if include_env: + autocomplete_script.environ["COMP_WORDS"] = words + autocomplete_script.environ["COMP_CWORD"] = cword result = autocomplete_script.run( "python", "-c", @@ -409,3 +417,16 @@ def test_completion_uses_same_executable_name( expect_stderr=deprecated_python, ) assert executable_name in result.stdout + + +def test_completion_without_env_vars(autocomplete: DoAutocomplete) -> None: + """ + Test getting completion after options in command + given absolute path + """ + res, env = autocomplete( + words="pip install ", + cword="", + include_env=False, + ) + assert res.stdout == "" From 323a64b5d194b079ae570f16f91ec017a40535c0 Mon Sep 17 00:00:00 2001 From: Tom Forbes Date: Tue, 14 Nov 2023 14:57:06 +0000 Subject: [PATCH 2/2] Handle missing COMP_WORDS and COMP_CWORD in completion script --- tests/functional/test_completion.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/tests/functional/test_completion.py b/tests/functional/test_completion.py index 66bb89382..5578b9afd 100644 --- a/tests/functional/test_completion.py +++ b/tests/functional/test_completion.py @@ -14,7 +14,6 @@ else: # dropping support for Python 3.7. Protocol = object - COMPLETION_FOR_SUPPORTED_SHELLS_TESTS = ( ( "bash", @@ -133,6 +132,7 @@ class DoAutocomplete(Protocol): cword: str, cwd: Union[Path, str, None] = None, include_env: bool = True, + expect_error: bool = True, ) -> Tuple[TestPipResult, PipTestEnvironment]: ... @@ -149,6 +149,7 @@ def autocomplete( cword: str, cwd: Union[Path, str, None] = None, include_env: bool = True, + expect_error: bool = True, ) -> Tuple[TestPipResult, PipTestEnvironment]: if include_env: autocomplete_script.environ["COMP_WORDS"] = words @@ -158,7 +159,7 @@ def autocomplete( "-c", "from pip._internal.cli.autocompletion import autocomplete;" "autocomplete()", - expect_error=True, + expect_error=expect_error, cwd=cwd, ) @@ -176,6 +177,17 @@ def test_completion_for_unknown_shell(autocomplete_script: PipTestEnvironment) - assert error_msg in result.stderr, "tests for an unknown shell failed" +def test_completion_without_env_vars(autocomplete: DoAutocomplete) -> None: + """ + Test getting completion after options in command + given absolute path + """ + res, env = autocomplete( + words="pip install ", cword="", include_env=False, expect_error=False + ) + assert res.stdout == "", "autocomplete function did not complete" + + def test_completion_alone(autocomplete_script: PipTestEnvironment) -> None: """ Test getting completion for none shell, just pip completion @@ -417,16 +429,3 @@ def test_completion_uses_same_executable_name( expect_stderr=deprecated_python, ) assert executable_name in result.stdout - - -def test_completion_without_env_vars(autocomplete: DoAutocomplete) -> None: - """ - Test getting completion after options in command - given absolute path - """ - res, env = autocomplete( - words="pip install ", - cword="", - include_env=False, - ) - assert res.stdout == ""