Skip to content

Commit fbbd8a2

Browse files
committed
Raise an error if a widget tries to be its own parent
See #1062
1 parent f474222 commit fbbd8a2

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

src/textual/widget.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ class Widget(DOMNode):
189189
hover_style: Reactive[Style] = Reactive(Style, repaint=False)
190190
highlight_link_id: Reactive[str] = Reactive("")
191191

192+
class WidgetError(Exception):
193+
"""Base widget error."""
194+
192195
def __init__(
193196
self,
194197
*children: Widget,
@@ -233,6 +236,10 @@ def __init__(
233236
id=id,
234237
classes=self.DEFAULT_CLASSES if classes is None else classes,
235238
)
239+
240+
if self in children:
241+
raise self.WidgetError("A widget can't be its own parent")
242+
236243
self._add_children(*children)
237244

238245
virtual_size = Reactive(Size(0, 0), layout=True)
@@ -374,7 +381,7 @@ def _get_virtual_dom(self) -> Iterable[Widget]:
374381
if self._scrollbar_corner is not None:
375382
yield self._scrollbar_corner
376383

377-
class MountError(Exception):
384+
class MountError(WidgetError):
378385
"""Error raised when there was a problem with the mount request."""
379386

380387
def _find_mount_point(self, spot: int | str | "Widget") -> tuple["Widget", int]:

tests/test_widget_mounting.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
import pytest
22

33
from textual.app import App
4+
from textual.widget import Widget
45
from textual.widgets import Static
56

7+
class SelfOwn(Widget):
8+
"""Test a widget that tries to own itself."""
9+
def __init__(self) -> None:
10+
super().__init__(self)
11+
612
async def test_mount_via_app() -> None:
713
"""Perform mount tests via the app."""
814

915
# Make a background set of widgets.
1016
widgets = [Static(id=f"starter-{n}") for n in range( 10 )]
1117

18+
async with App().run_test() as pilot:
19+
with pytest.raises(Widget.WidgetError):
20+
await pilot.app.mount(SelfOwn())
21+
1222
async with App().run_test() as pilot:
1323
# Mount the first one and make sure it's there.
1424
await pilot.app.mount(widgets[0])

0 commit comments

Comments
 (0)