Skip to main content

A minimal library to make your option-parsing easier.

Project description

Lethargy: Terse & tiny command-line option library

Lethargy 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 is not a framework. If you are building a complete CLI or want automatic help commands, you're better off using Click — a fantastic, declarative CLI framework.


You can use pip to install lethargy. It's tiny and only depends on the standard library.

pip install lethargy


import lethargy

# Accepts the option '--bytes <int>'. Show the error nicely if it goes wrong.
with lethargy.show_errors():
    n_bytes = lethargy.take_opt('bytes', 1, int) or 8

# Now the option and value have been removed from lethargy.argv
with lethargy.expect(IndexError, reason='Missing required argument: [DIR]'):
    directory = lethargy.argv[1]


Getting Started

This is both a tutorial and the documentation. All examples assume you've got import lethargy at the top.


Options can be flags. True if present, False if not.

# --debug
debug = lethargy.take_opt('debug')

$ python --debug
$ python


Options can have more than one name. Instead of a string, use a list of strings. Names are case-sensitive.

# -v|--verbose
verbose = lethargy.take_opt(['v', 'verbose'])

$ python -v
$ python --verbose
💡 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.


Options can take arguments, too. They can take any amount, and values are always space-separated.

# -o|--output <value>
output = lethargy.take_opt(['o', 'output'], 1)

$ python -o out.txt
$ python
💡 If there are fewer values than what the option takes, it'll raise lethargy.ArgsError. See Error Handling for how to present error messages nicely.


Options 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'], ...)

for pattern in ignored:
$ python --ignore .git .vscode .DS_Store
$ python --ignore experiments
$ python
💡 Variadic options are greedy and will take every argument that follows them, including values that look like other options. You should always try and take these last (after taking the fixed-count options).


Unpack multiple values into separate variables. If the option wasn't present, they'll all be None.

# --name <value> <value> <value>
first, middle, last = lethargy.take_opt('name', 3)

print(f'Hi, {first}!')
$ python --name Dwight Kurt Schrute
Hi, Dwight!
$ python
Hi, None!


Set sensible defaults. Use the or keyword 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}')
$ python
Employee works 9AM to 5PM
$ python --set-hours 8AM 4PM
Employee works 8AM to 4PM
💡 You should use defaults unless your option explicitly sets required=True. You'll thank yourself when you need to change something 6 months from now!


Convert 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) or 1970, 1, 1

from datetime import datetime
date = datetime(y, m, d)
delta = - date
print(f'it has been {delta.days} days since {date}')
$ python --date-ymd 1999 10 9
it has been 7500 days since 1999-10-09 00:00:00


Give clear error messages. Lethargy makes this easy with simple context managers.

with lethargy.show_errors():
    x, y = lethargy.take_opt(['p', 'pos'], 2, int) or 0, 0
$ python --pos 20
Expected 2 arguments for option '-p|--pos <int> <int>', but found 1 ('20')
$ python -p 20, 0
Option '-p|--pos <int> <int>' received an invalid value: '20,'
Learn more about handling errors

Use fail() 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.

with lethargy.expect(*errors: Exception, reason: Optional[str] = None)

When one of the given exceptions is raised, it calls fail() to exit and print the message.

with lethargy.show_errors()

Same behaviour as expect, but specifically for handling options. Exceptions raised during value conversions will also be caught by show_errors(), with a useful message.

💡 You can access the original exception that caused a TransformError with the __cause__ attribute (see the Python Built-in Exceptions docs).


Any 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! 😄


Lethargy is released under the MIT license.

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lethargy-3.1.0.tar.gz (9.3 kB view hashes)

Uploaded Source

Built Distribution

lethargy-3.1.0-py3-none-any.whl (9.6 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page