diff --git a/src/textual/widgets/_select.py b/src/textual/widgets/_select.py index 568ecd062a..d36209495c 100644 --- a/src/textual/widgets/_select.py +++ b/src/textual/widgets/_select.py @@ -253,13 +253,17 @@ def update(self, label: RenderableType | NoSelection) -> None: """ self.label = label self.has_value = label is not Select.NULL - self.query_one("#label", Static).update( - self.placeholder if isinstance(label, NoSelection) else label - ) + try: + self.query_one("#label", Static).update( + self.placeholder if isinstance(label, NoSelection) else label + ) + except NoMatches: + pass def compose(self) -> ComposeResult: """Compose label and down arrow.""" - yield NonSelectableStatic(self.placeholder, id="label") + label = self.placeholder if isinstance(self.label, NoSelection) else self.label + yield NonSelectableStatic(label, id="label") yield NonSelectableStatic("▼", classes="arrow down-arrow") yield NonSelectableStatic("▲", classes="arrow up-arrow") diff --git a/tests/select/test_mount_crash.py b/tests/select/test_mount_crash.py new file mode 100644 index 0000000000..6a7b1181b1 --- /dev/null +++ b/tests/select/test_mount_crash.py @@ -0,0 +1,24 @@ +import pytest +import asyncio + +from textual.app import App +from textual.widgets import Select + +SELECT_OPTIONS = [(str(n), n) for n in range(3)] + +from textual.widgets._select import SelectCurrent + +async def test_select_current_update_before_mount(): + """Test that updating SelectCurrent before mount does not crash.""" + app = App() + async with app.run_test(): + select_current = SelectCurrent("placeholder") + # Update before it is mounted / composed + select_current.update("new label") + + # After mounting, the label should reflect the updated value + app.mount(select_current) + await app.workers.wait_for_complete() + + # Wait for the next tick to ensure label is updated + # (Though we might need to check if label text is correct)