admin管理员组文章数量:1134247
I have set IPYTHONDIR=.ipython
, and created a startup file at .ipython/profile_default/startup/01_hello.py
. Now, when I run ipython
, it executes the contents of that file as if they had been entered into the IPython shell.
I can run sync code this way:
# contents of 01_hello.py
print( "hello!" )
$ ipython
Python 3.12.0 (main, Nov 12 2023, 10:40:37) [GCC 11.4.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.31.0 -- An enhanced Interactive Python. Type '?' for help.
hello
In [1]:
I can also run async code directly in the shell:
# contents of 01_hello.py
print( "hello!" )
async def foo():
print( "foo" )
$ ipython
Python 3.12.0 (main, Nov 12 2023, 10:40:37) [GCC 11.4.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.31.0 -- An enhanced Interactive Python. Type '?' for help.
hello
In [1]: await foo()
foo
In [2]:
However, I cannot run async code in the startup file, even though it's supposed to be as if that code was entered into the shell:
# contents of 01_hello.py
print( "hello!" )
async def foo():
print( "foo" )
await foo()
$ ipython
Python 3.12.0 (main, Nov 12 2023, 10:40:37) [GCC 11.4.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.31.0 -- An enhanced Interactive Python. Type '?' for help.
[TerminalIPythonApp] WARNING | Unknown error in handling startup files:
File ~/proj/.ipython/profile_default/startup/01_imports.py:5
await foo()
^
SyntaxError: 'await' outside function
Question: Why doesn't this work, and is there a way to run async code in the startup file without explicitly starting a new event loop just for that? (asyncio.run()
)
Doing that wouldn't make sense, since that event loop would have to close by the end of the file, which makes it impossible to do any initialization work that involves context vars (which is where Tortoise-ORM stores its connections), which defeats the purpose.
Or stated differently: How can I access the event loop that IPython starts for the benefit of the interactive shell?
I have set IPYTHONDIR=.ipython
, and created a startup file at .ipython/profile_default/startup/01_hello.py
. Now, when I run ipython
, it executes the contents of that file as if they had been entered into the IPython shell.
I can run sync code this way:
# contents of 01_hello.py
print( "hello!" )
$ ipython
Python 3.12.0 (main, Nov 12 2023, 10:40:37) [GCC 11.4.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.31.0 -- An enhanced Interactive Python. Type '?' for help.
hello
In [1]:
I can also run async code directly in the shell:
# contents of 01_hello.py
print( "hello!" )
async def foo():
print( "foo" )
$ ipython
Python 3.12.0 (main, Nov 12 2023, 10:40:37) [GCC 11.4.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.31.0 -- An enhanced Interactive Python. Type '?' for help.
hello
In [1]: await foo()
foo
In [2]:
However, I cannot run async code in the startup file, even though it's supposed to be as if that code was entered into the shell:
# contents of 01_hello.py
print( "hello!" )
async def foo():
print( "foo" )
await foo()
$ ipython
Python 3.12.0 (main, Nov 12 2023, 10:40:37) [GCC 11.4.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.31.0 -- An enhanced Interactive Python. Type '?' for help.
[TerminalIPythonApp] WARNING | Unknown error in handling startup files:
File ~/proj/.ipython/profile_default/startup/01_imports.py:5
await foo()
^
SyntaxError: 'await' outside function
Question: Why doesn't this work, and is there a way to run async code in the startup file without explicitly starting a new event loop just for that? (asyncio.run()
)
Doing that wouldn't make sense, since that event loop would have to close by the end of the file, which makes it impossible to do any initialization work that involves context vars (which is where Tortoise-ORM stores its connections), which defeats the purpose.
Or stated differently: How can I access the event loop that IPython starts for the benefit of the interactive shell?
Share Improve this question asked Jan 7 at 18:52 odigityodigity 8,0565 gold badges41 silver badges57 bronze badges 1- FYI - Until now, I've only been using iPython as a fancier shell alternative to the default REPL. I have not delved into the land of notebooks and cells and all that other stuff. I guess I'll have to, now, to understand some of these answers. – odigity Commented 19 hours ago
3 Answers
Reset to default 1From version 8, ipython uses a function called get_asyncio_loop
to get access to the event loop that it runs async cells on. You can use this event loop during your startup script to run any tasks you want on the same event loop that async cells will run on.
NB. This is only uses for the asyncio
package in Python's standard library and not any other async libraries (such as trio
).
from IPython.core.async_helpers import get_asyncio_loop as _get_asyncio_loop
async def foo():
print("foo")
_get_asyncio_loop().run_until_complete(foo())
Caveat
The event loop that ipython uses DOES NOT run in the background. What this means is that unless you are running an async cell, no tasks that you have started will be running. ie. None of your Tortoise ORM connections will be serviced, which may cause them to break.
As such, you may need to run your Tortoise ORM in a separate event loop anyway, and write some glue for passing data back and forth between the two event loops.
Edit: I initially suggested using IPython's get_ipython
function to access the IPython instance and start a new event loop, but that doesn't meet odigity's needs at all. Instead, IPython's run_cell
hook could be used in the startup file:
import asyncio
from IPython import get_ipython
async def foo():
print("foo")
# Define a function to run async code using IPython's event loop
def run_async_initialization():
ipython = get_ipython()
if ipython is not None:
coro = foo()
future = asyncio.ensure_future(coro)
# Register the function to run after the IPython shell initializes
ip = get_ipython()
if ip is not None:
ip.events.register('post_run_cell', lambda: run_async_initialization())
You want to use IPython's autoawait feature, that is currently not applied to the startup scripts, only to cells.
You can run cells from within the startup script, so autoawait would work:
# contents of 01_hello.py
ip = get_ipython()
ip.run_cell("""
async def foo():
print( "foo" )
await foo()
""")
本文标签: pythonHow to run async code in IPython startup filesStack Overflow
版权声明:本文标题:python - How to run async code in IPython startup files? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736781091a1952599.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论