fix: make Signal.fire keyword-only to type the dispatch contract - #1784
fix: make Signal.fire keyword-only to type the dispatch contract#1784bluetoothbot wants to merge 7 commits into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1784 +/- ##
=======================================
Coverage 99.81% 99.81%
=======================================
Files 33 33
Lines 3750 3750
Branches 533 533
=======================================
Hits 3743 3743
Misses 5 5
Partials 2 2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Coverage is incomplete. Ci is failing |
Rebase with requested adjustmentsBranch StatsActions performed
CI statusCI will be checked asynchronously. Automated by Kōan |
Confirmed, both still open. Coverage: Protocol CI: test plan skipped mypy and pre-commit. Suspect Cleanest fix drops Protocol entirely. Keep Note: last force-push rebased only. Feedback step aborted on session limit. |
|
|
Signal._handlers was typed list[Callable[..., None]] and fire accepted arbitrary **kwargs, so a typo at a fire site or a missing parameter at a handler only blew up the moment a real service event dispatched - hours into a run on a quiet network. mypy could not catch dispatch mismatches when the contract shifted. Lock the contract down: define a ServiceStateChangeHandler Protocol describing the (zeroconf, service_type, name, state_change) keyword signature, type Signal._handlers as a list of that Protocol, and make Signal.fire keyword-only with the four named parameters. register_handler / unregister_handler still accept Callable[..., None] for back-compat and cast at the boundary.
Rebase with requested adjustmentsBranch Changes applied
StatsActions performed
CI statusCI will be checked asynchronously. Automated by Kōan |
034cd22 to
1220891
Compare
Re-reviewed at head Protocol gone. Diff now matches your requested variant: keyword-only mypy ignores at Only remaining nit: retitle. Suggest |
|
|
Rebase with requested adjustmentsBranch Changes applied
Not changed (and why)
StatsActions performed
CI statusCI will be checked asynchronously. Automated by Kōan |
PR Review — fix: make Signal.fire keyword-only to type the dispatch contractThe Specific strengths: the keyword-only signature matches the sole internal caller (
🟡 Important
1. Unrelated Cython <3.3 build-system cap bundled into a typing fix — and it likely doesn't cover the jobs that run on PRs
|
Rebase with requested adjustmentsBranch Changes applied
Not changed (and why)
StatsActions performed
CI statusCI will be checked asynchronously. Automated by Kōan |
Summary
Signal.fire(**kwargs: Any)forwarded arbitrary kwargs to handlers typedCallable[..., None], so a typo at a fire site or a missing parameter at ahandler only surfaced when a real service event happened to dispatch. mypy
could not catch dispatch mismatches.
fire()is now keyword-only with the four documented parameters(
zeroconf,service_type,name,state_change) and forwards themexplicitly, so the dispatch contract is checked statically.
Closes #1779
Changes
Signal.firekeyword-only with an explicit(*, zeroconf, service_type, name, state_change)signature.**kwargs.positional-arg rejection.
Behaviour notes
Signalis importable from the top-level package (back-compat import insrc/zeroconf/__init__.py, not in__all__). Third-party code thatinstantiated its own
Signaland calledfire()with other kwargs nowgets a
TypeErrorinstead of dispatching.Signalis undocumented; thistightening is the intent of the issue.
_services/__init__.pyis inTO_CYTHONIZEandSignalis acdef class. With Cython 3's defaultannotation_typing,service_type: strand
name: strbecome typed arguments in the compiled wheel, so anon-
strargument raisesTypeErrorthere while pure Python forwards it.The only in-tree caller (
browser.py) always passesstr.Test plan
SKIP_CYTHON=1 poetry run pytest tests/(full suite green).poetry run ruff check/ruff format --checkon the touched files (clean).REQUIRE_CYTHON=1regeneration succeeds for_services/__init__.py.Generated by Kōan