Package: vutils-cli
vutils-cli: Auxiliary Library for Writing CLI ApplicationsThis package provides a set of tools for writing applications with command line
interface.InstallationTo installvutils-cli, type$pipinstallvutils-cliHow to Usevutils-cli provides three mixins:vutils.cli.application.ApplicationMixinproviding methods for launching the
application code and error management;vutils.cli.io.StreamsProxyMixinproviding methods for I/O streams
manipulation;vutils.cli.logging.LoggerMixinproviding methods for logging support.Combined together, these three mixins form a base for creating command line
interface applications. User can make a subclass from each of mixins to reach
desired behavior. A simple application can be made in a way like this:fromvutils.cli.applicationimportApplicationMixinfromvutils.cli.ioimportStreamsProxyMixinfromvutils.cli.loggingimportLoggerMixinclassCommandBase(ApplicationMixin,StreamsProxyMixin,LoggerMixin):def__init__(self):ApplicationMixin.__init__(self)StreamsProxyMixin.__init__(self)LoggerMixin.__init__(self)classApplication(CommandBase):def__init__(self):CommandBase.__init__(self)defmain(self,argv):s=" ".join(argv)self.wout(f"{s}\n")returntype(self).EXIT_SUCCESSApplication.start(__name__)When the application starts, it prints its command line arguments to the
standard output. Methods provided byApplicationMixinrelated to running the
application are:main(self, argv)provides the application entry point. The application
logic should be placed into this method. This method is called fromrunand
the value it returns is used as an application exit code.argvis an array
containing command line arguments.run(self, argv)runsmainand handles errors occurred insidemain.
Returns the exit code returned bymainor byApplicationMixin.exitor byon_errorhandler.start(cls, modname="__main__")runs the application. In greater detail, it
calls therunmethod withsys.argvonly ifmodnameis equal to"__main__".In the example above,CommandBasehas been introduced to indicate that it is
possible to use these three mixins also for implementing subcommands. This is
due no one of these three mixins has a global dependencies.Error ManagementApplicationMixinprovides a set of methods for doing error management:catch(self, exc)register an exceptionexcthat should be caught when it
is raised insidemain. If an exception raised insidemainis not
registered, the exception is not caught and it is propagated outside ofmain.ApplicationErrorfromvutils.cli.errorsis registered by default.error(self, msg, ecode=1)logsmsgand callsApplicationMixin.exitwithecode. To make logging work,ApplicationMixinmust be used together withLoggerMixin(fromvutils.cli.logging) andStreamsProxyMixin(fromvutils.cli.io) mixins.exit(self, ecode)exits the application with the exit codeecode. Unlikesys.exit, it causeson_exithook to be called, ifexithas been invoked
withinmain. Ifexitis called outside themain's stack frame, the
behavior is undefined.on_exit(self, ecode)is a hook which is called whenexithas been invoked
withinmain.ecodeis the exit code given toexit. This method is
dedicated to be overridden by a user. The default implementation logs the
exit event, so to make it work properlyApplicationMixinmust be used
together withLoggerMixinandStreamsProxyMixinmixins.on_error(self, exc)is an exception handler to where a user can put his/her
code to handle the caught exceptionexc. Everything registered bycatchthat comes frommainis caught and passed asexcto this handler. The
value returned by this handler is used as the application's exit code. The
default implementation logs theexcand returnsEXIT_FAILURE, thus the
application must implement logging, at least by inheriting fromLoggerMixinandStreamsProxyMixinmixins.ApplicationMixinalso provides two constantsEXIT_SUCCESSandEXIT_FAILUREwhich equals to 0 and 1, respectively.User can make his/her custom errors by deriving fromApplicationErrorfromvutils.cli.errors. By implementingdetailmethod, user can provide more
detail about his/her error.Input and Output StreamsAddingStreamsProxyMixinfromvutils.cli.ioto the list of base classes of
an application allow to use a set of methods for manipulating streams:set_streams(self, ostream=None, estream=None)set the output and error
output streams.Nonemeans the original setting is left untouched. The
default output and error output stream issys.stdoutandsys.stderr,
respectively.wout(self, text)writestextto the output stream.werr(self, text)writestextto the error output stream.vutils.cli.ioprovides also functions for colorizing the text, namelynocolor,red,green,blue,yellow, andbrown.LoggingAs noted many times above, to support logging, use bothLoggerMixinandStreamsProxyMixinmixins together withApplicationMixin:importpathlibfromvutils.cli.applicationimportApplicationMixinfromvutils.cli.ioimportStreamsProxyMixinfromvutils.cli.loggingimportLoggerMixinclassMyApp(ApplicationMixin,StreamsProxyMixin,LoggerMixin):def__init__(self):ApplicationMixin.__init__(self)StreamsProxyMixin.__init__(self)LoggerMixin.__init__(self)defmain(self,argv):self.set_logger_props(logpath=pathlib.Path("/var/tmp/MyApp.log"))self.linfo("Hello from MyApp!\n")returnApplicationMixin.EXIT_SUCCESSLoggerMixinextendsMyAppabout these methods:set_logger_props(self, logpath=None, formatter=None, vlevel=None, dlevel=None)allows to modify the logging facility properties.logpathsets the path of
the log file,formattersets the new formatter object (seeLogFormatter),vlevelsets the verbosity level, anddlevelsets the debug level. The
initial values of these properties given during the time ofLoggerMixininitialization areNoneforlogpath,LogFormatterinstance forformatter, 1 forvlevel, and 0 fordlevel. A property is set only if a
new value of the property is notNone.set_log_style(self, name, color)sets the style of log messages (currently
only color).nameis the name of the type of log messages. The value should
be one of the following constants provided byLogFormatter:INFO,WARNING,ERROR, andDEBUG.coloris the color function, seevutils.cli.io. This method modifies directly the formatter object set byset_logger_props.wlog(self, msg)writesmsgto the log file if it is set.Following methods write a message to the both error output stream and log
file:linfo(self, msg, vlevel=1): ifvlevelis less or equal to the verbosity
level, issuemsgas an info message.lwarn(self, msg)issuesmsgas a warning message.lerror(self, msg)issuesmsgas an error message.ldebug(self, msg, dlevel=1): ifdlevelis less or equal to the debug
level, issuemsgas a debug message.vutils.cli.loggingprovides also facility for formatting log messages,LogFormatter.LogFormatterprovides four constants to identify four
different types of log messages:INFOfor info messages;WARNINGfor warning messages;ERRORfor error messages;DEBUGfor debug messages.LogFormatter.FORMATcontains a format string used to format every message.
The format string is interpolated usingstr.formatmethod and it recognizeslabelfor the message label andmessagefor the message itself. Methods
provided byLogFormatterare:set_style(self, name, color)sets the style (currently only color) of log
messages.nameis the name of the message type andcoloris the message
color. By default,LogFormatterprintsINFOmessages in blue,WARNINGmessages in yellow,ERRORmessages in red, andDEBUGmessages in brown.colorize(self, name, msg, nocolor=False)colorizesmsgusing the color
associated withnameby previous call ofset_style. IfnocolorisTrueornamehas no color associated with it,msgis not colorized.format(self, name, msg)formatsmsgby interpolatingFORMATwith
uppercasednameaslabelandmsgasmessage. By overriding this
method user can customize how log messages are formatted.