@@ -102,30 +102,39 @@ def run(self) -> None:
102102
103103 try :
104104 while True :
105- # Read.
106105 try :
107- text = self .read ()
108- except EOFError :
109- return
110-
111- # Eval.
112- try :
113- result = self .eval (text )
114- except KeyboardInterrupt as e : # KeyboardInterrupt doesn't inherit from Exception.
106+ # Read.
107+ try :
108+ text = self .read ()
109+ except EOFError :
110+ return
111+
112+ # Eval.
113+ try :
114+ result = self .eval (text )
115+ except KeyboardInterrupt as e : # KeyboardInterrupt doesn't inherit from Exception.
116+ raise
117+ except SystemExit :
118+ return
119+ except BaseException as e :
120+ self ._handle_exception (e )
121+ else :
122+ # Print.
123+ if result is not None :
124+ self .show_result (result )
125+
126+ # Loop.
127+ self .current_statement_index += 1
128+ self .signatures = []
129+
130+ except KeyboardInterrupt as e :
131+ # Handle all possible `KeyboardInterrupt` errors. This can
132+ # happen during the `eval`, but also during the
133+ # `show_result` if something takes too long.
134+ # (Try/catch is around the whole block, because we want to
135+ # prevent that a Control-C keypress terminates the REPL in
136+ # any case.)
115137 self ._handle_keyboard_interrupt (e )
116- except SystemExit :
117- return
118- except BaseException as e :
119- self ._handle_exception (e )
120- else :
121- # Print.
122- if result is not None :
123- self .show_result (result )
124-
125- # Loop.
126- self .current_statement_index += 1
127- self .signatures = []
128-
129138 finally :
130139 if self .terminal_title :
131140 clear_title ()
@@ -152,31 +161,38 @@ async def run_async(self) -> None:
152161
153162 try :
154163 while True :
155- # Read.
156164 try :
157- text = await loop .run_in_executor (None , self .read )
158- except EOFError :
159- return
160-
161- # Eval.
162- try :
163- result = await self .eval_async (text )
164- except KeyboardInterrupt as e : # KeyboardInterrupt doesn't inherit from Exception.
165+ # Read.
166+ try :
167+ text = await loop .run_in_executor (None , self .read )
168+ except EOFError :
169+ return
170+
171+ # Eval.
172+ try :
173+ result = await self .eval_async (text )
174+ except KeyboardInterrupt as e : # KeyboardInterrupt doesn't inherit from Exception.
175+ raise
176+ except SystemExit :
177+ return
178+ except BaseException as e :
179+ self ._handle_exception (e )
180+ else :
181+ # Print.
182+ if result is not None :
183+ await loop .run_in_executor (
184+ None , lambda : self .show_result (result )
185+ )
186+
187+ # Loop.
188+ self .current_statement_index += 1
189+ self .signatures = []
190+
191+ except KeyboardInterrupt as e :
192+ # XXX: This does not yet work properly. In some situations,
193+ # `KeyboardInterrupt` exceptions can end up in the event
194+ # loop selector.
165195 self ._handle_keyboard_interrupt (e )
166- except SystemExit :
167- return
168- except BaseException as e :
169- self ._handle_exception (e )
170- else :
171- # Print.
172- if result is not None :
173- await loop .run_in_executor (
174- None , lambda : self .show_result (result )
175- )
176-
177- # Loop.
178- self .current_statement_index += 1
179- self .signatures = []
180196 finally :
181197 if self .terminal_title :
182198 clear_title ()
@@ -273,12 +289,18 @@ def _compile_with_flags(self, code: str, mode: str):
273289 def show_result (self , result : object ) -> None :
274290 """
275291 Show __repr__ for an `eval` result.
292+
293+ Note: this can raise `KeyboardInterrupt` if either calling `__repr__`,
294+ `__pt_repr__` or formatting the output with "Black" takes to long
295+ and the user presses Control-C.
276296 """
277297 out_prompt = to_formatted_text (self .get_output_prompt ())
278298
279299 # If the repr is valid Python code, use the Pygments lexer.
280300 try :
281301 result_repr = repr (result )
302+ except KeyboardInterrupt :
303+ raise # Don't catch here.
282304 except BaseException as e :
283305 # Calling repr failed.
284306 self ._handle_exception (e )
@@ -313,6 +335,8 @@ def show_result(self, result: object) -> None:
313335 )
314336 if isinstance (formatted_result_repr , list ):
315337 formatted_result_repr = FormattedText (formatted_result_repr )
338+ except KeyboardInterrupt :
339+ raise # Don't catch here.
316340 except :
317341 # For bad code, `__getattr__` can raise something that's not an
318342 # `AttributeError`. This happens already when calling `hasattr()`.
0 commit comments