Skip to content

Commit fcf1655

Browse files
committed
shutdown procedures
1 parent 66a1639 commit fcf1655

File tree

3 files changed

+32
-12
lines changed

3 files changed

+32
-12
lines changed

src/textual/app.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,20 +108,31 @@ async def _process_messages(self) -> None:
108108
log.exception("error starting application mode")
109109
raise
110110
try:
111-
self.refresh()
111+
# self.refresh()
112112
await super().process_messages()
113113
finally:
114114
try:
115115
driver.stop_application_mode()
116116
finally:
117117
loop.remove_signal_handler(signal.SIGINT)
118118

119-
await asyncio.gather(*(child.close_messages() for child in self.children))
120-
self.children.clear()
119+
if self.children:
120+
121+
async def close_all() -> None:
122+
for child in self.children:
123+
await child.close_messages()
124+
await asyncio.gather(*(child.task for child in self.children))
125+
126+
try:
127+
await asyncio.wait_for(close_all(), timeout=5)
128+
except asyncio.TimeoutError:
129+
raise
130+
131+
self.children.clear()
121132

122133
async def add(self, child: MessagePump) -> None:
123134
self.children.add(child)
124-
asyncio.create_task(child.process_messages())
135+
child.start_messages()
125136
await child.post_message(events.Created(sender=self))
126137

127138
def refresh(self) -> None:

src/textual/message_pump.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from __future__ import annotations
22

3-
from typing import NamedTuple
3+
from typing import Any, Coroutine, Awaitable, NamedTuple
44
import asyncio
5-
from asyncio import PriorityQueue, QueueEmpty
5+
from asyncio import Event, PriorityQueue, Task, QueueEmpty
66

77
import logging
88

@@ -57,6 +57,12 @@ def __init__(self, queue_size: int = 10, parent: MessagePump | None = None) -> N
5757
self._closed: bool = False
5858
self._disabled_messages: set[type[Message]] = set()
5959
self._pending_message: MessageQueueItem | None = None
60+
self._task: Task | None = None
61+
62+
@property
63+
def task(self) -> Task:
64+
assert self._task is not None
65+
return self._task
6066

6167
def set_parent(self, parent: MessagePump) -> None:
6268
self._parent = parent
@@ -133,9 +139,16 @@ def set_interval(
133139
asyncio.get_event_loop().create_task(timer.run())
134140
return timer
135141

136-
async def close_messages(self) -> None:
142+
async def close_messages(self, wait: bool = False) -> None:
143+
"""Close message queue, and optionally wait for queue to finish processing."""
137144
self._closing = True
138145
await self._message_queue.put(None)
146+
if wait and self._task is not None:
147+
await self._task
148+
149+
def start_messages(self) -> None:
150+
task = asyncio.create_task(self.process_messages())
151+
self._task = task
139152

140153
async def process_messages(self) -> None:
141154
"""Process messages until the queue is closed."""

src/textual/view.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ class NoWidget(Exception):
2929
pass
3030

3131

32-
@rich_repr
3332
class View(ABC, MessagePump):
3433
@property
3534
def app(self) -> "App":
@@ -45,10 +44,6 @@ def __rich_console__(
4544
return
4645
yield
4746

48-
def __rich_repr__(self) -> RichReprResult:
49-
return
50-
yield
51-
5247
@abstractmethod
5348
async def mount(self, widget: Widget, *, slot: str = "main") -> None:
5449
...
@@ -61,6 +56,7 @@ async def forward_input_event(self, event: events.Event) -> None:
6156
pass
6257

6358

59+
@rich_repr
6460
class LayoutView(View):
6561
layout: Layout
6662

0 commit comments

Comments
 (0)