Skip to content

Commit 41009f0

Browse files
committed
Add a documentation page on Typer compatibility
1 parent 283e740 commit 41009f0

3 files changed

Lines changed: 42 additions & 0 deletions

File tree

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- Add the `DumpConfigOption` class and the `SERIALIZABLE_FORMATS` constant to the public API.
1010
- Fix Carapace dynamic completion: an option's value or a subcommand argument with a custom `shell_complete` now resolves through the generated spec, instead of returning empty or root-level candidates.
1111
- Verify generated Carapace specs against the real `carapace-spec` engine in the test suite.
12+
- Add a documentation page on Typer compatibility, explaining why click-extra cannot be combined with Typer and how to get the same options natively.
1213

1314
## [`8.1.4` (2026-06-27)](https://github.com/kdeldycke/click-extra/compare/v8.1.3...v8.1.4)
1415

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pytest
3636
wrap
3737
man-page
3838
carapace
39+
typer
3940
benchmark
4041
```
4142

docs/typer.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# {octicon}`git-compare` Typer compatibility
2+
3+
[Typer](https://typer.tiangolo.com) builds command-line interfaces from function type hints, on top of Click. Since click-extra also builds on Click, it is natural to expect the two to combine: a Typer app that picks up click-extra's configuration loading, logging and themed help. They do not combine, and this page explains why, and what to reach for instead.
4+
5+
## Why click-extra and Typer don't compose
6+
7+
click-extra extends the Click and [Cloup](https://cloup.readthedocs.io) classes installed in your environment: its commands, options and context all derive from them. Recent Typer bundles its own private copy of Click instead of using the one click-extra extends. A Typer command therefore subclasses Typer's bundled `Command`, a different class from the `click.Command` that click-extra subclasses, even though both descend from a common Click codebase.
8+
9+
Because the two come from separate class lineages, they cannot be merged. A hybrid such as `class MyCommand(click_extra.Command, TyperCommand)` is a valid class declaration, but it inherits two unrelated `Command` implementations at once and cannot be instantiated: Typer hands it arguments that click-extra's Click base does not accept. Construction aside, click-extra's options are `click.Parameter` objects that Typer's bundled parser does not recognize, so they would never be parsed. No `cls=` argument or runtime patch bridges this: the gap is between two copies of Click, not between two ways of using one.
10+
11+
## How this differs from rich-click
12+
13+
[rich-click](https://rich-click.readthedocs.io) does integrate with Typer, through its [`patch_typer()`](https://rich-click.readthedocs.io/en/latest/documentation/typer/) helper, which can look like a counterexample. The difference is in what each library changes. rich-click only restyles the help *output*: it overrides how help is rendered and leaves Typer's own command construction and parsing untouched, so it never crosses the Click-lineage boundary.
14+
15+
click-extra's value is the opposite kind of work. Its features run *during parsing*: `--config` loads a file and feeds it into the command's defaults, `--verbosity` configures logging, `--color` and `--version` resolve ahead of the rest. That requires being a working Click command inside the same parser that runs it, which is exactly what Typer's bundled Click forecloses. Restyling output transfers to Typer; parse-time behavior does not.
16+
17+
## Using click-extra's features instead
18+
19+
If you want the options Typer lacks (configuration files, logging control, a metadata-aware `--version`, themed help), build the CLI with click-extra's own decorators. `@command` and `@group` are drop-in replacements for Click's, and they add the full set of extra options automatically:
20+
21+
```{click:source}
22+
from click_extra import command, option
23+
24+
@command
25+
@option("--unit", help="Temperature scale.")
26+
def forecast(unit):
27+
"""Show today's forecast."""
28+
```
29+
30+
The extra options are there without declaring them:
31+
32+
```{click:run}
33+
result = invoke(forecast, args=["--help"])
34+
assert result.exit_code == 0
35+
assert "--config" in result.output
36+
assert "--verbosity" in result.output
37+
assert "--version" in result.output
38+
```
39+
40+
See the [tutorial](tutorial.md) and [commands](commands.md) pages for the full feature set. The trade-off is the authoring style: click-extra defines parameters with explicit `@option` and `@argument` decorators rather than from function type hints. If type-hint-driven definition matters more than the extra options, stay on Typer and reach for rich-click to prettify its help.

0 commit comments

Comments
 (0)