Skip to content

Yet another cli library , click-like but sub-command friendly and designed for cli auto-generating.

License

Notifications You must be signed in to change notification settings

winkidney/cmdtree

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

53 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CMDTree

PyPI version Build Status Coverage Status

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.

Feature

  • 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)

Install

run pip install cmdtree or clone the repo and use it.

Run Test

  • pip install -r test-requirements.txt
  • make test or py.test cmdtree

Quick Start

Note: Follow the examples in folder examples.

Hello world

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

SubCommand of SubCommand

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.

Why cmdtree?

Alternatives:

  • click from pocoo
  • argparse

But when you should choose cmdtree?

When you need:

  • fully sub-command support(not group in click)
  • 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()

Change Log

  • 2016.09.22 Fix help-message missing in command and group
  • 2016.09.08 Global argument support

Inspired by

  • click
  • argparse

About

Author: winkidney@github

Repo: GithubRepo

Blog: Blog

About

Yet another cli library , click-like but sub-command friendly and designed for cli auto-generating.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages