Package: clipyarser
clipyarserclipyarseris a simple, declarative and easy-testable command line argument parser.
Inspired byTyper.Simply decorate yournormalpython functions with@clipyarser.mainor@clipyarser.subcommandand
you have a fully working cli program.clipyarserparses the arguments from the console and calls the matching function with the right arguments.TutorialHere we will create a small command line application withclipyarser.SetupCreate a new directory and an emptymain.pyfile.Inmain.pyimportclipyarser:fromclipyarserimportCLICreate a CLI parserTo create aclipyarserparser, simply write this to yourmain.pyfile.fromclipyarserimportClipyarserclipyarser=Clipyarser()Now we create a simple greeting function.@clipyarser.maindefmain(name:str)->str:returnf'Hello{name}'This function simply returns a string which says hello to a person.
The name of the person is specified in the arguments of the function.Note that we use type hints in the function arguments.
This is necessary forclipyarser, because it parses the arguments from the console according to the specified types.
So when adding an argumentagewith typeint,clipyarserdoes the parsing and validation of anintfor you.Now, we have to executeclipyarserwhen the program is run.if__name__=='__main__':clipyarser.run()And that is the first running example ofclipyarser.Now lets test it.$python3main.py
usage:example.py[-h]name{}...
example.py:error:thefollowingargumentsarerequired:nameOk, we have to specify the name of the person we want to greet.
This makes sense, because we takenameas argument in ourmain()function.$python3main.pyLinus
HelloLinusOk nice. That worked.Default Arguments/OptionsSometimes it is convenient that a function has default arguments, which can be overridden when calling the function.
This is also possible withclipyarser. Let's try to take our greeting function from above and extend it with an
optional argument.@clipyarser.maindefmain(name:str,greeting:str='Hello')->str:returnf'{greeting}{name}'So a user can customize the greeting. By default, the greeting is 'Hello', but it can be overridden.
Now let's see how this looks in the console.$python3main.pyLinus
HelloLinus
$python3main.pyLinus--greetingHi
HiLinusPretty intiutive, right?SubcommandsIn a bigger application, you may don't want all logic in amain()function.
Therefore,clipyarserallows you to add subcommands.fromclipyarserimportClipyarserclipyarser=Clipyarser()@clipyarser.subcommanddefadd(a:int,b:int)->int:returna+bThis subcommand is a function which adds to numbers together.$python3main.pyadd246But what has happened to the main function? For simplicity, we have deleted it.
Let's try to add one again.@clipyarser.main
defmain(verbose:bool=False):return'verbose is {verbose}'Now, when calling our application, themain()function always runs.
This might be handy when you have some logic or arguments that are independent of am individual subcommand, like a
more verbose output.$python3main.pyadd32verboseisFalse5$python3main.py--verbosetrueadd32verboseisTrue5Printing multiple linesUntil now when we want to print something to the console, we just returned it.
This might seem ok, but sometimes you want to print multiple lines or want to print something during a calculation.
But simple doprint()is not a good idea. We will se soon why.To print multiple lines, use theyieldstatement.Back to our greeting example from the beginning.fromtimeimportsleepfromclipyarserimportClipyarserclipyarser=Clipyarser()@clipyarser.maindefmain(name:str):yield'Hello'sleep(2)yieldnameyield42$python3main.pyLinus
Hello
Linus42Because yield turnsmain()into a generator function, the output 'Hello' is printed immediately, butnametakes
two seconds to print.Maybe one could think of another solution: Just add all things to be printed to a list and return this list at the
end of the function.
This is bad, because the whole output takes two seconds to print, in particular the 'Hello' line.
This makes yourclipyarsernot very responsive to the end user.Ok. But why is just printing a bad idea? Testing.TestingThe advantage of CLI is simple testing.
Functions likemain()andadd()are normal python functions, so you can call them like normal functions.
They takenormalarguments. They returnnormalthings.
This means that you can also test these functions like normal functions.importunittestfromclipyarserimportClipyarserclipyarser=Clipyarser()classTestMyCli(unittest.TestCase):deftest_greet(self):actual=list(main('Linus'))expected=['Hello','Linus',42]self.assertEqual(actual,expected)Sincemain()is a generator function, we can convert its output to a list and check if it is what we expect.
If usingprint(), this would not be as easy.Ok, this is the end of the tutorial. Have fun usingclipyarser.