Run Pyrefly alongside Mypy - #232
Merged
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #232 +/- ##
=======================================
Coverage 96.68% 96.68%
=======================================
Files 22 22
Lines 1540 1540
=======================================
Hits 1489 1489
Misses 51 51 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Click makes Option.get_help_record() responsible for deciding whether an option contributes a row to help output: its return type is a tuple or None. Click currently returns None only for hidden options, which Cloup already filtered before calling it, so this does not fix an observed runtime bug. Custom Option subclasses, or a future Click implementation, may omit a row for other reasons. Build the result from every non-None help record so OptionGroup honors that upstream contract and its tuple-only return annotation remains accurate. The assignment expression evaluates get_help_record() once and makes the separate hidden check unnecessary. Cover the extension point with a visible custom option that returns None.
janluke
force-pushed
the
codex/add-pyrefly-check
branch
from
September 10, 2026 22:58
54c27a6 to
dd7147f
Compare
Click exposes Command.context_class and Context.formatter_class as writable class attributes typed as subclasses of its Context and HelpFormatter bases. Cloup narrows them because its command and formatting implementations rely on the corresponding Cloup extensions. That narrowing violates the Liskov substitution principle at the type level. Code accepting a Click base class may assign any compatible Click factory, including one that does not produce a Cloup subclass. The same assignment is not valid for Cloup, so a mutable override cannot safely narrow its type and Pyrefly is correct to reject it. These settings should have been modeled as read-only class-level accessors. In the absence of class properties, a class method returning the factory type would let each subclass override it with a covariant return type while keeping clients from assigning a different factory. Final is not an alternative because it would also forbid subclasses from specializing the setting. Click's public API and internals already use attributes, so Cloup cannot adopt the class-method design without breaking compatibility. Retain the established runtime contract and suppress only these two deliberate mutable-override diagnostics.
Click's Group.command() and Group.group() methods accept bare decorator use and additional positional forms. Cloup deliberately requires parentheses and makes the class and Cloup-specific settings keyword-only. This narrower API is documented and tested, but it is not substitutable for every invocation accepted by the Click base methods. Keep Cloup's existing overloads and runtime behavior. Suppress Pyrefly's bad-override diagnostic at the two declarations, alongside the existing Mypy override suppression, rather than widening the public signatures to advertise forms that Cloup rejects.
Constraint.check() accepts either a sequence of parameter names or a sequence of Click Parameter objects. After the first element is shown not to be a string, Pyrefly narrows the union to the Parameter sequence and considers the existing cast redundant. Mypy does not generalize that element check to the sequence variant and still needs the cast in strict mode. Keep the cast so Mypy can verify the downstream calls, explain why it remains, and suppress only Pyrefly's redundant-cast warning at that expression.
janluke
force-pushed
the
codex/add-pyrefly-check
branch
2 times, most recently
from
September 11, 2026 00:44
9b1b1b9 to
1e6075d
Compare
Add Pyrefly to the shared development environment. In Hatch's aggregate typing script, run it before Mypy so it provides fast feedback, while the subsequent Mypy runs retain compatibility with the project's established checker and its strict source policy. These commands intentionally stop after the first failure. Split type checking into named Pyrefly and Mypy Hatch scripts, then compose them in that order in the aggregate typing script. Expose the same scripts as individual Task targets. The plain Task workflow also runs Pyrefly before Mypy, while the full matrix workflow runs both checkers and all prepared environments concurrently for throughput. Require the shared Hatch runner's inputs so malformed internal calls fail clearly. Run the checker-specific Hatch scripts as separate sequential CI steps in each supported Python and Click environment. This keeps their results visible in the GitHub job while preserving the same Pyrefly-first failure behavior. Select Pyrefly's default preset explicitly instead of relying on automatic migration from the small Mypy configuration. Start with package sources and the dedicated public typing tests, and make unused Pyrefly suppressions errors so checker-specific exceptions cannot silently become stale.
The command decorator overloads now preserve the concrete cloup.Command type for the two test helpers. Their casts predate that typing improvement and no longer communicate a real uncertainty: Pyrefly reports them as redundant, and Mypy accepts the direct return values as well. Return the decorated commands directly and remove the unused cast imports.
Expand Pyrefly's project inputs to the same source, test, and example trees covered by the existing Mypy commands. Keep Pyrefly's default analysis and return inference for examples. Unlike Mypy's default mode, Pyrefly normally checks bodies of completely unannotated functions. Much of the test suite intentionally uses dynamic fixtures, monkey-patching, and invalid calls to exercise runtime errors. Disable body checking only for unannotated test helpers to match the existing Mypy policy; annotated tests, including the public typing-contract tests, remain fully checked. Add explicit roots for the src layout, the tests package, and the standalone Manim example modules. Ignore only the optional click_default_group import when it is unavailable, instead of hiding unrelated missing dependencies.
janluke
force-pushed
the
codex/add-pyrefly-check
branch
from
September 11, 2026 00:46
1e6075d to
b403bd8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add Pyrefly to the Hatch typing workflow and every CI test environment, using its default preset across package sources, tests, and examples. Hatch, CI, and the plain Task typing workflow run Pyrefly before Mypy for fast failure; the full Task matrix runs both checkers concurrently for throughput. Unannotated test helper bodies retain Mypy's existing treatment, while annotated tests remain fully checked.
The integration also makes option-group help collection defer to Click's
Option.get_help_record()contract, including custom options that omit a help row, and records the intentional checker differences around Cloup's fixed class factories, narrower group decorator API, and sequence narrowing. The individual commit messages explain the motivation and tradeoffs for each change in detail.Closes #233.