Skip to main content

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
main("-x", "1", "--dev")
{'x': 1, 'dev': True, 'prod': False}

Ordinarily you would call main with no arguments and it would get arguments from the command line:

from dollar_lambda import parser

parser.TESTING = False  # False by default but needs to be true for doctests
import sys

sys.argv[1:] = ["-x", "1", "--dev"]
main()
{'x': 1, 'dev': True, 'prod': False}
parser.TESTING = True

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}

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

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)]

Again, you would ordinarily provide parse_args no arguments and it would get the. from the command line.

Thanks

Special thanks to "Functional Pearls" by Graham Hutton and Erik Meijer for bringing these topics to life.

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

dollar-lambda-0.3.3.tar.gz (28.2 kB view hashes)

Uploaded Source

Built Distribution

dollar_lambda-0.3.3-py3-none-any.whl (31.0 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