mirror of
ssh://git.janware.com/janware/proj/jw-pkg
synced 2026-04-28 10:05:23 +02:00
lib.App, .Cmd: Add modules
Add App and Cmd as generic base classes for multi-command applications. The code is taken from jw-python: The exising jw.pkg.App is very similar to the more capable jwutils.Cmds class, so, to avoid code duplication, add it here to allow for jwutils.Cmds and jw.pkg.App to derive from it at some point in the future. Both had to be slightly modified to work within jw-pkg's less equipped context, and will need futher code cleanup. Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
parent
18467a6500
commit
0be02c7154
2 changed files with 256 additions and 0 deletions
107
src/python/jw/pkg/lib/Cmd.py
Normal file
107
src/python/jw/pkg/lib/Cmd.py
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
# -*- 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
|
||||
|
||||
# full blown example of one level of nested subcommands
|
||||
# git -C project remote -v show -n myremote
|
||||
|
||||
class Cmd(abc.ABC): # export
|
||||
|
||||
def __init__(self, name: str, help: str) -> None:
|
||||
from . import App
|
||||
self.__app: App|None = None
|
||||
self.__parent: App|Cmd|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):
|
||||
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)
|
||||
|
||||
@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()
|
||||
cmd.set_parent(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 ({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
|
||||
|
||||
def conf_value(self, path, default=None):
|
||||
ret = None if self.app is None else self.app.conf_value(path, default)
|
||||
if ret is None and default is not None:
|
||||
return default
|
||||
return ret
|
||||
Loading…
Add table
Add a link
Reference in a new issue