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.