-
-
Notifications
You must be signed in to change notification settings - Fork 684
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
[FEATURE] REPL mode #185
Comments
This would be similar to what plac's interactive mode ( Click seems to have a package for this? click-shell (although did not investigate if/how it works) |
Definitely would love to see this. Was looking to see if the feature was supported and stumbled upon this request, so I assume it isn't. Would be quite handy when I want to interact with the app a lot. |
You can do this with click-repl package : https://github.com/click-contrib/click-repl import click
import typer
from click_repl import repl
app = typer.Typer()
remote = typer.Typer()
app.add_typer(remote, name="remote")
@remote.command()
def add(origin: str):
typer.echo(f"Setting origin : {origin}")
@remote.command()
def remove(origin: str):
typer.echo(f"Removing origin : {origin}")
@app.command()
def myrepl(ctx: typer.Context):
repl(ctx)
if __name__ == "__main__":
app() |
After some brief experimentation, I've concluded that I prefer Here's how I believe we integrate it with from typer import Context, Typer
from click_shell import make_click_shell
app: Typer = Typer()
@app.command()
def foobar():
print("foobar")
@app.callback(invoke_without_command=True)
def launch(ctx: Context):
shell = make_click_shell(ctx, prompt="<shell_prompt>", intro="<shell_introduction>")
shell.cmdloop()
if __name__ == "__main__":
app() Nota bene: I'm new to all three projects ( Edit, five days later: here's a quick project I threw together using |
This demo is good but one thing that took me a while was figuring out how to take advantage of typers nice help printing: from typer import Context, Typer
from click_shell import make_click_shell
from rich import print
app: Typer = Typer()
@app.command()
def foobar():
print("foobar")
@app.callback(invoke_without_command=True)
def launch(ctx: Context):
shell = make_click_shell(ctx, prompt="<shell_prompt>", intro="<shell_introduction>")
shell.cmdloop()
@app.command(hidden=True)
def help(ctx: Context):
print("\n Type 'command --help' for help on a specific command.")
ctx.parent.get_help()
if __name__ == "__main__":
app() maybe there is a better way to do it. The default click-shell help is pretty sad by comparison. |
btw i also checked out click-repl, was hard to choose between them cause neither of them are very well documented and both have stregths:
|
Actually let me do you one better even. For all future generations, I leave this here: from typer import Context, Typer, Argument
from typing import Optional
from typing_extensions import Annotated
@app.command(hidden=True)
def help(ctx: Context, command: Annotated[Optional[str], Argument()] = None):
print("\n Type 'command --help' or 'help <command>' for help on a specific command.")
if command:
command = ctx.parent.command.get_command(ctx, command)
command.get_help(ctx)
else:
ctx.parent.get_help() enjoy |
Okay let me do you one more, from typing_extensions import Annotated
from typing import Optional, Callable
from click_shell import make_click_shell
from typer import Context, Typer, Argument
from rich import print
def make_typer_shell(
app: Typer,
prompt: str = ">> ",
intro: str = "\n Welcome to typer-shell! Type help to see commands.\n",
default: Optional[Callable] = None
) -> None:
@app.command(hidden=True)
def help(ctx: Context, command: Annotated[Optional[str], Argument()] = None):
print("\n Type 'command --help' or 'help <command>' for help on a specific command.")
if not command:
ctx.parent.get_help()
return
ctx.parent.command.get_command(ctx, command).get_help(ctx)
@app.command(hidden=True)
def _default(args: Annotated[Optional[str], Argument()] = None):
"""Default command"""
if default:
default(args)
else:
print("Command not found. Type 'help' to see commands.")
@app.callback(invoke_without_command=True)
def launch(ctx: Context):
if ctx.invoked_subcommand is None:
shell = make_click_shell(ctx, prompt=prompt, intro=intro)
shell.default = _default
shell.cmdloop() and #!/usr/bin/env python
from rich import print
from typer import Typer
from typer_shell import make_typer_shell
app: Typer = Typer()
make_typer_shell(app, prompt="🔥: ")
subapp: Typer = Typer()
default = lambda x: print(f"Inner Default, args: {x}")
make_typer_shell(
subapp,
prompt="🌲: ",
intro="\n Welcome to the inner shell! Type help to see commands.\n",
default=default
)
app.add_typer(subapp, name="inner")
@app.command()
def foobar():
"Foobar command"
print("foobar")
@subapp.command(name="foobar")
def _foobar():
"Foobar command"
print("foobar")
if __name__ == "__main__":
app() and some footage: Shall I make this a PR? Would you want this? @mgielda |
i just made this, pretty simple really but very nice results: |
A simple REPL with Typer can be rolled as follows: import shlex
import typer
class SampleRepl:
def __init__(self):
self.x = 0
def drop_to_shell(self):
app = typer.Typer(no_args_is_help=True, add_completion=False)
app.command(help="set x")(self.set)
app.command(help="get x")(self.get)
typer.echo("Type --help to show help.")
typer.echo("Type 'exit' to quit.")
while True:
args = shlex.split(typer.prompt("> "))
if not args:
continue
if args == ["exit"]:
typer.echo("bye!")
break
app(args, standalone_mode=False)
def set(self, value: int):
self.x = value
def get(self) -> int:
typer.echo(f"x = {self.x}")
return self.x
def main():
SampleRepl().drop_to_shell()
if __name__ == "__main__":
main() |
An 'interactive' mode would be extremely useful:
|
Is your feature request related to a problem
I want to keep context (e.g. session) between different CLI invocations.
The solution you would like
by activaticating REPL mode, e.g. with a
--repl
flag, user gets in interactive shell that he can communicate multiple commands and share the same context between them.The text was updated successfully, but these errors were encountered: