Can argparse.Action reserve an attribute named complete? That is, for any action:
action = parser.add_argument("--dir", default=".")
print(action.complete)
will get None, user can customize it by
action.complete = {"bash": "some string about bash completion", "zsh": "some string about zsh completion"}
or
action = parser.add_argument("--dir", default="." complete={"bash": "XXX", "zsh": "XXX"})
Then let any third-party library to use action.complete
to generate completion script for specific shell.
A library to allow user to convert
a parser to shell completion script, it inject complete
to action by shtab.add_argument_to
.
parser = argparse.ArgumentParser()
shtab.add_argument_to(parser, ["-s", "--print-completion"]) # magic!
# file & directory tab complete
parser.add_argument("--file").complete = shtab.FILE
parser.add_argument("--dir", default=".").complete = shtab.DIRECTORY
However, it must need shtab
. I think perhaps we can
def get_parser()
parser = argparse.ArgumentParser()
parser.add_argument("--file", complete={"zsh": "_files"}, help = "input file")
parser.add_argument("--dir", default=".", complete={"zsh": "_dirs"}, help = "input dir", metavar="INPUT_DIR")
parser.add_argument("--config-file", default="~/.config/foo/config.py", complete={"zsh": "_files -g '*.py'"}, help = "config file")
return parser
Then
from foo.__main__ import get_parser
from a_library import generate_shell_completion
print(generate_shell_completion(get_parser(), shell="zsh"))
Will print
_argument -S -s \
"--dir[input dir]:INPUT_DIR:_dirs" \
"--file[input file]:FILE:_files" \
"--config-file[config file]:CONFIG_FILE:_files -g '*.py'"
which is a legal zsh completion script.
This is the effect:
$ foo --<TAB>
options
--dir input dir
--file input file
--config-file config file
I think parser.add_argument("--file", complete=XXX)
is more convenient than
parser.add_argument("--file").complete=XXX
, and it will not break the
compatibility. (the old code will not use action.complete
). And argparse will
not use action.complete
: it just let any third-party library to use
action.complete
to support different shells. That is, if a package developer
want to their command line program support a new shell, it need:
- the command line program developer use complete attribute to decide what to complete
(such as only complete'*.py'
:_files -g '*.py'
) - The third party library developer develop a package to utilize complete attribute to
support their familiar shells, such aspython -m generate_shell_completion --shell zsh foo.__main__:get_parser > the_file_name
- The packager of linux distributions to generate this shell completion
the_file_name
and move it to correct path such as
/usr/share/zsh/site-functions
or/usr/local/share/zsh/site-functions
The command line program developer can get rid of shtab.add_argument_to
and just use complete attribute.
And moreover, the parser can also provide complete attribute like this:
def get_parser()
parser = argparse.ArgumentParser(complete = {"zsh": "function _complete_py() { _files -g '*.py' }"})
parser.add_argument("--config-file", default="~/.config/foo/config.py", complete={"zsh": "_complete_py"})
parser.add_argument("--source-file", complete={"zsh": "_complete_py"})
return parser
Which allow command line program developer to utilize the same code scratch:
function _complete_py() { _files -g '*.py' }
_argument -S -s \
"--config-file[]:CONFIG_FILE:_complete_py" \
"--source-file[]:SOURCE_FILE:_complete_py"
In conclusion, I hope argparse can reverse an attribute named complete.
This is just my 2C. I think it is better than https://github.com/python/cpython/issues/48506 (which want to argparse support --help-options
).
Thanks to discuss!