Refactor CLI implementation: add help callback and improve help handling; update setup.py dependencies

This commit is contained in:
Chipperfluff 2026-04-03 14:31:06 +02:00
parent c9176dbbce
commit 37eaee3dbe
3 changed files with 60 additions and 26 deletions

View File

@ -1,7 +1,12 @@
from cli import CLI from .cli import CLI
def help_text():
return [
"%bold%%cyan%nut CLI ... you expected a help menu? cute :3%reset%"
]
def main(): def main():
cli = CLI("nut") cli = CLI(help_callback=help_text)
cli.command("run") \ cli.command("run") \
.flag("debug", "d") \ .flag("debug", "d") \
@ -12,17 +17,13 @@ def main():
return cli.run() return cli.run()
def cmd_run(subcommands, flags): def cmd_run(args, flags):
print("RUN") print("RUN", args, flags)
print("sub:", subcommands)
print("flags:", flags)
return 0 return 0
def cmd_build(subcommands, flags): def cmd_build(args, flags):
print("BUILD") print("BUILD", args, flags)
print("sub:", subcommands)
print("flags:", flags)
return 0 return 0
if __name__ == "__main__": if __name__ == "__main__":
raise SystemExit(main()) raise SystemExit(main())

View File

@ -1,46 +1,78 @@
import argparse import argparse
from colorama import Fore, Style, init
init(autoreset=True)
class CLI: class CLI:
def __init__(self, prog="nut"): def __init__(self, prog="nut", help_callback=None):
self.parser = argparse.ArgumentParser(prog=prog) self.parser = argparse.ArgumentParser(prog=prog, add_help=False)
self.subparsers = self.parser.add_subparsers(dest="command", required=True) self.subparsers = self.parser.add_subparsers(dest="command")
self.help_callback = help_callback
self.parser.add_argument("-h", "--help", action="store_true")
def command(self, name): def command(self, name):
parser = self.subparsers.add_parser(name) parser = self.subparsers.add_parser(name, add_help=False)
cmd = _Command(parser) cmd = _Command(parser)
return cmd return cmd
def run(self): def run(self):
args = self.parser.parse_args() args = self.parser.parse_args()
# extract structured data if getattr(args, "help", False) or not getattr(args, "command", None):
sub_args = getattr(args, "_args", []) if self.help_callback:
for line in self.help_callback():
print(self._color(line))
else:
self.parser.print_help()
return 0
args_list = getattr(args, "_args", [])
flags = { flags = {
k: v for k, v in vars(args).items() k: v for k, v in vars(args).items()
if k not in ("command", "func", "_args") if k not in ("command", "func", "_args", "help")
} }
return args.func(sub_args, flags) return args.func(args_list, flags)
def _color(self, text: str) -> str:
mapping = {
"%red%": Fore.RED,
"%green%": Fore.GREEN,
"%yellow%": Fore.YELLOW,
"%blue%": Fore.BLUE,
"%magenta%": Fore.MAGENTA,
"%cyan%": Fore.CYAN,
"%white%": Fore.WHITE,
"%reset%": Style.RESET_ALL,
"%bold%": Style.BRIGHT,
}
for key, value in mapping.items():
text = text.replace(key, value)
return text
class _Command: class _Command:
def __init__(self, parser): def __init__(self, parser):
self.parser = parser self.parser = parser
self.parser.set_defaults(func=self._missing) self.parser.set_defaults(func=self._missing)
# default catch-all args
self.parser.add_argument("_args", nargs="*") self.parser.add_argument("_args", nargs="*")
self.parser.add_argument("-h", "--help", action="store_true")
def arg(self, name, **kwargs): def arg(self, name, **kwargs):
self.parser.add_argument(name, **kwargs) self.parser.add_argument(name, **kwargs)
return self return self
def flag(self, name, short=None): def flag(self, name, short=None):
flags = [f"--{name}"] opts = [f"--{name}"]
if short: if short:
flags.append(f"-{short}") opts.append(f"-{short}")
self.parser.add_argument(*flags, action="store_true") self.parser.add_argument(*opts, action="store_true")
return self return self
def handle(self, func): def handle(self, func):
@ -48,4 +80,5 @@ class _Command:
return self return self
def _missing(self, *_): def _missing(self, *_):
raise RuntimeError("No handler defined for command") raise RuntimeError("No handler defined")

View File

@ -7,5 +7,5 @@ setup(
author="Chipperfluff", author="Chipperfluff",
packages=find_packages(), packages=find_packages(),
python_requires=">=3.8", python_requires=">=3.8",
install_requires=["chipenv"], install_requires=["chipenv", "colorama", "PyYAML"],
) )