pyo3-async-runtimes

PyO3 bridges between Rust async runtimes and Python's asyncio

Library
Cargo
v0.29.0
196stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
63/100Good
Development Activity56
Maintenance52
Community72
Maturity44
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
75/100Good
Architecture80
Code Quality82
Innovation75
Learning Curve62

pyo3-async-runtimes converts between Rust Futures and Python asyncio coroutines, letting native PyO3 extension modules expose async Rust functions as awaitable Python functions, and letting Rust applications embedding Python await async Python code. It supports both tokio and async-std as the Rust-side runtime, selected via Cargo feature flags, with all async Python code still running on the standard asyncio event loop for compatibility with existing Python libraries.

The crate is a fork of the now-unmaintained pyo3-asyncio, continued to track newer PyO3 releases (0.21+) and maintained under the official PyO3 GitHub organization. It provides both a low-level generic module for building custom runtime integrations and ready-made tokio/async_std modules with #[main]-style attribute macros for the common cases.

What You Get

  • into_future() to convert a Python coroutine into an awaitable Rust Future
  • future_into_py() to expose a Rust Future as an awaitable object callable from Python async def code
  • Runtime-specific modules for tokio and async-std, each with #[main] attribute macros for managing event-loop startup
  • A generic module for implementing support for additional custom async runtimes
  • A testing feature with utilities for writing PyO3 async integration tests that run under both asyncio and uvloop

Common Use Cases

  • Writing native Python extension modules (via maturin) that expose async Rust functions as async def-callable Python functions
  • Calling existing async Python libraries (e.g. an asyncio-based SDK) from a Rust application that embeds the Python interpreter
  • Building performance-critical async I/O paths in Rust while keeping the surrounding application logic in Python
  • Testing PyO3 async integrations against multiple event-loop implementations (stock asyncio, uvloop) via the crate’s testing feature

Under The Hood

Architecture — The crate’s core logic lives in src/generic.rs (the largest module, ~1,900 lines), which implements runtime-agnostic conversion logic between Rust futures and Python awaitables using a generic Runtime trait, so each concrete backend only needs to supply an executor and spawn primitive. src/tokio.rs and src/async_std.rs (each 700-850 lines) implement that trait for their respective runtimes and re-export the #[main] proc-macro attributes (defined in the separate pyo3-async-runtimes-macros workspace member) that wrap a user’s async fn main to correctly initialize the Python interpreter and hand control of the main thread to Python’s event loop — a PyO3-specific constraint the README documents at length, since Python’s asyncio needs the main thread for signal handling. src/testing.rs provides a clap+inventory-based test harness for running the same test suite against multiple event-loop backends.

Tech Stack — Rust, organized as a Cargo workspace with a pyo3-async-runtimes-macros proc-macro crate; core dependency is pyo3 itself, with tokio and async-std as optional runtime backends behind feature flags (tokio-runtime, async-std-runtime), plus async-channel/futures-channel for the unstable-streams feature. Requires Rust 1.83+ and targets Python 3.9+ (CPython and PyPy).

Code Quality — The pytests/ directory contains dedicated integration tests for every runtime/event-loop combination (test_tokio_multi_thread_uvloop.rs, test_async_std_asyncio.rs, test_race_condition_regression.rs, etc.) plus a documented race-condition regression test, indicating the project actively tracks and guards against concurrency bugs at the Rust/Python boundary. CI badges (GitHub Actions, codecov) are present in the README, and the crate has 24 contributors and 8 tagged releases since its 2024 fork, showing sustained maintenance under new ownership.

API Design — The primary entry points (into_future, future_into_py) are two functions, and the attribute macros (#[pyo3_async_runtimes::tokio::main]) remove most of the event-loop bootstrapping boilerplate a user would otherwise have to write by hand. The tradeoff, clearly documented in the README, is that Python’s need for main-thread control means users can’t use the runtime’s own convenience macros (#[tokio::main]) directly — they must use this crate’s variants instead, which is a small but real learning curve for developers new to embedding Python.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search