{"id":19251912,"url":"https://github.com/thrawn01/subcommand","last_synced_at":"2025-10-08T19:19:27.969Z","repository":{"id":34076406,"uuid":"37880818","full_name":"thrawn01/subcommand","owner":"thrawn01","description":"CLI SubCommand Parser for python","archived":false,"fork":false,"pushed_at":"2016-05-11T18:07:33.000Z","size":21,"stargazers_count":0,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-05T06:42:13.136Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"RohmSemiconductor/Arduino","license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thrawn01.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-06-22T21:11:19.000Z","updated_at":"2016-02-29T18:09:43.000Z","dependencies_parsed_at":"2022-07-17T22:00:43.130Z","dependency_job_id":null,"html_url":"https://github.com/thrawn01/subcommand","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thrawn01%2Fsubcommand","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thrawn01%2Fsubcommand/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thrawn01%2Fsubcommand/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thrawn01%2Fsubcommand/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thrawn01","download_url":"https://codeload.github.com/thrawn01/subcommand/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240347818,"owners_count":19787234,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T18:24:31.928Z","updated_at":"2025-10-08T19:19:22.921Z","avatar_url":"https://github.com/thrawn01.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\nComplete documentation is available [here](http://subcommand.org)\n\n# SubCommand CLI Parser\n\nSubCommand is a simple and concise SubCommand parser to assist CLI developers\nin creating relatively complex sub commands.\n\nThe SubCommand project fits into a single file, which is less than 500 lines.\nThe interface consists of 3 Classes and a few decorators and that is it.\n\n**Doesn't argparse already support sub commands?**\n\nI does, but in practice it can be quite complex and it makes keeping the args\nand the subcommands together and easily reasoned about difficult in large CLI\ncode bases.\n\n**Doesn't project X already do this?**\n\nThere are several projects that attempt to solve the sub command problem.\n\n* *Plumbum* - http://plumbum.readthedocs.org/en/latest/cli.html\n* *Click* - http://click.pocoo.org\n* *Cliff* - http://docs.openstack.org/developer/cliff\n\nWhen I originally wrote `SubCommand` none of these projects existed, and even\nnow none of them are as small and simple to use as SubCommand. IMHO =)\n\nIn fact `SubCommand` is so small you can easily copy single .py module into your\nown project to avoid carrying around yet another external dependency.\n\n## Installation\n\nInstall via pip\n```\n$ pip install cli-subcommand\n```\n\n## What does it look like?\n\nHere is simple example\n``` python\nfrom subcommand import opt, noargs\nimport subcommand\nimport sys\n\nclass TestCommands(subcommand.Commands):\n\n    def __init__(self):\n        subcommand.Commands.__init__(self)\n        self.opt('-d', '--debug', action='store_const',\n                 const=True, default=False, help=\"Output debug\")\n        self.count = 0\n\n    @opt('--count', default=1, type=int, help=\"Num of Hello's\")\n    @opt('name', help=\"Your name\")\n    def hello(self, name, count=1):\n        \"\"\" Docstring for hello \"\"\"\n        for x in range(count):\n            print('Hello, %s' % name)\n            self.count += 1\n        return 0\n\n    @noargs\n    def return_non_zero(self):\n        if self.debug:\n            print('Exit with non-zero status')\n        return 1\n\nif __name__ == \"__main__\":\n    parser = subcommand.Parser([TestCommands()],\n                               desc='Test Application')\n    sys.exit(parser.run())\n```\n\nIt looks like this when run\n```\n    $ python hello.py hello derrick --count 5\n    Hello, derrick\n    Hello, derrick\n    Hello, derrick\n    Hello, derrick\n    Hello, derrick\n    $ echo $?\n```\nWhat it looks like when you pass no arguments\n```\n    $ python hello.py\n    Usage: hello.py \u003ccommand\u003e [-h]\n\n    Test Application\n\n    Available Commands:\n       return-non-zero\n       hello\n```\nWhat it looks like when you ask for `hello -h`\n```\n    $ python hello.py hello -h\n    usage: hello [-h] [--count COUNT] [-d] name\n\n    Docstring for hello\n\n    positional arguments:\n      name           Your name\n\n    optional arguments:\n      -h, --help     show this help message and exit\n      --count COUNT  Num of Hello's\n      -d, --debug    Output debug\n```\n\n## Can my commands have subcommands?\nIn order to use subcommands you must use the **subcommand.SubParser** class to\nparse your **subcommand.Commands** objects. In addition you must give your\n**Commands** object a name by giving it the **_name** attribute.\n\nExample\n```python\n    from subcommand import opt, noargs\n    import subcommand\n    import sys\n\n    class BaseCommands(subcommand.Commands):\n        def pre_command(self):\n            self.client = self.client_factory()\n\n    class TicketCommands(BaseCommands):\n        \"\"\" Ticket SubCommand Docs \"\"\"\n        _name = 'tickets'\n        @opt('tkt-num', help=\"tkt number to get\")\n        def get(self, tkt_num):\n            \"\"\" Get Ticket docstring \"\"\"\n            print(self.client.get_ticket(tkt_num))\n\n    class QueueCommands(BaseCommands):\n        \"\"\" Queue SubCommand Docs \"\"\"\n        _name = 'queues'\n        @opt('queue-num', help=\"queue to get\")\n        def get(self, queue_num):\n            print(self.client.get_queue(queue_num))\n\n    if __name__ == \"__main__\":\n        parser = subcommand.SubParser([TicketCommands(),\n                                       QueueCommands()],\n                                      desc='Ticket Client')\n        sys.exit(parser.run())\n```\n\nWhat it looks like when you run it\n```\n    $ python hello.py\n    Usage: hello.py \u003ccommand\u003e [-h]\n\n    Ticket Client\n\n    Available Commands:\n       tickets\n       queues\n```\n\nWhen you run the subcommands\n```\n    $ python hello.py tickets\n    Usage: hello.py tickets \u003ccommand\u003e [-h]\n\n    Ticket SubCommand Docs\n\n    Available Commands:\n       get\n```\n\nGetting help from the sub command\n```\n    $ python hello.py tickets get -h\n    usage: get [-h] tkt-num\n\n    Get Ticket docstring\n\n    positional arguments:\n      tkt-num     tkt number to get\n\n    optional arguments:\n      -h, --help  show this help message and exit\n```\n\n## API Documentation\n\nComplete documentation is available [here](http://thrawn01.org/subcommand)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthrawn01%2Fsubcommand","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthrawn01%2Fsubcommand","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthrawn01%2Fsubcommand/lists"}