Yet another cli library for python, click-like but sub-command friendly and designed for cli auto-generating.
Let's generate your command line tools from a cmd_path
or just use shortcut decorators like click
.
- Designed for cli auto-generating(make your commands by program)
- Easy to use: works like
click
- Friendly low-level api(Use a tree and add your command by
command path
!) - no extra dependencies(only
six
is needed) - Python3 support
- argument-type support
- decorators has no side-effect on function call(call it in any other place in python style)
run pip install cmdtree
or clone the repo and use it.
pip install -r test-requirements.txt
make test
orpy.test cmdtree
Note: Follow the examples in folder examples
.
from cmdtree import INT
from cmdtree import command, argument, option
@argument("host", help="server listen address")
@option("reload", is_flag=True, help="if auto-reload on")
@option("port", help="server port", type=INT, default=8888)
@command(help="run a http server on given address")
def run_server(host, reload, port):
print(
"Your server running on {host}:{port}, auto-reload is {reload}".format(
host=host,
port=port,
reload=reload
)
)
if __name__ == "__main__":
from cmdtree import entry
entry()
Get help
➜ examples git:(master) python command.py --help
usage: command.py [-h] {run_server} ...
positional arguments:
{run_server} sub-commands
run_server
optional arguments:
-h, --help show this help message and exit
Run command
➜ examples git:(master) python command.py run_server localhost
Your server running on localhost:8888, auto-reload is False
Code here:
from cmdtree import group, argument, entry
@group("docker")
@argument("ip")
def docker():
pass
# nested command
@docker.command("run")
@argument("container-name")
def run(ip, container_name):
print(
"container [{name}] on host [{ip}]".format(
ip=ip,
name=container_name,
)
)
# nested command group
@docker.group("image")
def image():
pass
@image.command("create")
@argument("name")
def image_create(ip, name):
print(
"iamge {name} on {ip} created.".format(
ip=ip,
name=name,
)
)
if __name__ == "__main__":
entry()
Run command:
➜ examples git:(master) python command_group.py docker localhost image create your-docker
iamge your-docker on localhost created.
Alternatives:
click
frompocoo
argparse
But when you should choose cmdtree
?
When you need:
- fully sub-command support(not
group
inclick
) - Higher-level api support(compared to
argparse
) - More arg-type support(compared to
argparse
) - decorators has no side-effect on function call(compared to
click
)
In both of them, you have to make implementation yourself. CmdTree works on this point.
In most case , you can make your command flat
.
But when you need sub-command?
I use it in my schema-sugar
project,
the project generate cli-tool from schema that describes REST-API.
For example:
You want to generate a CRUD
commandline for http resources,
# list the resource
GET http://example.com/computer/disks
# show one of the disk info
GET http://example.com/computer/disks/1
# delete
DELETE http://example.com/computer/disks/1
I want to make a command line just like
rest-cli computer disks list
rest-cli computer disks delete <id>
rest-cli computer disks show <id>
The computer
is to used to make the resource unique
, so I can not
ensure that all of the commands could be made flat
.
click
lacks the support for multiple-level sub-command.
argparse
has very low-level api(really makes me crazy).
So I wrote cmdtree
to handle this problem. Now I just wrote:
from cmdtree.tree import CmdTree
tree = CmdTree()
def index():
print("Hi, you have 10 disks in your computer...")
def show(disk_id):
print("This is disk %s" % disk_id)
def delete(disk_id):
print("disk %s deleted" % disk_id)
# Add list command
tree.add_commands(["computer", "list"], index)
# get the parser in any place, any time
tree.add_commands(["computer", "show"], show)
tree_node = tree.get_cmd_by_path(["computer", "show"])
show_parser = tree_node['cmd']
show_parser.argument("disk_id")
# Add delete command
delete3 = tree.add_commands(["computer", "delete"], delete)
delete3.argument("disk_id")
# run your tree
tree.root.run()
- 2016.09.22 Fix help-message missing in command and group
- 2016.09.08 Global argument support
click
argparse
Author: winkidney@github
Repo: GithubRepo
Blog: Blog