Textualize / textual

The lean application framework for Python. Build sophisticated user interfaces with a simple Python API. Run your apps in the terminal and a web browser.
https://textual.textualize.io/
MIT License
25.36k stars 777 forks source link

textual._on.OnDecoratorError: The message class must have a 'control' to match with the on decorator #5144

Open machin3io opened 2 hours ago

machin3io commented 2 hours ago

Using the Enter or Leave event decorators with a CSS selector throws the following exception:

Traceback (most recent call last):
  File "/home/x/Archive/python/2024/textual/enter_leave_css_selector.py", line 9, in <module>
    class EnterLeave(App):
  File "/home/x/Archive/python/2024/textual/enter_leave_css_selector.py", line 14, in EnterLeave
    @on(Enter, "Button")
  File "/home/x/.local/lib/python3.10/site-packages/textual/_on.py", line 69, in on
    raise OnDecoratorError(
textual._on.OnDecoratorError: The message class must have a 'control' to match with the on decorator

Textual Diagnostics

Versions

Name Value
Textual 0.83.0
Rich 13.8.1

Python

Name Value
Version 3.10.12
Implementation CPython
Compiler GCC 11.4.0
Executable /usr/bin/python3

Operating System

Name Value
System Linux
Release 6.9.3-76060903-generic
Version #202405300957~1718348209~22.04~7817b67 SMP PREEMPT_DYNAMIC Mon J

Terminal

Name Value
Terminal Application Alacritty
TERM alacritty
COLORTERM truecolor
FORCE_COLOR Not set
NO_COLOR Not set

Rich Console options

Name Value
size width=229, height=43
legacy_windows False
min_width 1
max_width 229
is_terminal True
encoding utf-8
max_height 43
justify None
overflow None
no_wrap False
highlight None
markup None
height None

It will be helpful if you run the following command and paste the results:

Example Code


#!/usr/bin/python

from textual import on
from textual.app import App
from textual.events import Enter, Leave
from textual.widgets import Button

class EnterLeave(App):
    def compose(self):
        yield Button("Hello")

    @on(Enter, "Button")
    @on(Leave, "Button")
    def hover_button(self, event):
        button = self.query_one(Button)

        if event.handler_name == "on_enter":
            button.label = "Hovering" 

        else:
            button.label = "Hello" 

EnterLeave().run()

Without the selectors it works fine, but then I have to check within the method if I'm entering or leaving a specific widget I want to act on:

#!/usr/bin/python

from textual import on
from textual.app import App
from textual.events import Enter, Leave
from textual.widgets import Button

class EnterLeave(App):
    def compose(self):
        yield Button("Hello")

    @on(Enter)
    @on(Leave)
    def hover_button(self, event):
        button = self.query_one(Button)

        if event.handler_name == "on_enter":
            button.label = "Hovering" 

        else:
            button.label = "Hello" 

EnterLeave().run()
github-actions[bot] commented 2 hours ago

We found the following entries in the FAQ which you may find helpful:

Feel free to close this issue if you found an answer in the FAQ. Otherwise, please give us a little time to review.

This is an automated reply, generated by FAQtory