lib.App: Add root command slot #66
Loading…
Reference in a new issue
No description provided.
Delete branch "jan/feature/20260817-lib-app-add-cmd-to-parser-make-sub-parser"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Up to now, options and run() of an Application object derived from lib.App have to be defined by reimplementation in inheriting classes. What subcommands do, OTOH, is defined in classes derived from lib.AbstractCmd. This PR makes it possible to use classes derived from lib.AbstractCmd as defining source of what an application does at its root.
lib.App.add_cmd_to_parser -> .make_sub_parser()
Code beautification: add_cmd_to_parser() isn't very telling about its return type and the fact that it creates an object, hence the name change. Also, annotate its argument with a private argparse type to avoid a cast. My concern that argparse will break the private type at some point in the future is outweighed by the gained clode clarity in this function.
lib.App: Add a root command slot
The application's top-level behavior is defined by overriding App._add_arguments() and App._run(). The lightweight run-and-options unit, Cmd, can already be mounted at any node of the command tree, but the root is reserved for the application itself. An application that wants to host a plain command at the top level therefore has to subclass App and carry its full lifecycle implementation.
Add a root parameter to App.init(). When it is given a command class, App instantiates it and uses it as the top level: the command's options are registered on the top-level parser, it becomes the parent of the top-level subcommands, and App._run() delegates the run to it. The command's children are wired as the top-level subcommands, so the same Cmd can now occupy the root node. When root is not given, the previous auto-discovery behavior is preserved unchanged.
Keep the top-level subcommand heading as plain "Available subcommands" whether it is hosted by the application or by a root command, while nested command levels continue to qualify the heading with the parent name. Add a unit test that mounts a root command hosting a child and checks option registration, dispatch, setup and teardown, and resolution of the application through the parent chain.
lib.App.add_cmd_to_parser -> .make_sub_parser()to lib.App: Add root command slot