From 745f491b650ded0e47c722854106531553ad1d8a Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Fri, 30 Oct 2026 13:28:57 -0400 Subject: [PATCH] Declare the shared key-declaring class contract --- src/textual/keys.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/textual/keys.py b/src/textual/keys.py index 3295198a22..6864296f58 100644 --- a/src/textual/keys.py +++ b/src/textual/keys.py @@ -3,7 +3,7 @@ import unicodedata import inspect import re -from abc import ABC, abstractmethod +from abc import ABC, ABCMeta, abstractmethod from typing import TYPE_CHECKING, Callable, ClassVar, Generic, Iterator, TypeVar from enum import Enum from dataclasses import dataclass @@ -18,6 +18,14 @@ NodeT = TypeVar("NodeT", bound="DOMNode", contravariant=True) +class KeyDeclarationType(ABCMeta): + """A key-declaring class, including declarations supplied by a metaclass.""" + + def permits_key_overlap(cls, other: KeyDeclarationType) -> bool: + """An explicitly declared alternative may share this declaration's key.""" + return False + + class KeyInvocation(ABC): """The concrete command a binding invokes, independent of its active mode.""" @@ -51,7 +59,7 @@ def visible_for_focus(self, mode: type[EditingMode], focused: frozenset[str]) -> def permits_invocation_overlap(self, other: KeyInvocation) -> bool: return False - def overlaps_declaration(self, other: type[KeyDeclaration]) -> bool: + def overlaps_declaration(self, other: KeyDeclarationType) -> bool: return False @@ -62,7 +70,7 @@ def __get__(self, instance: object, owner: type[KeyDeclaration]) -> str: return owner.default_title() -class KeyDeclaration(KeyInvocation, Generic[NodeT]): +class KeyDeclaration(KeyInvocation, Generic[NodeT], metaclass=KeyDeclarationType): """Shared metadata for application actions and native editor commands. Each provider retains its existing family registry. This view discovers the @@ -109,7 +117,7 @@ def key_system(self) -> bool: def permits_invocation_overlap(self, other: KeyInvocation) -> bool: return other.overlaps_declaration(type(self)) - def overlaps_declaration(self, other: type[KeyDeclaration]) -> bool: + def overlaps_declaration(self, other: KeyDeclarationType) -> bool: return type(self).permits_key_overlap(other) @abstractmethod @@ -125,11 +133,6 @@ def bindings_for(cls, mode: type[EditingMode]) -> tuple[Binding, ...]: def summary(cls) -> str: return inspect.cleandoc(cls.__doc__ or "") - @classmethod - def permits_key_overlap(cls, other: type[KeyDeclaration]) -> bool: - """An explicitly declared alternative may share a key with another declaration.""" - return False - @classmethod def declarations(cls) -> Iterator[type[KeyDeclaration]]: """Project each key family from the declaration owner's registry."""