An argument parser for Python built from functional first principles
Project description
$λ 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
Documentation
Highlights
$λ
comes with syntactic sugar that came make building parsers completely boilerplate-free.
However, with more concise syntax comes less flexibility. For more complex parsing situations,
there are modular building blocks that lie behind the syntactic sugar which enable parsers to
handle any reasonable amount of logical complexity.
The @command
decorator
This syntax is best for simple parsers that take a set of unordered arguments:
from dollar_lambda import command
@command()
def main(x: int, dev: bool = False, prod: bool = False):
return dict(x=x, dev=dev, prod=prod)
Here is the help text generated by this parser:
main("-h")
usage: -x X --dev --prod
Note that ordinarily you would call main
with no arguments and it would get arguments from the command line (sys.argv[1:]
).
In this tutorial we feed arguments explicitly for demonstration purposes only.
main("-x", "1", "--dev")
{'x': 1, 'dev': True, 'prod': False}
command
takes arguments that allow you to supply
help strings and custom types:
@command(
types=dict(x=lambda x: int(x) + 1), help=dict(x="A number that gets incremented.")
)
def main(x: int, dev: bool = False, prod: bool = False):
return dict(x=x, dev=dev, prod=prod)
main("-h")
usage: -x X --dev --prod
x: A number that gets incremented.
main("-x", "1", "--dev")
{'x': 2, 'dev': True, 'prod': False}
CommandTree
for dynamic dispatch
For many programs, a user will want to use one entrypoint for one set of
arguments, and another for another set of arguments. Returning to our example,
let's say we wanted to execute prod_function
when the user provides the
--prod
flag, and dev_function
when the user provides the --dev
flag:
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))
Let's see how this parser handles different inputs.
If we provide the --prod
flag, $λ
automatically invokes
prod_function
with the parsed arguments:
tree("-x", "1", "--prod")
Ran prod_function with arguments: {'x': 1, 'prod': True}
If we provide the --dev
flag, $λ
invokes dev_function
:
tree("-x", "1", "--dev")
Ran dev_function with arguments: {'x': 1, 'dev': True}
With this configuration, the parser will run base_function
if neither
--prod
nor --dev
are given:
tree("-x", "1")
Ran base_function with arguments: {'x': 1}
There are many other ways to use CommandTree
,
including some that make use of the base_function
.
To learn more, we recommend the CommandTree
tutorial.
Lower-level syntax
@command
and CommandTree
cover many use cases,
but they are both syntactic sugar for a lower-level interface that is far
more expressive.
Suppose you want to implement a parser that first tries to parse an option
(a flag that takes an argument),
-x X
and if that fails, tries to parse the input as a variadic sequence of
floats:
from dollar_lambda import argument, option
p = option("x", type=int) | argument("y", type=float).many()
We go over this syntax in greater detail in the tutorial.
For now, suffice to say that argument
defines a positional argument,
many
allows parsers to be applied
zero or more times, and |
expresses alternatives.
Here is the help text:
p.parse_args("-h")
usage: [-x X | [Y ...]]
As promised, this succeeds:
p.parse_args("-x", "1")
{'x': 1}
And this succeeds:
p.parse_args("1", "2", "3", return_dict=False)
[('y', 1.0), ('y', 2.0), ('y', 3.0)]
Thanks
Special thanks to "Functional Pearls" by Graham Hutton and Erik Meijer for bringing these topics to life.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for dollar_lambda-0.2.0-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a90ad2b450f657a5dc3cfb6a52469458ea494ba987a625af6f21c68df90d6789 |
|
MD5 | bb51b38209b7ed562561173ed5689785 |
|
BLAKE2b-256 | 17ed8bd6a3c668c7a04d1834e62d78e82f4fd1201f64970c85c4290b206be5f6 |