~brenns10/subc

4442027a16856ca973d81cbc07d5eb2f7385f9bd — Stephen Brennan 2 years ago cc544f0
Allow command subclasses, which are not instantiated
1 files changed, 17 insertions(+), 5 deletions(-)

M subc.py
M subc.py => subc.py +17 -5
@@ 3,6 3,7 @@
A simple sub-command library for writing rich CLIs
"""
import argparse
import collections
from abc import ABC
from abc import abstractproperty
from abc import abstractmethod


@@ 62,11 63,22 @@ class Command(ABC):
    def add_commands(cls, parser):
        # type: (argparse.ArgumentParser) -> None
        subparsers = parser.add_subparsers(title='sub-command')
        for subcls in cls.__subclasses__():
            cmd = subcls()
            cmd_parser = subparsers.add_parser(cmd.name, description=cmd.description)
            cmd.add_args(cmd_parser)
            cmd_parser.set_defaults(func=cmd.base_run)
        subclasses = collections.deque(cls.__subclasses__())
        while subclasses:
            subcls = subclasses.popleft()
            this_node_subclasses = subcls.__subclasses__()
            if this_node_subclasses:
                # Assume that any class with children is not executable. Add
                # its children to the queue (BFS) but do not instantiate it.
                subclasses.extend(this_node_subclasses)
            else:
                cmd = subcls()
                cmd_parser = subparsers.add_parser(
                    cmd.name, description=cmd.description
                )
                cmd.add_args(cmd_parser)
                cmd_parser.set_defaults(func=cmd.base_run)

        def default(*args, **kwargs):
            raise Exception('you must select a sub-command')
        parser.set_defaults(func=default)