eepprog.py: Implement Click CategorizedGroup
This commit is contained in:
parent
d9a7cb401d
commit
d17d5341ce
|
|
@ -4,9 +4,10 @@ import click
|
||||||
import serial.tools.list_ports
|
import serial.tools.list_ports
|
||||||
|
|
||||||
from helpers import CliContext, Logger, EepromProgrammer
|
from helpers import CliContext, Logger, EepromProgrammer
|
||||||
|
from helpers.click import CategorizedGroup
|
||||||
|
|
||||||
|
|
||||||
@click.group()
|
@click.group(cls=CategorizedGroup)
|
||||||
@click.option('--device', '-d', default='/dev/ttyUSB0', show_default=True,
|
@click.option('--device', '-d', default='/dev/ttyUSB0', show_default=True,
|
||||||
metavar='DEVICE', help="Set the serial device")
|
metavar='DEVICE', help="Set the serial device")
|
||||||
@click.option('--baud', '-b', default=38400, show_default=True,
|
@click.option('--baud', '-b', default=38400, show_default=True,
|
||||||
|
|
@ -29,7 +30,7 @@ def eepprog(ctx: click.Context, device: str, baud: int, verbose: bool) -> None:
|
||||||
ctx.call_on_close(eeprom_programmer.close)
|
ctx.call_on_close(eeprom_programmer.close)
|
||||||
|
|
||||||
|
|
||||||
@eepprog.command('hello', short_help='Say hello. :)')
|
@eepprog.command('hello', category='Test commands', short_help='Say hello. :)')
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
def hello(context: CliContext) -> None:
|
def hello(context: CliContext) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
@ -46,7 +47,7 @@ def hello(context: CliContext) -> None:
|
||||||
context.logger.success('yay!')
|
context.logger.success('yay!')
|
||||||
|
|
||||||
|
|
||||||
@eepprog.command('test', short_help="Send INIT command to the programmer and read answer")
|
@eepprog.command('test', category='Test commands', short_help="Send INIT command to the programmer and read answer")
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
def test(context: CliContext) -> None:
|
def test(context: CliContext) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
@ -57,7 +58,7 @@ def test(context: CliContext) -> None:
|
||||||
context.eeprom_programmer.test_command()
|
context.eeprom_programmer.test_command()
|
||||||
|
|
||||||
|
|
||||||
@eepprog.command('list-devices', short_help="List available serial ports")
|
@eepprog.command('list-devices', category='Helper commands', short_help="List available serial ports")
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
def list_devices(context: CliContext) -> None:
|
def list_devices(context: CliContext) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
import click
|
||||||
|
import collections
|
||||||
|
|
||||||
|
|
||||||
|
class CategorizedGroup(click.Group):
|
||||||
|
"""
|
||||||
|
Click command group that categorizes subcommands in the help text by the additional 'category' attribute.
|
||||||
|
Commands that don't have a 'category' attribute are grouped under the default category "Commands" as usual.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
`@categorized_group.command('foobar', category='Debug commands')`
|
||||||
|
"""
|
||||||
|
default_category: str
|
||||||
|
|
||||||
|
def __init__(self, name=None, commands=None, default_category: str = 'Commands', **attrs):
|
||||||
|
super().__init__(name, commands, **attrs)
|
||||||
|
self.commands = commands or collections.OrderedDict()
|
||||||
|
self.default_category = default_category
|
||||||
|
|
||||||
|
def list_commands(self, ctx):
|
||||||
|
""" List commands in the order they were added to the group. """
|
||||||
|
return self.commands
|
||||||
|
|
||||||
|
def command(self, *args, **kwargs):
|
||||||
|
""" Extends the command decorator by setting a category attribute on the command. """
|
||||||
|
category = kwargs.pop('category', None)
|
||||||
|
orig_decorator = super().command(*args, **kwargs)
|
||||||
|
|
||||||
|
def decorator(f):
|
||||||
|
cmd = orig_decorator(f)
|
||||||
|
if category:
|
||||||
|
cmd.category = category
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
def format_commands(self, ctx, formatter):
|
||||||
|
"""
|
||||||
|
Prints commands in help messages.
|
||||||
|
This version groups them into categories and is based on the original Group.format_commands method.
|
||||||
|
"""
|
||||||
|
categorized_commands = {self.default_category: []}
|
||||||
|
|
||||||
|
# Collect subcommands grouped by category
|
||||||
|
for subcommand in self.list_commands(ctx):
|
||||||
|
cmd = self.get_command(ctx, subcommand)
|
||||||
|
if cmd is None or cmd.hidden:
|
||||||
|
continue
|
||||||
|
|
||||||
|
category = getattr(cmd, 'category', self.default_category)
|
||||||
|
if categorized_commands.get(category) is None:
|
||||||
|
categorized_commands[category] = []
|
||||||
|
|
||||||
|
categorized_commands[category].append((subcommand, cmd))
|
||||||
|
|
||||||
|
# Print help sections for each subcommand category
|
||||||
|
for category, subcommands in categorized_commands.items():
|
||||||
|
if not len(subcommands):
|
||||||
|
continue
|
||||||
|
|
||||||
|
limit = formatter.width - 6 - max(len(cmd[0]) for cmd in subcommands)
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
for subcommand, cmd in subcommands:
|
||||||
|
help_str = cmd.get_short_help_str(limit)
|
||||||
|
rows.append((subcommand, help_str))
|
||||||
|
|
||||||
|
with formatter.section(category):
|
||||||
|
formatter.write_dl(rows)
|
||||||
Loading…
Reference in New Issue