Package: jobtools
jobtoolsThis package contains a convenient way to invokePythoncode from the command line to execute jobs of any kind.General ideaTo run aPythonfile from the command line you can do something likepython task.py, considering that you have a file calledtask.py. However, if you routine needs parameters, then you have to do all the parsing of the arguments by hand. This has some limitations:Naming conventions in bash or Windows Command line are different. For instance parameters in bash are usually indicated as--my-parameterwhile inPythonthe-character is not valid.Type parsing has to be done by hand withargparser.It requires to handle how the file is invoked.Complex types are hard to indicate.This leads to a lot of repetitive code being done each time you want to execute code inPythonfrom the command line. This library seeks to help to do:Automatic parameters parsing.Automatic enforcement and detection of optional parameters.Automatic naming convention matching (args like--my-parameterare passed asmy_parameter).Support for some complex types.HowThe code that you want to execute will be indicated in a callable function. Arguments for the callable are automatically parsed from the command line and enforced depending on if they are required or not. Parameters with a default value are inferred to be optional while parameters without one are marked required. Type conversion is automatically handled using type hints. Special type conversion is supported for arguments of typeSimpleNamespacewhich can be passed as arguments usingYMLorJSONfiles. Enumerators are also supported as arguments. SeeUsing enumerators as argumentsfor details.How isjobtoolsdifferent fromclick?At first,jobtoolsmay look very similar toclick. However,clickis intended to create command line tools using Python. That means that the code that you are writing has to be modified to meetclickrequirements. You source code is coupled with the wayclickworks (you will importclickin your namespace, add decorators, etc). On the other hand,jobtoolsis intended to be  generic way to execute Python code from the command line. No modifications shall be made to the source code in order to execute the code usingjobtools(besides adding type hints). Some advance features, like enums, may be facilitated by importingjobtoolsbut it is not required as you can implement enumerators in your code in a native Pythonic way. Then, you code can be completely decoupled fromjobtools.Usagetask.pyfromtypesimportSimpleNamespacedefmytask(name:str,max_buffer:int,params:SimpleNamespace,optional_arg:int=10)->int:"""This is the function you want to run"""...text=f'parameters are automatically parse so I can use{name}. Since params\is a `SimpleNamespace` argument, then the `YML` file structure will\be mapped. I can use{params.trips.origin}and{params.trips.destiny}\including{params.budget}.'print(text)return...Then this file can be called using the commandjobtoolsorpyrunit(they are aliases):jobtoolstask.pymytask--name"my name"--max-buffer1024--paramsparams.ymlorjobtoolstask.pymytask--name"my name"--max-buffer1024--paramsparams.yml--optional-arg15The correspondingYMLfile would be like:params.ymltrips:origin:'BUE'destiny:'SFO'budget:700Other ways to run itBothjobtoolsandpyrunitare bash scripts installed by pipx. If you environment cannot access them because of how it is set, then you have alternatives:As aPythonmodule:python-mjobtoolstask.pyMyTask--arg1value1Handling the execution yourself:pythontask.py--arg1value1In yourPythonscript add:fromjobtools.runnerimportTaskRunnerdefMyMethod(arg1:str):(...)if__name__=="__main__":tr=TaskRunner()tr.run(MyMethod)Using enumerators as argumentsYou can use enumerators as parameters of your jobs. This results handy when you want to enforce specific values instead of handling strings as parameters. You can indicate a parameters as an enumerator using the classjobtools.arguments.StringEnumlike follows:fromtypesimportSimpleNamespacefromjobtools.argumentsimportStringEnumclassCompareStrategy(StringEnum):BIGGER_BETTER='Bigger is better'SMALLER_BETTER='Smaller is better'defmytask(name:str,logic:CompareStrategy=CompareStrategy.BIGGER_BETTER)->int:"""This is the function you want to run"""...iflogic==CompareStrategy.BIGGER_BETTER:...return...Then this file can be called as:jobtoolstask.pymytask--name"my name"--logic"Bigger is better"The values in the argumentlogicneeds to be any of the choices in the enum indicated in the type. This is automatically enforced.Running functions in packages/modules (new in version 0.0.12)Sometimes, you code is packaged inside of a Python package or module. In the following example, assuming that you have a module that can be loaded from the path you are currently located, you can usejobtoolsto run them using the following sintax:jobtoolsmypkg.mymodule.mysubmodmy_task--arg1value1--arg2value2The package should be resolvable from the location you are invoking the method. If it is a local package, then you should be placed outside of the package itself.Loading and saving configuration files fromYAMLandJSON(new in version 0.0.14)jobtoolsextends the support ofSimpleNamespacein the classParamsNamespacewhich supports loading and writing configuration files directly. This is useful when authoring the configuration files in Jupyter Notebooks for instance. You can construct the configuration and save it like this:fromjobtools.argumentsimportParamsNamespaceparams=ParamsNamespace()params.argument1=123params.argument2="this is a string"params.save('params.yml')In the same way, loading can be done with:fromjobtools.argumentsimportParamsNamespaceParamsNamespace.load('params.yml)Note that this functionality is added mostly for helping unit testing or fast creation of configuration files. We do not recommend loading configuration files manually, but to rely on using parameters of typeSimpleNamespacewhichjobtoolsautomatically map to configuration files.Displaying helpYou can display help about how to run an specific function by using the flag--helpor-h. Note how argument typing help is also provided including: possible values for enums, type hints and optional vs required arguments.>jobtoolstask.pymytask--help

usage:jobtoolstask.pymytask[-h]--integerINTEGER--decimalDECIMAL--compare-strategy{Biggerisbetter,Smallerisbetter}[--booleanBOOLEAN]positionalarguments:task_types.pymytask

arguments:-h,--helpshowthishelpmessageandexit--integerINTEGERoftypeint--decimalDECIMALoftypefloat--compare-strategy{Biggerisbetter,Smallerisbetter}optionalarguments:--booleanBOOLEANoftypeboolContributingIdeas and contributions are more than welcome!