prompt-toolkit / python-prompt-toolkit

Library for building powerful interactive command line applications in Python
https://python-prompt-toolkit.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
9.1k stars 717 forks source link

Catching exception from key bindings handler #1851

Open tage64 opened 4 months ago

tage64 commented 4 months ago

Is it possible to catch an exception raised in a key bindings handler? Not inside the application, but it should be possible outside the application. Consider the following MVE:

import asyncio

from prompt_toolkit import PromptSession
from prompt_toolkit.key_binding import KeyBindings

async def main():
    bindings = KeyBindings()

    @bindings.add("c-t")
    def handler(_):
        raise Exception("Hello!")

    try:
        await PromptSession().prompt_async("> ", key_bindings=bindings)
    except Exception as ex:
        print(f"Caught exception: {ex}")

if __name__ == "__main__":
    asyncio.run(main())

Running that program and hitting CTRL+T at the prompt should raise an exception in the handler function, and since keyboard processing happen inside the prompt_async application the exception should be propagated to the caller of prompt_async(), I think.

But I get the following error:

Unhandled exception in event loop:                                                                                                                          
  File "/usr/lib/python3.11/asyncio/events.py", line 80, in _run                                                                                            
    self._context.run(self._callback, *self._args)                                                                                                          
  File "/usr/lib/python3.11/site-packages/prompt_toolkit/input/vt100.py", line 162, in callback_wrapper                                                     
    callback()                                                                                                                                              
  File "/usr/lib/python3.11/site-packages/prompt_toolkit/application/application.py", line 714, in read_from_input_in_context                               
    context.copy().run(read_from_input)                                                                                                                     
  File "/usr/lib/python3.11/site-packages/prompt_toolkit/application/application.py", line 694, in read_from_input                                          
    self.key_processor.process_keys()                                                                                                                       
  File "/usr/lib/python3.11/site-packages/prompt_toolkit/key_binding/key_processor.py", line 272, in process_keys                                           
    self._process_coroutine.send(key_press)                                                                                                                 
  File "/usr/lib/python3.11/site-packages/prompt_toolkit/key_binding/key_processor.py", line 187, in _process                                               
    self._call_handler(matches[-1], key_sequence=buffer[:])                                                                                                 
  File "/usr/lib/python3.11/site-packages/prompt_toolkit/key_binding/key_processor.py", line 322, in _call_handler                                          
    handler.call(event)                                                                                                                                     
  File "/usr/lib/python3.11/site-packages/prompt_toolkit/key_binding/key_bindings.py", line 126, in call                                                    
    result = self.handler(event)                                                                                                                            
             ^^^^^^^^^^^^^^^^^^^                                                                                                                            
  File "$HOME/ptktest.py", line 12, in handler                                                                                                         
    raise Exception("Hello!")                                                                                                                               

Exception Hello!                                                                                                                                            
Press ENTER to continue...                                                                                                                                  

I expect it to just print:

Caught exception: Hello!

And then exit.

Is this possible in any way?

Best regards, Tage