Skip to content

Commit c3e00ae

Browse files
authored
Merge pull request #5039 from Textualize/inline-exit-fix
fix error when exiting inline more prematurely
2 parents 322a85c + 8212f4c commit c3e00ae

File tree

7 files changed

+50
-4
lines changed

7 files changed

+50
-4
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8+
## Unreleased
9+
10+
### Fixed
11+
12+
- Fixed crash when exiting the app prematurely https://github.com/Textualize/textual/pull/5039
13+
814
## [0.80.0] - 2024-09-23
915

1016
### Added

src/textual/drivers/linux_driver.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ def process_selector_events(
408408
try:
409409
while not self.exit_event.is_set():
410410
process_selector_events(selector.select(0.1))
411+
selector.unregister(self.fileno)
411412
process_selector_events(selector.select(0.1), final=True)
412413

413414
finally:

src/textual/drivers/linux_inline_driver.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,11 @@ def process_selector_events(
161161
self.cursor_origin = (event.x, event.y)
162162
else:
163163
self.process_event(event)
164-
self.process_event(event)
165164

166165
try:
167166
while not self.exit_event.is_set():
168167
process_selector_events(selector.select(0.1))
168+
selector.unregister(self.fileno)
169169
process_selector_events(selector.select(0.1), final=True)
170170

171171
finally:
@@ -296,7 +296,10 @@ def disable_input(self) -> None:
296296
if self._key_thread is not None:
297297
self._key_thread.join()
298298
self.exit_event.clear()
299-
termios.tcflush(self.fileno, termios.TCIFLUSH)
299+
try:
300+
termios.tcflush(self.fileno, termios.TCIFLUSH)
301+
except termios.error:
302+
pass
300303

301304
except Exception as error:
302305
# TODO: log this

src/textual/screen.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ def render(self) -> RenderableType:
451451
background = self.styles.background
452452
try:
453453
base_screen = visible_screen_stack.get().pop()
454-
except IndexError:
454+
except LookupError:
455455
base_screen = None
456456

457457
if base_screen is not None and background.a < 1:

src/textual/widgets/_directory_tree.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class DirectoryTree(Tree[DirEntry]):
3535
ICON_NODE_EXPANDED = "📂 "
3636
ICON_NODE = "📁 "
3737
ICON_FILE = "📄 "
38+
"""Unicode 'icon' to represent a file."""
3839

3940
COMPONENT_CLASSES: ClassVar[set[str]] = {
4041
"directory-tree--extension",

src/textual/widgets/_tree.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,9 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
517517
"""A widget for displaying and navigating data in a tree."""
518518

519519
ICON_NODE = "▶ "
520+
"""Unicode 'icon' to use for an expandable node."""
520521
ICON_NODE_EXPANDED = "▼ "
522+
"""Unicode 'icon' to use for an expanded node."""
521523

522524
BINDINGS: ClassVar[list[BindingType]] = [
523525
Binding("shift+left", "cursor_parent", "Cursor to parent", show=False),

tests/test_app.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from rich.terminal_theme import DIMMED_MONOKAI, MONOKAI, NIGHT_OWLISH
44

55
from textual.app import App, ComposeResult
6-
from textual.widgets import Button, Input
6+
from textual.widgets import Button, Input, Static
77

88

99
def test_batch_update():
@@ -140,3 +140,36 @@ async def test_ansi_theme():
140140

141141
app.dark = True
142142
assert app.ansi_theme == DIMMED_MONOKAI
143+
144+
145+
async def test_early_exit():
146+
"""Test exiting early doesn't cause issues."""
147+
from textual.app import App
148+
149+
class AppExit(App):
150+
def compose(self):
151+
yield Static("Hello")
152+
153+
def on_mount(self) -> None:
154+
# Exit after creating app
155+
self.exit()
156+
157+
app = AppExit()
158+
async with app.run_test():
159+
pass
160+
161+
162+
def test_early_exit_inline():
163+
"""Test exiting early in inline mode doesn't break."""
164+
from textual.app import App
165+
166+
class AppExit(App):
167+
def compose(self):
168+
yield Static("Hello")
169+
170+
def on_mount(self) -> None:
171+
# Exit after creating app
172+
self.exit()
173+
174+
app = AppExit()
175+
app.run(inline=True, inline_no_clear=True)

0 commit comments

Comments
 (0)