-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Closed
Description
I think it is related to: #5629
Best to have some stress on your machine. I've got a basic Ryzen 5600x
and
stress --cpu 4 --timeout 600s --vm 4 --io 4 --vm-bytes 1024M
is enough for me.
To reproduce, you just need to spam "LMB" on the notification to close it, it will crash. If there is no notification title, it will crash with same error as in #5629
MRE:
from __future__ import annotations
from textual.app import App, ComposeResult
from textual.widgets import Static
class ExampleApp(App):
def compose(self) -> ComposeResult:
yield Static("Close notifications as fast as you can :)")
def on_mount(self) -> None:
self.set_interval(0.2, lambda: self.notify(title="Press me to close!", message="not me"))
if __name__ == "__main__":
ExampleApp().run()Stacktrace:
╭───────────────────────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────────────────────╮
│ /home/mzebrak/.pyenv/versions/clive-3.10.13/lib/python3.10/site-packages/textual/app.py:3748 in on_event │
│ │
│ 3745 │ │ │ │ │ │ # Shouldn't occur, since at the very least this will find the Sc │
│ 3746 │ │ │ │ │ │ self._mouse_down_widget = None │
│ 3747 │ │ │ │ │
│ ❱ 3748 │ │ │ │ self.screen._forward_event(event) │
│ 3749 │ │ │ │ │
│ 3750 │ │ │ │ # If a MouseUp occurs at the same widget as a MouseDown, then we should │
│ 3751 │ │ │ │ # consider it a click, and produce a Click event. │
│ │
│ ╭───────────────────────────────────────────── locals ─────────────────────────────────────────────╮ │
│ │ _ = Region(x=89, y=35, width=60, height=4) │ │
│ │ event = MouseDown(None, x=103, y=36, pointer_x=103.0, pointer_y=36.0, button=1) │ │
│ │ self = ExampleApp(title='ExampleApp', classes={'-dark-mode'}, pseudo_classes={'focus', 'dark'}) │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /home/mzebrak/.pyenv/versions/clive-3.10.13/lib/python3.10/site-packages/textual/screen.py:1533 in _forward_event │
│ │
│ 1530 │ │ │ elif isinstance(event, events.MouseDown) and not self.app.mouse_captured: │
│ 1531 │ │ │ │ self._box_select = event.shift │
│ 1532 │ │ │ │ self._mouse_down_offset = event.screen_offset │
│ ❱ 1533 │ │ │ │ select_widget, select_offset = self.get_widget_and_offset_at( │
│ 1534 │ │ │ │ │ event.screen_x, event.screen_y │
│ 1535 │ │ │ │ ) │
│ 1536 │ │ │ │ if ( │
│ │
│ ╭──────────────────────────────────── locals ─────────────────────────────────────╮ │
│ │ event = MouseDown(None, x=103, y=36, pointer_x=103.0, pointer_y=36.0, button=1) │ │
│ │ self = Screen(id='_default') │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /home/mzebrak/.pyenv/versions/clive-3.10.13/lib/python3.10/site-packages/textual/screen.py:634 in get_widget_and_offset_at │
│ │
│ 631 │ │ Returns: ╭─────────── locals ───────────╮ │
│ 632 │ │ │ Tuple of Widget and Offset, both of which may be None. │ self = Screen(id='_default') │ │
│ 633 │ │ """ │ x = 103 │ │
│ ❱ 634 │ │ return self._compositor.get_widget_and_offset_at(x, y) │ y = 36 │ │
│ 635 │ ╰──────────────────────────────╯ │
│ 636 │ def find_widget(self, widget: Widget) -> MapGeometry: │
│ 637 │ │ """Get the screen region of a Widget. │
│ │
│ /home/mzebrak/.pyenv/versions/clive-3.10.13/lib/python3.10/site-packages/textual/_compositor.py:904 in get_widget_and_offset_at │
│ │
│ 901 │ │ y -= region.y + gutter_right │
│ 902 │ │ │
│ 903 │ │ visible_screen_stack.set(widget.app._background_screens) │
│ ❱ 904 │ │ line = widget.render_line(y) │
│ 905 │ │ │
│ 906 │ │ end = 0 │
│ 907 │ │ start = 0 │
│ │
│ ╭──────────────────────────────────────────────────────── locals ─────────────────────────────────────────────────────────╮ │
│ │ gutter_left = 2 │ │
│ │ gutter_right = 1 │ │
│ │ region = Region(x=89, y=35, width=60, height=4) │ │
│ │ self = <Compositor size=Size(width=151, height=40) widgets={Static(), Toast(), Screen(id='_default'), Toast()}> │ │
│ │ widget = Toast() │ │
│ │ x = -90 │ │
│ │ y = -36 │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /home/mzebrak/.pyenv/versions/clive-3.10.13/lib/python3.10/site-packages/textual/widget.py:3902 in render_line │
│ │
│ 3899 │ │ │ A rendered line. ╭──── locals ────╮ │
│ 3900 │ │ """ │ self = Toast() │ │
│ 3901 │ │ if self._dirty_regions: │ y = -36 │ │
│ ❱ 3902 │ │ │ self._render_content() ╰────────────────╯ │
│ 3903 │ │ try: │
│ 3904 │ │ │ line = self._render_cache.lines[y] │
│ 3905 │ │ except IndexError: │
│ │
│ /home/mzebrak/.pyenv/versions/clive-3.10.13/lib/python3.10/site-packages/textual/widget.py:3887 in _render_content │
│ │
│ 3884 │ def _render_content(self) -> None: ╭───── locals ─────╮ │
│ 3885 │ │ """Render all lines.""" │ height = 0 │ │
│ 3886 │ │ width, height = self.size │ self = Toast() │ │
│ ❱ 3887 │ │ visual = self._render() │ width = 0 │ │
│ 3888 │ │ strips = Visual.to_strips(self, visual, width, height, self.visual_style) ╰──────────────────╯ │
│ 3889 │ │ self._render_cache = _RenderCache(self.size, strips) │
│ 3890 │ │ self._dirty_regions.clear() │
│ │
│ /home/mzebrak/.pyenv/versions/clive-3.10.13/lib/python3.10/site-packages/textual/widget.py:4110 in _render │
│ │
│ 4107 │ │ if cached_visual is not None: ╭───────────── locals ─────────────╮ │
│ 4108 │ │ │ assert isinstance(cached_visual, Visual) │ cache_key = '_render.visual' │ │
│ 4109 │ │ │ return cached_visual │ cached_visual = None │ │
│ ❱ 4110 │ │ visual = visualize(self, self.render(), markup=self._render_markup) │ self = Toast() │ │
│ 4111 │ │ self._layout_cache[cache_key] = visual ╰──────────────────────────────────╯ │
│ 4112 │ │ return visual │
│ 4113 │
│ │
│ /home/mzebrak/.pyenv/versions/clive-3.10.13/lib/python3.10/site-packages/textual/widgets/_toast.py:115 in render │
│ │
│ 112 │ │ """ │
│ 113 │ │ notification = self._notification │
│ 114 │ │ if notification.title: │
│ ❱ 115 │ │ │ header_style = self.get_component_rich_style("toast--title") │
│ 116 │ │ │ notification_text = Text.assemble( │
│ 117 │ │ │ │ (notification.title, header_style), │
│ 118 │ │ │ │ "\n", │
│ │
│ ╭────────────────────────────── locals ───────────────────────────────╮ │
│ │ notification = Notification( │ │
│ │ │ message='not me', │ │
│ │ │ title='Press me to close!', │ │
│ │ │ severity='information', │ │
│ │ │ raised_it=1741871626.2424397, │ │
│ │ │ identity='62d4cbfe-cc95-4e80-946c-a15af6778914', │ │
│ │ │ time_left=4.593467473983765, │ │
│ │ │ has_expired=False │ │
│ │ ) │ │
│ │ self = Toast() │ │
│ ╰─────────────────────────────────────────────────────────────────────╯ │
│ │
│ /home/mzebrak/.pyenv/versions/clive-3.10.13/lib/python3.10/site-packages/textual/widget.py:1032 in get_component_rich_style │
│ │
│ 1029 │ │ """ ╭────────── locals ───────────╮ │
│ 1030 │ │ │ names = ('toast--title',) │ │
│ 1031 │ │ if names not in self._rich_style_cache: │ partial = False │ │
│ ❱ 1032 │ │ │ component_styles = self.get_component_styles(*names) │ self = Toast() │ │
│ 1033 │ │ │ style = component_styles.rich_style ╰─────────────────────────────╯ │
│ 1034 │ │ │ text_opacity = component_styles.text_opacity │
│ 1035 │ │ │ if text_opacity < 1 and style.bgcolor is not None: │
│ │
│ /home/mzebrak/.pyenv/versions/clive-3.10.13/lib/python3.10/site-packages/textual/dom.py:570 in get_component_styles │
│ │
│ 567 │ │ ╭──────────── locals ────────────╮ │
│ 568 │ │ for name in names: │ name = 'toast--title' │ │
│ 569 │ │ │ if name not in self._component_styles: │ names = ('toast--title',) │ │
│ ❱ 570 │ │ │ │ raise KeyError(f"No {name!r} key in COMPONENT_CLASSES") │ self = Toast() │ │
│ 571 │ │ │ component_styles = self._component_styles[name] │ styles = RenderStyles(Toast()) │ │
│ 572 │ │ │ styles.node = component_styles.node ╰────────────────────────────────╯ │
│ 573 │ │ │ styles.base.merge(component_styles.base) │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
KeyError: "No 'toast--title' key in COMPONENT_CLASSES"Metadata
Metadata
Assignees
Labels
No labels