Arguments

Similar to commands, use of cappa-specific argument annotations are “only” required when the default behavior is not what you want. A completely un-annotated dataclass like

@dataclass
class Example:
    name: str

is perfectly valid. However, a CLI of any real complexity will need to use the Arg annotation.

By default:

  • Each class member is inferred to be a positional argument

  • Its name is the dash-case version of the class member name

  • Its value is coerced to the annotated type

  • Its help text is inferred from various natural sources (See Help Text Inference for details)

However, by using Arg, with syntax like name: Annotated[str, cappa.Arg(...)], you can customize the behavior of the field.

  • short=True (equivalent to short='-n' for this example) turns the option from a positional argument into a flag.

  • long works the same way as short (and can be used together), but for -- flags, like --name.

  • count=True counts the number of flag instance. Frequently used for -v, -vv, -vvv verbosity handling.

  • help='...' allows customizing the help text outside the docstring.

  • parse=<callable> allows parsing of more complex input values the cannot be handled through the type annotation system directly.

Note

See the annotation docs for more details on how annotations can be used and are interpreted to handle different kinds of CLI input.

class cappa.Arg

Describe a CLI argument.

Parameters:
  • value_name – Placeholder for the argument’s value in the help message / usage. Defaults to the name of the corresponding class field.

  • short – If True, uses first letter of the name to infer a (ex. -s) short flag. If a string is supplied, that will be used instead. If a string is supplied, it is split on ‘/’ (forward slash), to support multiple options. Additionally accepts a list of strings.

  • long – If True, uses first letter of the name to infer a (ex. –long) long flag. If a string is supplied, that will be used instead. If a string is supplied, it is split on ‘/’ (forward slash), to support multiple options. Additionally accepts a list of strings.

  • count – If True the resultant argmuent will count instances and accept zero arguments.

  • default – An explicit default CLI value. When left unspecified, the default is inferred from the class’ default or the adapter default/default_factory.

  • help – By default, the help text will be inferred from the containing class’ arguments’ section, if it exists. Alternatively, you can directly supply the help text here.

  • parse – An optional function which accepts the raw string argument as input and returns a parsed value type’s instance. This should only be required for complex types that the type system’s built-in parsing cannot handle.

  • group – Optional group names for the argument. This affects how they’re displayed in the backended help text.

  • hidden – Whether the argument should be hidden in help text. Defaults to False.

  • action – Generally automatically inferred from the data type. This allows to override the default.

  • num_args – Generally automatically inferred from the data type. This allows to override the default.

  • choices – Generally automatically inferred from the data type. This allows to override the default.

  • completion – Used to provide custom completions. If specified, should be a function which accepts a partial string value and returns a list of [cappa.Completion](cappa.Completion) objects.

  • required – Defaults to automatically inferring requiredness, based on whether the class’s value has a default. By setting this, you can force a particular value.

  • field_name – The name of the class field to populate with this arg. In most usecases, this field should be left unspecified and automatically inferred.

  • deprecated – If supplied, the argument will be marked as deprecated. If given True, a default message will be generated, otherwise a supplied string will be used as the deprecation message.

action
annotations
choices
classmethod collect(field, type_hint, fallback_help=None, default_short=False, default_long=False)
Parameters:
  • field (cappa.class_inspect.Field)

  • type_hint (type)

  • fallback_help (str | None)

  • default_short (bool)

  • default_long (bool)

Return type:

Arg

completion
count = False
default
deprecated = False
field_name
group
help
hidden = False
long = False
names(*, n=0)
Return type:

list[str]

names_str(delimiter=', ', *, n=0)
Parameters:

delimiter (str)

Return type:

str

normalize(annotation=NoneType, fallback_help=None, action=None, default=missing, field_name=None, default_short=False, default_long=False)
Parameters:
Return type:

Arg

num_args
parse
required
short = False
value_name

Action

Obliquely referenced through other Arg options like count, every Arg has a corrresponding “action”. The action is automatically inferred, most of the time, based on other options (i.e. count), the annotated type (i.e. bool -> ArgAction.set_true/ArgAction.set_false, list -> ArgAction.append), etc.

However the inferred action can always be directly set, in order to override the default inferred behavior.

Custom Actions

Note

This feature is currently experimental, in particular because the parser state available to either backend’s callable is radically different. However, for an action callable which accepts no arguments, behaviors is unlikely to change.

In addition to one of the literal ArgAction variants, the provided action can be given as an arbitrary callable.

The callable will be called as the parser “action” in response to parsing that argument.

Note

Custom actions may interfere with general inference features, depending on what you’re doing (given that you’re taking over the parser’s duty of determining how the code ought to handle the argument).

As such, you may need to specify options like num_args, where you wouldn’t have otherwise needed to.

Similarly to the [invoke][./invoke.md] system, you can use the type system to automatically inject objects of supported types from the parse context into the function in question. The return value of the function will be used as the result of parsing that particular argument.

The set of available objects to inject include:

  • Command: The command currently being parsed (a relevant piece of context when using subcommands)

  • Arg: The argument being parsed.

  • Value: The raw input value parsed in the context of the argument. Depending on other settings, this may be a list (when num_args > 1), or a raw value otherwise.

  • RawOption: In the event the value in question corresponds to an option value, the representation of that option from the original input.

The above set of objects is of potentially limited value. More parser state will likely be exposed through this interface in the future.

For example:

def example():
    return 'foo!'

def example(arg: Arg):
    return 'foo!'

def example2(value: Value):
    return value.value[1:]


@dataclass
class Example:
    ex1: Annotated[str, cappa.Arg(action=example)
    ex2: Annotated[str, cappa.Arg(action=example2)
    ex3: Annotated[str, cappa.Arg(action=example3)

Warning

ArgAction.append and num_args=-1 can be potentially confused, in that they can both produce list/sequence types as outputs. They can be used in conjunction or separately, but they are not the same!

Given some example option --foo:

ArgAction generally, affects the way the parser maps input CLI values to a given field overall. As such ArgAction.append causes the field-level value to be a sequence, and for multiple instances of --foo to accumulate into a list. e.x. --foo 1 --foo 2 -> [1, 2].

num_args instead, affects the number of values that a single instance of --foo will consume before stopping. e.x. --foo 1 2 -> [1, 2].

From an input perspective, the above examples show how they present differently at the CLI interface, requiring different inputs to successfully parse. From an output perspective, the table below shows how their parsed output will end up looking when mapped to real values.

action

num_args

result

set

1

1

set

-1

[1]

append

1

[1]

append

-1

[[1]]

Num Args

num_args controls the number of arguments that the parser will consume in order to fullfill a specific field. num_args=1 is the default behavior, meaning only one argument/value will be consumed for that field. This yields a scalar-type value.

num_args=3 would therefore mean that exactly 3 values would be required, resulting in a sequence-type output, rather than a scalar one.

num_args=-1 can be used to indicate that 0 or more (i.e. unbounded number of) arguments will be consumed, similarly resulting in a sequence-type output (even in the zero case).

Note

Generally num_args will be automatically inferred by your type annotation. For example, tuple[int, int, int] implies num_args=3.

However, an explicitly provided value is always preferred to the inferred value. See annotations for more details.

Default

Controls the default argument value at the CLI level. Generally, you can avoid direct use of cappa’s default by simply using the source class’ native default mechanism. (i.e. foo: int = 0 or foo: int = field(default=0) for dataclasses).

However it can be convenient to use cappa’s default because it does not affect the optionality of the field in question in the resultant class constructor.

Environment Variable Fallback

You can also use the default field to supply supported kinds of default-value-getting behaviors.

Env is one such example, where with Arg(..., default=Env("FOO", default='default value')), cappa will attempt to look up the environment variable FOO for the default value, if there was no supplied value at the CLI level.

class cappa.Env(env_var, *env_vars, default=None)

Lazily evaluates environment variables in the order given.

Argument value interpolation will handle and Arg’s default being an Env instance, by evaluating the Env, in the event the parser-level value fell back to the default.

Examples

>>> from cappa import Arg, Env
>>> arg = Arg(default=Env("HOST", "HOSTNAME", default="localhost"))
Parameters:
  • env_var (str)

  • env_vars (str)

  • default (str | None)

default
env_vars
evaluate()
Return type:

str | None