Package: gearup
GearUpHave you ever had a moment, when the code is ready, you are eager to launch it,
you want to know if your new and shiny method works or not, just to realize you need to write
100+ lines ofargparseorclick?Gear up and get ready to go!Quick introAssume your project containsmain.pyscript with the following functions:### main.pydeftrain(method:str,dataset:str,alpha:float):<dostuff>deftest_accuracy(method:str,dataset:str):<dotesting>deftest_robustness(method:str):<dotesting>Just add:if__name__=='__main__':fromgearupimportgearupgearup(train,test=dict(accuracy=test_accuracy,robustness=test_robustness))()and you are ready to go!>pythonmain.pytrainmethod=resnetdataset=mnistalpha=0.01
>pythonmain.pytestaccuracymethod=resnetdataset=mnist
>pythonmain.pytestrobustnessmethod=resnetInstallationAs usual:pipinstallgearuporpipinstallgit+https://gitlab.com/craynn/gearup.gitHow it worksgearup, applied to a function, reads the signature of the function
and infers which arguments should be passed to it:deff(x:int,y:int):returnx+yWhen gear-uped function is called without arguments it readssys.argv,
alternatively, it can be called with a list of strings:gearup(f)(['1','2'])### result = 3gearup(f)()### read from console argumentsgearuprelies onomegaconfandPyYAML:arguments are converted according to YAML rules, e.g.,1is parsed as an integer,1.0--- as a float,'1'--- as a string;keyword arguments, likeclassifier.alpha=1.0, are parsed as adot-list;positional arguments (ones that do not contain=sign) are always passed to the function.After that the underlying function is called:f(*args, **kwargs),passing only the arguments required by the function...Yes, no flags, no aliases, just launch script like
a python function (Haskell style)...>pythonmain.py1y=2Notes:spaces should not appear between argument name,=and argument value:a=xsets value of argumentatox;a = xis interpreted as three separate arguments: two positional:aandx, and a keyword one
(with empty name and value);if you need to supply a value with a space character in it, use quotes:python main.py x='a b c';if you need to supply a value with=character in it, just specify argument name:python main.py x=a=bor, better,python main.py x='a=b';it is impossible to set one of variational positional arguments (*args) to a value,
that contains=character;lists are valid values:python main.py x=[1,2,3,4]or
(in case you want to add spaces)python main.py 'x=[1, 2, 3, 4]'.As a bonus,gearup.apply(f)(*args, **kwargs)provides a Python-friendly way to pass down a subconfig.importgearupdefmethod1(x:int,y:int):returnx+ydefmethod2(x:int,z:float):returnx/zdefmain(method,x:int,**kwargs):ifmethod=='method1':method=method1elifmethod=='method2':method=method2else:raiseValueError()gearup.apply(method,x,**kwargs)if__name__=='__main__':gearup.gearup(main)()CommandsSometimes you need to pack several functions into one script:gearup(train,test)()### orgearup(train=train,test=test)()### orgearup(train,test=test)()>pythonmain.pytrain<argumentsfortrain>
>pythonmain.pytest<argumentsfortest>More precisely, if supplied with more than one argument or at least one keyword argument,gearupconsumes the first CLI argument and
switches between provided functions.Bonus: it is recursive!deftrain(...):passdeftest_fast(...):passdeftest_slow(...):passgearup(train,test=dict(fast=test_fast,slow=test_slow))()>pythonmain.pytrainmethod=resnetalpha=0.1
>pythonmain.pytestslowmethod=resnetNote: when a non-keyword argument is passed togearup,
it reads__name__attribute of this argument. For example,gearup(f1, f2)is equivalent togearup(f1=f1, f2=f2).HelpJust addhelp:> python examples/main.py help
Available commands:
train -> (method, power, alpha: float = 0.001, flag: bool = False)
         Trains method with alpha.
test -> a -> (method)
             Tests method...
        b -> (method)
             Undocumented test function.The helper keyword can be overriden (or turned off) with:gearup(...).without_helper()gearup(...).with_helper(helper=None)gearup(...).with_helper(helper='helpme')Configuration filegearup()can be supplied with a configuration file.gearup(...).with_config('/path/to/config.yaml')The config will be merged with CLI arguments, with the latter having priority:### config.yamlpoint:x:1y:4### main.pydefnorm(point):importmathreturnmath.sqrt(point['x']**2+point['y']**2)if__name__=='__main__':importgearupresult=gearup(norm).with_config('config.yaml')()print(result)>pythonmain.py4.123105625617661
>pythonmain.pypoint.x=35.0