# sniffio: Sniff out which async library your code is running under

You’re writing a library. You’ve decided to be ambitious, and support multiple async I/O packages, like Trio, and asyncio, and … You’ve written a bunch of clever code to handle all the differences. But… how do you know which piece of clever code to run?

This is a tiny package whose only purpose is to let you detect which async library your code is running under.

- Documentation: https://sniffio.readthedocs.io

- Bug tracker and source code: https://github.com/python-trio/sniffio

- License: MIT or Apache License 2.0, your choice

- Contributor guide: https://trio.readthedocs.io/en/latest/contributing.html

- Code of conduct: Contributors are requested to follow our code of conduct in all project spaces.

This library is maintained by the Trio project, as a service to the async Python community as a whole.

## Usage

sniffio.current_async_library() → str

  Detect which async library is currently running.

  The following libraries are currently supported:

  Library | Requires | Magic string
  --- | --- | ---
  Trio | Trio v0.6+ | `"trio"`

  Curio

  `"curio"`

  asyncio |  | `"asyncio"`
  Trio-asyncio | v0.8.2+ | `"trio"` or `"asyncio"`, depending on current mode

  Returns:

    A string like `"trio"`.

  Raises:

    AsyncLibraryNotFoundError – if called from synchronous context, or if the current async library was not recognized.

  Examples

      from sniffio import current_async_library

      async def generic_sleep(seconds):
          library = current_async_library()
          if library == "trio":
              import trio
              await trio.sleep(seconds)
          elif library == "asyncio":
              import asyncio
              await asyncio.sleep(seconds)
          # ... and so on ...
          else:
              raise RuntimeError(f"Unsupported library {library!r}")

exception sniffio.AsyncLibraryNotFoundError

## Adding support to a new async library

If you’d like your library to be detected by `sniffio`, it’s pretty easy.

Step 1: Pick the magic string that will identify your library. To avoid collisions, this should match your library’s PEP 503 normalized name on PyPI.

Step 2: There’s a special `threading.local` object:

thread_local.name

Make sure that whenever your library is calling a coroutine `throw()`, `send()`, or `close()` that this is set to your identifier string. In most cases, this will be as simple as:

    from sniffio import thread_local

    # Your library's step function
    def step(...):
         old_name, thread_local.name = thread_local.name, "my-library's-PyPI-name"
         try:
             result = coro.send(None)
         finally:
             thread_local.name = old_name

Step 3: Send us a PR to add your library to the list of supported libraries above.

That’s it!

There are libraries that directly drive a sniffio-naive coroutine from another, outer sniffio-aware coroutine such as trio_asyncio. These libraries should make sure to set the correct value while calling a synchronous function that will go on to drive the sniffio-naive coroutine.

    from sniffio import thread_local

    # Your library's compatibility loop
    async def main_loop(self, ...) -> None:
         ...
         handle: asyncio.Handle = await self.get_next_handle()
         old_name, thread_local.name = thread_local.name, "asyncio"
         try:
             result = handle._callback(obj._args)
         finally:
             thread_local.name = old_name

- Release history

# Indices and tables

- Index

- Module Index

- Search Page

- glossary