Package: ackermann
Ackermann - Command/Config LibraryThis library simplifies the startup process of a more complicated python project with multiple
subcommands, a complicated configuration, aswell as certain targets that need to be run
or initialized before starting commands in a specific order.The point of this library is to easily provide a way to setup a commandline interface usingloggingandargparseandcontextvarsthat looks like this:my-programm-vvv-c<config_file.py>my-custom-command--my-custom-optionsWhile providing a default way of starting the programm you might implemented way. Just have a look
atackermann.units. The main purpose of this library is just to provide an extentable way to
implement commands and startup targets.UsageThe most simple setup is just to callackermann.runin your__main__file, like so:fromackermannimportrunfromackermann.unitsimportrun_commandrun(targets=[run_command])Now if you execute your module withpython -m <module>you can specify a config with-cchange the verbosity level with-vand specify a subcommand.CommandsIf you want to write your own command you can do so:fromackermannimportCommand,ConfigfromargparseimportArgumentParserfromtimeimportsleepclassMyCommand(Command):name="my-command"@classmethoddefget_arguments(cls,parser:ArgumentParser):parser.add_argument("-s","--skip",action="store_true")defrun(self,config:Config):ifconfig["ARGS"].skip:print("You wanted to skip")else:print("We are doing it as you are not skipping")sleep(1000)If you run your program as suggested you are able to run this command with:python-m<project>my-command-sThe same works forasynccommands aswell:fromackermannimportCommand,ConfigfromargparseimportArgumentParserfromasyncioimportsleepclassMyAsyncCommand(Command):name="my-async-command"is_async=True@classmethoddefget_arguments(cls,parser:ArgumentParser):parser.add_argument("-s","--skip",action="store_true")asyncdefasync_run(self,config:Config):ifconfig["ARGS"].skip:print("You wanted to skip")else:print("We are doing it as you are not skipping")awaitsleep(1000)running this command would look like this:python-m<project>my-async-command-sTargets / UnitsMore complicated commands might want to reuse certain parts of code to initialize their project in
the correct way. For thisackermannhasConfigUnits. These work pretty similiar to context
managers around your command.A unit might be defined like this:fromackermannimportConfig,config_unit@config_unitasyncdefdo_sth(config:Config):print("I want to do sth before my command starts")yieldprint("Now I need to cleanup as the command finished")This unit will not run by default, but it must be explicitly stated in the command. Using thetargetsvariable. Config units might depend on each other, might conflict with one another or must
be run in a certain order.
They might also force the programm to be run in an async context or on multiple processors.SignalsIf your programm needs to signal certain parts of code about it's state you might also add signals.
To your config by default before executing a command ackermann will signalreadyand after
exiting a command it will signalstopping. This might be used to signal systemd in case of using
a notify service.Config VariablesAll commands, units and signals are called with the current instance ofConfigwhich itself
stores configuration variables that might be stored in a python module supplied with the-cflag.
If you want to explicitly tell the programm about these variables you can use the small wrapperackermann.ConfigVararoundcontextvars.ContextVarwhich allows you to specify the format,
type, and default value for a config variable.These variables might then be imported in your programm without worrying where the get the correct
value like so:fromackermannimportConfigVarconfig_my_config_var=ConfigVar("MY_CONFIG_VAR",description="Does something",type=int,default=0)# At some point in the codedefdo_sth():my_config_var_value=config_my_config_var.get()One benefit of using this interface is that you can easily check the variables set when starting the
programm with the-Vflag.