Repository navigation
fix(typing): check mypy --strict against the pinned OWNd 2.0.0b11 types - #765
Merged
GreenGrassBlueOcean merged 1 commit intoOct 21, 2026
Merged
Conversation
The strict-typing workflow never installed OWNd and pyproject.toml ignored missing OWNd.* imports, so every OWNd name was Any in CI and the ratchet reported 0 errors without checking the boundary. With the pinned OWNd==2.0.0b11 wheel visible, mypy --strict found 14 errors in 7 modules. - strict-typing.yml installs the exact OWNd== pin from manifest.json, and OWNd.* leaves the ignore_missing_imports override. - Drop the pre-b11 ImportError fallbacks in where_grammar.py, gateway_events.py and services.py (the WHO 25 frame-table fallback included); b11's builders emit the same frames. - Type GatewayIdentityMixin.gateway as OWNGateway, read is_closed via getattr in cover.py, widen cover_scope.handle_event to OWNMessage, and give push_button/scenario/where locals their Optional types. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
GreenGrassBlueOcean
added a commit
that referenced
this pull request
Oct 21, 2026
…rrect the OWNd licence OWNd.discovery.find_gateways() and get_gateway() fetch the gateway's UPnP/SOAP description over HTTP and accept an optional aiohttp session. The config flow called them without one, so OWNd opened its own ClientSession per call. Pass async_get_clientsession(self.hass) and mark inject-websession done in quality_scale.yaml. quality_scale.yaml also described OWNd as MIT/GPL licensed; it is Apache-2.0 (OWNd LICENSE and pyproject.toml). Rebuilt on v2-phase1-architecture: the typing changes this branch carried before are in #765, and the OWNd pin stays at 2.0.0b11. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged
1 task done
GreenGrassBlueOcean
added a commit
that referenced
this pull request
Oct 21, 2026
… b11 Since #765 the mypy ratchet checks against the pinned OWNd 2.0.0b11 types, and expose.py reported 15 errors: gateway.send() takes OWNCommand while the frame lists were list[OWNMessage], and cmd/confirm took the type of their first branch (OWNEnergyCommand) before being reassigned to gateway, lighting and automation commands. Every builder returns an OWNCommand subclass, so the lists and both variables are now typed OWNCommand. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 21, 2026
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.
Follow-up to OWNd 2.0.0b11, which
manifest.jsononv2-phase1-architecturepins. Found while verifying #764.1. What is the problem?
.github/workflows/strict-typing.yml,pyproject.toml):strict-typing.ymlinstalls Home Assistant and mypy but not OWNd, andpyproject.tomllistsOWNd.*underignore_missing_imports = true. In CI everyOWNdname is thereforeAny, and the ratchet reports0 error(s); baseline 0without ever checking the MyHOME ↔ OWNd boundary.OWNd ships
py.typed. With the pinnedOWNd==2.0.0b11wheel visible,mypy --strictreports 14 errors in 7 modules:gateway_events.pytype: ignore[misc]on the pre-b11OWNScenarioPlusEventstub;push_button(int | None) andscenario(str | None) assigned to narrower localsservices.pyOWNScenarioPlusCommand = Nonefallback assignsNoneto a classgateway_sessions.pygatewayproperties returnhandler.gateway, typedAnyonGatewayIdentityMixincover.pymessage.is_closedread onOWNMessage, which has no such attributewhere_grammar.pyis_apl_address/area_of_where/normalize_wheresignatures differ from OWNd'sgateway_resync.pyOWNLightingEvent.where(str | None) passed to_normalize_ptp_where(str | int)cover_scope.pyhandle_event(OWNAutomationEvent)narrows theMyHOMECover.handle_event(OWNMessage)overridewhere_grammar.py,gateway_events.pyandservices.pystill carryexcept ImportErrorfallbacks for OWNd 2.0.0b10 (local copies of the WHERE grammar, stubOWNScenarioPlusEvent/OWNDoorEntryEventclasses, and a hand-built WHO 25 frame table). WithOWNd==2.0.0b11pinned they can never run, and three of the errors above come from them.2. How is it solved?
strict-typing.yml,pyproject.toml):strict-typing.ymlreads the exactOWNd==pin frommanifest.jsonand installs it next to Home Assistant and mypy, so the ratchet checks the types users actually install. It uses the PyPI release, not a git branch.OWNd.*is removed from theignore_missing_importsoverride (serial_asynciostays), so a missing OWNd is an error instead of a silentAny.[project.optional-dependencies]floor moves fromOWNd>=2.0.0b10toOWNd>=2.0.0b11.where_grammar.py: importsarea_of_where,is_apl_addressandnormalize_wherefromOWNd.messagedirectly. The fallback copies and thesetattr(_ownd_msg, …)back-patching are gone.gateway_events.py: importsOWNDoorEntryEventandOWNScenarioPlusEventdirectly.services.py:send_scenario_plus_commandalways usesOWNScenarioPlusCommand. TheOWNCommand.parseframe-table fallback is gone. b11's builder produces the same*25*11#0*W##,*25*12*W##,*25*13#0#5*W##,*25*14#0#5*W##and*25*15*W##frames, whichtest_send_scenario_plus_command_serviceasserts.identity.py:GatewayIdentityMixin.gatewayis typedOWNGatewayinstead ofAny.cover.py: readsis_closedonce withgetattrand storesbool(is_closed).cover_scope.py:handle_event(message: OWNMessage), matchingMyHOMECover.gateway_events.py:pb_val: int | None.scene_val: int | str | Noneconverts only a non-Nonescenario toint; the behaviour is unchanged, sinceint(None)previously hit theTypeErrorbranch and keptNone.gateway_resync.py:_normalize_ptp_where(raw_where: str | int | None, …)states what it already receives.tests/test_services.py: the fallback parse-failure case becomes a typed-builder case, whereOWNScenarioPlusCommand.turn_onreturns a command withis_valid=Falseand the service raisesscenario_plus_command_invalid.docs/quality_scale_plan.md: the "OWNd does not shippy.typed" note now says OWNd is checked at its pin.Overlap with #757: #757 makes the same
pyproject.toml/strict-typing.ymlchange and fixes 11 of these errors, but it installs OWNd from a git branch and pinsOWNd==2.0.0b10. If this PR lands first, #757 can shrink to its websession injection andquality_scale.yamllicence fix.3. State Diagram
flowchart LR M["manifest.json\nOWNd==2.0.0b11"] --> I["strict-typing.yml\npip install OWNd==2.0.0b11"] I --> Y["mypy --strict\n(OWNd py.typed, no ignore override)"] Y --> R["scripts/typing_ratchet.py\nbaseline 0"] R -->|"any OWNd boundary error"| F["job fails"] R -->|"0 errors"| P["job passes"]4. Where are the traces (real ones)?
No bus behaviour changes, so no new trace applies. The only runtime path touched is
send_scenario_plus_command, which now always uses OWNd's builder. Its frames are pinned bytests/test_services.py::test_send_scenario_plus_command_service, and the WHO 25 traces intests/fixtures/traces/keep replaying unchanged in the full suite.5. What does the Firmware Oracle / Encyclopedia say?
Not applicable: this PR changes typing, CI and dead import fallbacks, not protocol behaviour. The WHO 25 frames
send_scenario_plus_commandemits are byte-identical before and after.Verification
mypy --strict(pyproject.tomlconfig) with the releasedOWNd==2.0.0b11wheel:Success: no issues found in 71 source files;scripts/typing_ratchet.py:0 error(s) in 0 module(s); baseline 0. Before this PR, the same run reported 14 errors in 7 modules.Full suite against the released
OWNd==2.0.0b11wheel with--cov=custom_components/myhome:4358 passed, 5 snapshots passed,TOTAL 14456 statements, 0 missed, 100.0%ruff check custom_components tests scripts,scripts/verify_ha_standards.py,scripts/sync_documentation.py --check: all passV2 Architecture: New entities implement
handle_event()and do not manually subscribe viaasync_dispatcher_connect. (No entities are added;MyHOMEScopeCover.handle_eventonly changes its annotation.)🤖 Generated with Claude Code