lib.Cmd.AbstractCmd.aliases: Add property
Add a property aliases to AbstractCmd in prepeparation for commands to bear multiple names / abbreviations / aliases.
The App.add_cmds_to_parser() function uses parse_known_args() to determine which subcommand was invoked, then conditionally registers nested subcommands. The lookup dictionary (scs) contains only canonical names, not aliases, so add them too, otherwise using the alias instead of the canonical name causes the lookup to fail and nested subcommands to never be registered.
Fix: Register each alias in scs pointing to the same SubCommand object, and deduplicate with id(sc) when iterating in all=True mode to avoid infinite recursion on help output.
Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
parent
9d78eac696
commit
effda76f33
3 changed files with 38 additions and 8 deletions
|
|
@ -6,12 +6,19 @@ from ..App import App as Parent
|
|||
from ..CmdBase import CmdBase as Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Iterable
|
||||
from ..lib.Distro import Distro
|
||||
|
||||
class Cmd(Base): # export
|
||||
|
||||
def __init__(self, parent: Parent, name: str, help: str) -> None:
|
||||
super().__init__(parent, name, help)
|
||||
def __init__(
|
||||
self,
|
||||
parent: Parent,
|
||||
name: str,
|
||||
help: str,
|
||||
aliases: Iterable[str] | None = None
|
||||
) -> None:
|
||||
super().__init__(parent, name, help, aliases = aliases)
|
||||
|
||||
async def _run(self, args):
|
||||
# Missing subcommand
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ class App: # export
|
|||
cmd.name,
|
||||
help = cmd.help,
|
||||
description = cmd.description,
|
||||
aliases = cmd.aliases,
|
||||
formatter_class = ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
parser.set_defaults(func = cmd.run)
|
||||
|
|
@ -88,14 +89,24 @@ class App: # export
|
|||
for cmd in cmds:
|
||||
cmd.set_parent(parent)
|
||||
scs[cmd.name] = SubCommand(cmd, add_cmd_to_parser(cmd, subparsers))
|
||||
for alias in cmd.aliases:
|
||||
scs[alias] = scs[cmd.name]
|
||||
if all:
|
||||
seen: set[int] = set()
|
||||
for sc in scs.values():
|
||||
add_cmds_to_parser(sc.cmd, sc.parser, sc.cmd.children, all = all)
|
||||
if id(sc) not in seen:
|
||||
seen.add(id(sc))
|
||||
add_cmds_to_parser(
|
||||
sc.cmd, sc.parser, sc.cmd.children, all = all
|
||||
)
|
||||
return
|
||||
args, unknown = self.__parser.parse_known_args()
|
||||
if args.command in scs:
|
||||
sc = scs[args.command]
|
||||
add_cmds_to_parser(sc.cmd, sc.parser, sc.cmd.children, all = all)
|
||||
cmd_name = getattr(args, 'command', None)
|
||||
if cmd_name in scs:
|
||||
sc = scs[cmd_name]
|
||||
add_cmds_to_parser(
|
||||
sc.cmd, sc.parser, sc.cmd.children, all = all
|
||||
)
|
||||
|
||||
from .Cmd import AbstractCmd
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ from .Types import LoadTypes, Types
|
|||
|
||||
if TYPE_CHECKING:
|
||||
from argparse import ArgumentParser
|
||||
from typing import Any
|
||||
from typing import Any, Iterable
|
||||
|
||||
from .App import App
|
||||
|
||||
|
|
@ -150,6 +150,13 @@ class AbstractCmd(abc.ABC):
|
|||
def description(self) -> str:
|
||||
return self._description()
|
||||
|
||||
def _aliases(self) -> Iterable[str]:
|
||||
return []
|
||||
|
||||
@property
|
||||
def aliases(self) -> Iterable[str]:
|
||||
return self._aliases()
|
||||
|
||||
class Cmd(AbstractCmd): # export
|
||||
|
||||
def __init__(
|
||||
|
|
@ -157,12 +164,14 @@ class Cmd(AbstractCmd): # export
|
|||
parent: App | Cmd,
|
||||
name: str,
|
||||
help: str,
|
||||
description: str | None = None
|
||||
description: str | None = None,
|
||||
aliases: Iterable[str] | None = None
|
||||
) -> None:
|
||||
super().__init__(parent)
|
||||
self.__name = name
|
||||
self.__help = help
|
||||
self.__description = description if description else help
|
||||
self.__aliases = aliases if aliases else []
|
||||
|
||||
def _name(self) -> str:
|
||||
return self.__name
|
||||
|
|
@ -172,3 +181,6 @@ class Cmd(AbstractCmd): # export
|
|||
|
||||
def _description(self) -> str:
|
||||
return self.__description
|
||||
|
||||
def _aliases(self) -> Iterable[str]:
|
||||
return self.__aliases
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue