Usage¶
Example¶
Here, we illustrate how to use the generate_options
function on a msgspec.Struct
type. The click.Option
instances it generates produce values that may be used to instantiate the type.
from __future__ import annotations
from typing import Annotated
import click
from msgspec import Meta, Struct, convert
from msgspec_click import generate_options
class Connection(Struct):
user: Annotated[
str,
Meta(
extra={
"help": "The user's name",
"params": ["-u", "--user"],
}
)
] = ""
password: Annotated[
str,
Meta(
extra={
"help": "The user's password",
"params": ["-p", "--pass"],
"prompt": True,
"hide_input": True,
"confirmation_prompt": True,
}
)
] = ""
headers: Annotated[list[str], Meta(extra={"params": ["-H"]})] = []
timeout: float = 10.0
allow_insecure: bool = False
@click.command()
def command(**kwargs) -> None:
connection = convert(kwargs, Connection)
print(connection)
command.params.extend(generate_options(Connection))
command()
You can view the help text like so:
$ python script.py --help
Usage: script.py [OPTIONS]
Options:
-u, --user TEXT The user's name
-p, --pass TEXT The user's password
-H LIST
--timeout FLOAT
--allow-insecure
--help Show this message and exit.
Running the script with secret
as the password produces the following output:
$ python script.py --user alice -H "Key: Value"
Password []:
Repeat for confirmation:
Connection(user='alice', password='secret', headers=['Key: Value'], timeout=10.0, allow_insecure=False)
How it works¶
The type of each field is used to determine the appropriate type of the associated option. Types may be annotated with a msgspec.Meta
instance to configure the option. All keys in the extra
dictionary are passed directly to the click.Option
constructor as keyword arguments, except for the params
key which is extracted and passed as an argument.
If the params
key is not set, then the name of the field is used as the only option parameter e.g. some_field
would become --some-field
. If the key is set but does not contain the expected flag name nor does it contain the field name, then the field name is appended to the list of parameters to force Click to use the field name as the option name without interfering with the chosen parameters.
If the default
key is set then it is used as the default value for the option with a fallback to the default value of the field. If a field has no default value, then required
is set to True
for the option.
Supported types¶
Primitive types¶
Type | Behavior |
---|---|
str | N/A |
bool | The is_flag key is set to True . |
int | If the count key is not set to True then the type key is set to int . Otherwise, the default key is set to [] to satisfy what Click expects for such repeatable options like -vvv . |
float | The type key is set to float . |
Collection types¶
Type | Behavior |
---|---|
list | The type key is set to item type and the cls is set to a click.Option subclass that only converts the final value to the proper type. If the nargs setting is not defined then multiple will be set to True . All of the primitive types are supported as items. If the item type is not defined or is typing.Any then the type is considered str . |
tuple | Both standard and variadic forms are supported. If the standard form (e.g. tuple[str, int] ) is used then the type key is set to click.Tuple and nargs is set to the number of items. If the variadic form (e.g. tuple[str, ...] ) is used then the type key is set to click.Tuple , and the nargs key must already be defined. All of the primitive types are supported as items. If an item type is not defined or is typing.Any then the type is considered str . |
dict | The type key is set to click.Tuple with the type of the key and value, multiple is set to True and the cls is set to a click.Option subclass that only converts the final value to the proper type. The key type must be str but values support all of the primitive types. If the value type is typing.Any then the type is considered str . |
TypedDict | The type key is set to a 2-ary click.Tuple with the first item being a click.Choice constructed from the keys of the dictionary and the second item set to str . As such, the type of each value in the typing.TypedDict must be str . The multiple key is set to True and the cls is set to a click.Option subclass that only converts the final value to the proper type. |
Complex types¶
Type | Behavior |
---|---|
Union | Only TYPE_DEF | None union types are supported i.e. exactly 2 types with the final being None . This is to allow the default value being None for easily checking if options were set by the user. The first type may be any supported type except another union. |
Literal | The type key is set to click.Choice with the literal's values. Only str literals are supported. |
Caveats¶
Type annotations that are not supported by the Python version at runtime will not work. For example, subscripting built-in types like list[int]
became supported in Python 3.9 and using the |
operator for unions became supported in Python 3.10.
Although from __future__ import annotations
may hide these runtime errors due to postponed evaluation of annotations, it does not change the supported syntax of the interpreter.