sniffio
A tiny Python library that detects which async framework (trio, asyncio, or curio) your code is currently running under.
Repository Health
Technical Analysis
sniffio solves a narrow but recurring problem for library authors who want to support multiple async I/O frameworks without hard-coding a dependency on any one of them. Calling current_async_library() from inside a coroutine returns a string identifying the active runtime, letting a library branch its implementation accordingly instead of forcing callers into a single async stack.
The detection order is deliberate: it first checks a contextvars.ContextVar and a thread-local override (used by frameworks like Trio and Trio-asyncio to explicitly declare themselves), then falls back to sniffing sys.modules for a running asyncio task, and finally checks for a running Curio loop. If none of these match, it raises AsyncLibraryNotFoundError rather than guessing.
Maintained by the Trio project as a shared utility for the async Python ecosystem, sniffio has become a de facto standard dependency pulled in transitively by major HTTP and networking libraries (httpx, anyio, and others) that need to stay framework-agnostic.
What You Get
- A single
current_async_library()function that returns a string ("trio","asyncio", or"curio") identifying the running async framework - An explicit opt-in mechanism via
current_async_library_cvar(aContextVar) andthread_local.name, so frameworks can declare their identity directly rather than relying on sniffing - Automatic fallback detection for asyncio (via
asyncio.current_task()) and curio (viacurio.meta.curio_running()) when no explicit declaration is present - A dedicated
AsyncLibraryNotFoundErrorexception raised when called outside any recognized async context, instead of returningNoneor a wrong guess - Zero runtime dependencies and a
py.typedmarker for full static type-checking support
Common Use Cases
- HTTP and networking libraries (like httpx and anyio) that expose a single async API surface but need to dispatch to trio- or asyncio-specific primitives internally
- Async compatibility shims that provide a
generic_sleep()-style helper and need to know which underlyingsleepimplementation to call - Testing utilities that must detect the active event loop implementation before setting up fixtures
- Any library author who wants to support Trio and asyncio users from one codebase without forcing a dependency on either at import time
Under The Hood
Architecture
The entire runtime behavior lives in sniffio/_impl.py, a single module with no internal layering: a module-level ContextVar (current_async_library_cvar) and a threading.local subclass (_ThreadLocal) hold explicit declarations, and current_async_library() checks them in a fixed priority order (thread-local, then contextvar, then asyncio sniffing via sys.modules and asyncio.current_task(), then curio sniffing via curio.meta.curio_running()) before raising AsyncLibraryNotFoundError. There is no dependency injection or configuration surface; the public API is exactly one function plus the two state objects frameworks use to opt in explicitly, so the only thing that would break by changing the core abstraction is the detection order itself.
Tech Stack
Pure standard-library Python: contextvars.ContextVar, threading.local, and sys.modules introspection, with zero runtime dependencies declared in pyproject.toml. The package is built with setuptools (using setuptools_scm for version derivation from git tags) and requires Python 3.10+. Test and docs tooling is isolated into [dependency-groups] (pytest, pytest-cov, curio for tests; sphinx + sphinx_rtd_theme for docs), and .mypy.ini configures strict-ish static typing with targeted ignore_missing_imports for the untyped curio and pytest packages.
Code Quality
Testing uses pytest with pytest-cov for coverage, and _tests/test_sniffio.py covers all four detection paths explicitly (contextvar override, thread-local override, live asyncio task, live curio task) plus the not-found error case, including a second call per branch to exercise caching behavior. Error handling is intentional rather than defensive: AsyncLibraryNotFoundError is a distinct RuntimeError subclass raised deliberately rather than swallowed. The codebase ships a py.typed marker and is checked with mypy, and CI (ci.sh) enforces yapf formatting and mypy --pretty on every push in addition to running the pytest suite with -W error (warnings promoted to failures).
API Design
The public surface is deliberately minimal: one function (current_async_library) plus two low-level state hooks (current_async_library_cvar, thread_local) for frameworks that want to declare themselves explicitly rather than be sniffed. There is no configuration object, no classes to instantiate, and no boilerplate — a caller imports one name and calls it. The docstring documents the exact detection table (library, minimum version required, returned string) inline, and the single custom exception type gives callers one clear thing to catch.
Used by 13 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.
ClickHouse
Databases · Analytics · Data Engineering
Open-source column-oriented database that delivers real-time analytical queries on petabyte-scale data with millisecond latency.
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.
Helicone
Monitoring · AI Development · Analytics
An open-source AI gateway and LLM observability platform that routes requests to 100+ models while logging cost, latency, and full traces for every call.
knowhere
AI Development · Developer Tools
Transform messy, unstructured documents into persistent, navigable memory that AI agents can actually use.
marimo
Developer Tools · Data Engineering
A reactive Python notebook that eliminates hidden state, runs reproducibly, and deploys as a web app or script — stored as pure Python, built for the AI era.
rowboat
AI Assistants · AI Development
Build, test, and deploy multi-agent AI workflows with a visual editor, RAG data sources, MCP tool integration, and a production-ready REST API.
Scalar
Developer Tools
Beautiful, interactive OpenAPI documentation with a built-in offline-first API client and multi-language code generation — all in one open-source platform.