nest_asyncio
Patch asyncio to allow nested event loops in Jupyter, web servers, and GUIs
Repository Health
Technical Analysis
nest_asyncio is a tiny, single-purpose Python library that patches the standard library’s asyncio module to allow its event loop to be nested. By design, asyncio refuses to let you call run_until_complete or asyncio.run from inside a coroutine that is already running on the same loop, raising RuntimeError: This event loop is already running. That restriction becomes a real obstacle in environments like Jupyter notebooks, IPython kernels, and GUI toolkits that already own a running event loop, since any code path that itself wants to drive async work to completion hits the wall immediately.
Calling nest_asyncio.apply() monkey-patches asyncio’s Task/Future classes, the event loop policy, and the loop’s run_forever/run_until_complete/_run_once internals so that reentrant calls are handled safely instead of raising. The patch is applied once per loop (guarded by a _nest_patched flag) and optionally makes Tornado’s Future class asyncio-compatible when Tornado is already imported. It requires no configuration beyond the single apply() call and adds no runtime dependencies of its own, making it a common low-ceremony fix wherever nested async execution is unavoidable.
What You Get
- A single
apply(loop=None)function that patches the current (or a given) event loop to be reentrant - Compatibility patches for asyncio’s Task/Future classes across supported Python versions
- An event loop policy patch so any newly created loop is automatically patched
- Optional Tornado Future compatibility patching when Tornado is already imported
- Zero runtime dependencies and a single-file implementation that’s easy to audit
Common Use Cases
- Running
loop.run_until_complete()from inside a Jupyter or IPython notebook cell that already has a running event loop - Calling blocking async code from within a GUI application’s own event loop (e.g. Qt, Tkinter integrations)
- Allowing libraries or test harnesses that call
asyncio.run()internally to work when invoked from an already-running async context - Unblocking synchronous wrapper functions around async APIs inside frameworks that manage their own asyncio loop
Under The Hood
Architecture - The entire library lives in one 220-line module, nest_asyncio.py. apply(loop=None) orchestrates three monkey-patch passes: _patch_asyncio() rebinds asyncio.Task/asyncio.Future to their pure-Python implementations and replaces asyncio.run; _patch_policy() wraps the event loop policy’s get_event_loop so any freshly created loop is patched automatically; _patch_loop(loop) replaces the loop class’s run_forever, run_until_complete, and _run_once methods with reentrant-safe versions that temporarily pop and restore the ‘current task’ bookkeeping around each handle invocation so nested run_until_complete calls don’t trip asyncio’s own reentrancy guards. A manage_run context manager tracks nested-run depth and IOCP proactor state on Windows. Idempotency is guarded by _nest_patched flags on both the module and the loop instance. Tech Stack - Pure standard-library Python with no runtime dependencies; the only external interaction is an optional patch of Tornado’s Future class if Tornado is already imported. Packaging uses a plain setup.py/setup.cfg plus a pyproject.toml for build-system metadata; there is no compiled extension or platform-specific code besides a Windows IOCP proactor-loop branch. Code Quality - The test suite (tests/nest_test.py) uses unittest and covers the core scenarios directly: two and three levels of nested run_until_complete, ensure_future combined with nested runs, asyncio.wait, timeout propagation, running two nested loops within one outer loop, and context-variable propagation across nested runs. There are no type annotations and no linting/formatting config beyond defaults, but given the module’s small, single-purpose surface area this is proportionate; naming is clear and each patched method carries a docstring explaining its divergence from the stdlib original. API Design - The public surface is a single function, apply(loop=None), which is about as low-friction as an API can get — no configuration object, no class to instantiate, and it can be called defensively at import time without side effects on an already-patched loop. This makes onboarding trivial: one line unblocks the exact failure users hit, at the cost of relying on monkey-patching private asyncio internals, which is an inherent, load-bearing tradeoff for what the library needs to accomplish.
Used by 8 apps in this directory
Agno
Devops · AI Development · Automation
Build, run, and manage agent platforms with a full production stack — SDK, runtime, and control plane included.
argilla
AI Development · Data Engineering
Collaborate on high-quality AI training data with a self-hosted annotation platform built for LLMs, NLP, and multimodal models.
ART
AI Development
Give your LLM agents on-the-job training—ART lets you apply GRPO reinforcement learning to any multi-step agentic workflow with minimal code changes.
Firecrawl
AI Development · Developer Tools
Turn any website into clean, LLM-ready data with a single API call — no proxy headaches, no scraping complexity.
GPT Researcher
Productivity · AI Assistants
The pioneering open-source autonomous AI agent that conducts deep, multi-source research and produces citation-backed reports exceeding 2,000 words — faster and more reliably than any human researcher.
Langflow
AI Agents · AI Development
Build, test, and deploy AI agents and RAG workflows visually with native API and MCP server export.
PrivateGPT
AI Development
The open-source API layer that turns local LLMs into production private AI applications with full Claude API compatibility
QRev
CRM · AI Agents
Open source AI-first sales platform that replaces Salesforce with autonomous agents handling prospecting, outreach, and lead management at scale.