Skip to content

Make command decorators interchangeable with Click's - #238

Merged
janluke merged 2 commits into
masterfrom
click-compatible-decorators
Sep 11, 2026
Merged

Make command decorators interchangeable with Click's#238
janluke merged 2 commits into
masterfrom
click-compatible-decorators

Conversation

@janluke

@janluke janluke commented Sep 11, 2026

Copy link
Copy Markdown
Owner

Starting with v4.0.0, Cloup will make an effort to be interchangeable with Click. This PR aligns Cloup with Click in how you can call command decorators. There are indeed two (undocumented) differences right now:

  1. in click, you can use command decorators without parenthesis ("bare decorators"); cloup requires parenthesis even when no args are passed
  2. in click, cls can be passed as 2nd positional argument; in Cloup, it must be a keyword argument.

Click allows `@command(name, CommandCls)`; Cloup made every argument but `name`
keyword-only in 0.9.0, so the same call raised TypeError. That made Cloup's
decorators non-substitutable for Click's, which matters now that Cloup
re-exports Click's top-level namespace.

Move `cls` ahead of the keyword-only marker in the no-`cls` overloads and the
implementations, and add an overload for the positional form.

That overload repeats the keyword arguments of the keyword-`cls` overload rather
than collapsing them into `**kwargs` the way Click's does. Click's shape also
matches `name` positional plus `cls` by keyword, which would shadow the precise
overload and silently stop type-checking standard keyword arguments whenever a
`cls` was passed at all. Marking the parameters positional-only avoids that but
forces every implementation signature to become `(*args, **kwargs)`, since MyPy
rejects a named implementation under a positional-only overload. Repeating the
list keeps both call styles checked and leaves the implementations readable:
`command("n", MyCmd, hidden="yes")` is now reported, which Click itself does not
report.

Claude-Session: https://claude.ai/code/session_017ynEswQdUZFthFUdh7fKAW
Click has supported `@command` without parentheses since 8.1. Cloup raised a
custom exception telling the user to add them, so the most common line in any
Click application failed at import time when the import was switched to Cloup.

Accept a callback in place of `name` in all four decorators, via a shared
`_resolve_decorator_first_arg` helper, and add an overload for the bare form.
The "you forgot parenthesis" error and its tests go away: the form it guarded
against is now valid.

The bare overload also drops both `# type: ignore[override]` on Group.command
and Group.group. Click's base overloads are typed `(*args: Any, **kwargs: Any)`,
which MyPy reads as an unspecified signature that any override may narrow -- but
its first overload returns a command rather than a decorator, so an override had
to cover that shape before MyPy would accept it.

Pyrefly implements no such leniency, not even for a plain non-overloaded
`(*args: Any, **kwargs: Any)`, so its two suppressions stay. Removing them would
take a trailing `(*args: Any, **kwargs: Any)` overload, which would silence every
keyword argument error on these two methods.

Claude-Session: https://claude.ai/code/session_017ynEswQdUZFthFUdh7fKAW
@codecov

codecov Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.88%. Comparing base (14731cc) to head (6317da6).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #238      +/-   ##
==========================================
+ Coverage   96.87%   96.88%   +0.01%     
==========================================
  Files          22       22              
  Lines        1633     1639       +6     
==========================================
+ Hits         1582     1588       +6     
  Misses         51       51              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@janluke janluke added this to the v4.0.0 milestone Sep 11, 2026
@janluke
janluke merged commit 866e645 into master Sep 11, 2026
15 checks passed
@janluke
janluke deleted the click-compatible-decorators branch September 12, 2026 03:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant