Modify REPL behaviour#
Remove repl command after invoking the REPL#
The register_repl() decorator assigns the repl() function
as a command to your group. However, it’s possible to initialize a REPL session within an another REPL session,
because the repl command is still available within the REPL session itself.
1import click
2from click_repl import register_repl
3
4@register_repl
5@click.group()
6def main():
7 pass
8
9@main.command()
10def my_command():
11 pass
12
13
14main()
As shown, invoking the repl() command within its own REPL leads to a nested REPL.
Exiting the entire REPL requires exiting each layer of the REPL individually.
To prevent this behavior and remove the repl() command before invoking the REPL, set the remove_command_before_repl parameter to True
in register_repl(). By default, this parameter is set to False, meaning it doesn’t remove the repl command.
1import click
2from click_repl import register_repl
3
4@register_repl(remove_command_before_repl=True)
5@click.group()
6def main():
7 pass
8
9@main.command()
10def my_command():
11 pass
12
13
14main()
ReplGroup#
The ReplGroup class inherits from Group, and can also invoke REPL.
1# file: app.py
2
3import click
4from click_repl import ReplGroup
5
6@click.group(cls=ReplGroup)
7def main():
8 pass
9
10@main.command()
11@click.argument('name')
12def greet(name):
13 print(f'Hi {name}!')
14
15
16main()
It invokes REPL only when no extra arguments were passed to the group.
$ python app.py greet Sam
Hi Sam!
$ python app.py
> greet Sam
Hi Sam!
>
However, ReplGroup offers more features than using either
register_repl() or repl().
Startup and Cleanup Callbacks#
ReplGroup allows you to run code before invoking the REPL, and after exiting it.
You can provide the code to be executed before invoking the REPL as a callback to the
startup parameter of ReplGroup,
and similarly for cleanup using the cleanup parameter.
1# file: app.py
2
3import click
4from click_repl import ReplGroup
5
6@click.group(
7 cls=ReplGroup,
8 startup=lambda: print('Entering REPL...'),
9 cleanup=lambda: print('Exiting REPL...')
10)
11def main():
12 pass
13
14@main.command()
15@click.argument('name')
16def greet(name):
17 print(f'Hi {name}!')
18
19
20main()
$ python app.py greet Sam
Hi Sam!
$ python app.py
Entering REPL...
> greet Sam
Hi Sam!
> :exit
Exiting REPL...
$
Custom Prompt#
By default, click-repl uses > as its prompt. You can customize the prompt by:
Assigning your prompt to the
messagekey inrepl()’sprompt_kwargsdictionary.1# file: app.py 2 3import click 4from click_repl import repl 5 6@click.group(invoke_without_command=True) 7@click.pass_context 8def main(ctx): 9 repl(ctx, prompt_kwargs={ 10 'message': '>>> ' 11 }) 12 13 14main()
$ python app.py >>>
Pass it via the
promptparameter inReplGroup.1import click 2from click_repl import ReplGroup 3 4@click.group(cls=ReplGroup, prompt='>>> ') 5def main(): 6 pass 7 8 9main()
Accessing and modifying the prompt during runtime using the
promptproperty.1import os 2 3import click 4import click_repl 5from pathlib import Path 6 7@click.group(cls=click_repl.ReplGroup, prompt='user@/$ ') 8def main(): 9 pass 10 11@main.command('cd') 12@click.argument('path', type=click.Path(file_okay=False)) 13@click_repl.pass_context 14def change_directory(repl_ctx, path): 15 resolved_path = Path(repl_ctx.prompt.split('@')[1].removesuffix('$ ') + path).resolve() 16 os.chdir(resolved_path) 17 repl_ctx.prompt = f"user@{resolved_path}$ " 18 19 20main()
prompt_kwargs#
click-repl uses an instance of PromptSession as its prompt interface. You can provide custom arguments to
this PromptSession instance via the prompt_kwargs parameter of repl() function
or ReplGroup class.
1import click
2from click_repl import ReplGroup
3from prompt_toolkit.history import FileHistory
4
5@click.group(
6 cls=ReplGroup,
7 prompt_kwargs={
8 "history": FileHistory("/etc/myrepl/myrepl-history"),
9 }
10)
11def main():
12 pass
13
14
15main()
With this configuration, the click-repl application stores a history of previously executed commands in the specified file.
This dictionary of keyword arguments will be updated with the default keyword arguments of PromptSession
when initializing the REPL. The default arguments and their values for
PromptSession are:
history-InMemoryHistory(Object for storing previous command history per REPL session.)message-"> "complete_in_thread-Truecomplete_while_typing-Truevalidate_while_typing-Truemouse_support-Truerefresh_interval- 0.15
These default values are supplied from get_default_prompt_kwargs() method.
For further details about these parameters, refer to PromptSession docs.
Repl#
The Repl class is the central component of this module, responsible for configuring and
executing the REPL action through its loop() method.
Custom Repl#
If you require extensive customization of the REPL configuration and execution, you can create your own Repl class
based on the blueprint/template of the Repl. It’s recommended to inherit and use it
from the Repl class.
Once you’ve created your custom Repl class, you can use it by passing it into cls
parameter of repl() function.
1import click
2from click_repl import Repl, repl
3
4class MyRepl(Repl):
5 # Implement your own REPL customization.
6 ...
7
8@click.group(invoke_without_command=True)
9@click.pass_context
10def main(ctx):
11 repl(ctx, cls=MyRepl)
12
13
14main()
ReplContext#
Unlike Context, the ReplContext class is instantiated for every new REPL session.
This object tracks the current REPL’s state, while parsing arguments from the prompt while typing.
From this context object, you can obtain many objects responsible for the REPL’s functionality, allowing extreme flexibility in customizing your REPL session during runtime.
You can access it using the click_repl’s pass_context() decorator, which is similar to click’s
pass_context(). Ensure not to accidentally switch them.
Note
A ReplContext is instantiated only when the REPL is invoked. Therefore, you won’t be able to use it inside the group.
1import click
2import click_repl
3
4@click_repl.register_repl
5@click.group()
6@click.pass_context
7def main(ctx):
8 pass
9
10@main.command()
11@click.pass_context
12@click_repl.pass_context
13def command(ctx, repl_ctx):
14 # You can do whatever you want with the current repl session's context object.
15 ...
PromptSession object#
click-repl utilzes the PromptSession object, resopnsible for the REPL’s functionality.
This object can be accessed via the session attribute of the ReplContext
object. You can leverage this to extend the functionality of the REPL. Refer to
python-prompt-toolkit’s
PromptSession docs.