Metadata-Version: 2.1
Name: dollar-lambda
Version: 0.3.3
Summary: An argument parser for Python built from functional first principles
Home-page: https://ethanabrooks.github.io/dollar-lambda/
Keywords: argument-parser,parser,parser-combinators,functional-programming
Author: Ethan Brooks
Author-email: ethanabrooks@gmail.com
Maintainer: Ethan Brooks
Maintainer-email: ethanabrooks@gmail.com
Requires-Python: >=3.8,<4.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Requires-Dist: pytypeclass (>=0.1.1,<0.2.0)
Project-URL: Repository, https://github.com/ethanabrooks/dollar-lambda
Description-Content-Type: text/markdown

<p align="center">
  <img height="300" src="https://ethanabrooks.github.io/dollar-lambda/logo.png">
</p>

[$λ](https://ethanabrooks.github.io/dollar-lambda/) provides an alternative to [`argparse`](https://docs.python.org/3/library/argparse.html)
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](https://ethanabrooks.github.io/dollar-lambda/dollar_lambda/)

# 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`](https://ethanabrooks.github.io/dollar-lambda/dollar_lambda/#dollar_lambda.command) decorator
This syntax is best for simple parsers that take a set of unordered arguments:


```python
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:


```python
main("-h")
```

    usage: -x X --dev --prod



```python
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:


```python
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}




```python
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:


```python
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:


```python
tree("-x", "1", "--prod")
```

    Ran prod_function with arguments: {'x': 1, 'prod': True}


If we provide the `--dev` flag, `$λ` invokes `dev_function`:


```python
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:


```python
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](https://ethanabrooks.github.io/dollar-lambda/dollar_lambda/#commandtree-tutorial).

## Lower-level syntax
[`@command`](https://ethanabrooks.github.io/dollar-lambda/dollar_lambda/#dollar_lambda.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:


```python
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](https://ethanabrooks.github.io/dollar-lambda/dollar_lambda/#tutorial).
For now, suffice to say that `argument` defines a positional argument,
[`many`](https://ethanabrooks.github.io/dollar-lambda/dollar_lambda/#dollar_lambda.Parser.many) allows parsers to be applied
zero or more times, and [`|`](https://ethanabrooks.github.io/dollar-lambda/dollar_lambda/#dollar_lambda.Parser.__or__) expresses alternatives.

Here is the help text:


```python
p.parse_args("-h")
```

    usage: [-x X | [Y ...]]


As promised, this succeeds:


```python
p.parse_args("-x", "1")
```




    {'x': 1}



And this succeeds:


```python
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"](https://www.cs.nott.ac.uk/~pszgmh/pearl.pdf) by Graham Hutton and Erik Meijer for bringing these topics to life.

