Package: lethargy
Lethargy: Terse & tiny command-line option libraryLethargy was born out of frustration. It gets out of your way as soon as possible to let you get on with the actual logic. No bullshit, no magic, no objects to understand, you just call a function.I write a lot of small scripts to get my job done faster, and manually working with options is a pain. Existing libraries are extremely verbose or just don't feel good to use.Lethargy is designed to make writing scripts easier and faster, and to reduce effort needed to maintain them.No boilerplate.Headaches are directly proportional to lines of code.No bloat.Small API surface area, very little to learn.No ambiguity.Lethargy raises exceptions instead of getting your code into bad state.Clear errors.Great error messages and context managers for dealing with them.Flexible.You're not locked in to any styles or paradigms.Lethargy is completely imperative and isnota framework. If youarebuilding a complete CLI or want automatic help commands, you're better off usingClick— a fantastic, declarative CLI framework.InstallationYou can use pip to install lethargy. It's tiny and only depends on the standard library.pip install lethargyUsageimportlethargy# Accepts the option '--bytes <int>'. Show the error nicely if it goes wrong.withlethargy.show_errors():n_bytes=lethargy.take_opt('bytes',1,int)or8# Now the option and value have been removed from lethargy.argvwithlethargy.expect(IndexError,reason='Missing required argument: [DIR]'):directory=lethargy.argv[1]...Getting StartedThis is both a tutorial and the documentation. All examples assume you've gotimport lethargyat the top.FLAGSOptions can be flags.Trueif present,Falseif not.# --debugdebug=lethargy.take_opt('debug')print(debug)$pythonexample.py--debugTrue$pythonexample.pyFalseNAMESOptions can have more than one name.Instead of a string, use a list of strings. Names are case-sensitive.# -v|--verboseverbose=lethargy.take_opt(['v','verbose'])print(verbose)$pythonexample.py-vTrue$pythonexample.py--verboseTrue💡Names are created automatically (POSIX style) if the given names start with a letter or number. Names like'-test'and'/f'are treated as literal because of the first character.ARGUMENTSOptions can take arguments, too.They can take any amount, and values arealwaysspace-separated.# -o|--output <value>output=lethargy.take_opt(['o','output'],1)print(output)$pythonexample.py-oout.txtout.txt$pythonexample.pyNone💡If there are fewer values than what the option takes, it'll raiselethargy.ArgsError. SeeError Handlingfor how to present error messages nicely.GREEDINESSOptions can be variadic (greedy).Use...instead of a number to take every value following the option.# -i|--ignore [value]...ignored=lethargy.take_opt(['i','ignore'],...)forpatterninignored:print(pattern)$pythonexample.py--ignore.git.vscode.DS_Store.git.vscode.DS_Store$pythonexample.py--ignoreexperimentsexperiments$pythonexample.py$▏💡Variadic options are greedy and will takeeveryargument that follows them, including values that look like other options. You should always try and take these last (aftertaking the fixed-count options).UNPACKINGUnpack multiple values into separate variables.If the option wasn't present, they'll all beNone.# --name <value> <value> <value>first,middle,last=lethargy.take_opt('name',3)print(f'Hi,{first}!')$pythonexample.py--nameDwightKurtSchruteHi, Dwight!$pythonexample.pyHi, None!DEFAULTSSet sensible defaults.Use theorkeyword and your default value(s).# -h|--set-hours <value> <value>start,finish=lethargy.take_opt(['set hours','h'],2)or'9AM','5PM'print(f'Employee now works{start}to{finish}')$pythonexample.pyEmployee works 9AM to 5PM$pythonexample.py--set-hours8AM4PMEmployee works 8AM to 4PM💡You should use defaults unless your option explicitly setsrequired=True. You'll thank yourself when you need to change something 6 months from now!TYPES & CONVERSIONConvert your option's values.Use a function or type as the final argument. Defaults aren't converted.# --date-ymd <int> <int> <int>y,m,d=lethargy.take_opt('date ymd',3,int)or1970,1,1fromdatetimeimportdatetimedate=datetime(y,m,d)delta=datetime.today()-dateprint(f'it has been{delta.days}days since{date}')$pythonexample.py--date-ymd1999109it has been 7500 days since 1999-10-09 00:00:00ERROR HANDLINGGive clear error messages.Lethargy makes this easy with simple context managers.withlethargy.show_errors():x,y=lethargy.take_opt(['p','pos'],2,int)or0,0$pythonexample.py--pos20Expected 2 arguments for option '-p|--pos <int> <int>', but found 1 ('20')$pythonexample.py-p20,0Option '-p|--pos <int> <int>' received an invalid value: '20,'Learn more about handling errorsUsefail()to exit with status code 1. You can optionally give it a message.Lethargy provides two context managers for easier error handling. These share similar behaviour, but are separate to make intent clearer.withlethargy.expect(*errors: Exception, reason: Optional[str] = None)When one of the given exceptions is raised, it callsfail()to exit and print the message.withlethargy.show_errors()Same behaviour asexpect, but specifically for handling options. Exceptions raised during value conversions will also be caught byshow_errors(), with a useful message.💡You can access the original exception that caused aTransformErrorwith the__cause__attribute (see the PythonBuilt-in Exceptionsdocs).ContributingAny and all contributions are absolutely welcome. Feel free to open an issue or just jump straight to a PR. Let's discuss and make this the best it can be! 😄LicenseLethargy is released under theMIT license.