From bd3a723d86f9c550b0324153975580b70509cb22 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Mon, 10 Oct 2022 10:46:33 +0100 Subject: [PATCH] Move aliasing/normalisation logic into Key --- src/textual/events.py | 16 ++++++++++++++-- src/textual/message_pump.py | 10 ++-------- tests/test_message_pump.py | 8 -------- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/textual/events.py b/src/textual/events.py index d0cb8c24a..ae68cc758 100644 --- a/src/textual/events.py +++ b/src/textual/events.py @@ -1,12 +1,13 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Awaitable, Callable, Type, TypeVar +from typing import TYPE_CHECKING, Awaitable, Callable, Type, TypeVar, Iterable import rich.repr from rich.style import Style from ._types import MessageTarget from .geometry import Offset, Size +from .keys import _get_key_aliases from .message import Message MouseEventT = TypeVar("MouseEventT", bound="MouseEvent") @@ -209,7 +210,13 @@ class Key(InputEvent): @property def key_name(self) -> str | None: """Name of a key suitable for use as a Python identifier.""" - return self.key.replace("+", "_") + return _normalize_key(self.key) + + @property + def key_aliases(self) -> Iterable[str]: + """Get the aliases for the key, including the key itself""" + for alias in _get_key_aliases(self.key): + yield _normalize_key(alias) @property def is_printable(self) -> bool: @@ -222,6 +229,11 @@ class Key(InputEvent): return False if self.char is None else self.char.isprintable() +def _normalize_key(key: str) -> str: + """Convert the key string to a name suitable for use as a Python identifier.""" + return key.replace("+", "_") + + @rich.repr.auto class MouseEvent(InputEvent, bubble=True): """Sent in response to a mouse event. diff --git a/src/textual/message_pump.py b/src/textual/message_pump.py index 552664355..0f47b9a71 100644 --- a/src/textual/message_pump.py +++ b/src/textual/message_pump.py @@ -548,11 +548,6 @@ class MessagePump(metaclass=MessagePumpMeta): private_handler_name = f"_key_{key}" private_handler = getattr(pump, private_handler_name, None) - if public_handler and private_handler: - _raise_duplicate_key_handlers_error( - key, public_handler_name, private_handler_name - ) - return public_handler or private_handler invoked_method = None @@ -560,9 +555,8 @@ class MessagePump(metaclass=MessagePumpMeta): if not key_name: return False - key_aliases = _get_key_aliases(event.key) - for key_alias in key_aliases: - key_method = get_key_handler(self, key_alias.replace("+", "_")) + for key_alias in event.key_aliases: + key_method = get_key_handler(self, key_alias) if key_method is not None: if invoked_method: _raise_duplicate_key_handlers_error( diff --git a/tests/test_message_pump.py b/tests/test_message_pump.py index 716704088..749afa1d8 100644 --- a/tests/test_message_pump.py +++ b/tests/test_message_pump.py @@ -47,14 +47,6 @@ class DuplicateHandlersWidget(Widget): self.called_by = self.key_ctrl_i -async def test_dispatch_key_raises_when_public_and_private_handlers(): - """When both a public and private handler exists for one key, we fail fast via exception.""" - widget = DuplicateHandlersWidget() - with pytest.raises(DuplicateKeyHandlers): - await widget.dispatch_key(Key(widget, key="x", char="x")) - assert widget.called_by is None - - async def test_dispatch_key_raises_when_conflicting_handler_aliases(): """If you've got a handler for e.g. ctrl+i and a handler for tab, that's probably a mistake. In the terminal, they're the same thing, so we fail fast via exception here."""