dataclass-click
Structure your click arguments.
dataclass-click lets you move your user arguments from kwargs to dataclasses, keeping things self-contained.
Click is pretty simple to start with, but when your program gets complex, you find yourself repeating a lot of work. This is particularly true if you have command groups with shared arguments.
The idea of dataclass-click is to move the @option and @argument decorators off into annotations on dataclasses
and pass dataclass objects instead of kwargs.
Simple Example
from dataclasses import dataclass
from pathlib import Path
from typing import Annotated
import click
from dataclass_click import argument, dataclass_click, option
@dataclass
class Config:
# Auto-inferred type for built-in click types
target: Annotated[Path, argument()]
# Auto-inferred option names
foo: Annotated[float, option(required=True)]
# Automatically map mismatched names
bar: Annotated[int | None, option("--other")]
@click.command()
@dataclass_click(Config)
def main(config: Config):
# All args neatly packaged.
print(config.target, config.foo, config.bar)
print(list(config.target.iterdir()))
Inference Features
Name inference
The pythonic name for options and attributes is copied from the dataclass attribute name. Options can then be named whatever you want. If you don't specify an option name, it will be inferred for you:
from dataclasses import dataclass
from dataclass_click import option, argument
from typing import Annotated
@dataclass
class Config:
foo: Annotated[str, argument()]
bar: Annotated[str, option()]
baz: Annotated[str, option("--bonno")]
Usage: main.py [OPTIONS] FOO
Options:
--bonno TEXT
--bar TEXT
--help Show this message and exit.
Type Inference (Extensible)
Out of the box...
data-class click can infer click parameter type (eg: option(type=click.INT)) from the attribute type.
These types are static so if, like click.Path, you need arguments, you can always specify the type yourself like
normal.
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path
from typing import Annotated
from uuid import UUID
from dataclass_click import option
@dataclass
class Config:
a: Annotated[str, option()] # click.STRING
b: Annotated[bool, option()] # click.BOOL
c: Annotated[int, option()] # click.INT
d: Annotated[float, option()] # click.FLOAT
e: Annotated[UUID, option()] # click.UUID
f: Annotated[datetime, option()] # click.DateTime()
g: Annotated[Path, option()] # click.Path(path_type=Path)
Extending it...
Type inference is extensible so a program can add and even change the default click ParameterTypes associated with a
Python data type. Eg: if you want to add a Decimal:
from decimal import Decimal
import click
import dataclass_click
class DecimalParameterType(click.ParamType):
name = "integer"
def convert(self, value, param, ctx):
if isinstance(value, Decimal):
return value
try:
return Decimal(value)
except ValueError:
self.fail(f"{value!r} is not a valid decimal number", param, ctx)
DECIMAL = DecimalParameterType()
# Extend type inference to add Decimal
dataclass_click.register_type_inference(Decimal, DECIMAL)
Required Inference
To avoid tricky mismatches between required options and optional attributes, dataclass-click will infer a field is
required if neither default= nor required= are explicitly set and the attribute type hint is not optional:
from dataclasses import dataclass
from typing import Annotated
from dataclass_click import option
@dataclass
class Config:
# Infer --foo is required because str is not optional
foo: Annotated[str, option()]
# Infer --bar is not required because str | None is optional
bar: Annotated[str | None, option()]
# No inference performed because required= is set.
baz: Annotated[str | None, option(required=True)]
# Infer not required because default= set.
bob: Annotated[str, option(default="no")]
# If you want to shoot yourself in the foot, you can!
# Not inferred because required=False.
# Click will pass None even though the attribute is not optional
bonno: Annotated[str, option(required=False)]
Usage: main.py [OPTIONS]
Options:
--bob TEXT
--baz TEXT [required]
--bar TEXT
--foo TEXT [required]
--bonno
--help Show this message and exit.
Metadata
Release files for dataclass-click 1.0.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dataclass_click-1.0.4.tar.gz | 7.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dataclass_click-1.0.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 16.1 kB
Release files / dataclass_click-1.0.4.tar.gz
| Download URL | dataclass_click-1.0.4.tar.gz |
|---|---|
| Size | 7.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
10e7de638dd9e68ae9abd5086f61d8ddee42b1873a70f5fd9fd2167856afac11
|
|
BLAKE2b-256 checksum How to use checksums |
89825b6035efd90621771fa039960eab3e1ec7ff2a8625033272856843e8bd27
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2025.
Transparency logRelease files / dataclass_click-1.0.4-py3-none-any.whl
| Download URL | dataclass_click-1.0.4-py3-none-any.whl |
|---|---|
| Size | 8.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a225d30c04e4abbdba411cc3d5ec0a2ea829e1dca6500afe5f87cc243e5ead72
|
|
BLAKE2b-256 checksum How to use checksums |
86dc38a94a2eb5f756724a6dc87a7aea38f7b747fe7b2e9daabc34a65e6cd9ac
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2025.
Transparency log