click-contrib / click-completion Goto Github PK
View Code? Open in Web Editor NEWAdd or enhance bash, fish, zsh and powershell completion in Click
License: MIT License
Add or enhance bash, fish, zsh and powershell completion in Click
License: MIT License
This package is not intended to use with Click v8.
Click v8 offers some automation support 'nativly', however not for powershell.
I'm interested in using this package to offer cli completion for powershell in my click v8 cli.
Has anyone was able to do so? Thanks in advance!
This repo appears to duplicate (and maybe pre-date?) the official Click completion functionality.
Is this the predecessor to that/was that rolled into Click core at some point? If so, it might be good to:
If this is not a dupe of the click core functionality, and is instead an alternative implementation (or internal implementation component of the Click core func), it would be good to indicate that prominently in the README.
Commands decorated with
@click.command(hidden=True)
should not be shown in the completion list.
The same to #22
hidden
options should not be shown in the completion list, too.
Clink is an enhanced Windows console that supports completion with Lua scripts. There is a clink-completions project that provides more completion profiles. It would be totally rad if both could work together to get click completion on clink.
Hi!
I have the following reduced example:
# file: xdummy
import click
import click_completion
click_completion.init()
@click.command()
@click.option('--upper/--lower', default=None, help="Change text to upper or lower case")
def echo(upper):
click.echo(' foo ')
if __name__ == "__main__":
echo()
When I try to complete
"xdummy "
(a single space after the name) I do not get any completions.
I would have expected to get "--upper" "--lower", and perhaps "--help" but I do not get anything.
What am I doing wrong?
First of all, thank you for this library - it's great.
When running PowerShell, cmder by default invoke's the shell with a few parameters:
*PowerShell -ExecutionPolicy Bypass -NoLogo -NoProfile -NoExit -Command "Invoke-Expression '. ''%ConEmuDir%\..\profile.ps1'''"
(these can be found in the cmder Settings)
These parameters affect click-completion install a couple of ways:
Process
scope to Bypass. When click-completion's install command runs, it tries to set the ExecutionPolicy to Unrestricted on the CurrentUser
scope. We end up with this:Set-ExecutionPolicy : Windows PowerShell updated your execution policy successfully, but the setting is overridden by a policy defined at a more
specific scope. Due to the override, your shell will retain its current effective execution policy of Bypass. Type "Get-ExecutionPolicy -List" to
view your execution policy settings. For more information please see "Get-Help Set-ExecutionPolicy".
At line:1 char:1
+ Set-ExecutionPolicy Unrestricted -Scope CurrentUser
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (:) [Set-ExecutionPolicy], SecurityException
+ FullyQualifiedErrorId : ExecutionPolicyOverride,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand
Traceback (most recent call last):
...
File "c:\code\click-completion\click_completion\core.py", line 353, in install
subprocess.check_call(['powershell', 'Set-ExecutionPolicy Unrestricted -Scope CurrentUser'])
File "c:\users\pstephenson.aa\appdata\local\programs\python\python37-32\lib\subprocess.py", line 328, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['powershell', 'Set-ExecutionPolicy Unrestricted -Scope CurrentUser']' returned non-zero exit status 1.
user_profile.ps1
file that, by default, does not load the PowerShell profile defined in $profile
. This has been noted in some GitHub issues, but it's also relevant for this project because it means that while the completion code gets added to the $profile
file, you won't get the expected behavior without dot sourcing $profile each time you load a new cmder window.I am happy to submit some documentation for cmder users to look out for these things. However, I wanted to ask your thoughts on the first issue: One thing to consider might be to before setting the execution policy, you could first check the execution policy on the Process scope to see if it's anything other than Undefined
or Unrestricted
: https://github.com/click-contrib/click-completion/blob/master/click_completion/core.py#L353. If that is the case, maybe we throw an exception and display a helpful error message to the user indicating the issue? What are your thoughts?
I just asked the click folks if they had a mechanism for automatically showing the shell completion code and installing it, like click-completion has. They said there are no plans to add any mechanism for it. Sad. You can see the issue here:
pallets/click#2127
Is there an update to click-completion that outputs click 8.0 compatible shell completion eval code that works?
I'm using click 8.0.3 and the completion code generated doesn't work.
Here is a sample
└─> aprsd completion show
#compdef aprsd
_aprsd() {
eval $(env COMMANDLINE="${words[1,$CURRENT]}" _APRSD_COMPLETE=complete-zsh aprsd)
}
if [[ "$(basename -- ${(%):-%x})" != "_aprsd" ]]; then
compdef _aprsd aprsd
fi
╭─aprsd on master [$!?] via 🐍 v3.8.5 (.venv) ❯
└─> aprsd completion install
zsh completion installed in /Users/i530566/.zshrc
Unfortunately that doesn't work with click 8.0.
I updated the code in my ~/.zshrc
eval "$(_APRSD_COMPLETE=zsh_source aprsd)"
and that works.
I tried following the example, but I am unable to get click-completion working with powershell. I could not get the example scripts to work, because they are not directly executable in powershell. Is there a simple example for powershell that I can follow? (By the way, completion seems to be activated but just not working. When I enter a tab after my command, the help text gets inserted but the commands are not selected and completed correctly.)
psutil is a soft-dependency of click-completion so it must be listed as an setup.cfg/setup.py extra, so users that want this functionality can install the package with extra.
Also the fact that psutil is not even listed it also means that is not tested, so users would never know which version range is safe to use.
This isn't a huge deal, but the format of conditional dependency declaration has changed somewhat (I am in the process of updating our vendored dependencies in pipenv which is why I caught this)
Before:
install_requires=[
'click',
'jinja2',
'six',
'shellingham',
],
extras_require={
":python_version < '3'": ["enum34"],
},
After:
install_requires=[
'click',
'jinja2',
'six',
'shellingham',
'enum34; python_version<"3"'
],
> python examples\click-completion-command install
Error: pwsh is not supported.
> powershell
Windows PowerShell
[...]
PS > python examples\click-completion-command install
powershell completion installed in b'C:\\Users\\thorsten\\Documents\\WindowsPowerShell\\Microsoft.PowerShell_profile.ps1'
My usecase was to have a option which can take comma separated values
-c val1, val2
I followed what is suggested in stackoverflow
It seems when I use -c tab it doesn't suggest choices for such options. Is there a workaround for such a scenario?
I am testing it on Python 3.7.0 (Mac OS Catalina) and am using pyenv for virtualenv environment.
See pallets/click#1484 and pallets/click#1622. The documentation can be found here for now: https://click.palletsprojects.com/en/8.0.x/shell-completion/. In the new system:
shell_complete
method that provides completions at that level and can be overridden. Parameters additionally accept a shell_complete
function in __init__
to override or extend the type's completion.However, Click doesn't provide these features:
install
command. This is probably out of scope for Click.Due to all these changes, the click-completion won't work with the next release of Click. We've talked about merging this project into Click before, but I think we pretty much have what we want in core at this point. One option is to make a release that specifies click<8
in install_requires
, then have the next version specify click>=8
and continue to support the parts that Click doesn't provide.
Is it possible to do filename completion without having to load all files of a matching folder in the complete
method? That strikes me as very expensive if there are a lot of files.
Currently, I have something like:
def complete(self, ctx, incomplete):
if incomplete.startswith("/"):
path_orig = incomplete
else:
path_orig = os.path.join(os.getcwd(), incomplete)
path, file_prefix = path_orig.rsplit("/", 1)
result = []
if not path:
path = "/"
for filename in os.listdir(path):
if not file_prefix or filename.startswith(file_prefix):
file_path = os.path.join(path, filename)
if os.path.isdir(file_path):
filename += "/"
if incomplete.startswith("/"):
result.append(os.path.join(path, filename))
else:
result.append(filename)
return result
This will complete a folder with an appended '/', but also a whitespace, and there's no way to complete on the content of this folder? Am I missing something? Thanks!
Apparently click-completion fails under zsh, as I tested with two different tools that use click-completion, molecule and pipenv, and I got similar errors.
ssbarnea@imac: ~
$ _PIPENV_COMPLETE=source pipenv #compdef pipenv
_pipenv() {
eval $(env COMMANDLINE="${words[1,$CURRENT]}" _PIPENV_COMPLETE=complete-zsh pipenv)
}
if [[ "$(basename -- ${(%):-%x})" != "_pipenv" ]]; then
autoload -U compinit && compinit
compdef _pipenv pipenv
fi
ssbarnea@imac: ~
$ $(_PIPENV_COMPLETE=source pipenv) zsh: command not found: #compdef
FAIL: 127
##molecule
ssbarnea@imac: ~
$ _MOLECULE_COMPLETE=source molecule #compdef molecule
_molecule() {
eval $(env COMMANDLINE="${words[1,$CURRENT]}" _MOLECULE_COMPLETE=complete-zsh molecule)
}
if [[ "$(basename -- ${(%):-%x})" != "_molecule" ]]; then
compdef _molecule molecule
zsh: command not found: ^[[0m#compdef
I can assure that compdef
exists:
$ which compdef [10:16:59]
compdef () {
local opt autol type func delete eval new i ret=0 cmd svc
local -a match mbegin mend
emulate -L zsh
setopt extendedglob
if (( ! $# ))
then
print -u2 "$0: I need arguments"
return 1
fi
while getopts "anpPkKde" opt
do
case "$opt" in
(a) autol=yes ;;
(n) new=yes ;;
([pPkK]) if [[ -n "$type" ]]
then
print -u2 "$0: type already set to $type"
return 1
fi
if [[ "$opt" = p ]]
then
type=pattern
elif [[ "$opt" = P ]]
then
type=postpattern
elif [[ "$opt" = K ]]
then
type=widgetkey
else
type=key
fi ;;
(d) delete=yes ;;
(e) eval=yes ;;
esac
done
shift OPTIND-1
if (( ! $# ))
then
print -u2 "$0: I need arguments"
return 1
fi
if [[ -z "$delete" ]]
then
if [[ -z "$eval" ]] && [[ "$1" = *\=* ]]
then
while (( $# ))
do
if [[ "$1" = *\=* ]]
then
cmd="${1%%\=*}"
svc="${1#*\=}"
func="$_comps[${_services[(r)$svc]:-$svc}]"
[[ -n ${_services[$svc]} ]] && svc=${_services[$svc]}
[[ -z "$func" ]] && func="${${_patcomps[(K)$svc][1]}:-${_postpatcomps[(K)$svc][1]}}"
if [[ -n "$func" ]]
then
_comps[$cmd]="$func"
_services[$cmd]="$svc"
else
print -u2 "$0: unknown command or service: $svc"
ret=1
fi
else
print -u2 "$0: invalid argument: $1"
ret=1
fi
shift
done
return ret
fi
func="$1"
[[ -n "$autol" ]] && autoload -Uz "$func"
shift
case "$type" in
(widgetkey) while [[ -n $1 ]]
do
if [[ $# -lt 3 ]]
then
print -u2 "$0: compdef -K requires <widget> <comp-widget> <key>"
return 1
fi
[[ $1 = _* ]] || 1="_$1"
[[ $2 = .* ]] || 2=".$2"
[[ $2 = .menu-select ]] && zmodload -i zsh/complist
zle -C "$1" "$2" "$func"
if [[ -n $new ]]
then
bindkey "$3" | IFS=$' \t' read -A opt
[[ $opt[-1] = undefined-key ]] && bindkey "$3" "$1"
else
bindkey "$3" "$1"
fi
shift 3
done ;;
(key) if [[ $# -lt 2 ]]
then
print -u2 "$0: missing keys"
return 1
fi
if [[ $1 = .* ]]
then
[[ $1 = .menu-select ]] && zmodload -i zsh/complist
zle -C "$func" "$1" "$func"
else
[[ $1 = menu-select ]] && zmodload -i zsh/complist
zle -C "$func" ".$1" "$func"
fi
shift
for i
do
if [[ -n $new ]]
then
bindkey "$i" | IFS=$' \t' read -A opt
[[ $opt[-1] = undefined-key ]] || continue
fi
bindkey "$i" "$func"
done ;;
(*) while (( $# ))
do
if [[ "$1" = -N ]]
then
type=normal
elif [[ "$1" = -p ]]
then
type=pattern
elif [[ "$1" = -P ]]
then
type=postpattern
else
case "$type" in
(pattern) if [[ $1 = (#b)(*)=(*) ]]
then
_patcomps[$match[1]]="=$match[2]=$func"
else
_patcomps[$1]="$func"
fi ;;
(postpattern) if [[ $1 = (#b)(*)=(*) ]]
then
_postpatcomps[$match[1]]="=$match[2]=$func"
else
_postpatcomps[$1]="$func"
fi ;;
(*) if [[ "$1" = *\=* ]]
then
cmd="${1%%\=*}"
svc=yes
else
cmd="$1"
svc=
fi
if [[ -z "$new" || -z "${_comps[$1]}" ]]
then
_comps[$cmd]="$func"
[[ -n "$svc" ]] && _services[$cmd]="${1#*\=}"
fi ;;
esac
fi
shift
done ;;
esac
else
case "$type" in
(pattern) unset "_patcomps[$^@]" ;;
(postpattern) unset "_postpatcomps[$^@]" ;;
(key) print -u2 "$0: cannot restore key bindings"
return 1 ;;
(*) unset "_comps[$^@]" ;;
esac
fi
}
The 0.5.0 version is released on PyPI but not tagged in git / on GitHub.
Hi there,
Thanks for the fantastic library! 😃 Small bug report: I am encountering some issues with completing arguments that contain whitespace:
@click.command()
@click.option("--foo", type=click.Choice(["Foo Bar", "Foo Qux"]))
def cli(foo):
print(foo)
λ cli --foo
<TAB>
λ cli --foo Foo\
<TAB>
(nothing changes and no options are displayed)
click-completion: 0.5.2
shell: fish
My suspicion was that the .endswith
check here could be culprit:
click-completion/click_completion/core.py
Lines 191 to 196 in 6e08a5f
split_args
to return an (args, incomplete)
tuple, This is a follow up on #6
I think the -f
flag in the very end of https://github.com/click-contrib/click-completion/blob/master/click_completion/fish.j2#L1 inhibits file completion in my app.
I think this is related to a change in the behavior of the -f
flag in fish
itself after Nov. 2017, see this PR: fish-shell/fish-shell#4560
The ninja command here is older. When I remove the -f
locally, I see file completion.
Under zsh, you run the following code:
if [[ "$(basename ${(%):-%x})" != "..." ]]; then
Under a login shell, the shell executable begins with a dash (eg. '-zsh'), so basename
fails with:
$ eval "$(pipenv --completion)"
basename: illegal option -- z
usage: basename string [suffix]
basename [-a] [-s suffix] string [...]
(pipenv
uses click_completion
internally.) To fix this, you can do:
basename -- ${(%):-%x}
Adding --
stops anything starting with -
from being parsed as an argument.
Hello,
I tried installing molecule using pip on centos7 but getting following error:
Collecting click-completion>=0.5.1 (from molecule==3.0a1)
Using cached https://files.pythonhosted.org/packages/77/fd/2d7ec2b86cd4d487abf0b13dce58e98413096c45b9645470be0cb8de6ff2/click-completion-0.5.1.tar.gz
ERROR: Command errored out with exit status 1:
command: /bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-RyPp9J/click-completion/setup.py'"'"'; file='"'"'/tmp/pip-install-RyPp9J/click-completion/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(file);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, file, '"'"'exec'"'"'))' egg_info --egg-base pip-egg-info
cwd: /tmp/pip-install-RyPp9J/click-completion/
Complete output (1 lines):
error in click-completion setup command: 'install_requires' must be a string or list of strings containing valid project/version requirement specifiers
----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output
Any help would be appreciated
Thanks
Afroz Hussain
Hi, so in my CLI, I have some callbacks with complex functionality. One of them checks for a specific file in the current directory, and exits with an error printed to sys.stdout. The problem is that the shell tries to evaluate that printed string. I am not sure what this is happening, don't know much about shells and autocompletion. I'm using ZSH, and you can easily replicate this error in one of the examples of this repository.
At examples/click-completion-callback, line 15, add this print statement:
def install_callback(ctx, attr, value):
print("Hello World") # add this
if not value or ctx.resilient_parsing:
return value
shell, path = click_completion.core.install()
click.echo('%s completion installed in %s' % (shell, path))
exit(0)
If you try to complete this with TAB cli echo <TAB>'
, it produces this error
cli echo (eval):1: command not found: Hello
(eval):1: command not found: Hello
(eval):1: command not found: Hello
cli
How to run click_completion.core.install()
command after pip install
complete installing package?
$ pip install my-click-app
# Installing click app
# Installing click app completion
# Done
$ myapp g <TAB> <TAB>
$ myapp g
get generate ghost
Since I could not find a way to run myapp --completion
within pip install
, I have to run it manually to enable completion. I'm looking for a way to install completion the setup.py of the project.
#!/usr/bin/env python3
"""CLI App module."""
from typing import Any
import click
import click_completion
from click.core import Context
from .delpoy import deploy
from .download import get
from .generator import gen
from .paths import path
def install_callback(ctx: Context, attr: Any, value: Any) -> None:
"""Shell competion function.
Args:
ctx (click.core.Context): Context
attr: Attribute
value: Value
"""
if not value or ctx.resilient_parsing:
return value
shell, path = click_completion.core.install()
click.echo("%s completion installed in %s." % (shell, path))
click.echo("Use ", nl=False)
click.secho(f". {path}", fg="green", bold=True, nl=False)
click.echo(" to activate the completion.")
exit(0)
click_completion.init()
@click.group()
@click.option(
"-c",
"--completion",
is_flag=True,
callback=install_callback,
expose_value=False,
help="Install completion for the current shell.",
)
def cli():
"""Commnadline Interface."""
cli.add_command(deploy)
cli.add_command(gen)
cli.add_command(path)
cli.add_command(get)
I have a Choice option with the following values: "kotlin-rest-spring-boot-local", "kotlin-rest-spring-boot", "java-rest-spring-boot"
@click.option('--template', "template_key", type=click.Choice(["kotlin-rest-spring-boot-local", "kotlin-rest-spring-boot", "java-rest-spring-boot"]))
def create(template_key=None):
pass
when I hit 'tab'for the first time at
compdummy --template <tab>
I get
compdummy --template -rest-spring
because '-rest-spring' is a common substring. Hitting 'tab' again, nothing happens because:
def choice_complete(self, ctx, incomplete):
return [c for c in self.choices if c.startswith(incomplete)]
only checks for 'startswith'.
If I replace the above code with:
def choice_complete(self, ctx, incomplete):
return [c for c in self.choices if incomplete in c]
everything works fine
I noticed something that may be an error in the documentation.
In your documentation is states to put in ~/.config/fish/completions/foo-bar.fish
eval (_FOO_BAR_COMPLETE=source-fish foo-bar)
First, on my system it appears that ~/.config/fish/completions/
is not loaded in fish. Maybe you are using omf or some other scripts that load that subdir's scripts? I just have a plain fish install and it does not appear to look in the completions subdir (I'm on a mac and installed fish version 2.4.0 using brew) Secondly, the code you listed to load the completions raises following error when I try it:
Unsupported use of '='. To run 'foo-bar' with a modified environment, please use 'env _FOO_BAR_COMPLETE=source-fish foo-bar…' in command substitution
However, everything works if I put the following in ~/.config/fish/config.fish
eval (env _FOO_BAR_COMPLETE =source-fish foo-bar)
So I'm not sure if the documentation should be updated or if there is something weird on my system? Just thought I'd let you know.
Thanks for the nice work on this plugin. Once I made the above changes it works great.
I have a kind request to the author here (and happy to help if needed). Currently click-completion
only publishes .tar.gz package which forces "building" of the package when installing it. It would be great if we have also the .whl package published (not dependent on platform) so that it can be installed without building the package (and without the need of 'wheel' package to be installed.
That would make it easier to use click-completion for standalone python application installed with pipx
for example, because then just having a "bare" python and installing 'click-completion' would work - without having to have wheel
package installed.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.