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

RuntimeError: This event loop is already running #1824

Open auxsvr opened 6 months ago

auxsvr commented 6 months ago

Using prompt-toolkit 3.0.41, every time I launch scrapy shell (Scrapy 2.11.0) with ipython 8.18.0 and Python 3.10.12, the following stacktrace is produced:


RuntimeError Traceback (most recent call last) File ~/.local/bin/scrapy:8 6 if name == 'main': 7 sys.argv[0] = re.sub(r'(-script.pyw|.exe)?$', '', sys.argv[0]) ----> 8 sys.exit(execute())

File ~/.local/lib/python3.10/site-packages/scrapy/cmdline.py:161, in execute(argv, settings) 158 _run_print_help(parser, cmd.process_options, args, opts) 160 cmd.crawler_process = CrawlerProcess(settings) --> 161 _run_print_help(parser, _run_command, cmd, args, opts) 162 sys.exit(cmd.exitcode)

File ~/.local/lib/python3.10/site-packages/scrapy/cmdline.py:114, in _run_print_help(parser, func, *a, kw) 112 def _run_print_help(parser, func, *a, *kw): 113 try: --> 114 func(a, kw) 115 except UsageError as e: 116 if str(e):

File ~/.local/lib/python3.10/site-packages/scrapy/cmdline.py:169, in _run_command(cmd, args, opts) 167 _run_command_profiled(cmd, args, opts) 168 else: --> 169 cmd.run(args, opts)

File ~/.local/lib/python3.10/site-packages/scrapy/commands/shell.py:88, in Command.run(self, args, opts) 85 self._start_crawler_thread() 87 shell = Shell(crawler, update_vars=self.update_vars, code=opts.code) ---> 88 shell.start(url=url, redirect=not opts.no_redirect)

File ~/.local/lib/python3.10/site-packages/scrapy/shell.py:75, in Shell.start(self, url, request, response, spider, redirect) 73 # always add standard shell as fallback 74 shells += ["python"] ---> 75 start_python_console( 76 self.vars, shells=shells, banner=self.vars.pop("banner", "") 77 )

File ~/.local/lib/python3.10/site-packages/scrapy/utils/console.py:108, in start_python_console(namespace, banner, shells) 106 shell = get_shell_embed_func(shells) 107 if shell is not None: --> 108 shell(namespace=namespace, banner=banner) 109 except SystemExit: # raised when using exit() in python code.interact 110 pass

File ~/.local/lib/python3.10/site-packages/scrapy/utils/console.py:24, in _embed_ipython_shell..wrapper(namespace, banner) 20 InteractiveShellEmbed.clear_instance() 21 shell = InteractiveShellEmbed.instance( 22 banner1=banner, user_ns=namespace, config=config 23 ) ---> 24 shell()

File /usr/lib/python3.10/site-packages/IPython/terminal/embed.py:251, in InteractiveShellEmbed.call(self, header, local_ns, module, dummy, stack_depth, compile_flags, **kw) 247 self.show_banner() 249 # Call the embedding code with a stack depth of 1 so it can skip over 250 # our call and get the original caller's namespaces. --> 251 self.mainloop( 252 local_ns, module, stack_depth=stack_depth, compile_flags=compile_flags 253 ) 255 self.banner2 = self.old_banner2 257 if self.exit_msg is not None:

File /usr/lib/python3.10/site-packages/IPython/terminal/embed.py:343, in InteractiveShellEmbed.mainloop(self, local_ns, module, stack_depth, compile_flags) 340 self.set_completer_frame() 342 with self.builtin_trap, self.display_trap: --> 343 self.interact() 345 # now, purge out the local namespace of IPython's hidden variables. 346 if local_ns is not None:

File /usr/lib/python3.10/site-packages/IPython/terminal/interactiveshell.py:872, in TerminalInteractiveShell.interact(self) 869 print(self.separate_in, end='') 871 try: --> 872 code = self.prompt_for_code() 873 except EOFError: 874 if (not self.confirm_exit) \ 875 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):

File /usr/lib/python3.10/site-packages/IPython/terminal/interactiveshell.py:813, in TerminalInteractiveShell.prompt_for_code(self) 807 text = asyncio_loop.run_until_complete( 808 self.pt_app.prompt_async( 809 default=default, self._extra_prompt_options() 810 ) 811 ) 812 else: --> 813 text = self.pt_app.prompt( 814 default=default, 815 inputhook=self._inputhook, 816 self._extra_prompt_options(), 817 ) 819 return text

File ~/.local/lib/python3.10/site-packages/prompt_toolkit/shortcuts/prompt.py:1026, in PromptSession.prompt(self, message, editing_mode, refresh_interval, vi_mode, lexer, completer, complete_in_thread, is_password, key_bindings, bottom_toolbar, style, color_depth, cursor, include_default_pygments_style, style_transformation, swap_light_and_dark_colors, rprompt, multiline, prompt_continuation, wrap_lines, enable_history_search, search_ignore_case, complete_while_typing, validate_while_typing, complete_style, auto_suggest, validator, clipboard, mouse_support, input_processors, placeholder, reserve_space_for_menu, enable_system_prompt, enable_suspend, enable_open_in_editor, tempfile_suffix, tempfile, default, accept_default, pre_run, set_exception_handler, handle_sigint, in_thread, inputhook) 1023 with self._dumb_prompt(self.message) as dump_app: 1024 return dump_app.run(in_thread=in_thread, handle_sigint=handle_sigint) -> 1026 return self.app.run( 1027 set_exception_handler=set_exception_handler, 1028 in_thread=in_thread, 1029 handle_sigint=handle_sigint, 1030 inputhook=inputhook, 1031 )

File ~/.local/lib/python3.10/site-packages/prompt_toolkit/application/application.py:994, in Application.run(self, pre_run, set_exception_handler, handle_sigint, in_thread, inputhook) 991 return asyncio.run(coro) 992 else: 993 # Use existing loop. --> 994 return loop.run_until_complete(coro) 996 else: 997 # No loop installed. Run like usual. 998 return asyncio.run(coro)

File /usr/lib64/python3.10/asyncio/base_events.py:625, in BaseEventLoop.run_until_complete(self, future) 614 """Run until the Future is done. 615 616 If the argument is a coroutine, it is wrapped in a Task. (...) 622 Return the Future's result, or raise its exception. 623 """ 624 self._check_closed() --> 625 self._check_running() 627 new_task = not futures.isfuture(future) 628 future = tasks.ensure_future(future, loop=self)

File /usr/lib64/python3.10/asyncio/base_events.py:584, in BaseEventLoop._check_running(self) 582 def _check_running(self): 583 if self.is_running(): --> 584 raise RuntimeError('This event loop is already running') 585 if events._get_running_loop() is not None: 586 raise RuntimeError( 587 'Cannot run the event loop while another loop is running')

RuntimeError: This event loop is already running

The cause seems to be using asyncio.get_event_loop(), which will soon be deprecated. This is related to https://github.com/scrapy/scrapy/issues/6160.

wasertech commented 1 month ago

Very annoying indeed. It's polluting my xonsh sessions on python 3.12.3 (and prompt toolkit 3.0.36).

Until a suitable solution is found:

# to be added at the top of the definition of the prompt-toolkit shell
# in: xonsh.ptk_shell.shell
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning, module="prompt_toolkit.eventloop.utils", lineno=118)

To silence:

.../lib/python3.12/site-packages/prompt_toolkit/eventloop/utils.py:118: DeprecationWarning: There is no current event loop
  return asyncio.get_event_loop_policy().get_event_loop()

This won't fix op's runtime error but it will keep your shell clean if you'r using xonsh/0.16.0.

EDIT: updating to version 3.0.43 (>3.0.36) of the toolkit should fix it from my understanding of the code and this review on op's PR