From 864054ee6d6b2a13472a865678f21bc1d63272ac Mon Sep 17 00:00:00 2001
From: Philipp Hahn
Date: Fri, 10 Oct 2025 17:58:10 +0200
Subject: [PATCH 1/4] test: Compare exc.type with `is`
E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
Signed-off-by: Philipp Hahn
---
tests/test_shtab.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/test_shtab.py b/tests/test_shtab.py
index d730151..8e9161d 100644
--- a/tests/test_shtab.py
+++ b/tests/test_shtab.py
@@ -315,7 +315,7 @@ def test_add_argument_to_positional(shell, caplog, capsys):
completion_manual = shtab.complete(parser, shell=shell)
with pytest.raises(SystemExit) as exc:
sub._actions[-1](sub, Namespace(), shell)
- assert exc.type == SystemExit
+ assert exc.type is SystemExit
assert exc.value.code == 0
completion, err = capsys.readouterr()
print(completion)
From 827b6fa7a1a3153d4463368dcf572a3893126cfc Mon Sep 17 00:00:00 2001
From: Philipp Hahn
Date: Fri, 10 Oct 2025 13:53:26 +0200
Subject: [PATCH 2/4] main() does not return a value
> shtab/__main__.py:8: error: "main" does not return a value (it only ever returns None)
Signed-off-by: Philipp Hahn
---
shtab/__main__.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/shtab/__main__.py b/shtab/__main__.py
index 22c6f14..1018735 100644
--- a/shtab/__main__.py
+++ b/shtab/__main__.py
@@ -1,8 +1,7 @@
import logging
-import sys
from .main import main
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
- sys.exit(main(sys.argv[1:]) or 0)
+ main()
From 9b2a478acdfc3a0d858051c2ad342ee8440bdbbb Mon Sep 17 00:00:00 2001
From: Philipp Hahn
Date: Fri, 10 Oct 2025 13:33:47 +0200
Subject: [PATCH 3/4] Fix Action == SUPPRESS
ArgumentParser._get_optional_actions() will always return instances of
`Action` and never `SUPPRESS`, which is a `str`.
Signed-off-by: Philipp Hahn
---
shtab/__init__.py | 3 ---
1 file changed, 3 deletions(-)
diff --git a/shtab/__init__.py b/shtab/__init__.py
index e29a2e9..9b01041 100644
--- a/shtab/__init__.py
+++ b/shtab/__init__.py
@@ -245,9 +245,6 @@ def recurse(parser, prefix):
options_strings_str = "' '".join(get_option_strings(parser))
option_strings.append(f"{prefix}_option_strings=('{options_strings_str}')")
for optional in parser._get_optional_actions():
- if optional == SUPPRESS:
- continue
-
for option_string in optional.option_strings:
if hasattr(optional, "complete"):
# shtab `.complete = ...` functions
From d5b1fa3fe87dddb23854769b1f4e66e200d01a6a Mon Sep 17 00:00:00 2001
From: Philipp Hahn
Date: Fri, 10 Oct 2025 15:22:39 +0200
Subject: [PATCH 4/4] bash: Fix detection of redirection
Also handle input redirection.
Also handle other file descriptors than STDOUT and STDERR.
Signed-off-by: Philipp Hahn
---
shtab/__init__.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/shtab/__init__.py b/shtab/__init__.py
index 9b01041..683172f 100644
--- a/shtab/__init__.py
+++ b/shtab/__init__.py
@@ -437,8 +437,7 @@ def complete_bash(parser, root_prefix=None, preamble="", choice_functions=None):
if [[ $pos_only = 0 && "${completing_word}" == -* ]]; then
# optional argument started: use option strings
COMPREPLY=( $(compgen -W "${current_option_strings[*]}" -- "${completing_word}") )
- elif [[ "${previous_word}" == ">" || "${previous_word}" == ">>" ||
- "${previous_word}" =~ ^[12]">" || "${previous_word}" =~ ^[12]">>" ]]; then
+ elif [[ "${previous_word}" =~ ^[0-9\\&]*[\\<\\>]\\>?$ ]]; then
# handle redirection operators
COMPREPLY=( $(compgen -f -- "${completing_word}") )
else