cmdkit.app
#
The Application
class provides structure to command-line interfaces.
Create a new derived application class to share the common boilerplate among
all the entry-points in your project.
Reference#
- class Application(**parameters)[source]#
Abstract base class for all application interfaces.
An application is typically initialized with one of the factory methods
from_namespace()
orfrom_cmdline()
. These parse command-line arguments using the memberInterface
. Direct initialization takes named parameters and are simply assigned to the instance. These should be existing class-level attributes with annotations.- interface: Interface = None#
The command-line argument parser for this application. Calls to
add_argument()
should have their destination set to class-level attribute names.class MyApp(Application): ... interface = Interface('myapp', USAGE_TEXT, HELP_TEXT) output: str = '-' interface.add_argument('-o', '--output', default=output) debug_mode: bool = False interface.add_argument('-d', '--debug', action='store_true', dest='debug_mode')
- ALLOW_NOARGS: bool = False#
By default, if the
cmdline
list of arguments passed tomain()
is empty, the usage text is printed tosys.stdout
andexit_status.success
is returned.If instead the application should proceed to its
run
method even in the absence of any arguments, setALLOW_NOARGS
as a class-level attribute.class MyApp(Application): ... ALLOW_NOARGS = True
- exceptions: Dict[Type[Exception], Callable[[Exception], int]] = {}#
Map of exceptions to catch and their associated handler. The handlers should take an
Exception
instance as the single argument and return an integer value as the exit status to use.def log_and_exit(status: int, error: Exception) -> int: """Log the error message as critical and exit with `status`.""" log.critical(' - '.join(error.args)) return status class MyApp(Application): ... exceptions = { ConfigurationError: functools.partial(log_and_exit, exit_status.bad_config), }
- log_critical: Callable[[str], None] = <bound method Logger.critical of <Logger cmdkit.app (WARNING)>>#
- log_exception: Callable[[str], None] = <bound method Logger.exception of <Logger cmdkit.app (WARNING)>>#
Bound methods used by
main()
to log messages. In the main try/except block, this method is called with a message. This can be overridden by any function with the same interface. It is recommended to override this with your own logger.
- classmethod from_cmdline(cmdline: List[str] | None = None) TApp [source]#
Initialize via command-line arguments (e.g., sys.argv).
- classmethod from_namespace(namespace: Namespace) TApp [source]#
Initialize via existing namespace/namedtuple.
- classmethod main(cmdline: List[str] | None = None, shared: Namespace | None = None) int [source]#
Entry-point for application. This is a try-except block that handles standard scenarios.
- See Also:
The main method should be exposed as an entry-point in your
setup.py
script.def main() -> int: return MyApp.main(sys.argv[1:])
setup( ... # if main() is in myapp.__init__ entry_points = {'console_script': ['myapp=myapp:main']} )
- abstract run() None [source]#
Business-logic of the application.
class MyApp(Application): ... def run(self) -> None: log.info('started')
- __enter__() Application [source]#
Place-holder for context manager.
The
main()
method will essentially call the following on your behalf.with MyApp.from_cmdline(...) as app: app.run()
Placing resource acquisition code here makes it easy to ensure that the proper tear down procedures happen. If you need to open files or acquire connections, place the closing methods in
__exit__()
.class MyApp(Application): ... output: str = '-' output_file: IO = sys.stdout interface.add_argument('-o', '--output', default=output) def __enter__(self) -> MyApp: """Open output file if necessary.""" if self.output != '-': self.output_file = open(self.output, mode='w') def __exit__(self, *exc) -> None: """Close output file if necessary.""" if self.output != '-': self.output_file.close()
A shared
Namespace
with parameters from parent group(s). SeeApplicationGroup
.
- classmethod handle_usage(message: str) None [source]#
Handler method invoked by
main()
when no arguments are given. Default implementation simply prints theinterface.usage_text
.
- classmethod handle_help(message: str) None [source]#
Handler method invoked by
main()
after catching theHelpOption
exception. Default implementation simply prints theinterface.help_text
.
- classmethod handle_version(*args) None [source]#
Handler method invoked by
main()
after catching theVersionOption
exception. Default implementation simply prints the arguments given.
- class ApplicationGroup(**parameters)[source]#
A group entry-point delegates to a member Application.
class MainApp(ApplicationGroup): """Top-level entry-point for a hierarchical interface.""" interface = Interface('myapp', USAGE_TEXT, HELP_TEXT) command: str interface.add_argument('command') commands = { 'config': ConfigApp, 'list': ListApp, 'run': RunApp, }
Shared arguments from parent
ApplicationGroup
.
- ALLOW_PARSE: bool = False#
By default, the
cmdline
list passed tomain()
has its first argument popped and used to lookup which memberApplication
to run.If
ALLOW_PARSE
isTrue
, then known options of the groupinterface
are parsed fromcmdline
and retained in a memberNamespace
,Application.shared
, with the remainder passed on to the down-lineApplication
.class MainApp(ApplicationGroup): ... ALLOW_PARSED = True verbose: bool = False interface.add_argument('--verbose', action='store_true')
- exit_status = (0, 1, 2, 3, 4, 5, 6)#
Collection of exit status values.
This namespace of integer values provides structure to exit status management. It is used internally by the
Application
class. These values can be changed by re-assigning them.