lib.Cmd.load_subcommands(): Add method

Push cmds.Cmd._add_subcommands() as lib.Cmd.load_subcommands() one step up to the top of the type hierarchy ladder.

By default, it does the same thing, i.e. load subcommands matching frobnicate.Cmd* if called on class CmdFrobnicate.

This commit also replaces invocations of Cmd._add_subcommands() by invocations of this new method.

Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
Jan Lindemann 2026-05-01 10:17:24 +02:00
commit 7e2099877c
Signed by: Jan Lindemann
GPG key ID: 3750640C9E25DD61
8 changed files with 16 additions and 14 deletions

View file

@ -6,19 +6,12 @@ from argparse import ArgumentParser
from ..App import App from ..App import App
from ..lib.Cmd import Cmd as Base from ..lib.Cmd import Cmd as Base
from ..lib.Types import LoadTypes
class Cmd(Base): # export class Cmd(Base): # export
def __init__(self, parent: App|Base, name: str, help: str) -> None: def __init__(self, parent: App|Base, name: str, help: str) -> None:
super().__init__(parent, name, help) super().__init__(parent, name, help)
def _add_subcommands(self) -> None:
# Derive module search path for the calling module's subcommands from
# the module path of the calling module itself
cmds_module = type(self).__module__.replace('Cmd', '').lower()
self.add_subcommands(LoadTypes([cmds_module], type_name_filter=r'Cmd[^.]'))
async def _run(self, args): async def _run(self, args):
import sys import sys
# Missing subcommand # Missing subcommand

View file

@ -9,7 +9,7 @@ class CmdPkg(CmdBase): # export
def __init__(self, parent: App) -> None: def __init__(self, parent: App) -> None:
super().__init__(parent, 'pkg', help="System package manager wrapper") super().__init__(parent, 'pkg', help="System package manager wrapper")
self._add_subcommands() self.load_subcommands()
def add_arguments(self, p: ArgumentParser) -> None: def add_arguments(self, p: ArgumentParser) -> None:
super().add_arguments(p) super().add_arguments(p)

View file

@ -9,7 +9,7 @@ class CmdPlatform(CmdBase): # export
def __init__(self, parent: App) -> None: def __init__(self, parent: App) -> None:
super().__init__(parent, 'platform', help="Miscellaneous platform-related comamnds") super().__init__(parent, 'platform', help="Miscellaneous platform-related comamnds")
self._add_subcommands() self.load_subcommands()
def add_arguments(self, p: ArgumentParser) -> None: def add_arguments(self, p: ArgumentParser) -> None:
super().add_arguments(p) super().add_arguments(p)

View file

@ -9,7 +9,7 @@ class CmdPosix(CmdBase): # export
def __init__(self, parent: App) -> None: def __init__(self, parent: App) -> None:
super().__init__(parent, 'posix', help='Perform various operations on a distro through its POSIX utility interface') super().__init__(parent, 'posix', help='Perform various operations on a distro through its POSIX utility interface')
self._add_subcommands() self.load_subcommands()
def add_arguments(self, p: ArgumentParser) -> None: def add_arguments(self, p: ArgumentParser) -> None:
super().add_arguments(p) super().add_arguments(p)

View file

@ -10,7 +10,7 @@ class CmdProjects(CmdBase): # export
def __init__(self, parent: App) -> None: def __init__(self, parent: App) -> None:
super().__init__(parent, 'projects', help='Project metadata evaluation for building packages') super().__init__(parent, 'projects', help='Project metadata evaluation for building packages')
self._add_subcommands() self.load_subcommands()
def add_arguments(self, p: ArgumentParser) -> None: def add_arguments(self, p: ArgumentParser) -> None:
super().add_arguments(p) super().add_arguments(p)

View file

@ -9,7 +9,7 @@ class CmdSecrets(CmdBase): # export
def __init__(self, parent: App) -> None: def __init__(self, parent: App) -> None:
super().__init__(parent, 'secrets', help="Manage package secrets") super().__init__(parent, 'secrets', help="Manage package secrets")
self._add_subcommands() self.load_subcommands()
def add_arguments(self, p: ArgumentParser) -> None: def add_arguments(self, p: ArgumentParser) -> None:
super().add_arguments(p) super().add_arguments(p)

View file

@ -9,7 +9,7 @@ class CmdTar(Cmd): # export
def __init__(self, parent: CmdPosix) -> None: def __init__(self, parent: CmdPosix) -> None:
super().__init__(parent, 'tar', help='Handle tar archives') super().__init__(parent, 'tar', help='Handle tar archives')
self._add_subcommands() self.load_subcommands()
def add_arguments(self, parser: ArgumentParser) -> None: def add_arguments(self, parser: ArgumentParser) -> None:
super().add_arguments(parser) super().add_arguments(parser)

View file

@ -8,7 +8,7 @@ import inspect, sys, re, abc, argparse
from argparse import ArgumentParser, _SubParsersAction from argparse import ArgumentParser, _SubParsersAction
from .log import * from .log import *
from .Types import Types from .Types import Types, LoadTypes
class Cmd(abc.ABC): # export class Cmd(abc.ABC): # export
@ -106,6 +106,15 @@ class Cmd(abc.ABC): # export
return return
raise Exception(f'Tried to add sub-commands of unknown type {type(cmds)}') raise Exception(f'Tried to add sub-commands of unknown type {type(cmds)}')
def load_subcommands(self, modules: str|list[str]|None=None, name_filter: str=r'Cmd[^.]') -> None:
if modules is None:
# Derive module search path for the calling module's subcommands
# from the module path of the calling module itself
modules = [type(self).__module__.replace('Cmd', '').lower()]
elif isinstance(modules, str):
modules = [modules]
self.add_subcommands(LoadTypes(modules, type_name_filter=name_filter))
# To be overridden by derived class in case the command does take arguments. # To be overridden by derived class in case the command does take arguments.
# Will be called from App base class constructor and set up the parser hierarchy # Will be called from App base class constructor and set up the parser hierarchy
def add_arguments(self, parser: ArgumentParser) -> None: def add_arguments(self, parser: ArgumentParser) -> None: