API
API#
Defines the |
|
Defines |
|
Defines the |
|
Defines errors which can be raised by parsers. |
|
Defines parsing functions and the |
Defines Sequence,
a strongly-typed immutable list that implements
MonadPlus.
- class dollar_lambda.data_structures.KeyValue(key, value)#
Simple dataclass for storing key-value pairs.
- class dollar_lambda.data_structures.Output(get)#
This is the wrapper class for the output of
Parser.
- class dollar_lambda.data_structures.Sequence(get)#
This class combines the functionality of MonadPlus and
typing.Sequence>>> from dollar_lambda.data_structures import Sequence >>> s = Sequence([1, 2]) >>> len(s) 2 >>> s[0] 1 >>> s[-1] 2 >>> s + s # sequences emulate list behavior when added Sequence(get=[1, 2, 1, 2]) >>> [x + 1 for x in s] # sequences can be iterated over [2, 3] >>> Sequence([1, 2]) >= (lambda x: Sequence([x, -x])) Sequence(get=[1, -1, 2, -2])
- bind(f)#
>>> Sequence([1, 2]) >= (lambda x: Sequence([x, -x])) Sequence(get=[1, -1, 2, -2])
- static return_(a)#
>>> Sequence.return_(1) Sequence(get=[1])
- to_colliding_dict()#
>>> from dollar_lambda import Sequence, KeyValue >>> Sequence([KeyValue("a", 1), KeyValue("b", 2), KeyValue("a", 3)]).to_colliding_dict() {'a': [1, 3], 'b': 2} >>> Sequence([KeyValue("a", [1]), KeyValue("b", 2), KeyValue("a", [3])]).to_colliding_dict() {'a': [[1], [3]], 'b': 2}
- to_dict()#
>>> from dollar_lambda import Sequence, KeyValue >>> Sequence([KeyValue("a", 1), KeyValue("b", 2), KeyValue("a", 3)]).to_dict() {'a': [1, 3], 'b': 2} >>> from dollar_lambda import Sequence, KeyValue >>> Sequence([KeyValue("a", [1]), KeyValue("b", 2), KeyValue("a", [3])]).to_dict() {'a': [[1], [3]], 'b': 2} >>> from dollar_lambda.data_structures import _TreePath >>> Sequence([KeyValue("a", _TreePath.make("b", leaf="c"))]).to_dict() {'a': {'b': 'c'}} >>> Sequence( ... [ ... KeyValue("a", "b"), ... KeyValue("a", _TreePath.make("b", leaf="c")), ... KeyValue("a", _TreePath.make("b", "c", leaf=1)), ... KeyValue("a", _TreePath.make("b", "c", leaf=2)), ... ] ... ).to_dict() {'a': ['b', {'b': ['c', {'c': [1, 2]}]}]}
Defines parsing functions and the
Parser
class that they instantiate.
- class dollar_lambda.parsers.Parse(parsed, unparsed)#
A
Parseis the output of parsing.
- class dollar_lambda.parsers.Parser(f, usage, helps)#
Main class powering the argument parser.
- __add__(other)#
Parse two arguments in either order.
>>> from dollar_lambda import flag >>> p = flag("verbose") + flag("debug") >>> p.parse_args("--verbose", "--debug") {'verbose': True, 'debug': True} >>> p.parse_args("--debug", "--verbose") {'debug': True, 'verbose': True} >>> p.parse_args("--debug") usage: --verbose --debug Expected '--verbose'. Got '--debug'
Note that if more than two arguments are chained together with
+, some combinations will not parse:>>> p = flag("a") + flag("b") + flag("c") >>> p.parse_args("-c", "-a", "-b") # this works {'c': True, 'a': True, 'b': True} >>> p.parse_args("-a", "-c", "-b") # this doesn't usage: -a -b -c Expected '-b'. Got '-c'
This makes more sense when one supplies the implicit parentheses:
>>> p = (flag("a") + flag("b")) + flag("c")
In order to chain together more than two arguments, use
nonpositional:>>> from dollar_lambda import nonpositional >>> p = nonpositional(flag("a"), flag("b"), flag("c")) >>> p.parse_args("-a", "-c", "-b") {'a': True, 'c': True, 'b': True}
- __ge__(f)#
Return self>=value.
- __or__(other)#
Tries apply the first parser. If it fails, tries the second. If that fails, the parser fails.
>>> from dollar_lambda import argument, option, flag >>> p = option("option") | flag("verbose") >>> p.parse_args("--option", "x") {'option': 'x'} >>> p.parse_args("--verbose") {'verbose': True}
Note that by default,
Parser.parse_argsadds>> Parser.done()to the end of parsers, causingpto fail when both arguments are supplied:>>> p.parse_args("--verbose", "--option", "x") usage: [--option OPTION | --verbose] Unrecognized argument: --option
To disable this behavior, use
allow_unparsed:>>> p.parse_args("--verbose", "--option", "x", allow_unparsed=True) {'verbose': True}
- __rshift__(p)#
This applies parsers in sequence. If the first parser succeeds, the unparsed remainder gets handed off to the second parser. If either parser fails, the whole thing fails.
>>> from dollar_lambda import argument, flag >>> p = argument("first") >> argument("second") >>> p.parse_args("a", "b") {'first': 'a', 'second': 'b'} >>> p.parse_args("a") usage: FIRST SECOND The following arguments are required: second >>> p.parse_args("b") usage: FIRST SECOND The following arguments are required: second
- __xor__(other)#
This is the same as
|, but it succeeds only if one of the two parsers fails.>>> p = argument("int", type=int) ^ argument("div", type=lambda x: 1 / float(x)) >>> p.parse_args("inf") # succeeds because int("inf") fails {'div': 0.0} >>> p.parse_args("0") # succeeds because 1 / 0 throws an error {'int': 0} >>> p.parse_args("1") # fails because both parsers succeed Both parsers succeeded. This causes ^ to fail.
- apply(f)#
Takes the output of parser and applies
fto it. Convert any errors that arise intoArgumentError.>>> p1 = flag("hello") >>> p1.parse_args("--hello") {'hello': True}
This will double
p1’s output:>>> from dollar_lambda import Result >>> p2 = p1.apply(lambda out: Result.return_(out + out)) >>> p2.parse_args("--hello") {'hello': [True, True]}
- bind(f)#
Returns a new parser that
applies
self;if this succeeds, applies
fto the parsed component of the result.
Parser.bind()is one of the functions that makesParsera Monad. But most users will avoid using it directly, preferring higher level combinators like>>,|and+.Note that
>=as a synonym forbind(as defined in pytypeclass) and we typically prefer using the infix operator to the spelled out method.To demonstrate one use of
bindor>=, let’s use thematches()parser to write a function that takes the output of a parser and fails unless the next argument is the same as the first:>>> from dollar_lambda import Output, Sequence, KeyValue, Parser, matches, argument >>> def f(out: Output[Sequence[KeyValue]]) -> Parser[Output[str]]: ... *_, kv = out.get ... return matches(kv.value) ... >>> p = argument("some_dest") >= f >>> p.parse_args("a", "a") {'a': 'a'} >>> p.parse_args("a", "b") Expected 'a'. Got 'b'
- classmethod done(a=None)#
Parser.done()succeeds on the end of input and fails on everything else.>>> Parser.done().parse_args() {} >>> Parser.done().parse_args("arg") Unrecognized argument: arg
Without
Parser.done()the parser will not complain about leftover (unparsed) input:>>> flag("verbose").parse_args("--verbose", "--quiet", allow_unparsed=True) {'verbose': True}
When
allow_unparsed=False(the default),Parser.parse_args()adds>> done()to the end of the parser:
- classmethod empty(a=None)#
Always returns
{}, no matter the input. Mostly useful for use innonpositional().>>> Parser.empty().parse_args("any", "arguments", allow_unparsed=True) {}
- fails(a=None)#
Succeeds only if
selffails. Does not consume any input.>>> flag("x").fails().parse_args("not x", allow_unparsed=True) # succeeds {} >>> flag("x").fails().parse_args("-x", allow_unparsed=True) # fails Parser unexpectedly succeeded.
- ignore(a=None)#
Ignores the output from a parser. This is useful when you expect to give arguments to the command line that some other utility will handle.
>>> p = flag("hello").ignore()
This will not bind any value to
"hello":>>> p.parse_args("--hello") {}
But
--hellois still required:>>> p.parse_args() The following arguments are required: --hello
- many(max=80)#
Applies
selfzero or more times (like*in regexes).- Parameters
max (int) – Limits the number of times
Parser.many()is applied in order to prevent aRecursionError. The default for this can be increased by either settingparser.MAX_MANYor the environment variableDOLLAR_LAMBDA_MAX_MANY.
Examples
>>> from dollar_lambda import argument, flag >>> p = argument("as-many-as-you-like").many() >>> p.parse_args() {} >>> p = argument("as-many-as-you-like").many() >>> p.parse_args("a") {'as-many-as-you-like': 'a'} >>> p = argument("as-many-as-you-like").many() >>> p.parse_args("a", "b") {'as-many-as-you-like': ['a', 'b']}
Note that if
selfcontains|, the arguments can be heterogenous:>>> p = flag("verbose") | flag("quiet") >>> p = p.many() >>> p.parse_args("--verbose", "--quiet") # mix --verbose and --quiet {'verbose': True, 'quiet': True}
- many1(max=80)#
Applies
selfone or more times (like+in regexes).- Parameters
max (int) – Limits the number of times
Parser.many()is applied in order to prevent aRecursionError. The default for this can be increased by either settingparser.MAX_MANYor the environment variableDOLLAR_LAMBDA_MAX_MANY.
Examples
>>> from dollar_lambda import argument, flag >>> p = argument("1-or-more").many1() >>> p.parse_args("1") {'1-or-more': '1'} >>> p.parse_args("1", "2") {'1-or-more': ['1', '2']} >>> p.parse_args() usage: 1-OR-MORE [1-OR-MORE ...] The following arguments are required: 1-or-more
- nesting()#
Breaks the output of the wrapped parser into nested outputs. See the Nesting and grouping output section of the documentation for more information.
- optional()#
Allows arguments to be optional:
>>> p1 = flag("optional") >>> p = p1.optional() >>> p.parse_args("--optional") {'optional': True} >>> p.parse_args("--misspelled", allow_unparsed=True) # succeeds with no output {} >>> p1.parse_args("--misspelled") usage: --optional Expected '--optional'. Got '--misspelled'
- parse(cs)#
Applies the parser to the input sequence
cs.
- parse_args(*args, allow_unparsed=False, check_help=True)#
The main way the user extracts parsed results from the parser.
- Parameters
args (str) – A sequence of strings to parse. If empty, defaults to
sys.argv[1:].allow_unparsed (bool) – Whether to cause parser to fail if there are unparsed inputs. Note that setting this to false may cause unexpected behavior when using
nonpositional()orArgs.check_help (bool) – Before running the parser, checks if the input string is
--helpor-h. If it is, returns the usage message.
Examples
>>> argument("a").parse_args("-h") usage: A >>> argument("a").parse_args("--help") usage: A
- classmethod return_(a)#
This method is required to make
Parsera Monad. It consumes none of the input and always returns a as the result. For the most part, the user will not use this method unless building custom parsers.>>> Parser.return_(Output.from_dict(some_key="some_value")).parse_args() {'some_key': 'some_value'}
- sat(predicate, on_fail)#
Applies
parser, appliespredicateto the result and fails if this returns false.>>> from dollar_lambda import ArgumentError >>> p = option("x", type=int).many().sat( ... lambda out: sum(out.get.values()) > 0, ... lambda out: ArgumentError(f"The values in {list(out.get.values())} must sum to more than 0."), ... ) >>> p.parse_args("-x", "-1", "-x", "1") # fails usage: [-x X ...] The values in [-1, 1] must sum to more than 0. >>> p.parse_args("-x", "-1", "-x", "2") # succeeds {'x': [-1, 2]}
- Parameters
parser (Parser[Monoid]) – The parser to apply.
predicate (Callable[[Monoid], bool]) – The predicate to apply to the result of
parser.Parser.sat()fails if this predicate returns false.on_fail (Callable[[Monoid], ArgumentError]) – A function producing an
ArgumentErrorto return if the predicate fails. Takes the output ofparseras an argument.
- type(f)#
A wrapper around
Parser.apply()that simply appliesfto the value of the most recently parsed input.>>> p1 = option("x") >> option("y") >>> p = p1.type(int) >>> p.parse_args("-x", "1", "-y", "2") # converts "1" but not "2" {'x': '1', 'y': 2}
- wrap_help(a=None)#
This checks for the
--helpor-hflag before applyingparser. If either of the flags is present, returns the usage message forparser.>>> p = flag("help", help="Print this help message.").wrap_help() >>> p.parse_args("--help") usage: --help help: Print this help message. >>> p.parse_args("-h") usage: --help help: Print this help message.
We can use
Parser.wrap_help()to print partial usage messages, e.g. for subcommands:>>> subcommand1 = matches("subcommand1") >> option("option1").wrap_help() >>> subcommand2 = matches("subcommand2") >> option("option2").wrap_help() >>> p = subcommand1 | subcommand2 >>> p.parse_args("subcommand1", "-h") usage: --option1 OPTION1 >>> p.parse_args("subcommand2", "-h") usage: --option2 OPTION2
- classmethod zero(error=None)#
This parser always fails. This method is necessary to make
Parsera Monoid.- Parameters
error (Optional[ArgumentError]) – Customize the error returned by
Parser.zero().
Examples
>>> Parser.zero().parse_args() zero >>> Parser.zero().parse_args("a") zero >>> Parser.zero(error=ArgumentError("This is a test.")).parse_args("a") This is a test.
- exception dollar_lambda.parsers.SuccessError(usage: str, input: 'Sequence[str]', output: 'NonemptyList[Parse[A_monoid]]')#
- dollar_lambda.parsers.apply(f, description)#
A shortcut for
item(description).apply(f).In contrast to
Parser.apply(), this function sparesfthe trouble of outputting aResultobject. Here is an example of usage. First we define a simpleargument()parser:>>> p1 = argument("foo") >>> p1.parse_args("bar") {'foo': 'bar'}
Here we use
fto directly manipulate the binding generated byargument():>>> from dollar_lambda import apply >>> p2 = apply(lambda bar: Output.from_dict(**{bar + "e": bar + "f"}), description="baz") >>> p2.parse_args("bar") {'bare': 'barf'}
- dollar_lambda.parsers.argument(dest, nesting=True, help=None, type=None)#
Parses a single word and binds it to
dest. Useful for positional arguments.- Parameters
dest (str) – The name of variable to bind to:
nesting (bool) – If
True, then the parser will split the parsed output on.yielding nested output. See Examples for more details.help (Optional[str]) – The help message to display for the option:
type (Optional[Callable[[str], Any]]) – Use the
typeargument to convert the input to a different type:
Examples
>>> from dollar_lambda import argument >>> argument("name").parse_args("Dante") {'name': 'Dante'} >>> argument("name").parse_args() usage: NAME The following arguments are required: name
Here are some examples that take advantage of
nesting=True:>>> argument("config.name").parse_args("-h") usage: CONFIG.NAME >>> argument("config.name").parse_args("Dante") {'config': {'name': 'Dante'}}
You can disable this by setting
nesting=False:>>> argument("config.name", nesting=False).parse_args("Dante") {'config.name': 'Dante'} >>> (argument("config.first.name") >> argument("config.last.name")).parse_args("Dante", "Alighieri") {'config': {'first': {'name': 'Dante'}, 'last': {'name': 'Alighieri'}}}
- dollar_lambda.parsers.binary_usage(a, op, b, add_brackets=True)#
Utility for generating usage strings for binary operators.
- dollar_lambda.parsers.defaults(**kwargs)#
Useful for assigning default values to arguments. It ignore the input and always returns
kwargsconverted into aSequenceofKeyValuepairs.defaults()never fails:>>> from dollar_lambda import defaults >>> defaults(a=1, b=2).parse_args() {'a': 1, 'b': 2} >>> (flag("fails") | defaults(fails="succeeds")).parse_args() {'fails': 'succeeds'}
Here’s a more complex example derived from the tutorial:
>>> from dollar_lambda import nonpositional, flag, defaults, option >>> p = nonpositional( ... ( ... flag("verbose") + defaults(quiet=False) # either --verbose and default "quiet" to False ... | flag("quiet") + defaults(verbose=False) # or --quiet and default "verbose" to False ... ), ... option("x", type=int, help="the base"), ... option("y", type=int, help="the exponent"), ... ) ... >>> p.parse_args("-x", "1", "-y", "2", "--verbose") {'x': 1, 'y': 2, 'verbose': True, 'quiet': False}
- dollar_lambda.parsers.flag(dest, default=None, help=None, nesting=True, regex=True, replace_dash=True, short=True, string=None)#
Binds a boolean value to a variable.
>>> p = flag("verbose") >>> p.parse_args("--verbose") {'verbose': True}
- Parameters
dest (str) – The variable to which the value will be bound.
default (Optional[bool]) – An optional default value.
help (Optional[str]) – An optional help string.
nesting (bool) – If
True, then the parser will split the parsed output on.yielding nested output. See Examples for more details.regex (bool) – If
True, then the parser will use a regex to match the flag string.replace_dash (bool) – If
True, then the parser will replace-with_in the dest string in order to make dest a valid Python identifier.short (bool) – Whether to check for the short form of the flag, which uses a single dash and the first character of
dest, e.g.-fforfoo.string (Optional[str]) – A custom string to use for the flag. Defaults to
--{dest}.
Examples
Here is an example using the
defaultparameter:>>> p = flag("verbose", default=False) >>> p.parse_args("-h") usage: --verbose >>> p.parse_args() {'verbose': False}
By default
flagfails when it does not receive expected input:>>> p = flag("verbose") >>> p.parse_args() usage: --verbose The following arguments are required: --verbose
Here is an example using the
helpparameter:>>> p = flag("verbose", help="Turn on verbose output.") >>> p.parse_args("-h") usage: --verbose verbose: Turn on verbose output.
Here is an example using the
shortparameter:>>> flag("verbose", short=True).parse_args("-v") # this is the default {'verbose': True} >>> flag("verbose", short=False).parse_args("-v") # fails usage: --verbose Expected '--verbose'. Got '-v'
Here is an example using the
stringparameter:>>> flag("value", string="v").parse_args("v") # note that string does not have to start with - {'value': True} >>> flag("config.value").parse_args("--config.value") {'config': {'value': True}}
- dollar_lambda.parsers.item(name, usage_name=None)#
Parses a single word and binds it to
dest. One of the lowest level building blocks for parsers.- Parameters
usage_name (Optional[str]) – Used for generating usage text
Examples
>>> from dollar_lambda import item >>> p = item("name", usage_name="Your first name") >>> p.parse_args("Alice") {'name': 'Alice'} >>> p.parse_args() usage: name The following arguments are required: Your first name
- dollar_lambda.parsers.matches(s, peak=False, regex=True)#
Checks if the next word is
s.>>> from dollar_lambda import matches >>> matches("hello").parse_args("hello") {'hello': 'hello'} >>> matches("hello").parse_args("goodbye") usage: hello Expected 'hello'. Got 'goodbye'
- Parameters
s (str) – The word to that input will be checked against for equality.
peak (bool) – If
False, then the parser will consume the word and return the remaining words asunparsed. IfTrue, then the parser leaves theunparsedcomponent unchanged.regex (bool) – Whether to treat
sas a regular expression. IfFalse, then the parser will only succeed on string equality.
Examples
>>> p = matches("hello") >> matches("goodbye") >>> p.parse_args("hello", "goodbye") {'hello': 'hello', 'goodbye': 'goodbye'}
Look what happens when
peak=True:>>> p = matches("hello", peak=True) >> matches("goodbye") >>> p.parse_args("hello", "goodbye") usage: hello goodbye Expected 'goodbye'. Got 'hello'
The first parser didn’t consume the word and so
"hello"got passed on toequals("goodbye"). But this would work:>>> p = matches("hello", peak=True) >> matches("hello") >> matches("goodbye") >>> p.parse_args("hello", "goodbye") {'hello': ['hello', 'hello'], 'goodbye': 'goodbye'}
- dollar_lambda.parsers.nonpositional(*parsers, max=80, repeated=None)#
nonpositional()takes a sequence of parsers as arguments and attempts all permutations of them, returning the first permutations that is successful:>>> from dollar_lambda import nonpositional, flag >>> p = nonpositional(flag("verbose"), flag("quiet")) >>> p.parse_args("--verbose", "--quiet") {'verbose': True, 'quiet': True} >>> p.parse_args("--quiet", "--verbose") # reverse order also works {'quiet': True, 'verbose': True}
- Parameters
max (int) – Limits the number of times
repeatedis applied in order to prevent aRecursionError. The default for this can be increased by either settingparser.MAX_MANYor the environment variableDOLLAR_LAMBDA_MAX_MANY.repeated (Optional[Parser[Sequence[Monoid]]]) – If provided, this parser gets applied repeatedly (zero or more times) at all positions.
Examples
>>> p = nonpositional(repeated=flag("x")) >>> p.parse_args() {} >>> p.parse_args("-x") {'x': True} >>> p.parse_args("-x", "-x") {'x': [True, True]}
>>> p = nonpositional(flag("y"), repeated=flag("x")) >>> p.parse_args("-y") {'y': True} >>> p.parse_args("-y", "-x") {'y': True, 'x': True} >>> p.parse_args("-x", "-y") {'x': True, 'y': True} >>> p.parse_args("-y", "-x", "-x") {'y': True, 'x': [True, True]} >>> p.parse_args("-x", "-y", "-x") {'x': [True, True], 'y': True} >>> p.parse_args("-x", "-x", "-y") {'x': [True, True], 'y': True}
>>> p = nonpositional(flag("y"), repeated=(flag("x") | flag("z")).ignore()) >>> p.parse_args("-x", "-y", "-z") {'y': True}
- dollar_lambda.parsers.option(dest, default=None, flag=None, help=None, nesting=True, regex=True, replace_dash=True, short=True, type=<class 'str'>)#
Parses two words, binding the second to the first.
- Parameters
dest (str) – The name of variable to bind to:
default (Optional[Any]) – The default value to bind on failure:
flag (Optional[str]) – The flag to use for the option. If not provided, defaults to
--{dest}.help (Optional[str]) – The help message to display for the option:
nesting (bool) – If
True, then the parser will split the parsed output on.yielding nested output. See Examples for more details.regex (bool) –
If
True, then the parser will match the flag string as a regex.- replace_dashbool
If
True, then the parser will replace-with_in the dest string in order to make dest a valid Python identifier.
short (bool) – Whether to check for the short form of the flag, which uses a single dash and the first character of
dest, e.g.-cforcount.type (Callable[[str], Any]) – Use the
typeargument to convert the input to a different type:
Examples
>>> option("count").parse_args("--count", "1") {'count': '1'}
In this example, you can see that the
flagparameter allows the user to specify an arbitrary lead string, including one that doesn’t start with a dash.>>> option("count", flag="ct").parse_args("ct", "1") {'count': '1'}
This example demonstrates the use of the
defaultparameter:>>> p = option("count", default=2) >>> p.parse_args("-h") usage: --count COUNT count: (default: 2) >>> p.parse_args() {'count': 2}
Here we specify a help-string using the
helpparameter:>>> option("count", help="The number we should count to").parse_args("-h") usage: --count COUNT count: The number we should count to
This example demonstrates the difference between
short=Trueandshort=False:>>> option("count", short=True).parse_args("-c", "1") {'count': '1'} >>> option("count", short=False).parse_args("-c", "1") usage: --count COUNT Expected '--count'. Got '-c'
As with argparse, the
typeargument allows you to convert the input to a different type using a function that takes a single string argument:>>> option("x", type=int).parse_args("-x", "1") # converts "1" to an int {'x': 1} >>> option("x", type=lambda x: int(x) + 1).parse_args("-x", "1") {'x': 2} >>> option("config.x").parse_args("--config.x", "a") {'config': {'x': 'a'}}
- dollar_lambda.parsers.peak(name, description=None)#
Bind the next word to a variable but keep that word in the input (so that other parsers can still see it).
- dollar_lambda.parsers.sat(predicate, on_fail, name)#
A wrapper around
Parser.sat()that usesitem()to parse the argument and just appliespredicateto the value output byitem().>>> from dollar_lambda import sat, ArgumentError >>> p = sat(lambda x: len(x) == 1, lambda x: ArgumentError(f"'{x}' must have exactly one character."), "x") >>> p.parse_args("a") # succeeds {'x': 'a'} >>> p.parse_args("aa") # fails usage: x 'aa' must have exactly one character.
- Parameters
predicate (Callable[[A], bool]) – The predicate to apply to the result of
item().sat()fails if this predicate returns false.on_fail (Callable[[A], ArgumentError]) – A function producing an
ArgumentErrorto return if the predicate fails. Takes the output ofitem()as an argument.name (str) – The value to bind the result to.
- dollar_lambda.parsers.sat_peak(predicate, on_fail, name)#
A convenience function that peaks at the next word using
peak()and then checks if it satisfies the predicate.
Defines the @command decorator
and the CommandTree class.
- class dollar_lambda.decorators.CommandTree(_children=<factory>, _can_run=True)#
Allows parsers to dynamically dispatch their results based on the input. For usage details, see the CommandTree Tutorial.
- command(can_run=True, flip_bools=True, help=None, parsers=None, repeated=None)#
A decorator for adding a function as a child of this tree.
- Parameters
can_run (bool) – Whether the parser will permit the decorated function to run if no further arguments are supplied.
flip_bools (bool) – Whether to add
--no-<argument>before arguments that default toTrue.help (dict) – A dictionary of help strings for the arguments.
parsers (Dict[str, Parser | List[Parser]]) – A dictionary reserving arguments for custom parsers. If the value is a list, the key must correspond to a variadic argument. See
@commandfor examples.repeated (Optional[Parser[Sequence[KeyValue[Any]]]]) – If provided, this parser gets applied repeatedly (zero or more times) at all positions.
Examples
With
flip_boolsset toTrue:>>> from dollar_lambda import CommandTree >>> tree = CommandTree() ... >>> @tree.command(flip_bools=True) ... def f1(b: bool = True): ... return dict(f1=dict(b=b)) ... >>> tree("-h") usage: --no-b b: (default: True)
With
flip_boolsset toFalse:>>> tree = CommandTree() ... >>> @tree.command(flip_bools=False) ... def f1(b: bool = True): ... return dict(f1=dict(b=b)) ... >>> tree("-h") usage: -b b: (default: True)
With
can_runset toTrue(the default), we can runf1by not passing arguments for thef1’s children:>>> tree = CommandTree() ... >>> @tree.command(can_run=True) # <- ... def f1(b: bool): ... return dict(f1=dict(b=b)) ... >>> @f1.command() ... def g1(n: int): ... return dict(g1=dict(b=b, n=n)) ... >>> tree("-h") usage: -b -n N >>> tree("-b") {'f1': {'b': True}}
With
can_runset toFalse, the parser will fail if the child function arguments are not supplied:>>> tree = CommandTree() ... >>> @tree.command(can_run=False) # <- ... def f1(b: bool): ... return dict(f1=dict(b=b)) ... >>> @f1.command() ... def g1(n: int): ... return dict(g1=dict(b=b, n=n)) ... >>> tree("-h") usage: -b -n N >>> tree("f1", "-b") usage: -b -n N Expected '-b'. Got 'f1'
- subcommand(can_run=True, flip_bools=True, help=None, parsers=None, repeated=None)#
A decorator for adding a function as a child of this tree. As a subcommand, the function’s name must be invoked on the command line for the function to be called.
- Parameters
can_run (bool) – Whether the parser will permit the decorated function to run if no further arguments are supplied.
flip_bools (bool) – Whether to add
--no-<argument>before arguments that default toTrue.help (Dict[str, str]) – A dictionary of help strings for the arguments.
parsers (Dict[str, Parser | List[Parser]]) – A dictionary reserving arguments for custom parsers. If the value is a list, the key must correspond to a variadic argument. See
@commandfor examples.repeated (Optional[Parser[Sequence[KeyValue[Any]]]]) – If provided, this parser gets applied repeatedly (zero or more times) at all positions. See
nonpositionalfor examples.
Examples
With
flip_boolsset toTrue:>>> tree = CommandTree() ... >>> @tree.subcommand(flip_bools=True) ... def f1(b: bool = True): ... return dict(f1=dict(b=b)) ... >>> tree("-h") usage: f1 --no-b b: (default: True)
With
flip_boolsset toFalse:>>> tree = CommandTree() ... >>> @tree.subcommand(flip_bools=False) ... def f1(b: bool = True): ... return dict(f1=dict(b=b)) ... >>> tree("-h") usage: f1 -b b: (default: True)
With
can_runset toTrue(the default), we can runf1by not passing arguments for thef1’s children:>>> tree = CommandTree() ... >>> @tree.subcommand(can_run=True) # <- ... def f1(b: bool): ... return dict(f1=dict(b=b)) ... >>> @f1.subcommand() ... def g1(b: bool, n: int): ... return dict(g1=dict(b=b, n=n)) ... >>> tree("-h") usage: f1 -b g1 -n N >>> tree("f1", "-b") {'f1': {'b': True}}
With
can_runset toFalse, the parser will fail if the child function arguments are not supplied:>>> tree = CommandTree() ... >>> @tree.subcommand(can_run=False) # <- ... def f1(b: bool): ... return dict(f1=dict(b=b)) ... >>> @f1.subcommand() ... def g1(b: bool, n: int): ... return dict(g1=dict(b=b, n=n)) ... >>> tree("-h") usage: f1 -b g1 -n N >>> tree("f1", "-b") usage: f1 -b g1 -n N The following arguments are required: g1
- dollar_lambda.decorators.command(flip_bools=True, help=None, parsers=None, repeated=None)#
A succinct way to generate a simple
nonpositionalparser.@commandderives the component parsers from the function’s signature and automatically executes the function with the parsed arguments, if parsing succeeds:>>> from dollar_lambda import command >>> @command(help=dict(a="something about a")) ... def f(a: int = 1, b: bool = False): ... print(dict(a=a, b=b)) ... >>> f("-a", "2", "-b") {'a': 2, 'b': True}
If the wrapped function receives no arguments (as in
f()), the parser will takesys.argv[1:]as the input.- Parameters
flip_bools (bool) – For boolean arguments that default to true, this changes the flag from
--{dest}to--no-{dest}:help (dict[str, str]) – A dictionary of help strings for the arguments.
parsers (Dict[str, Parser | List[Parser]]) – A dictionary reserving arguments for custom parsers. If the value is a list, the key must correspond to a variadic argument.
repeated (Optional[Parser[Sequence[KeyValue[Any]]]]) – If provided, this parser gets applied repeatedly (zero or more times) at all positions.
Examples
>>> @command() ... def f(cuda: bool = True): ... return dict(cuda=cuda) >>> f() {'cuda': True} >>> f("--no-cuda") # flip_bools adds --no- to the flag {'cuda': False}
As the following example demonstrates, when
flip_bools=Falseoutput can be somewhat confusing:>>> @command(flip_bools=False) ... def f(cuda: bool = True): ... return dict(cuda=cuda) >>> f("--cuda") {'cuda': False}
Here is an example using the
helpparameter:>>> @command(help=dict(quiet="Be quiet")) ... def f(quiet: bool): ... return dict(quiet=quiet) >>> f("--help") usage: --quiet quiet: Be quiet
Here is an example using the
parsersparameter:>>> from dollar_lambda import flag >>> @command(parsers=dict(kwargs=(flag("dev") | flag("prod")))) ... def main(x: int, **kwargs): ... print(dict(x=x, **kwargs))
This parser requires either a
--devor--prodflag and maps it to thekwargsargument:>>> 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
- dollar_lambda.decorators.parser(prefix=None, flip_bools=True, help=None, parsers=None, repeated=None)#
Adds a
.parserattribute to the wrapped function which can then be used in combination with other parsers. For examples, see: Grouping with the @parser decorator.- Parameters
prefix (Optional[str]) – This causes the variables bound by this parser to nest under the given prefix, as demonstrated in Grouping with the @parser decorator.
flip_bools (bool) – For boolean arguments that default to true, this changes the flag from
--{dest}to--no-{dest}:help (dict[str, str]) – A dictionary of help strings for the arguments.
parsers (Dict[str, Parser | List[Parser]]) – A dictionary reserving arguments for custom parsers. If the value is a list, the key must correspond to a variadic argument.
repeated (Optional[Parser[Sequence[KeyValue[Any]]]]) – If provided, this parser gets applied repeatedly (zero or more times) at all positions.
Defines the Args dataclass and associated functions.
- class dollar_lambda.args.Args#
Argsis sugar for thenonpositionalfunction and removes much of the boilerplate from defining parsers with many arguments.>>> from dataclasses import dataclass >>> from dollar_lambda import Args >>> @dataclass ... class MyArgs(Args): ... verbose: bool ... count: int >>> MyArgs.parse_args("--verbose", "--count", "1") {'verbose': True, 'count': 1}
MyArgswill accept these arguments in any order:>>> MyArgs.parse_args("--count", "1", "--verbose") {'count': 1, 'verbose': True}
Note that when the default value of an argument is
True,Argswill, by default add--no-to the front of the flag (while still assigning the value to the original key):>>> @dataclass ... class MyArgs(Args): ... tests: bool = True >>> MyArgs.parse_args("--no-tests") {'tests': False} >>> MyArgs.parse_args() {'tests': True}
To suppress this behavior, set
flip_bools=False:>>> MyArgs.parse_args("--tests", flip_bools=False) {'tests': False}
By using the
Args.parser()method,Argscan take advantage of all the same combinators as other parsers:>>> from dollar_lambda import argument >>> p = MyArgs.parser() >>> p1 = p >> argument("a") >>> p1.parse_args("--no-tests", "hello") {'tests': False, 'a': 'hello'}
To supply other metadata, like
helptext or custom parsers, usefield():>>> from dollar_lambda import field, option >>> @dataclass ... class MyArgs(Args): ... x: int = field(default=0, help="a number") ... y: int = field( ... default=1, ... parser=option("y", type=lambda s: int(s) + 1, help="a number to increment"), ... ) >>> MyArgs.parse_args("-h") usage: -x X -y Y x: a number y: a number to increment
This supplies defaults for
ywhen omitted:>>> MyArgs.parse_args("-x", "10") {'x': 10, 'y': 1}
It also applies the custom type to
ywhen"-y"is given>>> MyArgs.parse_args() {'x': 0, 'y': 1}
- classmethod parse_args(*args, flip_bools=True, repeated=None)#
Parses the arguments and returns a dictionary of the parsed values.
- classmethod parser(flip_bools=True, repeated=None)#
Returns a parser for the dataclass. Converts each field to a parser (
optionorflagdepending on its type). Combines these parsers usingnonpositional.- Parameters
flip_bools (bool) – Whether to add
--no-<argument>before arguments that default toTrue.
Examples
>>> @dataclass ... class MyArgs(Args): ... tests: bool = True
Note the leading
--no-:>>> MyArgs.parse_args("--no-tests") {'tests': False} >>> MyArgs.parse_args() {'tests': True}
To suppress this behavior, set
flip_bools=False:>>> MyArgs.parse_args("--tests", flip_bools=False) {'tests': False}
- dollar_lambda.args.field(help=None, metadata=None, parser=None, **kwargs)#
This is a thin wrapper around
dataclasses.field().- Parameters
help (str) – An optional help string for the argument.
metadata (str) – Identical to the metadata argument for
dataclasses.field().type (Optional[type | Callable[[str], Any]]) – A function that takes a string and returns a value just like the
typeargument forargparse.ArgumentParser.add_argument().
- Return type
A
dataclasses.Fieldobject that can be used in place of a default argument as described in thedataclasses.Fielddocumentation.
Defines errors which can be raised by parsers.
- exception dollar_lambda.errors.BinaryError(usage: str, error1: dollar_lambda.errors.ArgumentError, error2: dollar_lambda.errors.ArgumentError)#