Reputation: 12858
I am trying to do a CLI that accepts multiple arguments that I guess you would say are nested and are predefined. For example, say I am trying to create a utility that manages a relational database. I want commands like the following:
dbmgr.py create table --name="mytab"
dbmgr.py create view --name="myview" --other-opt=...
dbmgr.py drop table --name=...
dbmgr.py drop user --username=...
In this case there are a pre-defined set of operations ("create", "drop", etc) and each operation has a specific pre-defined set of objects that each operation can operate upon. In this case, the "create" operation can only accept the "table" or "view" object.
In the case of the "drop" operation, a user can only specify the "table", and "user" objects. In the case of click are "create", "table", "view", and "drop" just arguments? If so, how do I restrict what can be specified to specific values? I'm not sure if this is a case where groups, commands, etc are used and if so, how?
Upvotes: 2
Views: 576
Reputation: 49794
What you are trying to do is the exact use case for click groups. In your example create
and drop
are groups, and table
, view
, etc... are commands. This type of structure is (in my opinion) what makes Click better then the other Python command line parsing libraries. It can describe these structures quite nicely.
import click
@click.group()
def cli():
"""DB Manager CLI"""
@cli.group()
def create():
"""create objects"""
@create.command()
def table():
click.echo('create table command')
@create.command()
def view():
click.echo('create view command')
@cli.group()
def drop():
"""create objects"""
@drop.command()
def table():
click.echo('drop table command')
@drop.command()
@click.option('--username')
def user(username):
click.echo('drop user command: {}'.format(username))
if __name__ == "__main__":
cli()
if __name__ == "__main__":
commands = (
'create table',
'create view',
'drop table',
'drop user --username a-user',
'--help',
'drop --help',
'drop user --help',
)
import sys, time
time.sleep(1)
print('Click Version: {}'.format(click.__version__))
print('Python Version: {}'.format(sys.version))
for cmd in commands:
try:
time.sleep(0.1)
print('-----------')
print('> ' + cmd)
time.sleep(0.1)
cli(cmd.split())
except BaseException as exc:
if str(exc) != '0' and \
not isinstance(exc, (click.ClickException, SystemExit)):
raise
Click Version: 7.0
Python Version: 3.8.1 (tags/v3.8.1:1b293b6, Dec 18 2019, 22:39:24) [MSC v.1916 32 bit (Intel)]
-----------
> create table
create table command
-----------
> create view
create view command
-----------
> drop table
drop table command
-----------
> drop user --username a-user
drop user command: a-user
-----------
> --help
Usage: test.py [OPTIONS] COMMAND [ARGS]...
DB Manager CLI
Options:
--help Show this message and exit.
Commands:
create create objects
drop create objects
-----------
> drop --help
Usage: test.py drop [OPTIONS] COMMAND [ARGS]...
create objects
Options:
--help Show this message and exit.
Commands:
table
user
-----------
> drop user --help
Usage: test.py drop user [OPTIONS]
Options:
--username TEXT
--help Show this message and exit.
Upvotes: 5