asyncio.py 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. """
  2. Inputhook for running the original asyncio event loop while we're waiting for
  3. input.
  4. By default, in IPython, we run the prompt with a different asyncio event loop,
  5. because otherwise we risk that people are freezing the prompt by scheduling bad
  6. coroutines. E.g., a coroutine that does a while/true and never yield back
  7. control to the loop. We can't cancel that.
  8. However, sometimes we want the asyncio loop to keep running while waiting for
  9. a prompt.
  10. The following example will print the numbers from 1 to 10 above the prompt,
  11. while we are waiting for input. (This works also because we use
  12. prompt_toolkit`s `patch_stdout`)::
  13. In [1]: import asyncio
  14. In [2]: %gui asyncio
  15. In [3]: async def f():
  16. ...: for i in range(10):
  17. ...: await asyncio.sleep(1)
  18. ...: print(i)
  19. In [4]: asyncio.ensure_future(f())
  20. """
  21. from prompt_toolkit import __version__ as ptk_version
  22. from IPython.core.async_helpers import get_asyncio_loop
  23. PTK3 = ptk_version.startswith("3.")
  24. def inputhook(context):
  25. """
  26. Inputhook for asyncio event loop integration.
  27. """
  28. # For prompt_toolkit 3.0, this input hook literally doesn't do anything.
  29. # The event loop integration here is implemented in `interactiveshell.py`
  30. # by running the prompt itself in the current asyncio loop. The main reason
  31. # for this is that nesting asyncio event loops is unreliable.
  32. if PTK3:
  33. return
  34. # For prompt_toolkit 2.0, we can run the current asyncio event loop,
  35. # because prompt_toolkit 2.0 uses a different event loop internally.
  36. # get the persistent asyncio event loop
  37. loop = get_asyncio_loop()
  38. def stop():
  39. loop.stop()
  40. fileno = context.fileno()
  41. loop.add_reader(fileno, stop)
  42. try:
  43. loop.run_forever()
  44. finally:
  45. loop.remove_reader(fileno)