asynchronous imports in pythonยค
lets say we have a python module with a top level await statement. this is valid in javascript and ipython, but not python due to the ambiguity of the top level await. we'll start digging into what it takes to have async imports in python
https://gist.github.com/Rich-Harris/0b6f317657f5167663b493c722647221
dream
is a our async
function and catcher
is a value we have access to
async def dream():
await __import__("asyncio").sleep(1)
return "dream on"
print(catcher := await dream())
by default, importing modules with top level await is a fail because await
can't be outside a function.
try:
with __import__("importnb").Notebook(): import __
except SyntaxError as error: assert "'await' outside function" == error.args[0], error
# boiler plate
import importnb, ast; from IPython import get_ipython
shell = get_ipython();
we're about to do some nasty nested async
business when we are working interactively.
below we ask IPython
to prefer to the trio
thread when we execute code cells
this way we can own the asyncio
event loop.
if "__file__" not in locals():
__import__('nest_asyncio').apply()
shell.loop_runner =__import__("IPython").core.async_helpers._trio_runner
luckily there is a flag for top level awaits thanks to matthias and his hard work on IPython
.
https://docs.python.org/3/library/ast.html#ast.PyCF_ALLOW_TOP_LEVEL_AWAIT
we'll make an importer that includes the PyCF_ALLOW_TOP_LEVEL_AWAIT
flag and executes the module through an asynchronous version of eval
class ANotebook(importnb.Notebook):
def exec_module(self, module):
code = self.get_code(self.name)
return __import__("asyncio").run(eval(code, vars(module)))
def source_to_code(self, nodes, path, *, _optimize=-1):
if not isinstance(nodes, ast.Module):
nodes = self.parse(nodes)
return compile(self.visit(nodes), path, "exec", optimize=_optimize, flags=ast.PyCF_ALLOW_TOP_LEVEL_AWAIT)
with ANotebook(): import __11_12_async_import as anb
assert anb.catcher == "dream on"
we haven't done anything fancy with asyncing the reading the and decoding of the source. we'll get there though. this is just opening the can of worms. the jokes should follow.