Welcome to $λ#

This package provides an alternative to argparse based on parser combinators and functional first principles. Arguably, is way more expressive than any reasonable person would ever need… but even if it’s not the parser that we need, it’s the parser we deserve.

Installation#

pip install dollar-lambda

Highlights#

comes with syntactic sugar that came make building parsers completely boilerplate-free. For complex parsing situations that exceed the expressive capacity of this syntax, the user can also drop down to the lower-level syntax that lies behind the sugar, which can handle any reasonable amount of logical complexity.

The @command decorator#

For the vast majority of parsing patterns, @command is the most concise way to define a parser:

>>> from dollar_lambda import command
>>> @command()
... def main(x: int, dev: bool = False, prod: bool = False):
...     print(dict(x=x, dev=dev, prod=prod))
...
>>> main("-h")
usage: -x X --dev --prod
dev: (default: False)
prod: (default: False)
>>> main("-x", "1", "-dev")
{'x': 1, 'dev': True, 'prod': False}

Note

Ordinarily you would provide main no arguments and it would get them from the command line.

Add custom logic with the parsers argument:

>>> @command(parsers=dict(kwargs=(flag("dev") | flag("prod"))))
... def main(x: int, **kwargs):
...     print(dict(x=x, **kwargs))
...
>>> main("-h")
usage: -x X [--dev | --prod]
>>> main("-x", "1", "-dev")
{'x': 1, 'dev': True}
>>> main("-x", "1", "-prod")
{'x': 1, 'prod': True}
>>> main("-x", "1")
usage: -x X [--dev | --prod]
The following arguments are required: --dev

CommandTree for dynamic dispatch#

Execute prod_function for one set of command line arguments and dev_function for another:

>>> from dollar_lambda import CommandTree
...
>>> tree = CommandTree()
...
...
>>> @tree.command()
... def base_function(x: int):
...     print("Ran base_function with arguments:", dict(x=x))
...
>>> @base_function.command()
... def prod_function(x: int, prod: bool):
...     print("Ran prod_function with arguments:", dict(x=x, prod=prod))
...
>>> @base_function.command()
... def dev_function(x: int, dev: bool):
...     print("Ran dev_function with arguments:", dict(x=x, dev=dev))
...
>>> tree("-x", "1", "--prod")  # runs prod_function because of --prod
Ran prod_function with arguments: {'x': 1, 'prod': True}
>>> tree("-x", "1", "--dev")  # runs dev_function because of --dev
Ran dev_function with arguments: {'x': 1, 'dev': True}
>>> tree("-x", "1")  # runs base_function because of no flags
Ran base_function with arguments: {'x': 1}

Note

As with main in the previous example, you would ordinarily provide tree no arguments and it would get them from the command line.

Lower-level syntax#

Use lower-level syntax for more complex parsers:

>>> from dollar_lambda import argument
>>> p = option("x", type=int) | argument("y", type=float).many()
...
>>> p.parse_args("-h")
usage: [-x X | [Y ...]]
>>> p.parse_args("-x", "1")  # execute parser on left side of |
{'x': 1}
>>> p.parse_args("1", "2", "3")  # execute parser on right side of |
{'y': [1.0, 2.0, 3.0]}

Note

Again, parse_args takes arguments from the command line when given no arguments.