-
Notifications
You must be signed in to change notification settings - Fork 841
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LinuxDriver: Exit if thread dies #3431
Changes from 3 commits
a0b7516
054b9f0
646dcad
dda3bb3
afcd5de
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,9 +9,10 @@ | |
import tty | ||
from codecs import getincrementaldecoder | ||
from threading import Event, Thread | ||
from typing import TYPE_CHECKING, Any | ||
from typing import TYPE_CHECKING, Any, Callable | ||
|
||
import rich.repr | ||
import rich.traceback | ||
|
||
from .. import events, log | ||
from .._xterm_parser import XTermParser | ||
|
@@ -23,6 +24,25 @@ | |
from ..app import App | ||
|
||
|
||
class ExceptionHandlingThread(Thread): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extending Thread doesn't seem warranted here. Could we not wrap There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's what Or do you mean we could wrap the body of We could also pass a new method as the We could also set threading.exceptionhook to a function that terminates the application. But that would affect all threads in the entire application. I don't think that's a good idea because developers might want to set that themselves. Breaking textual by configuring exception in your application would a pretty annoying bug. We would also have to bump the minimum Python version to 3.8. The benefit of If you really don't like the new class, I'd recommend the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I ws proposing a wrapper. I would just call it |
||
""" | ||
Thread that passes any exception from `target` to `exception_handler` | ||
|
||
WARNING: `exception_handler` is called inside the thread. You can | ||
schedule calls via `App.call_later`. | ||
""" | ||
|
||
def __init__(self, *args, exception_handler, **kwargs) -> None: | ||
super().__init__(*args, **kwargs) | ||
self._exception_handler: Callable = exception_handler | ||
|
||
def run(self) -> None: | ||
try: | ||
super().run() | ||
except BaseException as error: | ||
self._exception_handler(error) | ||
|
||
|
||
@rich.repr.auto(angular=True) | ||
class LinuxDriver(Driver): | ||
"""Powers display and input for Linux / MacOS""" | ||
|
@@ -164,7 +184,10 @@ def on_terminal_resize(signum, stack) -> None: | |
self.write("\x1b[?25l") # Hide cursor | ||
self.write("\033[?1003h\n") | ||
self.flush() | ||
self._key_thread = Thread(target=self.run_input_thread) | ||
self._key_thread = ExceptionHandlingThread( | ||
target=self.run_input_thread, | ||
exception_handler=self._handle_input_thread_exception, | ||
) | ||
send_size_event() | ||
self._key_thread.start() | ||
self._request_terminal_sync_mode_support() | ||
|
@@ -264,7 +287,11 @@ def more_data() -> bool: | |
unicode_data = decode(read(fileno, 1024)) | ||
for event in feed(unicode_data): | ||
self.process_event(event) | ||
except Exception as error: | ||
log(error) | ||
finally: | ||
selector.close() | ||
|
||
def _handle_input_thread_exception(self, error): | ||
self._app.call_later( | ||
self._app.panic, | ||
rich.traceback.Traceback(), | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need
Callable
?