-
-
Notifications
You must be signed in to change notification settings - Fork 672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Command aliases #132
Comments
Hey, as Typer doesn't modify the function, and only "registers" it, you could do this: import typer
app = typer.Typer()
@app.command("delete")
@app.command("uninstall")
@app.command("d")
def delete(name: str):
typer.echo(f"Deleting {name}")
if __name__ == "__main__":
app() |
Manually adding aliases does not really scale well. Click has some code for implementing git-like behavior at https://click.palletsprojects.com/en/7.x/advanced/ but the tricky bit is that I have no idea on how to adapt this code to work for typer, especially as I do generate commands dynamically at https://github.com/pycontribs/mk/blob/main/src/mk/__main__.py#L87-L91 |
@tiangolo
What I want is:
How do I do this with typer? Thank you. |
@tddschn I solved this by hiding the subsequent option, works pretty well. @app.command(no_args_is_help=True, help='Open a log stream to a service. (also "logs")')
@app.command('logs', hidden=True)
def log(
service: Service = typer.Argument(..., help='The service whose logs to stream.'),
):
docker_execute(['logs', '-f', service]) |
I wonder if we could use https://click.palletsprojects.com/en/8.1.x/advanced/ in with typer as being able to just catch an unknown command and redirect it to the correct one is far more flexible and could also allow us to address typos by avoiding pre-generating all possible values in advance, which is quite ugly. |
I have also been looking for a solution to this, tried a few different methods, none of them worked nicely. The best one is just adding hidden commands: @app.command()
@app.command(name="f", hidden=True)
def foobar(hello: str):
"Foobar command"
print("foobar with hello: ", hello) but then we don't get a list of aliases, and you cant run something like If someone more experienced than me would give a pointer for how a function that does |
I always use bellow for alias (exactly, command is a decorator, so it is a caller too). # alias, it also use the decorator's logic and work well
app.command(name="byebye", help="alias of goodbye")(goodbye) |
@FFengIll thats neat but its only available on build right? what i want is something like @app.command()
def alias(ctx: Context, name: str, command: str):
aliases = ctx.obj.get('aliases', None)
command = ctx.parent.command.get_command(ctx, command)
if aliases and command:
aliases[name] = command
app.command(name=name)(command) # <-- this doesn't work because i cant get the global app obj? i also tried adding it to the context and running ctx.obj.app.... but it didn't work either
@app.command()
def unalias(.... that i can use from within a session.. |
You can support this with a tweak to the Group class: class AliasGroup(typer.core.TyperGroup):
_CMD_SPLIT_P = re.compile(r", ?")
def get_command(self, ctx, cmd_name):
cmd_name = self._group_cmd_name(cmd_name)
return super().get_command(ctx, cmd_name)
def _group_cmd_name(self, default_name):
for cmd in self.commands.values():
if cmd.name and default_name in self._CMD_SPLIT_P.split(cmd.name):
return cmd.name
return default_name Usage: app = typer.Typer(cls=AliasGroup)
@app.command("foo, f")
def foo():
"""Print a message and exit."""
print("Works as command 'foo' or its alias 'f'")
@app.callback()
def main():
pass
app() See the full Gist. One could imagine more explicit support of this with a mod to the upstream group class and a new app = Typer() # Uses TyperGroup, which is modified to look for an 'aliases' attr on commands
@app.command("foo", aliases=["f"])
def foo():
pass |
Thank you, @gar1t ! This works great! +1 for command It would be nice if it could include a custom parsing separator, and display separator override. E.g. I like to use b | build Build the dev environment
c | cmd Run a command inside the dev environment
d | dev Run the dev environment
m | manage Run a manage.py function
s | shell Enter into a python shell inside the dev environment
t | tui Run an interactive TUI |
@gar1t A slightly more robust solution that allows for multiple (or sloppy) delimiters: class AliasGroup(TyperGroup):
_CMD_SPLIT_P = r'[,| ?\/]' # add other delimiters inside the [ ]
...
def _group_cmd_name(self, default_name):
for cmd in self.commands.values():
if cmd.name and default_name in re.split(self._CMD_SPLIT_P, cmd.name):
return cmd.name
return default_name |
@mrharpo Not really a typo, but a feeling of improvement for the regex (or maybe I didn't really understand the
My full code is like: class AliasGroup(TyperGroup):
_CMD_SPLIT_P = re.compile(r" ?[,|] ?")
def get_command(self, ctx, cmd_name):
cmd_name = self._group_cmd_name(cmd_name)
return super().get_command(ctx, cmd_name)
def _group_cmd_name(self, default_name):
for cmd in self.commands.values():
name = cmd.name
if name and default_name in self._CMD_SPLIT_P.split(name):
return name
return default_name
app = typer.Typer(cls=AliasGroup)
@app.command("a | action | xyz")
def do_something():
"""
Some description here.
"""
... I agree the help text is certainly improved 🎉 : Usage: cmd [OPTIONS] COMMAND [ARGS]...
╭─ Options ──────────────────────────────────────────────────────────────────────────╮
│ --install-completion Install completion for the current shell. │
│ --show-completion Show completion for the current shell, to copy it or │
│ customize the installation. │
│ --help Show this message and exit. │
╰────────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ─────────────────────────────────────────────────────────────────────────╮
│ a | action | xyz Some description here. │
╰────────────────────────────────────────────────────────────────────────────────────╯ |
It would be nice to have command aliases, when all these commands do the same thing:
There is a module for click which can do it: https://github.com/click-contrib/click-aliases
Code looks like this:
Also this module click-aliases add info about alises to help:
The text was updated successfully, but these errors were encountered: