I have one large click application that I've developed, but navigating through the different commands/subcommands is getting rough. How do I organize my commands into separate files? Is it possible to organize commands and their subcommands into separate classes?
Here's an example of how I would like to separate it:
import click @click.group() @click.version_option() def cli(): pass #Entry Point
@cli.group() @click.pass_context def cloudflare(ctx): pass @cloudflare.group('zone') def cloudflare_zone(): pass @cloudflare_zone.command('add') @click.option('--jumpstart', '-j', default=True) @click.option('--organization', '-o', default='') @click.argument('url') @click.pass_obj @__cf_error_handler def cloudflare_zone_add(ctx, url, jumpstart, organization): pass @cloudflare.group('record') def cloudflare_record(): pass @cloudflare_record.command('add') @click.option('--ttl', '-t') @click.argument('domain') @click.argument('name') @click.argument('type') @click.argument('content') @click.pass_obj @__cf_error_handler def cloudflare_record_add(ctx, domain, name, type, content, ttl): pass @cloudflare_record.command('edit') @click.option('--ttl', '-t') @click.argument('domain') @click.argument('name') @click.argument('type') @click.argument('content') @click.pass_obj @__cf_error_handler def cloudflare_record_edit(ctx, domain): pass
@cli.group() @click.pass_context def uptimerobot(ctx): pass @uptimerobot.command('add') @click.option('--alert', '-a', default=True) @click.argument('name') @click.argument('url') @click.pass_obj def uptimerobot_add(ctx, name, url, alert): pass @uptimerobot.command('delete') @click.argument('names', nargs=-1, required=True) @click.pass_obj def uptimerobot_delete(ctx, names): pass
When a Click command callback is executed, it's passed all the non-hidden parameters as keyword arguments. Notably absent is the context. However, a callback can opt into being passed to the context object by marking itself with pass_context() .
Argparse is designed to parse arguments and provide extensive customization of cli help documentation. Click is designed to automatically handle common cli command tasks and quickly build a standard help menu.
I will use the ll and wc commands to highlight file changes. I advise you to have a quick look at the wc command to understand the output of the split command examples. Let’s see how to use it to split files in Linux. 1. Split files into multiple files By default, split command creates new files for each 1000 lines.
I advise you to have a quick look at the wc command to understand the output of the split command examples. Let’s see how to use it to split files in Linux. 1. Split files into multiple files By default, split command creates new files for each 1000 lines. If no prefix is specified, it will use ‘x’.
It’s also possible to use file size to break up files in split. Maybe you need to send a large file over a size-capped network as efficiently as possible. You can specify the exact size for your requirements. The syntax can get a little tricky as we continue to add options. So, I will explain how the -b command works before showing the example.
As you can guess, now the split files have 500 lines each, except the last one. Now you have many more files, but with half as many lines in each one. 3. Split the files into n number of files
The downside of using CommandCollection
for this is that it merges your commands and works only with command groups. The imho better alternative is to use add_command
to achieve the same result.
I have a project with the following tree:
cli/ ├── __init__.py ├── cli.py ├── group1 │ ├── __init__.py │ ├── commands.py └── group2 ├── __init__.py └── commands.py
Each subcommand has its own module, what makes it incredibly easy to manage even complex implementations with many more helper classes and files. In each module, the commands.py
file contains the @click
annotations. Example group2/commands.py
:
import click @click.command() def version(): """Display the current version.""" click.echo(_read_version())
If necessary, you could easily create more classes in the module, and import
and use them here, thus giving your CLI the full power of Python's classes and modules.
My cli.py
is the entry point for the whole CLI:
import click from .group1 import commands as group1 from .group2 import commands as group2 @click.group() def entry_point(): pass entry_point.add_command(group1.command_group) entry_point.add_command(group2.version)
With this setup, it is very easy to separate your commands by concerns, and also build additional functionality around them that they might need. It has served me very well so far...
Reference: http://click.pocoo.org/6/quickstart/#nesting-commands
Suppose your project have the following structure:
project/ ├── __init__.py ├── init.py └── commands ├── __init__.py └── cloudflare.py
Groups are nothing more than multiple commands and groups can be nested. You can separate your groups into modules and import them on you init.py
file and add them to the cli
group using the add_command.
Here is a init.py
example:
import click from .commands.cloudflare import cloudflare @click.group() def cli(): pass cli.add_command(cloudflare)
You have to import the cloudflare group which lives inside the cloudflare.py file. Your commands/cloudflare.py
would look like this:
import click @click.group() def cloudflare(): pass @cloudflare.command() def zone(): click.echo('This is the zone subcommand of the cloudflare command')
Then you can run the cloudflare command like this:
$ python init.py cloudflare zone
This information is not very explicit on the documentation but if you look at the source code, which is very well commented, you can see how groups can be nested.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With