Package: hermes.typeo
Typeo(Pronounced like the abbreviation of "typographical error")Turn annotated functions into command line scripts with a single line of code, and keep all your documentation!Uses type annotations on functions to parse command line arguments, and strips help strings from function documentation.Basic UsageSay we have a filesay_hello.pythat looks like:defsay_hello(name:str,friendliness:int):"""Say hello with various degrees of friendlinessArgs:name:The name of the person to greetfriendliness:The level of friendliness to greet them with"""iffriendliness==0:print("hey.")eliffriendliness==1:print(f"Hi{name}")eliffriendliness>1:print(f"Hello{name}!")else:raiseValueError("Friendliness level cannot be less than 0")This function can be run as a command line utility by just addingfromhermes.typeoimporttypeo@typeodefsay_hello(name:str,friendliness:int=1):"""Say hello to someone with various degrees of friendlinessArgs:name:The name of the person to greetfriendliness:The level of friendliness to greet them with"""iffriendliness==0:print("hey.")eliffriendliness==1:print(f"Hi{name}")eliffriendliness>1:print(f"Hello{name}!")else:raiseValueError("Friendliness level cannot be less than 0")if__name__=="__main__":say_hello()Now when we run from the command line:$pythonsay_hello.py-husage: say_hello [-h] --name NAME [--friendliness FRIENDLINESS]Say hello to someone with various degrees of friendlinessoptional arguments:-h, --help            show this help message and exit--name NAME           The name of the person to greet (default: None)--friendliness FRIENDLINESSThe level of friendliness to greet them with (default: 1)$pythonsay_hello.py--nameThomHi Thom$pythonsay_hello.py--nameThom--friendliness2Hello Thom!$pythonsay_hello.py--friendliness0usage: say_hello [-h] --name NAME [--friendliness FRIENDLINESS]say_hello: error: the following arguments are required: --nameNote that we can still importsay_helloin other scripts and call it with regular arguments, and its behavior won't be impacted.typeoworks by only reading from the command line if no arguments are passed in.fromsay_helloimportsay_hello# prints "Hi Thom"say_hello("Thom",1)Note also that we can drop theif __name__ == "__main__"syntax if we integrate with Poetry package scripts. For example, if mypyproject.tomlin the directory where I hostsay_hello.pyhas a section like:[tool.poetry.scripts]greet="say_hello:say_hello"Then I can drop theif __name__ == "__main__"fromsay_hello.pyand run my script like this$poetryrungreet--nameThomHi ThomSubcommandsWe can also add subcommands to our scripts. Let's saygreet.pylooks likefromhermes.typeoimporttypeodefvalidate_friendliness(friendliness:int):iffriendliness<0:raiseValueError("Friendliness level cannot be less than 0")defsay_goodbye(name:str,friendliness:int=1):"""Say goodbye to someone with various degrees of friendlinessArgs:name:The name of the person to bid farewellfriendliness:The level of friendliness to bid them farewell with"""validate_friendliness(friendliness)iffriendliness==0:print("bye.")eliffriendliness==1:print(f"Goodbye{name}")else:print(f"So long{name}!")defsay_hello(name:str,friendliness:int=1):"""Say hello to someone with various degrees of friendlinessArgs:name:The name of the person to greetfriendliness:The level of friendliness to greet them with"""validate_friendliness(friendliness)iffriendliness==0:print("hey.")eliffriendliness==1:print(f"Hi{name}")else:print(f"Hello{name}!")@typeo(hello=say_hello,goodbye=say_goodbye)defgreet(greeter:str):print(f"This is a greeting from{greeter}:")if__name__=="__main__":greet()$pythongreet.py-husage: greet [-h] --greeter GREETER {hello,goodbye} ...positional arguments:{hello,goodbye}optional arguments:-h, --help         show this help message and exit--greeter GREETER$pythongreet.pyhello-husage: greet hello [-h] --name NAME [--friendliness FRIENDLINESS]Say hello to someone with various degrees of friendlinessoptional arguments:-h, --help            show this help message and exit--name NAME           The name of the person to greet (default: None)--friendliness FRIENDLINESSThe level of friendliness to greet them with (default: 1)$pythongreet.pygoodbye-husage: greet goodbye [-h] --name NAME [--friendliness FRIENDLINESS]Say goodbye to someone with various degrees of friendlinessoptional arguments:-h, --help            show this help message and exit--name NAME           The name of the person to bid farewell (default: None)--friendliness FRIENDLINESSThe level of friendliness to bid them farewell with (default: 1)$pythongreet.py--greeterJonnyhello--nameThomThis is a greeting from Jonny:Hi Thom$pythongreet.py--greeterPhilgoodbye--nameJonny--friendliness2This is a greeting from Phil:So long Jonny!