Skip to content

Accept abstract ancestor capabilities without requiring Widget constructors - #181

Merged
trissim merged 2 commits into
mainfrom
fix/p407-ancestor-capability
Oct 21, 2026
Merged

trissim merged 2 commits into
mainfrom
fix/p407-ancestor-capability

Conversation

@trissim

@trissim trissim commented Oct 21, 2026 •

Copy link
Copy Markdown

P407: abstract ancestor capabilities

Fixes the Textual dependency of OpenHCSDev/toad#1115. SessionScope is an abstract DOMNode capability, not a concrete Widget constructor. The old type[QueryType] overload rejected both its Widget bound and its abstractness.

  • src/textual/css/query.py:53: one unbound AncestorType; existing Widget-bound QueryType is unchanged.
  • src/textual/dom.py:1820: replace the class-selector overload with TypeForm[AncestorType]; implementation returns DOMNode | AncestorType. String and expect_type overloads are unchanged.
  • Decode the external selector once. CSS strings retain the existing DOMQuery matcher; nominal classes use isinstance. Both feed one ancestor walk and one unchanged expect_type filter. Reject non-class type forms explicitly at that boundary. No cast, ignore, Any, alternate API, or duplicated walk.
  • Keep upstream Python 3.9 support: ordinary boundary decoding, not a match statement; metadata/ruff minimum unchanged.
  • tests/test_query.py: one abstract-mixin test returning the exact existing parent instance. The abstractmethod-only mixin follows Textual's metaclass-compatible convention.

Verification at ad554b3

Background commands, existing dependencies, timeout 300, faulthandler_timeout=60:

pytest -q -n 0 -o faulthandler_timeout=60 tests/test_query.py::test_query_ancestor_abstract_mixin
1 passed in 0.36s

pytest -q -n 0 -o faulthandler_timeout=60 tests/test_query.py
17 passed in 0.44s

The second count includes the new case. No full suite or local ratchet.

A focused mypy caller using the real Toad SessionScope and assert_type(child.query_ancestor(SessionScope), SessionScope) passes without a cast/ignore. The whole dom.py check still reports 33 diagnostics outside query_ancestor; the two introduced implementation errors from the first annotation-only checkpoint are gone. Python ast.parse(feature_version=(3,9)) accepts the changed module. No installation claim.

Owner/consumer evidence

Existing refactor-audit Package/Repository inventory: 255 production modules and 484 test modules, zero parse omissions. It enumerates query declarations, imports, QueryType/AncestorType, DOMQuery._matches, of_type, and every syntactic query_ancestor consumer. Toad's separate complete Scope inventory is on Textualize#1115. Dynamic aliases are not claimed resolved by AST.

Search: rg -n 'AncestorType|def query_ancestor|TypeForm' src/textual/{css/query,dom}.py shows one AncestorType declaration and the replacement overload/implementation. The superseded constructor overload is deleted, not kept alongside the new one.

Assumed:

  • Ancestor selectors are CSS strings or nominal runtime classes; arbitrary non-class TypeForm values are not a second selector language.
  • Runtime nominal membership remains Python isinstance; CSS selection remains DOMQuery's existing matcher.

@trissim
trissim marked this pull request as ready for review October 21, 2026 12:18
Copilot AI balanced review requested due to automatic review settings October 21, 2026 12:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

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.

2 participants