jw-pkg/src/python/jw/pkg/lib/Cmd.py
Jan Lindemann 7eb15f2477 jw.pkg.lib: Don't log {e}
Don't log an Exception as {e} but as str(e) producing nicer output.
Or as repr(e) if a backtrace is requested, because to people who can
read backtraces, type info might be of interest. Also, remove
pointless time stamps, those belong into the logging framework.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-02-18 11:31:13 +01:00

100 lines
3 KiB
Python

# -*- coding: utf-8 -*-
from __future__ import annotations
from typing import Any
import inspect, sys, re, abc, argparse
from argparse import ArgumentParser, _SubParsersAction
from .log import *
from .Types import Types
class Cmd(abc.ABC): # export
def __init__(self, parent: App|Cmd, name: str, help: str) -> None:
from . import App
self.__parent: App|Cmd|None = parent
self.__app: App|None = None
self.__name = name
self.__help = help
self.__children: list[Cmd] = []
self.__child_classes: list[type[Cmd]] = []
async def _run(self, args):
pass
def set_parent(self, parent: Any|Cmd):
self.__parent = parent
@property
def parent(self) -> App|Cmd:
if self.__parent is None:
raise Exception(f'Tried to access inexistent parent of command {self.name}')
return self.__parent
@property
def app(self) -> App:
from .App import App
if self.__app is None:
parent = self.__parent
while True:
if parent is None:
raise Exception("Can't get application object from command without parent")
if isinstance(parent, App):
self.__app = parent
break
assert parent != parent.__parent
parent = parent.__parent
return self.__app
@property
def name(self) -> str:
return self.__name
@property
def help(self) -> str:
return self.__help
@property
def children(self) -> list[Cmd]:
return tuple(self.__children)
@property
def child_classes(self) -> list[type[Cmd]]:
return tuple(self.__child_classes)
async def run(self, args):
return await self._run(args)
@abc.abstractmethod
async def _run(self, args):
pass
def add_subcommands(self, cmds: Cmd|list[Cmds]|Types|list[Types]) -> None:
if isinstance(cmds, Cmd):
assert False
return
if isinstance(cmds, list):
for cmd in cmds:
self.add_subcommands(cmd)
return
if isinstance(cmds, Types):
try:
for cmd_class in cmds:
if cmd_class in self.__child_classes:
continue
self.__child_classes.append(cmd_class)
cmd = cmd_class(self)
self.__children.append(cmd)
assert len(self.__children) == len(self.__child_classes)
except Exception as e:
cmds.dump(ERR, f"Failed to add subcommands ({str(e)})")
raise
return
raise Exception(f'Tried to add sub-commands of unknown type {type(cmds)}')
# 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
def add_arguments(self, parser: ArgumentParser) -> None:
pass