Skip to content
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

Importing trio-asyncio from within IPython crashes IPython #132

Closed
DRMacIver opened this issue Jan 10, 2024 · 2 comments · Fixed by #137
Closed

Importing trio-asyncio from within IPython crashes IPython #132

DRMacIver opened this issue Jan 10, 2024 · 2 comments · Fixed by #137

Comments

@DRMacIver
Copy link

When running IPython 8.20.0 and trio-asyncio 0.13.0, importing trio_asyncio immediately crashes IPython:

In [1]: %config Application.verbose_crash=True

In [2]: import trio_asyncio

/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/trio_asyncio/_loop.py:289: TrioAsyncioDeprecationWarning: Using trio-asyncio outside of a Trio event loop is deprecated since trio-asyncio 0.10.0 with no replacement
  return _trio_policy.new_event_loop()
Error in sys.excepthook:
Traceback (most recent call last):
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/pathlib.py", line 1250, in is_dir
    return S_ISDIR(self.stat().st_mode)
                   ^^^^^^^^^
AttributeError: 'str' object has no attribute 'stat'

Original exception was:
Traceback (most recent call last):
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/bin/ipython", line 8, in <module>
    sys.exit(start_ipython())
             ^^^^^^^^^^^^^^^
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/IPython/__init__.py", line 130, in start_ipython
    return launch_new_instance(argv=argv, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/traitlets/config/application.py", line 1043, in launch_instance
    app.start()
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/IPython/terminal/ipapp.py", line 317, in start
    self.shell.mainloop()
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/IPython/terminal/interactiveshell.py", line 911, in mainloop
    self.interact()
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/IPython/terminal/interactiveshell.py", line 896, in interact
    code = self.prompt_for_code()
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/IPython/terminal/interactiveshell.py", line 839, in prompt_for_code
    text = self.pt_app.prompt(
           ^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/prompt_toolkit/shortcuts/prompt.py", line 1026, in prompt
    return self.app.run(
           ^^^^^^^^^^^^^
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/prompt_toolkit/application/application.py", line 1002, in run
    return asyncio.run(coro)
           ^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/trio_asyncio/_sync.py", line 125, in run_until_complete
    return self.__run_in_thread(self._run_coroutine, future)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/trio_asyncio/_sync.py", line 172, in __run_in_thread
    return res.unwrap()
           ^^^^^^^^^^^^
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/outcome/_impl.py", line 138, in unwrap
    raise captured_error
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/trio_asyncio/_sync.py", line 160, in _run_coroutine
    return result.unwrap()
           ^^^^^^^^^^^^^^^
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/outcome/_impl.py", line 138, in unwrap
    raise captured_error
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/prompt_toolkit/application/application.py", line 875, in run_async
    loop = stack.enter_context(set_loop())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/contextlib.py", line 517, in enter_context
    result = _enter(cm)
             ^^^^^^^^^^
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/contextlib.py", line 137, in __enter__
    return next(self.gen)
           ^^^^^^^^^^^^^^
  File "/opt/homebrew/Caskroom/miniforge/base/envs/py311/lib/python3.11/site-packages/prompt_toolkit/application/application.py", line 789, in set_loop
    loop = get_running_loop()
           ^^^^^^^^^^^^^^^^^^
RuntimeError: no running event loop

This also happens if I import trio_asyncio indirectly (e.g. inside a function).

I cannot reproduce this crash outside of IPython - importing trio-asyncio doesn't crash in the same way, even if I do it for the first time inside a running asyncio event loop.

I was on the fence as to whether to file this with IPython or trio-asyncio - it's IPython exhibiting the problem, but I suspect it's due to shenanigans that importing trio-asyncio is doing to the running asyncio event loop. If you'd rather I file this with IPython, please let me know and I'll do so.

@oremanj
Copy link
Member

oremanj commented Jan 10, 2024

I've narrowed this down to a change in prompt-toolkit between version 3.0.36 and 3.0.37. If you downgrade your prompt-toolkit to 3.0.36, that will likely be sufficient to work around this issue for now.

trio-asyncio is doing some evil things here that it shouldn't be doing; it's not prompt-toolkit's fault (or IPython's). I'll see if I can fix it, but I don't totally understand how the existing code works.

@oremanj
Copy link
Member

oremanj commented Jan 10, 2024

Also, if you immediately reset the event loop policy (in the same cell), that seems to be a sufficient workaround also:

In [1]: import trio_asyncio, asyncio; asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy())

In [2]:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants