@@ -956,10 +956,17 @@ def run_in_thread() -> None:
956956 set_exception_handler = set_exception_handler ,
957957 handle_sigint = handle_sigint ,
958958 )
959- if inputhook is None :
960- # No loop installed. Run like usual.
961- return asyncio .run (coro )
962- else :
959+
960+ def _called_from_ipython () -> bool :
961+ try :
962+ return (
963+ "IPython/terminal/interactiveshell.py"
964+ in sys ._getframe (3 ).f_code .co_filename
965+ )
966+ except BaseException :
967+ return False
968+
969+ if inputhook is not None :
963970 # Create new event loop with given input hook and run the app.
964971 # In Python 3.12, we can use asyncio.run(loop_factory=...)
965972 # For now, use `run_until_complete()`.
@@ -969,6 +976,27 @@ def run_in_thread() -> None:
969976 loop .close ()
970977 return result
971978
979+ elif _called_from_ipython ():
980+ # workaround to make input hooks work for IPython until
981+ # https://github.com/ipython/ipython/pull/14241 is merged.
982+ # IPython was setting the input hook by installing an event loop
983+ # previously.
984+ try :
985+ # See whether a loop was installed already. If so, use that.
986+ # That's required for the input hooks to work, they are
987+ # installed using `set_event_loop`.
988+ loop = asyncio .get_event_loop ()
989+ except RuntimeError :
990+ # No loop installed. Run like usual.
991+ return asyncio .run (coro )
992+ else :
993+ # Use existing loop.
994+ return loop .run_until_complete (coro )
995+
996+ else :
997+ # No loop installed. Run like usual.
998+ return asyncio .run (coro )
999+
9721000 def _handle_exception (
9731001 self , loop : AbstractEventLoop , context : dict [str , Any ]
9741002 ) -> None :
0 commit comments