pyo3-async-runtimes-0.22.0/.cargo_vcs_info.json 0000644 00000000136 00000000001 0014766 0 ustar {
"git": {
"sha1": "41d0fe3bedfe4feb34229973b4011f7cbe26dcf6"
},
"path_in_vcs": ""
} pyo3-async-runtimes-0.22.0/.devcontainer/Dockerfile 0000644 0000000 0000000 00000000720 10461020230 0020306 0 ustar 0000000 0000000 # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/rust/.devcontainer/base.Dockerfile
# [Choice] Debian OS version (use bullseye on local arm64/Apple Silicon): buster, bullseye
ARG VARIANT="buster"
FROM mcr.microsoft.com/vscode/devcontainers/rust:0-${VARIANT}
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install python3-dev python3-pip
RUN python3 -m pip install uvloop pyo3-async-runtimes-0.22.0/.devcontainer/devcontainer.json 0000644 0000000 0000000 00000003130 10461020230 0021666 0 ustar 0000000 0000000 // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/rust
{
"name": "Rust",
"build": {
"dockerfile": "Dockerfile",
"args": {
// Use the VARIANT arg to pick a Debian OS version: buster, bullseye
// Use bullseye when on local on arm64/Apple Silicon.
"VARIANT": "buster"
}
},
"runArgs": [
"--cap-add=SYS_PTRACE",
"--security-opt",
"seccomp=unconfined"
],
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Set *default* container specific settings.json values on container create.
"settings": {
"lldb.executable": "/usr/bin/lldb",
// VS Code don't watch files under ./target
"files.watcherExclude": {
"**/target/**": true
},
"rust-analyzer.checkOnSave.command": "clippy"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"vadimcn.vscode-lldb",
"mutantdino.resourcemonitor",
"rust-lang.rust-analyzer",
"tamasfe.even-better-toml",
"serayuzgur.crates"
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "rustc --version",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode",
"features": {
"git": "latest",
"git-lfs": "latest"
}
}
pyo3-async-runtimes-0.22.0/.githooks/pre-commit 0000755 0000000 0000000 00000000065 10461020230 0017466 0 ustar 0000000 0000000 #!/bin/bash
cargo check --all-targets --all-features pyo3-async-runtimes-0.22.0/.githooks/pre-push 0000755 0000000 0000000 00000000042 10461020230 0017150 0 ustar 0000000 0000000 #!/bin/bash
make clippy
make test pyo3-async-runtimes-0.22.0/.github/dependabot.yml 0000644 0000000 0000000 00000001152 10461020230 0017745 0 ustar 0000000 0000000 # To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "cargo" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
allow:
- dependency-type: direct
- dependency-name: tokio # haven't been seeing updates for tokio
pyo3-async-runtimes-0.22.0/.github/issue_template.md 0000644 0000000 0000000 00000001340 10461020230 0020461 0 ustar 0000000 0000000 ## 🐛 Bug Reports
When reporting a bug, please provide the following information. If this is not a bug report you can just discard this template.
### 🌍 Environment
- Your operating system and version:
- Your python version:
- How did you install python (e.g. apt or pyenv)? Did you use a virtualenv?:
- Your Rust version (`rustc --version`):
- Your PyO3 version:
- Have you tried using latest PyO3 master (replace `version = "0.x.y"` with `git = "https://github.com/PyO3/pyo3-async-runtimes")?`:
### 💥 Reproducing
Please provide a [minimal working example](https://stackoverflow.com/help/mcve). This means both the Rust code and the Python.
Please also write what exact flags are required to reproduce your results.
pyo3-async-runtimes-0.22.0/.github/pull_request_template.md 0000644 0000000 0000000 00000000763 10461020230 0022065 0 ustar 0000000 0000000 Thank you for contributing to pyo3-async-runtimes!
Please consider adding the following to your pull request:
- an entry in CHANGELOG.md
- docs to all new functions and / or detail in the guide
- tests for all new or changed functions
Be aware the CI pipeline will check your pull request for the following:
- Rust tests (Just `cargo test`)
- Rust lints (`make clippy`)
- Rust formatting (`cargo fmt`)
- Python formatting (`black . --check`. You can install black with `pip install black`)
pyo3-async-runtimes-0.22.0/.github/workflows/ci.yml 0000644 0000000 0000000 00000012475 10461020230 0020302 0 ustar 0000000 0000000 name: CI
on:
push:
branches:
- main
pull_request:
branches:
- main
env:
CARGO_TERM_COLOR: always
jobs:
fmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.13"
- run: pip install black==24.10.0
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
components: rustfmt
- name: Check python formatting (black)
run: black --check .
- name: Check rust formatting (rustfmt)
run: cargo fmt --all -- --check
clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
components: clippy
- run: make clippy
build:
needs: [fmt] # don't wait for clippy as fails rarely and takes longer
name: python${{ matrix.python-version }}-${{ matrix.platform.python-architecture }} ${{ matrix.platform.os }} ${{ matrix.msrv }}
runs-on: ${{ matrix.platform.os }}
strategy:
fail-fast: false # If one platform fails, allow the rest to keep testing.
matrix:
rust: [stable]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "pypy-3.9"]
platform:
[
{
os: "macos-latest",
python-architecture: "arm64",
rust-target: "aarch64-apple-darwin",
},
{
os: "ubuntu-latest",
python-architecture: "x64",
rust-target: "x86_64-unknown-linux-gnu",
},
{
os: "windows-latest",
python-architecture: "x64",
rust-target: "x86_64-pc-windows-msvc",
},
{
os: "windows-latest",
python-architecture: "x86",
rust-target: "i686-pc-windows-msvc",
},
]
exclude:
# PyPy doesn't release 32-bit Windows builds any more
- python-version: pypy-3.9
platform: { os: "windows-latest", python-architecture: "x86" }
include:
# Test minimal supported Rust version
- rust: 1.63.0
python-version: "3.13"
platform:
{
os: "ubuntu-latest",
python-architecture: "x64",
rust-target: "x86_64-unknown-linux-gnu",
}
msrv: "MSRV"
# Test the `nightly` feature
- rust: nightly
python-version: "3.12"
platform:
{
os: "ubuntu-latest",
python-architecture: "x64",
rust-target: "x86_64-unknown-linux-gnu",
}
msrv: "nightly"
extra_features: "nightly"
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
architecture: ${{ matrix.platform.python-architecture }}
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ matrix.rust }}
target: ${{ matrix.platform.rust-target }}
- if: ${{ matrix.msrv == 'MSRV' }}
name: Set MSRV dependencies
run: |
cargo add tokio@=1.38.1
- name: Build (no features)
run: cargo build --no-default-features --verbose --target ${{ matrix.platform.rust-target }}
- name: Build
run: cargo build --features=${{env.features}} --verbose --target ${{ matrix.platform.rust-target }}
# uvloop doesn't compile under Windows and PyPy
- if: ${{ matrix.platform.os != 'windows-latest' && !startsWith(matrix.python-version, 'pypy') }}
name: Install pyo3-asyncio test dependencies
run: |
python -m pip install -U uvloop
- if: ${{ matrix.msrv != 'MSRV' && !startsWith(matrix.python-version, 'pypy') }}
name: Test
run: cargo test --all-features --target ${{ matrix.platform.rust-target }}
- if: ${{ matrix.msrv == 'MSRV' && !startsWith(matrix.python-version, 'pypy') }}
name: Test (MSRV, --no-default-features)
run: cargo test --no-default-features --features tokio-runtime,async-std-runtime,attributes,unstable-streams --target ${{ matrix.platform.rust-target }}
env:
RUST_BACKTRACE: 1
RUSTFLAGS: "-D warnings"
coverage:
needs: [fmt]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: nightly
override: true
- name: Install pyo3-asyncio test dependencies
run: |
python -m pip install -U uvloop
- uses: actions-rs/cargo@v1
with:
command: test
args: --all-features
env:
CARGO_INCREMENTAL: 0
RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Cllvm-args=--inline-threshold=0 -Clink-dead-code -Coverflow-checks=off"
RUSTDOCFLAGS: "-Zprofile -Ccodegen-units=1 -Cllvm-args=--inline-threshold=0 -Clink-dead-code -Coverflow-checks=off"
- uses: actions-rs/grcov@v0.1
id: coverage
- uses: codecov/codecov-action@v4
with:
file: ${{ steps.coverage.outputs.report }}
pyo3-async-runtimes-0.22.0/.github/workflows/guide.yml 0000644 0000000 0000000 00000003343 10461020230 0020776 0 ustar 0000000 0000000 name: gh-pages
on:
push:
branches:
- master
release:
types: [published]
env:
CARGO_TERM_COLOR: always
jobs:
deploy:
runs-on: ubuntu-latest
outputs:
tag_name: ${{ steps.prepare_tag.outputs.tag_name }}
steps:
- uses: actions/checkout@v3
# This adds the docs to gh-pages-build/doc
- name: Build the doc
run: |
cargo doc --no-deps --all-features
mkdir -p gh-pages-build
cp -r target/doc gh-pages-build/doc
echo "" > gh-pages-build/doc/index.html
- name: Prepare tag
id: prepare_tag
run: |
TAG_NAME="${GITHUB_REF##*/}"
echo "::set-output name=tag_name::${TAG_NAME}"
- name: Deploy
uses: peaceiris/actions-gh-pages@v3.7.0-8
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./gh-pages-build/
destination_dir: ${{ steps.prepare_tag.outputs.tag_name }}
full_commit_message: "Upload documentation for ${{ steps.prepare_tag.outputs.tag_name }}"
release:
needs: deploy
runs-on: ubuntu-latest
if: ${{ github.event_name == 'release' }}
steps:
- name: Create latest tag redirect
env:
TAG_NAME: ${{ needs.deploy.outputs.tag_name }}
run: |
mkdir public
echo "" > public/index.html
- name: Deploy
uses: peaceiris/actions-gh-pages@v3.7.0-8
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public/
full_commit_message: "Release ${{ needs.deploy.outputs.tag_name }}"
keep_files: true
pyo3-async-runtimes-0.22.0/Cargo.lock 0000644 00000063576 00000000001 0012762 0 ustar # This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [
"gimli",
]
[[package]]
name = "adler2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "anstream"
version = "0.6.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [
"anstyle",
"windows-sys 0.59.0",
]
[[package]]
name = "async-channel"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
dependencies = [
"concurrent-queue",
"event-listener 2.5.3",
"futures-core",
]
[[package]]
name = "async-channel"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a"
dependencies = [
"concurrent-queue",
"event-listener-strategy",
"futures-core",
"pin-project-lite",
]
[[package]]
name = "async-executor"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec"
dependencies = [
"async-task",
"concurrent-queue",
"fastrand",
"futures-lite",
"slab",
]
[[package]]
name = "async-global-executor"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c"
dependencies = [
"async-channel 2.3.1",
"async-executor",
"async-io",
"async-lock",
"blocking",
"futures-lite",
"once_cell",
]
[[package]]
name = "async-io"
version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8"
dependencies = [
"async-lock",
"cfg-if",
"concurrent-queue",
"futures-io",
"futures-lite",
"parking",
"polling",
"rustix",
"slab",
"tracing",
"windows-sys 0.59.0",
]
[[package]]
name = "async-lock"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
dependencies = [
"event-listener 5.3.1",
"event-listener-strategy",
"pin-project-lite",
]
[[package]]
name = "async-process"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb"
dependencies = [
"async-channel 2.3.1",
"async-io",
"async-lock",
"async-signal",
"async-task",
"blocking",
"cfg-if",
"event-listener 5.3.1",
"futures-lite",
"rustix",
"tracing",
]
[[package]]
name = "async-signal"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3"
dependencies = [
"async-io",
"async-lock",
"atomic-waker",
"cfg-if",
"futures-core",
"futures-io",
"rustix",
"signal-hook-registry",
"slab",
"windows-sys 0.59.0",
]
[[package]]
name = "async-std"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615"
dependencies = [
"async-channel 1.9.0",
"async-global-executor",
"async-io",
"async-lock",
"async-process",
"crossbeam-utils",
"futures-channel",
"futures-core",
"futures-io",
"futures-lite",
"gloo-timers",
"kv-log-macro",
"log",
"memchr",
"once_cell",
"pin-project-lite",
"pin-utils",
"slab",
"wasm-bindgen-futures",
]
[[package]]
name = "async-task"
version = "4.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
[[package]]
name = "atomic-waker"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "backtrace"
version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-targets",
]
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "blocking"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
dependencies = [
"async-channel 2.3.1",
"async-task",
"futures-io",
"futures-lite",
"piper",
]
[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_lex"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "concurrent-queue"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "errno"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]]
name = "event-listener"
version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "event-listener"
version = "5.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba"
dependencies = [
"concurrent-queue",
"parking",
"pin-project-lite",
]
[[package]]
name = "event-listener-strategy"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
dependencies = [
"event-listener 5.3.1",
"pin-project-lite",
]
[[package]]
name = "fastrand"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
[[package]]
name = "futures"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
[[package]]
name = "futures-executor"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
[[package]]
name = "futures-lite"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
dependencies = [
"fastrand",
"futures-core",
"futures-io",
"parking",
"pin-project-lite",
]
[[package]]
name = "futures-macro"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
[[package]]
name = "futures-task"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-util"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "gimli"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "gloo-timers"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
dependencies = [
"futures-channel",
"futures-core",
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
[[package]]
name = "indoc"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
[[package]]
name = "inventory"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "js-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "kv-log-macro"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
dependencies = [
"log",
]
[[package]]
name = "libc"
version = "0.2.159"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
[[package]]
name = "linux-raw-sys"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
dependencies = [
"value-bag",
]
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "memoffset"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
dependencies = [
"autocfg",
]
[[package]]
name = "miniz_oxide"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
dependencies = [
"adler2",
]
[[package]]
name = "object"
version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1"
dependencies = [
"portable-atomic",
]
[[package]]
name = "parking"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "piper"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
dependencies = [
"atomic-waker",
"fastrand",
"futures-io",
]
[[package]]
name = "polling"
version = "3.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511"
dependencies = [
"cfg-if",
"concurrent-queue",
"hermit-abi",
"pin-project-lite",
"rustix",
"tracing",
"windows-sys 0.59.0",
]
[[package]]
name = "portable-atomic"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "pyo3"
version = "0.22.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d922163ba1f79c04bc49073ba7b32fd5a8d3b76a87c955921234b8e77333c51"
dependencies = [
"cfg-if",
"indoc",
"libc",
"memoffset",
"once_cell",
"portable-atomic",
"pyo3-build-config",
"pyo3-ffi",
"pyo3-macros",
"unindent",
]
[[package]]
name = "pyo3-async-runtimes"
version = "0.22.0"
dependencies = [
"async-channel 2.3.1",
"async-std",
"clap",
"futures",
"inventory",
"once_cell",
"pin-project-lite",
"pyo3",
"pyo3-async-runtimes-macros",
"tokio",
]
[[package]]
name = "pyo3-async-runtimes-macros"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22c26fd8e9fc19f53f0c1e00bf61471de6789f7eb263056f7f944a9cceb5823e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pyo3-build-config"
version = "0.22.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc38c5feeb496c8321091edf3d63e9a6829eab4b863b4a6a65f26f3e9cc6b179"
dependencies = [
"once_cell",
"target-lexicon",
]
[[package]]
name = "pyo3-ffi"
version = "0.22.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94845622d88ae274d2729fcefc850e63d7a3ddff5e3ce11bd88486db9f1d357d"
dependencies = [
"libc",
"pyo3-build-config",
]
[[package]]
name = "pyo3-macros"
version = "0.22.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e655aad15e09b94ffdb3ce3d217acf652e26bbc37697ef012f5e5e348c716e5e"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn",
]
[[package]]
name = "pyo3-macros-backend"
version = "0.22.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1e3f09eecd94618f60a455a23def79f79eba4dc561a97324bf9ac8c6df30ce"
dependencies = [
"heck",
"proc-macro2",
"pyo3-build-config",
"quote",
"syn",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustc-demangle"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustix"
version = "0.38.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
dependencies = [
"libc",
]
[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "target-lexicon"
version = "0.12.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "tokio"
version = "1.40.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
dependencies = [
"backtrace",
"pin-project-lite",
]
[[package]]
name = "tracing"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
"pin-project-lite",
"tracing-core",
]
[[package]]
name = "tracing-core"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unindent"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "value-bag"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101"
[[package]]
name = "wasm-bindgen"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
dependencies = [
"cfg-if",
"once_cell",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
[[package]]
name = "web-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
pyo3-async-runtimes-0.22.0/Cargo.toml 0000644 00000011157 00000000001 0012771 0 ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.63"
name = "pyo3-async-runtimes"
version = "0.22.0"
authors = [
"Andrew J Westlake ",
"David Hewitt ",
]
build = false
exclude = [
"/.gitignore",
"/codecov.yml",
"/Makefile",
]
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "PyO3 bridges from Rust runtimes to Python's Asyncio library"
homepage = "https://github.com/PyO3/pyo3-async-runtimes"
documentation = "https://docs.rs/crate/pyo3-async-runtimes/"
readme = "README.md"
keywords = [
"pyo3",
"python",
"ffi",
"async",
"asyncio",
]
categories = [
"api-bindings",
"development-tools::ffi",
]
license = "Apache-2.0"
repository = "https://github.com/PyO3/pyo3-async-runtimes"
[package.metadata.docs.rs]
features = [
"attributes",
"testing",
"async-std-runtime",
"tokio-runtime",
]
[lib]
name = "pyo3_async_runtimes"
path = "src/lib.rs"
[[example]]
name = "async_std"
path = "examples/async_std.rs"
required-features = [
"attributes",
"async-std-runtime",
]
[[example]]
name = "tokio"
path = "examples/tokio.rs"
required-features = [
"attributes",
"tokio-runtime",
]
[[example]]
name = "tokio_current_thread"
path = "examples/tokio_current_thread.rs"
required-features = [
"attributes",
"tokio-runtime",
]
[[example]]
name = "tokio_multi_thread"
path = "examples/tokio_multi_thread.rs"
required-features = [
"attributes",
"tokio-runtime",
]
[[test]]
name = "test_async_std_asyncio"
path = "pytests/test_async_std_asyncio.rs"
harness = false
required-features = [
"async-std-runtime",
"testing",
"attributes",
]
[[test]]
name = "test_async_std_run_forever"
path = "pytests/test_async_std_run_forever.rs"
harness = false
required-features = [
"async-std-runtime",
"testing",
]
[[test]]
name = "test_async_std_uvloop"
path = "pytests/test_async_std_uvloop.rs"
harness = false
required-features = [
"async-std-runtime",
"testing",
]
[[test]]
name = "test_race_condition_regression"
path = "pytests/test_race_condition_regression.rs"
harness = false
required-features = [
"async-std-runtime",
"testing",
]
[[test]]
name = "test_tokio_current_thread_asyncio"
path = "pytests/test_tokio_current_thread_asyncio.rs"
harness = false
required-features = [
"tokio-runtime",
"testing",
"attributes",
]
[[test]]
name = "test_tokio_current_thread_run_forever"
path = "pytests/test_tokio_current_thread_run_forever.rs"
harness = false
required-features = [
"tokio-runtime",
"testing",
]
[[test]]
name = "test_tokio_current_thread_uvloop"
path = "pytests/test_tokio_current_thread_uvloop.rs"
harness = false
required-features = [
"tokio-runtime",
"testing",
]
[[test]]
name = "test_tokio_multi_thread_asyncio"
path = "pytests/test_tokio_multi_thread_asyncio.rs"
harness = false
required-features = [
"tokio-runtime",
"testing",
"attributes",
]
[[test]]
name = "test_tokio_multi_thread_run_forever"
path = "pytests/test_tokio_multi_thread_run_forever.rs"
harness = false
required-features = [
"tokio-runtime",
"testing",
]
[[test]]
name = "test_tokio_multi_thread_uvloop"
path = "pytests/test_tokio_multi_thread_uvloop.rs"
harness = false
required-features = [
"tokio-runtime",
"testing",
]
[dependencies.async-channel]
version = "2.3"
optional = true
[dependencies.async-std]
version = "1.12"
features = ["unstable"]
optional = true
[dependencies.clap]
version = "4.5"
optional = true
[dependencies.futures]
version = "0.3"
[dependencies.inventory]
version = "0.3"
optional = true
[dependencies.once_cell]
version = "1.14"
[dependencies.pin-project-lite]
version = "0.2"
[dependencies.pyo3]
version = "0.22"
[dependencies.pyo3-async-runtimes-macros]
version = "=0.22.0"
optional = true
[dependencies.tokio]
version = "1.13"
features = [
"rt",
"rt-multi-thread",
"time",
]
optional = true
[dev-dependencies.pyo3]
version = "0.22"
features = ["macros"]
[features]
async-std-runtime = ["async-std"]
attributes = ["pyo3-async-runtimes-macros"]
default = []
testing = [
"clap",
"inventory",
]
tokio-runtime = ["tokio"]
unstable-streams = ["async-channel"]
pyo3-async-runtimes-0.22.0/Cargo.toml.orig 0000644 0000000 0000000 00000007366 10461020230 0016461 0 ustar 0000000 0000000 [package]
name = "pyo3-async-runtimes"
description = "PyO3 bridges from Rust runtimes to Python's Asyncio library"
version = "0.22.0"
authors = [
"Andrew J Westlake ",
"David Hewitt ",
]
readme = "README.md"
keywords = ["pyo3", "python", "ffi", "async", "asyncio"]
homepage = "https://github.com/PyO3/pyo3-async-runtimes"
repository = "https://github.com/PyO3/pyo3-async-runtimes"
documentation = "https://docs.rs/crate/pyo3-async-runtimes/"
categories = ["api-bindings", "development-tools::ffi"]
license = "Apache-2.0"
exclude = ["/.gitignore", "/codecov.yml", "/Makefile"]
edition = "2021"
rust-version = "1.63"
[workspace]
members = ["pyo3-async-runtimes-macros"]
[features]
async-std-runtime = ["async-std"]
attributes = ["pyo3-async-runtimes-macros"]
testing = ["clap", "inventory"]
tokio-runtime = ["tokio"]
unstable-streams = ["async-channel"]
default = []
[package.metadata.docs.rs]
features = ["attributes", "testing", "async-std-runtime", "tokio-runtime"]
[[example]]
name = "async_std"
path = "examples/async_std.rs"
required-features = ["attributes", "async-std-runtime"]
[[example]]
name = "tokio"
path = "examples/tokio.rs"
required-features = ["attributes", "tokio-runtime"]
[[example]]
name = "tokio_current_thread"
path = "examples/tokio_current_thread.rs"
required-features = ["attributes", "tokio-runtime"]
[[example]]
name = "tokio_multi_thread"
path = "examples/tokio_multi_thread.rs"
required-features = ["attributes", "tokio-runtime"]
[[test]]
name = "test_async_std_asyncio"
path = "pytests/test_async_std_asyncio.rs"
harness = false
required-features = ["async-std-runtime", "testing", "attributes"]
[[test]]
name = "test_async_std_run_forever"
path = "pytests/test_async_std_run_forever.rs"
harness = false
required-features = ["async-std-runtime", "testing"]
[[test]]
name = "test_tokio_current_thread_asyncio"
path = "pytests/test_tokio_current_thread_asyncio.rs"
harness = false
required-features = ["tokio-runtime", "testing", "attributes"]
[[test]]
name = "test_tokio_current_thread_run_forever"
path = "pytests/test_tokio_current_thread_run_forever.rs"
harness = false
required-features = ["tokio-runtime", "testing"]
[[test]]
name = "test_tokio_multi_thread_asyncio"
path = "pytests/test_tokio_multi_thread_asyncio.rs"
harness = false
required-features = ["tokio-runtime", "testing", "attributes"]
[[test]]
name = "test_tokio_multi_thread_run_forever"
path = "pytests/test_tokio_multi_thread_run_forever.rs"
harness = false
required-features = ["tokio-runtime", "testing"]
[[test]]
name = "test_async_std_uvloop"
path = "pytests/test_async_std_uvloop.rs"
harness = false
required-features = ["async-std-runtime", "testing"]
[[test]]
name = "test_tokio_current_thread_uvloop"
path = "pytests/test_tokio_current_thread_uvloop.rs"
harness = false
required-features = ["tokio-runtime", "testing"]
[[test]]
name = "test_tokio_multi_thread_uvloop"
path = "pytests/test_tokio_multi_thread_uvloop.rs"
harness = false
required-features = ["tokio-runtime", "testing"]
[[test]]
name = "test_race_condition_regression"
path = "pytests/test_race_condition_regression.rs"
harness = false
required-features = ["async-std-runtime", "testing"]
[dependencies]
async-channel = { version = "2.3", optional = true }
clap = { version = "4.5", optional = true }
futures = "0.3"
inventory = { version = "0.3", optional = true }
once_cell = "1.14"
pin-project-lite = "0.2"
pyo3 = "0.22"
pyo3-async-runtimes-macros = { path = "pyo3-async-runtimes-macros", version = "=0.22.0", optional = true }
[dev-dependencies]
pyo3 = { version = "0.22", features = ["macros"] }
[dependencies.async-std]
version = "1.12"
features = ["unstable"]
optional = true
[dependencies.tokio]
version = "1.13"
features = ["rt", "rt-multi-thread", "time"]
optional = true
pyo3-async-runtimes-0.22.0/Code-of-Conduct.md 0000644 0000000 0000000 00000006404 10461020230 0016755 0 ustar 0000000 0000000 # Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
pyo3-async-runtimes-0.22.0/Contributing.md 0000644 0000000 0000000 00000005733 10461020230 0016557 0 ustar 0000000 0000000 # Contributing
Thank you for your interest in contributing to PyO3! All are welcome - please consider reading our [Code of Conduct](Code-of-Conduct.md) to keep our community positive and inclusive.
If you are searching for ideas how to contribute, please read the "Getting started contributing" section. Once you've found an issue to contribute to, you may find the section "Writing pull requests" helpful.
## Getting started contributing
Please join in with any part of PyO3 which interests you. We use Github issues to record all bugs and ideas. Feel free to request an issue to be assigned to you if you want to work on it.
The following sections also contain specific ideas on where to start contributing to PyO3.
### Help users identify bugs
The [PyO3 Gitter channel](https://gitter.im/PyO3/Lobby) is very active with users who are new to PyO3, and often completely new to Rust. Helping them debug is a great way to get experience with the PyO3 codebase.
Helping others often reveals bugs, documentation weaknesses, and missing APIs. It's a good idea to open Github issues for these immediately so the resolution can be designed and implemented!
### Review pull requests
Everybody is welcome to submit comments on open PRs. Please help ensure new PyO3 APIs are safe, performant, tidy, and easy to use!
## Writing pull requests
Here are a few things to note when you are writing PRs.
### Continuous Integration
The PyO3 Asyncio repo uses Github Actions. PRs are blocked from merging if CI is not successful.
Formatting, linting and tests are checked for all Rust and Python code. In addition, all warnings in Rust code are disallowed (using `RUSTFLAGS="-D warnings"`).
Tests run with all supported Python versions with the latest stable Rust compiler, as well as for Python 3.9 with the minimum supported Rust version.
### Minimum supported Rust version
PyO3 aims to make use of up-to-date Rust language features to keep the implementation as efficient as possible.
However, there will always be support for at least the last few Rust compiler versions, so that users have time to update.
If your PR needs to bump the minimum supported Rust version, this is acceptable with the following conditions:
- Any changes which require a more recent version than what is [currently available on stable Red Hat Enterprise Linux](https://access.redhat.com/documentation/en-us/red_hat_developer_tools/1/) will be postponed. (This is to allow package managers to update support for newer `rustc` versions; RHEL was arbitrarily picked because their update policy is clear.)
- You might be asked to do extra work to tidy up other parts of the PyO3 codebase which can use the compiler version bump :)
## Git Hooks (Recommended)
Using the project's githooks are recommended to prevent CI from failing for trivial reasons such as build checks or integration tests failing. Enabling the hooks should run `cargo check --all-targets` for every commit and `cargo test` for every push.
```
git config core.hookspath .githooks
``` pyo3-async-runtimes-0.22.0/LICENSE 0000644 0000000 0000000 00000025035 10461020230 0014570 0 ustar 0000000 0000000 Copyright (c) 2017-present PyO3 Project and Contributors. https://github.com/PyO3
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
pyo3-async-runtimes-0.22.0/README.md 0000644 0000000 0000000 00000067716 10461020230 0015056 0 ustar 0000000 0000000 # PyO3 Asyncio
[](https://github.com/PyO3/pyo3-async-runtimes)
[](https://codecov.io/gh/PyO3/pyo3-async-runtimes)
[](https://crates.io/crates/pyo3-async-runtimes)
[](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
***This is a fork of [`pyo3-asyncio`](https://github.com/awestlake87/pyo3-asyncio/) to deliver compatibility for PyO3 0.21. This may be the base for a permanent fork in the future, depending on the status of the original `pyo3-asyncio` maintainer.***
[Rust](http://www.rust-lang.org/) bindings for [Python](https://www.python.org/)'s [Asyncio Library](https://docs.python.org/3/library/asyncio.html). This crate facilitates interactions between Rust Futures and Python Coroutines and manages the lifecycle of their corresponding event loops.
- PyO3 Project: [Homepage](https://pyo3.rs/) | [GitHub](https://github.com/PyO3/pyo3)
- PyO3 Async Runtimes API Documentation: [stable](https://docs.rs/pyo3-async-runtimes/)
- Guide for Async / Await [stable](https://pyo3.rs/latest/ecosystem/async-await.html) | [main](https://pyo3.rs/main/ecosystem/async-await.html)
- Contributing Notes: [github](https://github.com/PyO3/pyo3-async-runtimes/blob/main/Contributing.md)
> PyO3 Asyncio is a _brand new_ part of the broader PyO3 ecosystem. Feel free to open any issues for feature requests or bugfixes for this crate.
**If you're a new-comer, the best way to get started is to read through the primer below! For `v0.13` and `v0.14` users I highly recommend reading through the [migration section](#migration-guide) to get a general idea of what's changed in `v0.14` and `v0.15`.**
## Usage
Like PyO3, PyO3 Asyncio supports the following software versions:
- Python 3.7 and up (CPython and PyPy)
- Rust 1.48 and up
## PyO3 Asyncio Primer
If you are working with a Python library that makes use of async functions or wish to provide
Python bindings for an async Rust library, [`pyo3-async-runtimes`](https://github.com/PyO3/pyo3-async-runtimes)
likely has the tools you need. It provides conversions between async functions in both Python and
Rust and was designed with first-class support for popular Rust runtimes such as
[`tokio`](https://tokio.rs/) and [`async-std`](https://async.rs/). In addition, all async Python
code runs on the default `asyncio` event loop, so `pyo3-asyncio` should work just fine with existing
Python libraries.
In the following sections, we'll give a general overview of `pyo3-asyncio` explaining how to call
async Python functions with PyO3, how to call async Rust functions from Python, and how to configure
your codebase to manage the runtimes of both.
### Quickstart
Here are some examples to get you started right away! A more detailed breakdown
of the concepts in these examples can be found in the following sections.
#### Rust Applications
Here we initialize the runtime, import Python's `asyncio` library and run the given future to completion using Python's default `EventLoop` and `async-std`. Inside the future, we convert `asyncio` sleep into a Rust future and await it.
```toml
# Cargo.toml dependencies
[dependencies]
pyo3 = { version = "0.22" }
pyo3-async-runtimes = { version = "0.22", features = ["attributes", "async-std-runtime"] }
async-std = "1.13"
```
```rust
//! main.rs
use pyo3::prelude::*;
#[pyo3_async_runtimes::async_std::main]
async fn main() -> PyResult<()> {
let fut = Python::with_gil(|py| {
let asyncio = py.import_bound("asyncio")?;
// convert asyncio.sleep into a Rust Future
pyo3_async_runtimes::async_std::into_future(asyncio.call_method1("sleep", (1.into_py(py),))?)
})?;
fut.await?;
Ok(())
}
```
The same application can be written to use `tokio` instead using the `#[pyo3_async_runtimes::tokio::main]`
attribute.
```toml
# Cargo.toml dependencies
[dependencies]
pyo3 = { version = "0.22" }
pyo3-async-runtimes = { version = "0.22", features = ["attributes", "tokio-runtime"] }
tokio = "1.40"
```
```rust
//! main.rs
use pyo3::prelude::*;
#[pyo3_async_runtimes::tokio::main]
async fn main() -> PyResult<()> {
let fut = Python::with_gil(|py| {
let asyncio = py.import_bound("asyncio")?;
// convert asyncio.sleep into a Rust Future
pyo3_async_runtimes::tokio::into_future(asyncio.call_method1("sleep", (1.into_py(py),))?)
})?;
fut.await?;
Ok(())
}
```
More details on the usage of this library can be found in the API docs
and the primer below.
#### PyO3 Native Rust Modules
PyO3 Asyncio can also be used to write native modules with async functions.
Add the `[lib]` section to `Cargo.toml` to make your library a `cdylib` that Python can import.
```toml
[lib]
name = "my_async_module"
crate-type = ["cdylib"]
```
Make your project depend on `pyo3` with the `extension-module` feature enabled and select your
`pyo3-asyncio` runtime:
For `async-std`:
```toml
[dependencies]
pyo3 = { version = "0.22", features = ["extension-module"] }
pyo3-async-runtimes = { version = "0.22", features = ["async-std-runtime"] }
async-std = "1.13"
```
For `tokio`:
```toml
[dependencies]
pyo3 = { version = "0.20", features = ["extension-module"] }
pyo3-async-runtimes = { version = "0.22", features = ["tokio-runtime"] }
tokio = "1.40"
```
Export an async function that makes use of `async-std`:
```rust
//! lib.rs
use pyo3::{prelude::*, wrap_pyfunction};
#[pyfunction]
fn rust_sleep(py: Python) -> PyResult> {
pyo3_async_runtimes::async_std::future_into_py(py, async {
async_std::task::sleep(std::time::Duration::from_secs(1)).await;
Ok(())
})
}
#[pymodule]
fn my_async_module(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(rust_sleep, m)?)?;
Ok(())
}
```
If you want to use `tokio` instead, here's what your module should look like:
```rust
//! lib.rs
use pyo3::{prelude::*, wrap_pyfunction};
#[pyfunction]
fn rust_sleep(py: Python) -> PyResult> {
pyo3_async_runtimes::tokio::future_into_py(py, async {
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
Ok(())
})
}
#[pymodule]
fn my_async_module(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(rust_sleep, m)?)?;
Ok(())
}
```
You can build your module with maturin (see the [Using Rust in Python](https://pyo3.rs/main/#using-rust-from-python) section in the PyO3 guide for setup instructions). After that you should be able to run the Python REPL to try it out.
```bash
maturin develop && python3
🔗 Found pyo3 bindings
🐍 Found CPython 3.8 at python3
Finished dev [unoptimized + debuginfo] target(s) in 0.04s
Python 3.8.5 (default, Jan 27 2021, 15:41:15)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>>
>>> from my_async_module import rust_sleep
>>>
>>> async def main():
>>> await rust_sleep()
>>>
>>> # should sleep for 1s
>>> asyncio.run(main())
>>>
```
### Awaiting an Async Python Function in Rust
Let's take a look at a dead simple async Python function:
```python
# Sleep for 1 second
async def py_sleep():
await asyncio.sleep(1)
```
**Async functions in Python are simply functions that return a `coroutine` object**. For our purposes,
we really don't need to know much about these `coroutine` objects. The key factor here is that calling
an `async` function is _just like calling a regular function_, the only difference is that we have
to do something special with the object that it returns.
Normally in Python, that something special is the `await` keyword, but in order to await this
coroutine in Rust, we first need to convert it into Rust's version of a `coroutine`: a `Future`.
That's where `pyo3-async-runtimes` comes in.
[`pyo3_async_runtimes::into_future`](https://docs.rs/pyo3-async-runtimes/latest/pyo3_async_runtimes/fn.into_future.html)
performs this conversion for us:
```rust no_run
use pyo3::prelude::*;
#[pyo3_async_runtimes::tokio::main]
async fn main() -> PyResult<()> {
let future = Python::with_gil(|py| -> PyResult<_> {
// import the module containing the py_sleep function
let example = py.import_bound("example")?;
// calling the py_sleep method like a normal function
// returns a coroutine
let coroutine = example.call_method0("py_sleep")?;
// convert the coroutine into a Rust future using the
// tokio runtime
pyo3_async_runtimes::tokio::into_future(coroutine)
})?;
// await the future
future.await?;
Ok(())
}
```
> If you're interested in learning more about `coroutines` and `awaitables` in general, check out the
> [Python 3 `asyncio` docs](https://docs.python.org/3/library/asyncio-task.html) for more information.
### Awaiting a Rust Future in Python
Here we have the same async function as before written in Rust using the
[`async-std`](https://async.rs/) runtime:
```rust
/// Sleep for 1 second
async fn rust_sleep() {
async_std::task::sleep(std::time::Duration::from_secs(1)).await;
}
```
Similar to Python, Rust's async functions also return a special object called a
`Future`:
```rust compile_fail
let future = rust_sleep();
```
We can convert this `Future` object into Python to make it `awaitable`. This tells Python that you
can use the `await` keyword with it. In order to do this, we'll call
[`pyo3_async_runtimes::async_std::future_into_py`](https://docs.rs/pyo3-asyncio/latest/pyo3_async_runtimes/async_std/fn.future_into_py.html):
```rust
use pyo3::prelude::*;
async fn rust_sleep() {
async_std::task::sleep(std::time::Duration::from_secs(1)).await;
}
#[pyfunction]
fn call_rust_sleep(py: Python) -> PyResult> {
pyo3_async_runtimes::async_std::future_into_py(py, async move {
rust_sleep().await;
Ok(())
})
}
```
In Python, we can call this pyo3 function just like any other async function:
```python
from example import call_rust_sleep
async def rust_sleep():
await call_rust_sleep()
```
## Managing Event Loops
Python's event loop requires some special treatment, especially regarding the main thread. Some of
Python's `asyncio` features, like proper signal handling, require control over the main thread, which
doesn't always play well with Rust.
Luckily, Rust's event loops are pretty flexible and don't _need_ control over the main thread, so in
`pyo3-asyncio`, we decided the best way to handle Rust/Python interop was to just surrender the main
thread to Python and run Rust's event loops in the background. Unfortunately, since most event loop
implementations _prefer_ control over the main thread, this can still make some things awkward.
### PyO3 Asyncio Initialization
Because Python needs to control the main thread, we can't use the convenient proc macros from Rust
runtimes to handle the `main` function or `#[test]` functions. Instead, the initialization for PyO3 has to be done from the `main` function and the main
thread must block on [`pyo3_async_runtimes::run_forever`](https://docs.rs/pyo3-asyncio/latest/pyo3_async_runtimes/fn.run_forever.html) or [`pyo3_async_runtimes::async_std::run_until_complete`](https://docs.rs/pyo3-asyncio/latest/pyo3_async_runtimes/async_std/fn.run_until_complete.html).
Because we have to block on one of those functions, we can't use [`#[async_std::main]`](https://docs.rs/async-std/latest/async_std/attr.main.html) or [`#[tokio::main]`](https://docs.rs/tokio/1.1.0/tokio/attr.main.html)
since it's not a good idea to make long blocking calls during an async function.
> Internally, these `#[main]` proc macros are expanded to something like this:
>
> ```rust compile_fail
> fn main() {
> // your async main fn
> async fn _main_impl() { /* ... */ }
> Runtime::new().block_on(_main_impl());
> }
> ```
>
> Making a long blocking call inside the `Future` that's being driven by `block_on` prevents that
> thread from doing anything else and can spell trouble for some runtimes (also this will actually
> deadlock a single-threaded runtime!). Many runtimes have some sort of `spawn_blocking` mechanism
> that can avoid this problem, but again that's not something we can use here since we need it to
> block on the _main_ thread.
For this reason, `pyo3-asyncio` provides its own set of proc macros to provide you with this
initialization. These macros are intended to mirror the initialization of `async-std` and `tokio`
while also satisfying the Python runtime's needs.
Here's a full example of PyO3 initialization with the `async-std` runtime:
```rust no_run
use pyo3::prelude::*;
#[pyo3_async_runtimes::async_std::main]
async fn main() -> PyResult<()> {
// PyO3 is initialized - Ready to go
let fut = Python::with_gil(|py| -> PyResult<_> {
let asyncio = py.import_bound("asyncio")?;
// convert asyncio.sleep into a Rust Future
pyo3_async_runtimes::async_std::into_future(
asyncio.call_method1("sleep", (1.into_py(py),))?
)
})?;
fut.await?;
Ok(())
}
```
#### A Note About `asyncio.run`
In Python 3.7+, the recommended way to run a top-level coroutine with `asyncio`
is with `asyncio.run`. In `v0.13` we recommended against using this function due to initialization issues, but in `v0.14` it's perfectly valid to use this function... with a caveat.
Since our Rust <--> Python conversions require a reference to the Python event loop, this poses a problem. Imagine we have a PyO3 Asyncio module that defines
a `rust_sleep` function like in previous examples. You might rightfully assume that you can call pass this directly into `asyncio.run` like this:
```python
import asyncio
from my_async_module import rust_sleep
asyncio.run(rust_sleep())
```
You might be surprised to find out that this throws an error:
```bash
Traceback (most recent call last):
File "example.py", line 5, in
asyncio.run(rust_sleep())
RuntimeError: no running event loop
```
What's happening here is that we are calling `rust_sleep` _before_ the future is
actually running on the event loop created by `asyncio.run`. This is counter-intuitive, but expected behaviour, and unfortunately there doesn't seem to be a good way of solving this problem within PyO3 Asyncio itself.
However, we can make this example work with a simple workaround:
```python
import asyncio
from my_async_module import rust_sleep
# Calling main will just construct the coroutine that later calls rust_sleep.
# - This ensures that rust_sleep will be called when the event loop is running,
# not before.
async def main():
await rust_sleep()
# Run the main() coroutine at the top-level instead
asyncio.run(main())
```
#### Non-standard Python Event Loops
Python allows you to use alternatives to the default `asyncio` event loop. One
popular alternative is `uvloop`. In `v0.13` using non-standard event loops was
a bit of an ordeal, but in `v0.14` it's trivial.
#### Using `uvloop` in a PyO3 Native Extensions
```toml
# Cargo.toml
[lib]
name = "my_async_module"
crate-type = ["cdylib"]
[dependencies]
pyo3 = { version = "0.22", features = ["extension-module"] }
pyo3-async-runtimes = { version = "0.22", features = ["tokio-runtime"] }
async-std = "1.13"
tokio = "1.40"
```
```rust
//! lib.rs
use pyo3::{prelude::*, wrap_pyfunction};
#[pyfunction]
fn rust_sleep(py: Python) -> PyResult> {
pyo3_async_runtimes::tokio::future_into_py(py, async {
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
Ok(())
})
}
#[pymodule]
fn my_async_module(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(rust_sleep, m)?)?;
Ok(())
}
```
```bash
$ maturin develop && python3
🔗 Found pyo3 bindings
🐍 Found CPython 3.8 at python3
Finished dev [unoptimized + debuginfo] target(s) in 0.04s
Python 3.8.8 (default, Apr 13 2021, 19:58:26)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> import uvloop
>>>
>>> import my_async_module
>>>
>>> uvloop.install()
>>>
>>> async def main():
... await my_async_module.rust_sleep()
...
>>> asyncio.run(main())
>>>
```
#### Using `uvloop` in Rust Applications
Using `uvloop` in Rust applications is a bit trickier, but it's still possible
with relatively few modifications.
Unfortunately, we can't make use of the `#[pyo3_async_runtimes::::main]` attribute with non-standard event loops. This is because the `#[pyo3_async_runtimes::::main]` proc macro has to interact with the Python
event loop before we can install the `uvloop` policy.
```toml
[dependencies]
async-std = "1.13"
pyo3 = "0.22"
pyo3-async-runtimes = { version = "0.22", features = ["async-std-runtime"] }
```
```rust no_run
//! main.rs
use pyo3::{prelude::*, types::PyType};
fn main() -> PyResult<()> {
pyo3::prepare_freethreaded_python();
Python::with_gil(|py| {
let uvloop = py.import_bound("uvloop")?;
uvloop.call_method0("install")?;
// store a reference for the assertion
let uvloop = PyObject::from(uvloop);
pyo3_async_runtimes::async_std::run(py, async move {
// verify that we are on a uvloop.Loop
Python::with_gil(|py| -> PyResult<()> {
assert!(uvloop
.bind(py)
.getattr("Loop")?
.downcast::()
.unwrap()
.is_instance(&pyo3_async_runtimes::async_std::get_current_loop(py)?)?);
Ok(())
})?;
async_std::task::sleep(std::time::Duration::from_secs(1)).await;
Ok(())
})
})
}
```
### Additional Information
- Managing event loop references can be tricky with pyo3-async-runtimes. See [Event Loop References and ContextVars](https://awestlake87.github.io/pyo3-asyncio/master/doc/pyo3_async_runtimes/#event-loop-references-and-contextvars) in the API docs to get a better intuition for how event loop references are managed in this library.
- Testing pyo3-asyncio libraries and applications requires a custom test harness since Python requires control over the main thread. You can find a testing guide in the [API docs for the `testing` module](https://awestlake87.github.io/pyo3-asyncio/master/doc/pyo3_async_runtimes/testing)
## Migration Guide
### Migrating from 0.13 to 0.14
So what's changed from `v0.13` to `v0.14`?
Well, a lot actually. There were some pretty major flaws in the initialization behaviour of `v0.13`. While it would have been nicer to address these issues without changing the public API, I decided it'd be better to break some of the old API rather than completely change the underlying behaviour of the existing functions. I realize this is going to be a bit of a headache, so hopefully this section will help you through it.
To make things a bit easier, I decided to keep most of the old API alongside the new one (with some deprecation warnings to encourage users to move away from it). It should be possible to use the `v0.13` API alongside the newer `v0.14` API, which should allow you to upgrade your application piecemeal rather than all at once.
**Before you get started, I personally recommend taking a look at [Event Loop References and ContextVars](https://awestlake87.github.io/pyo3-asyncio/master/doc/pyo3_async_runtimes/#event-loop-references-and-contextvars) in order to get a better grasp on the motivation behind these changes and the nuance involved in using the new conversions.**
### 0.14 Highlights
- Tokio initialization is now lazy.
- No configuration necessary if you're using the multithreaded scheduler
- Calls to `pyo3_async_runtimes::tokio::init_multithread` or `pyo3_async_runtimes::tokio::init_multithread_once` can just be removed.
- Calls to `pyo3_async_runtimes::tokio::init_current_thread` or `pyo3_async_runtimes::tokio::init_current_thread_once` require some special attention.
- Custom runtime configuration is done by passing a `tokio::runtime::Builder` into `pyo3_async_runtimes::tokio::init` instead of a `tokio::runtime::Runtime`
- A new, more correct set of functions has been added to replace the `v0.13` conversions.
- `pyo3_async_runtimes::into_future_with_loop`
- `pyo3_async_runtimes::::future_into_py_with_loop`
- `pyo3_async_runtimes::::local_future_into_py_with_loop`
- `pyo3_async_runtimes::::into_future`
- `pyo3_async_runtimes::::future_into_py`
- `pyo3_async_runtimes::::local_future_into_py`
- `pyo3_async_runtimes::::get_current_loop`
- `pyo3_async_runtimes::try_init` is no longer required if you're only using `0.14` conversions
- The `ThreadPoolExecutor` is no longer configured automatically at the start.
- Fortunately, this doesn't seem to have much effect on `v0.13` code, it just means that it's now possible to configure the executor manually as you see fit.
### Upgrading Your Code to 0.14
1. Fix PyO3 0.14 initialization.
- PyO3 0.14 feature gated its automatic initialization behaviour behind "auto-initialize". You can either enable the "auto-initialize" behaviour in your project or add a call to `pyo3::prepare_freethreaded_python()` to the start of your program.
- If you're using the `#[pyo3_async_runtimes::::main]` proc macro attributes, then you can skip this step. `#[pyo3_async_runtimes::::main]` will call `pyo3::prepare_freethreaded_python()` at the start regardless of your project's "auto-initialize" feature.
2. Fix the tokio initialization.
- Calls to `pyo3_async_runtimes::tokio::init_multithread` or `pyo3_async_runtimes::tokio::init_multithread_once` can just be removed.
- If you're using the current thread scheduler, you'll need to manually spawn the thread that it runs on during initialization:
```rust no_run
let mut builder = tokio::runtime::Builder::new_current_thread();
builder.enable_all();
pyo3_async_runtimes::tokio::init(builder);
std::thread::spawn(move || {
pyo3_async_runtimes::tokio::get_runtime().block_on(
futures::future::pending::<()>()
);
});
```
- Custom `tokio::runtime::Builder` configs can be passed into `pyo3_async_runtimes::tokio::init`. The `tokio::runtime::Runtime` will be lazily instantiated on the first call to `pyo3_async_runtimes::tokio::get_runtime()`
3. If you're using `pyo3_async_runtimes::run_forever` in your application, you should switch to a more manual approach.
> `run_forever` is not the recommended way of running an event loop in Python, so it might be a good idea to move away from it. This function would have needed to change for `0.14`, but since it's considered an edge case, it was decided that users could just manually call it if they need to.
```rust
use pyo3::prelude::*;
fn main() -> PyResult<()> {
pyo3::prepare_freethreaded_python();
Python::with_gil(|py| {
let asyncio = py.import_bound("asyncio")?;
let event_loop = asyncio.call_method0("new_event_loop")?;
asyncio.call_method1("set_event_loop", (&event_loop,))?;
let event_loop_hdl = PyObject::from(event_loop.clone());
pyo3_async_runtimes::tokio::get_runtime().spawn(async move {
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
// Stop the event loop manually
Python::with_gil(|py| {
event_loop_hdl
.bind(py)
.call_method1(
"call_soon_threadsafe",
(event_loop_hdl
.bind(py)
.getattr("stop")
.unwrap(),),
)
.unwrap();
})
});
event_loop.call_method0("run_forever")?;
Ok(())
})
}
```
4. Replace conversions with their newer counterparts.
> You may encounter some issues regarding the usage of `get_running_loop` vs `get_event_loop`. For more details on these newer conversions and how they should be used see [Event Loop References and ContextVars](https://awestlake87.github.io/pyo3-asyncio/master/doc/pyo3_async_runtimes/#event-loop-references-and-contextvars).
- Replace `pyo3_async_runtimes::into_future` with `pyo3_async_runtimes::::into_future`
- Replace `pyo3_async_runtimes::::into_coroutine` with `pyo3_async_runtimes::::future_into_py`
- Replace `pyo3_async_runtimes::get_event_loop` with `pyo3_async_runtimes::::get_current_loop`
5. After all conversions have been replaced with their `v0.14` counterparts, `pyo3_async_runtimes::try_init` can safely be removed.
> The `v0.13` API has been removed in version `v0.15`
### Migrating from 0.14 to 0.15+
There have been a few changes to the API in order to support proper cancellation from Python and the `contextvars` module.
- Any instance of `cancellable_future_into_py` and `local_cancellable_future_into_py` conversions can be replaced with their`future_into_py` and `local_future_into_py` counterparts.
> Cancellation support became the default behaviour in 0.15.
- Instances of `*_with_loop` conversions should be replaced with the newer `*_with_locals` conversions.
```rust no_run
use pyo3::prelude::*;
Python::with_gil(|py| -> PyResult<()> {
// *_with_loop conversions in 0.14
//
// let event_loop = pyo3_async_runtimes::get_running_loop(py)?;
//
// let fut = pyo3_async_runtimes::tokio::future_into_py_with_loop(
// event_loop,
// async move { Ok(Python::with_gil(|py| py.None())) }
// )?;
//
// should be replaced with *_with_locals in 0.15+
let fut = pyo3_async_runtimes::tokio::future_into_py_with_locals(
py,
pyo3_async_runtimes::tokio::get_current_locals(py)?,
async move { Ok(()) }
)?;
Ok(())
});
```
- `scope` and `scope_local` variants now accept `TaskLocals` instead of `event_loop`. You can usually just replace the `event_loop` with `pyo3_async_runtimes::TaskLocals::new(event_loop).copy_context(py)?`.
- Return types for `future_into_py`, `future_into_py_with_locals` `local_future_into_py`, and `local_future_into_py_with_locals` are now constrained by the bound `IntoPy` instead of requiring the return type to be `PyObject`. This can make the return types for futures more flexible, but inference can also fail when the concrete type is ambiguous (for example when using `into()`). Sometimes the `into()` can just be removed,
- `run`, and `run_until_complete` can now return any `Send + 'static` value.
### Migrating from 0.15 to 0.16
Actually, not much has changed in the API. I'm happy to say that the PyO3 Asyncio is reaching a
pretty stable point in 0.16. For the most part, 0.16 has been about cleanup and removing deprecated
functions from the API.
PyO3 0.16 comes with a few API changes of its own, but one of the changes that most impacted PyO3
Asyncio was it's decision to drop support for Python 3.6. PyO3 Asyncio has been using a few
workarounds / hacks to support the pre-3.7 version of Python's asyncio library that are no longer
necessary. PyO3 Asyncio's underlying implementation is now a bit cleaner because of this.
PyO3 Asyncio 0.15 included some important fixes to the API in order to add support for proper task
cancellation and allow for the preservation / use of contextvars in Python coroutines. This led to
the deprecation of some 0.14 functions that were used for edge cases in favor of some more correct
versions, and those deprecated functions are now removed from the API in 0.16.
In addition, with PyO3 Asyncio 0.16, the library now has experimental support for conversions from
Python's async generators into a Rust `Stream`. There are currently two versions `v1` and `v2` with
slightly different performance and type signatures, so I'm hoping to get some feedback on which one
works best for downstream users. Just enable the `unstable-streams` feature and you're good to go!
> The inverse conversion, Rust `Stream` to Python async generator, may come in a later release if
> requested!
pyo3-async-runtimes-0.22.0/examples/async_std.rs 0000644 0000000 0000000 00000000713 10461020230 0017732 0 ustar 0000000 0000000 use pyo3::prelude::*;
#[pyo3_async_runtimes::async_std::main]
async fn main() -> PyResult<()> {
let fut = Python::with_gil(|py| {
let asyncio = py.import_bound("asyncio")?;
// convert asyncio.sleep into a Rust Future
pyo3_async_runtimes::async_std::into_future(
asyncio.call_method1("sleep", (1.into_py(py),))?,
)
})?;
println!("sleeping for 1s");
fut.await?;
println!("done");
Ok(())
}
pyo3-async-runtimes-0.22.0/examples/tokio.rs 0000644 0000000 0000000 00000000654 10461020230 0017074 0 ustar 0000000 0000000 use pyo3::prelude::*;
#[pyo3_async_runtimes::tokio::main]
async fn main() -> PyResult<()> {
let fut = Python::with_gil(|py| {
let asyncio = py.import_bound("asyncio")?;
// convert asyncio.sleep into a Rust Future
pyo3_async_runtimes::tokio::into_future(asyncio.call_method1("sleep", (1.into_py(py),))?)
})?;
println!("sleeping for 1s");
fut.await?;
println!("done");
Ok(())
}
pyo3-async-runtimes-0.22.0/examples/tokio_current_thread.rs 0000644 0000000 0000000 00000000707 10461020230 0022164 0 ustar 0000000 0000000 use pyo3::prelude::*;
#[pyo3_async_runtimes::tokio::main(flavor = "current_thread")]
async fn main() -> PyResult<()> {
let fut = Python::with_gil(|py| {
let asyncio = py.import_bound("asyncio")?;
// convert asyncio.sleep into a Rust Future
pyo3_async_runtimes::tokio::into_future(asyncio.call_method1("sleep", (1.into_py(py),))?)
})?;
println!("sleeping for 1s");
fut.await?;
println!("done");
Ok(())
}
pyo3-async-runtimes-0.22.0/examples/tokio_multi_thread.rs 0000644 0000000 0000000 00000000732 10461020230 0021632 0 ustar 0000000 0000000 use pyo3::prelude::*;
#[pyo3_async_runtimes::tokio::main(flavor = "multi_thread", worker_threads = 10)]
async fn main() -> PyResult<()> {
let fut = Python::with_gil(|py| {
let asyncio = py.import_bound("asyncio")?;
// convert asyncio.sleep into a Rust Future
pyo3_async_runtimes::tokio::into_future(asyncio.call_method1("sleep", (1.into_py(py),))?)
})?;
println!("sleeping for 1s");
fut.await?;
println!("done");
Ok(())
}
pyo3-async-runtimes-0.22.0/pytests/common/mod.rs 0000644 0000000 0000000 00000003072 10461020230 0017710 0 ustar 0000000 0000000 use std::{thread, time::Duration};
use pyo3::prelude::*;
use pyo3_async_runtimes::TaskLocals;
pub(super) const TEST_MOD: &'static str = r#"
import asyncio
async def py_sleep(duration):
await asyncio.sleep(duration)
async def sleep_for_1s(sleep_for):
await sleep_for(1)
"#;
pub(super) async fn test_into_future(event_loop: PyObject) -> PyResult<()> {
let fut = Python::with_gil(|py| {
let test_mod =
PyModule::from_code_bound(py, TEST_MOD, "test_rust_coroutine/test_mod.py", "test_mod")?;
pyo3_async_runtimes::into_future_with_locals(
&TaskLocals::new(event_loop.into_bound(py)),
test_mod.call_method1("py_sleep", (1.into_py(py),))?,
)
})?;
fut.await?;
Ok(())
}
pub(super) fn test_blocking_sleep() -> PyResult<()> {
thread::sleep(Duration::from_secs(1));
Ok(())
}
pub(super) async fn test_other_awaitables(event_loop: PyObject) -> PyResult<()> {
let fut = Python::with_gil(|py| {
let functools = py.import_bound("functools")?;
let time = py.import_bound("time")?;
// spawn a blocking sleep in the threadpool executor - returns a task, not a coroutine
let task = event_loop.bind(py).call_method1(
"run_in_executor",
(
py.None(),
functools.call_method1("partial", (time.getattr("sleep")?, 1))?,
),
)?;
pyo3_async_runtimes::into_future_with_locals(
&TaskLocals::new(event_loop.into_bound(py)),
task,
)
})?;
fut.await?;
Ok(())
}
pyo3-async-runtimes-0.22.0/pytests/test_async_std_asyncio.rs 0000644 0000000 0000000 00000025320 10461020230 0022414 0 ustar 0000000 0000000 mod common;
use std::{
rc::Rc,
sync::{Arc, Mutex},
time::Duration,
};
use async_std::task;
use pyo3::{
prelude::*,
types::{IntoPyDict, PyType},
wrap_pyfunction, wrap_pymodule,
};
use pyo3_async_runtimes::TaskLocals;
#[cfg(feature = "unstable-streams")]
use futures::{StreamExt, TryStreamExt};
#[pyfunction]
fn sleep<'p>(py: Python<'p>, secs: Bound<'p, PyAny>) -> PyResult> {
let secs = secs.extract()?;
pyo3_async_runtimes::async_std::future_into_py(py, async move {
task::sleep(Duration::from_secs(secs)).await;
Ok(())
})
}
#[pyo3_async_runtimes::async_std::test]
async fn test_future_into_py() -> PyResult<()> {
let fut = Python::with_gil(|py| {
let sleeper_mod = PyModule::new_bound(py, "rust_sleeper")?;
sleeper_mod.add_wrapped(wrap_pyfunction!(sleep))?;
let test_mod = PyModule::from_code_bound(
py,
common::TEST_MOD,
"test_future_into_py_mod.py",
"test_future_into_py_mod",
)?;
pyo3_async_runtimes::async_std::into_future(
test_mod.call_method1("sleep_for_1s", (sleeper_mod.getattr("sleep")?,))?,
)
})?;
fut.await?;
Ok(())
}
#[pyo3_async_runtimes::async_std::test]
async fn test_async_sleep() -> PyResult<()> {
let asyncio = Python::with_gil(|py| {
py.import_bound("asyncio")
.map(|asyncio| PyObject::from(asyncio))
})?;
task::sleep(Duration::from_secs(1)).await;
Python::with_gil(|py| {
pyo3_async_runtimes::async_std::into_future(asyncio.bind(py).call_method1("sleep", (1.0,))?)
})?
.await?;
Ok(())
}
#[pyo3_async_runtimes::async_std::test]
fn test_blocking_sleep() -> PyResult<()> {
common::test_blocking_sleep()
}
#[pyo3_async_runtimes::async_std::test]
async fn test_into_future() -> PyResult<()> {
common::test_into_future(Python::with_gil(|py| {
pyo3_async_runtimes::async_std::get_current_loop(py)
.unwrap()
.into()
}))
.await
}
#[pyo3_async_runtimes::async_std::test]
async fn test_other_awaitables() -> PyResult<()> {
common::test_other_awaitables(Python::with_gil(|py| {
pyo3_async_runtimes::async_std::get_current_loop(py)
.unwrap()
.into()
}))
.await
}
#[pyo3_async_runtimes::async_std::test]
async fn test_panic() -> PyResult<()> {
let fut = Python::with_gil(|py| -> PyResult<_> {
pyo3_async_runtimes::async_std::into_future(
pyo3_async_runtimes::async_std::future_into_py::<_, ()>(py, async {
panic!("this panic was intentional!")
})?,
)
})?;
match fut.await {
Ok(_) => panic!("coroutine should panic"),
Err(e) => Python::with_gil(|py| {
if e.is_instance_of::(py) {
Ok(())
} else {
panic!("expected RustPanic err")
}
}),
}
}
#[pyo3_async_runtimes::async_std::test]
async fn test_local_future_into_py() -> PyResult<()> {
Python::with_gil(|py| {
let non_send_secs = Rc::new(1);
#[allow(deprecated)]
let py_future = pyo3_async_runtimes::async_std::local_future_into_py(py, async move {
async_std::task::sleep(Duration::from_secs(*non_send_secs)).await;
Ok(())
})?;
pyo3_async_runtimes::async_std::into_future(py_future)
})?
.await?;
Ok(())
}
#[pyo3_async_runtimes::async_std::test]
async fn test_cancel() -> PyResult<()> {
let completed = Arc::new(Mutex::new(false));
let py_future = Python::with_gil(|py| -> PyResult {
let completed = Arc::clone(&completed);
Ok(
pyo3_async_runtimes::async_std::future_into_py(py, async move {
async_std::task::sleep(Duration::from_secs(1)).await;
*completed.lock().unwrap() = true;
Ok(())
})?
.into(),
)
})?;
if let Err(e) = Python::with_gil(|py| -> PyResult<_> {
py_future.bind(py).call_method0("cancel")?;
pyo3_async_runtimes::async_std::into_future(py_future.into_bound(py))
})?
.await
{
Python::with_gil(|py| -> PyResult<()> {
assert!(e.value_bound(py).is_instance(
py.import_bound("asyncio")?
.getattr("CancelledError")?
.downcast::()
.unwrap()
)?);
Ok(())
})?;
} else {
panic!("expected CancelledError");
}
async_std::task::sleep(Duration::from_secs(1)).await;
if *completed.lock().unwrap() {
panic!("future still completed")
}
Ok(())
}
#[cfg(feature = "unstable-streams")]
const ASYNC_STD_TEST_MOD: &str = r#"
import asyncio
async def gen():
for i in range(10):
await asyncio.sleep(0.1)
yield i
"#;
#[cfg(feature = "unstable-streams")]
#[pyo3_async_runtimes::async_std::test]
async fn test_async_gen_v1() -> PyResult<()> {
let stream = Python::with_gil(|py| {
let test_mod = PyModule::from_code_bound(
py,
ASYNC_STD_TEST_MOD,
"test_rust_coroutine/async_std_test_mod.py",
"async_std_test_mod",
)?;
pyo3_async_runtimes::async_std::into_stream_v1(test_mod.call_method0("gen")?)
})?;
let vals = stream
.map(|item| Python::with_gil(|py| -> PyResult { Ok(item?.bind(py).extract()?) }))
.try_collect::>()
.await?;
assert_eq!((0..10).collect::>(), vals);
Ok(())
}
#[pyo3_async_runtimes::async_std::test]
fn test_local_cancel(event_loop: PyObject) -> PyResult<()> {
let locals = Python::with_gil(|py| -> PyResult {
Ok(TaskLocals::new(event_loop.into_bound(py)).copy_context(py)?)
})?;
async_std::task::block_on(pyo3_async_runtimes::async_std::scope_local(locals, async {
let completed = Arc::new(Mutex::new(false));
let py_future = Python::with_gil(|py| -> PyResult {
let completed = Arc::clone(&completed);
Ok(
pyo3_async_runtimes::async_std::future_into_py(py, async move {
async_std::task::sleep(Duration::from_secs(1)).await;
*completed.lock().unwrap() = true;
Ok(())
})?
.into(),
)
})?;
if let Err(e) = Python::with_gil(|py| -> PyResult<_> {
py_future.bind(py).call_method0("cancel")?;
pyo3_async_runtimes::async_std::into_future(py_future.into_bound(py))
})?
.await
{
Python::with_gil(|py| -> PyResult<()> {
assert!(e.value_bound(py).is_instance(
py.import_bound("asyncio")?
.getattr("CancelledError")?
.downcast::()
.unwrap()
)?);
Ok(())
})?;
} else {
panic!("expected CancelledError");
}
async_std::task::sleep(Duration::from_secs(1)).await;
if *completed.lock().unwrap() {
panic!("future still completed")
}
Ok(())
}))
}
/// This module is implemented in Rust.
#[pymodule]
fn test_mod(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
#![allow(deprecated)]
#[pyfunction(name = "sleep")]
fn sleep_(py: Python) -> PyResult> {
pyo3_async_runtimes::async_std::future_into_py(py, async move {
async_std::task::sleep(Duration::from_millis(500)).await;
Ok(())
})
}
m.add_function(wrap_pyfunction!(sleep_, m)?)?;
Ok(())
}
const MULTI_ASYNCIO_CODE: &str = r#"
async def main():
return await test_mod.sleep()
asyncio.new_event_loop().run_until_complete(main())
"#;
#[pyo3_async_runtimes::async_std::test]
fn test_multiple_asyncio_run() -> PyResult<()> {
Python::with_gil(|py| {
pyo3_async_runtimes::async_std::run(py, async move {
async_std::task::sleep(Duration::from_millis(500)).await;
Ok(())
})?;
pyo3_async_runtimes::async_std::run(py, async move {
async_std::task::sleep(Duration::from_millis(500)).await;
Ok(())
})?;
let d = [
("asyncio", py.import_bound("asyncio")?.into()),
("test_mod", wrap_pymodule!(test_mod)(py)),
]
.into_py_dict_bound(py);
py.run_bound(MULTI_ASYNCIO_CODE, Some(&d), None)?;
py.run_bound(MULTI_ASYNCIO_CODE, Some(&d), None)?;
Ok(())
})
}
#[pymodule]
fn cvars_mod(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
#![allow(deprecated)]
#[pyfunction]
pub(crate) fn async_callback(py: Python, callback: PyObject) -> PyResult> {
pyo3_async_runtimes::async_std::future_into_py(py, async move {
Python::with_gil(|py| {
pyo3_async_runtimes::async_std::into_future(callback.bind(py).call0()?)
})?
.await?;
Ok(())
})
}
m.add_function(wrap_pyfunction!(async_callback, m)?)?;
Ok(())
}
#[cfg(feature = "unstable-streams")]
#[pyo3_async_runtimes::async_std::test]
async fn test_async_gen_v2() -> PyResult<()> {
let stream = Python::with_gil(|py| {
let test_mod = PyModule::from_code_bound(
py,
ASYNC_STD_TEST_MOD,
"test_rust_coroutine/async_std_test_mod.py",
"async_std_test_mod",
)?;
pyo3_async_runtimes::async_std::into_stream_v2(test_mod.call_method0("gen")?)
})?;
let vals = stream
.map(|item| Python::with_gil(|py| -> PyResult { Ok(item.bind(py).extract()?) }))
.try_collect::>()
.await?;
assert_eq!((0..10).collect::>(), vals);
Ok(())
}
const CONTEXTVARS_CODE: &str = r#"
cx = contextvars.ContextVar("cx")
async def contextvars_test():
assert cx.get() == "foobar"
async def main():
cx.set("foobar")
await cvars_mod.async_callback(contextvars_test)
asyncio.run(main())
"#;
#[pyo3_async_runtimes::async_std::test]
fn test_contextvars() -> PyResult<()> {
Python::with_gil(|py| {
let d = [
("asyncio", py.import_bound("asyncio")?.into()),
("contextvars", py.import_bound("contextvars")?.into()),
("cvars_mod", wrap_pymodule!(cvars_mod)(py)),
]
.into_py_dict_bound(py);
py.run_bound(CONTEXTVARS_CODE, Some(&d), None)?;
py.run_bound(CONTEXTVARS_CODE, Some(&d), None)?;
Ok(())
})
}
fn main() -> pyo3::PyResult<()> {
pyo3::prepare_freethreaded_python();
Python::with_gil(|py| {
pyo3_async_runtimes::async_std::run(py, pyo3_async_runtimes::testing::main())
})
}
pyo3-async-runtimes-0.22.0/pytests/test_async_std_run_forever.rs 0000644 0000000 0000000 00000002606 10461020230 0023305 0 ustar 0000000 0000000 use std::time::Duration;
use pyo3::prelude::*;
fn dump_err(py: Python, e: PyErr) {
// We can't display Python exceptions via std::fmt::Display,
// so print the error here manually.
e.print_and_set_sys_last_vars(py);
}
fn main() {
pyo3::prepare_freethreaded_python();
Python::with_gil(|py| {
let asyncio = py.import_bound("asyncio")?;
let event_loop = asyncio.call_method0("new_event_loop")?;
asyncio.call_method1("set_event_loop", (&event_loop,))?;
let event_loop_hdl = PyObject::from(event_loop.clone());
async_std::task::spawn(async move {
async_std::task::sleep(Duration::from_secs(1)).await;
Python::with_gil(|py| {
event_loop_hdl
.bind(py)
.call_method1(
"call_soon_threadsafe",
(event_loop_hdl
.bind(py)
.getattr("stop")
.map_err(|e| dump_err(py, e))
.unwrap(),),
)
.map_err(|e| dump_err(py, e))
.unwrap();
})
});
event_loop.call_method0("run_forever")?;
println!("test test_async_std_run_forever ... ok");
Ok(())
})
.map_err(|e| Python::with_gil(|py| dump_err(py, e)))
.unwrap()
}
pyo3-async-runtimes-0.22.0/pytests/test_async_std_uvloop.rs 0000644 0000000 0000000 00000002174 10461020230 0022275 0 ustar 0000000 0000000 #[cfg(not(target_os = "windows"))]
fn main() -> pyo3::PyResult<()> {
use pyo3::{prelude::*, types::PyType};
pyo3::prepare_freethreaded_python();
Python::with_gil(|py| {
let uvloop = py.import_bound("uvloop")?;
uvloop.call_method0("install")?;
// store a reference for the assertion
let uvloop = PyObject::from(uvloop);
pyo3_async_runtimes::async_std::run(py, async move {
// verify that we are on a uvloop.Loop
Python::with_gil(|py| -> PyResult<()> {
assert!(
pyo3_async_runtimes::async_std::get_current_loop(py)?.is_instance(
uvloop
.bind(py)
.getattr("Loop")?
.downcast::()
.unwrap()
)?
);
Ok(())
})?;
async_std::task::sleep(std::time::Duration::from_secs(1)).await;
println!("test test_async_std_uvloop ... ok");
Ok(())
})
})
}
#[cfg(target_os = "windows")]
fn main() {}
pyo3-async-runtimes-0.22.0/pytests/test_race_condition_regression.rs 0000644 0000000 0000000 00000003716 10461020230 0024125 0 ustar 0000000 0000000 use pyo3::{prelude::*, wrap_pyfunction};
#[pyfunction]
fn sleep<'p>(py: Python<'p>, secs: Bound<'p, PyAny>) -> PyResult> {
let secs = secs.extract()?;
pyo3_async_runtimes::async_std::future_into_py(py, async move {
async_std::task::sleep(std::time::Duration::from_secs_f64(secs)).await;
Ok(())
})
}
const RACE_CONDITION_REGRESSION_TEST: &str = r#"
import asyncio
import random
async def trigger_race_condition(rust_sleeper, delay):
coro = asyncio.wrap_future(rust_sleeper(0.1))
await asyncio.sleep(delay)
coro.cancel()
def main(rust_sleeper):
race_condition_triggered = False
for i in range(1000):
delay = random.uniform(0.099, 0.101)
loop = asyncio.new_event_loop()
loop.set_debug(True)
def custom_exception_handler(loop, context):
nonlocal race_condition_triggered
race_condition_triggered = True
try:
loop.set_exception_handler(custom_exception_handler)
loop.run_until_complete(trigger_race_condition(rust_sleeper, delay))
if race_condition_triggered:
raise Exception("Race condition triggered")
finally:
loop.run_until_complete(loop.shutdown_asyncgens())
if hasattr(loop, 'shutdown_default_executor'):
loop.run_until_complete(loop.shutdown_default_executor())
loop.close()
"#;
fn main() -> pyo3::PyResult<()> {
pyo3::prepare_freethreaded_python();
Python::with_gil(|py| -> PyResult<()> {
let sleeper_mod = PyModule::new_bound(py, "rust_sleeper")?;
sleeper_mod.add_wrapped(wrap_pyfunction!(sleep))?;
let test_mod = PyModule::from_code_bound(
py,
RACE_CONDITION_REGRESSION_TEST,
"race_condition_regression_test.py",
"race_condition_regression_test",
)?;
test_mod.call_method1("main", (sleeper_mod.getattr("sleep")?,))?;
Ok(())
})
}
pyo3-async-runtimes-0.22.0/pytests/test_tokio_current_thread_asyncio.rs 0000644 0000000 0000000 00000001051 10461020230 0024636 0 ustar 0000000 0000000 mod common;
mod tokio_asyncio;
use pyo3::prelude::*;
fn main() -> pyo3::PyResult<()> {
pyo3::prepare_freethreaded_python();
Python::with_gil(|py| {
let mut builder = tokio::runtime::Builder::new_current_thread();
builder.enable_all();
pyo3_async_runtimes::tokio::init(builder);
std::thread::spawn(move || {
pyo3_async_runtimes::tokio::get_runtime().block_on(futures::future::pending::<()>());
});
pyo3_async_runtimes::tokio::run(py, pyo3_async_runtimes::testing::main())
})
}
pyo3-async-runtimes-0.22.0/pytests/test_tokio_current_thread_run_forever.rs 0000644 0000000 0000000 00000000716 10461020230 0025534 0 ustar 0000000 0000000 mod tokio_run_forever;
fn main() {
pyo3::prepare_freethreaded_python();
let mut builder = tokio::runtime::Builder::new_current_thread();
builder.enable_all();
pyo3_async_runtimes::tokio::init(builder);
std::thread::spawn(move || {
pyo3_async_runtimes::tokio::get_runtime().block_on(futures::future::pending::<()>());
});
tokio_run_forever::test_main();
println!("test test_tokio_current_thread_run_forever ... ok");
}
pyo3-async-runtimes-0.22.0/pytests/test_tokio_current_thread_uvloop.rs 0000644 0000000 0000000 00000002623 10461020230 0024523 0 ustar 0000000 0000000 #[cfg(not(target_os = "windows"))]
fn main() -> pyo3::PyResult<()> {
use pyo3::{prelude::*, types::PyType};
pyo3::prepare_freethreaded_python();
let mut builder = tokio::runtime::Builder::new_current_thread();
builder.enable_all();
pyo3_async_runtimes::tokio::init(builder);
std::thread::spawn(move || {
pyo3_async_runtimes::tokio::get_runtime().block_on(futures::future::pending::<()>());
});
Python::with_gil(|py| {
let uvloop = py.import_bound("uvloop")?;
uvloop.call_method0("install")?;
// store a reference for the assertion
let uvloop = PyObject::from(uvloop);
pyo3_async_runtimes::tokio::run(py, async move {
// verify that we are on a uvloop.Loop
Python::with_gil(|py| -> PyResult<()> {
assert!(
pyo3_async_runtimes::tokio::get_current_loop(py)?.is_instance(
uvloop
.bind(py)
.getattr("Loop")?
.downcast::()
.unwrap()
)?
);
Ok(())
})?;
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
println!("test test_tokio_current_thread_uvloop ... ok");
Ok(())
})
})
}
#[cfg(target_os = "windows")]
fn main() {}
pyo3-async-runtimes-0.22.0/pytests/test_tokio_multi_thread_asyncio.rs 0000644 0000000 0000000 00000000352 10461020230 0024311 0 ustar 0000000 0000000 mod common;
mod tokio_asyncio;
use pyo3::prelude::*;
fn main() -> pyo3::PyResult<()> {
pyo3::prepare_freethreaded_python();
Python::with_gil(|py| pyo3_async_runtimes::tokio::run(py, pyo3_async_runtimes::testing::main()))
}
pyo3-async-runtimes-0.22.0/pytests/test_tokio_multi_thread_run_forever.rs 0000644 0000000 0000000 00000000264 10461020230 0025202 0 ustar 0000000 0000000 mod tokio_run_forever;
fn main() {
pyo3::prepare_freethreaded_python();
tokio_run_forever::test_main();
println!("test test_tokio_multi_thread_run_forever ... ok");
}
pyo3-async-runtimes-0.22.0/pytests/test_tokio_multi_thread_uvloop.rs 0000644 0000000 0000000 00000002172 10461020230 0024172 0 ustar 0000000 0000000 #[cfg(not(target_os = "windows"))]
fn main() -> pyo3::PyResult<()> {
use pyo3::{prelude::*, types::PyType};
pyo3::prepare_freethreaded_python();
Python::with_gil(|py| {
let uvloop = py.import_bound("uvloop")?;
uvloop.call_method0("install")?;
// store a reference for the assertion
let uvloop = PyObject::from(uvloop);
pyo3_async_runtimes::tokio::run(py, async move {
// verify that we are on a uvloop.Loop
Python::with_gil(|py| -> PyResult<()> {
assert!(
pyo3_async_runtimes::tokio::get_current_loop(py)?.is_instance(
uvloop
.bind(py)
.getattr("Loop")?
.downcast::()
.unwrap()
)?
);
Ok(())
})?;
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
println!("test test_tokio_multi_thread_uvloop ... ok");
Ok(())
})
})
}
#[cfg(target_os = "windows")]
fn main() {}
pyo3-async-runtimes-0.22.0/pytests/tokio_asyncio/mod.rs 0000644 0000000 0000000 00000025626 10461020230 0021303 0 ustar 0000000 0000000 use std::{
rc::Rc,
sync::{Arc, Mutex},
time::Duration,
};
use pyo3::{
prelude::*,
types::{IntoPyDict, PyType},
wrap_pyfunction, wrap_pymodule,
};
use pyo3_async_runtimes::TaskLocals;
#[cfg(feature = "unstable-streams")]
use futures::{StreamExt, TryStreamExt};
use crate::common;
#[pyfunction]
fn sleep<'p>(py: Python<'p>, secs: Bound<'p, PyAny>) -> PyResult> {
let secs = secs.extract()?;
pyo3_async_runtimes::tokio::future_into_py(py, async move {
tokio::time::sleep(Duration::from_secs(secs)).await;
Ok(())
})
}
#[pyo3_async_runtimes::tokio::test]
async fn test_future_into_py() -> PyResult<()> {
let fut = Python::with_gil(|py| {
let sleeper_mod = PyModule::new_bound(py, "rust_sleeper")?;
sleeper_mod.add_wrapped(wrap_pyfunction!(sleep))?;
let test_mod = PyModule::from_code_bound(
py,
common::TEST_MOD,
"test_future_into_py_mod.py",
"test_future_into_py_mod",
)?;
pyo3_async_runtimes::tokio::into_future(
test_mod.call_method1("sleep_for_1s", (sleeper_mod.getattr("sleep")?,))?,
)
})?;
fut.await?;
Ok(())
}
#[pyo3_async_runtimes::tokio::test]
async fn test_async_sleep() -> PyResult<()> {
let asyncio = Python::with_gil(|py| {
py.import_bound("asyncio")
.map(|asyncio| PyObject::from(asyncio))
})?;
tokio::time::sleep(Duration::from_secs(1)).await;
Python::with_gil(|py| {
pyo3_async_runtimes::tokio::into_future(asyncio.bind(py).call_method1("sleep", (1.0,))?)
})?
.await?;
Ok(())
}
#[pyo3_async_runtimes::tokio::test]
fn test_blocking_sleep() -> PyResult<()> {
common::test_blocking_sleep()
}
#[pyo3_async_runtimes::tokio::test]
async fn test_into_future() -> PyResult<()> {
common::test_into_future(Python::with_gil(|py| {
pyo3_async_runtimes::tokio::get_current_loop(py)
.unwrap()
.into()
}))
.await
}
#[pyo3_async_runtimes::tokio::test]
async fn test_other_awaitables() -> PyResult<()> {
common::test_other_awaitables(Python::with_gil(|py| {
pyo3_async_runtimes::tokio::get_current_loop(py)
.unwrap()
.into()
}))
.await
}
#[pyo3_async_runtimes::tokio::test]
fn test_local_future_into_py(event_loop: PyObject) -> PyResult<()> {
tokio::task::LocalSet::new().block_on(pyo3_async_runtimes::tokio::get_runtime(), async {
Python::with_gil(|py| {
let non_send_secs = Rc::new(1);
#[allow(deprecated)]
let py_future = pyo3_async_runtimes::tokio::local_future_into_py_with_locals(
py,
TaskLocals::new(event_loop.bind(py).clone()),
async move {
tokio::time::sleep(Duration::from_secs(*non_send_secs)).await;
Ok(())
},
)?;
pyo3_async_runtimes::into_future_with_locals(
&TaskLocals::new(event_loop.into_bound(py)),
py_future,
)
})?
.await?;
Ok(())
})
}
#[pyo3_async_runtimes::tokio::test]
async fn test_panic() -> PyResult<()> {
let fut = Python::with_gil(|py| -> PyResult<_> {
pyo3_async_runtimes::tokio::into_future(
pyo3_async_runtimes::tokio::future_into_py::<_, ()>(py, async {
panic!("this panic was intentional!")
})?,
)
})?;
match fut.await {
Ok(_) => panic!("coroutine should panic"),
Err(e) => Python::with_gil(|py| {
if e.is_instance_of::(py) {
Ok(())
} else {
panic!("expected RustPanic err")
}
}),
}
}
#[pyo3_async_runtimes::tokio::test]
async fn test_cancel() -> PyResult<()> {
let completed = Arc::new(Mutex::new(false));
let py_future = Python::with_gil(|py| -> PyResult {
let completed = Arc::clone(&completed);
Ok(pyo3_async_runtimes::tokio::future_into_py(py, async move {
tokio::time::sleep(Duration::from_secs(1)).await;
*completed.lock().unwrap() = true;
Ok(())
})?
.into())
})?;
if let Err(e) = Python::with_gil(|py| -> PyResult<_> {
py_future.bind(py).call_method0("cancel")?;
pyo3_async_runtimes::tokio::into_future(py_future.into_bound(py))
})?
.await
{
Python::with_gil(|py| -> PyResult<()> {
assert!(e.value_bound(py).is_instance(
py.import_bound("asyncio")?
.getattr("CancelledError")?
.downcast::()
.unwrap()
)?);
Ok(())
})?;
} else {
panic!("expected CancelledError");
}
tokio::time::sleep(Duration::from_secs(1)).await;
if *completed.lock().unwrap() {
panic!("future still completed")
}
Ok(())
}
#[pyo3_async_runtimes::tokio::test]
#[allow(deprecated)]
fn test_local_cancel(event_loop: PyObject) -> PyResult<()> {
let locals = Python::with_gil(|py| -> PyResult {
Ok(TaskLocals::new(event_loop.into_bound(py)).copy_context(py)?)
})?;
tokio::task::LocalSet::new().block_on(
pyo3_async_runtimes::tokio::get_runtime(),
pyo3_async_runtimes::tokio::scope_local(locals, async {
let completed = Arc::new(Mutex::new(false));
let py_future = Python::with_gil(|py| -> PyResult {
let completed = Arc::clone(&completed);
#[allow(deprecated)]
Ok(
pyo3_async_runtimes::tokio::local_future_into_py(py, async move {
tokio::time::sleep(Duration::from_secs(1)).await;
*completed.lock().unwrap() = true;
Ok(())
})?
.into(),
)
})?;
if let Err(e) = Python::with_gil(|py| -> PyResult<_> {
py_future.bind(py).call_method0("cancel")?;
pyo3_async_runtimes::tokio::into_future(py_future.into_bound(py))
})?
.await
{
Python::with_gil(|py| -> PyResult<()> {
assert!(e.value_bound(py).is_instance(
py.import_bound("asyncio")?
.getattr("CancelledError")?
.downcast::()
.unwrap()
)?);
Ok(())
})?;
} else {
panic!("expected CancelledError");
}
tokio::time::sleep(Duration::from_secs(1)).await;
if *completed.lock().unwrap() {
panic!("future still completed")
}
Ok(())
}),
)
}
/// This module is implemented in Rust.
#[pymodule]
fn test_mod(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
#![allow(deprecated)]
#[pyfunction(name = "sleep")]
fn sleep_(py: Python) -> PyResult> {
pyo3_async_runtimes::tokio::future_into_py(py, async move {
tokio::time::sleep(Duration::from_millis(500)).await;
Ok(())
})
}
m.add_function(wrap_pyfunction!(sleep_, m)?)?;
Ok(())
}
const TEST_CODE: &str = r#"
async def main():
return await test_mod.sleep()
asyncio.new_event_loop().run_until_complete(main())
"#;
#[pyo3_async_runtimes::tokio::test]
fn test_multiple_asyncio_run() -> PyResult<()> {
Python::with_gil(|py| {
pyo3_async_runtimes::tokio::run(py, async move {
tokio::time::sleep(Duration::from_millis(500)).await;
Ok(())
})?;
pyo3_async_runtimes::tokio::run(py, async move {
tokio::time::sleep(Duration::from_millis(500)).await;
Ok(())
})?;
let d = [
("asyncio", py.import_bound("asyncio")?.into()),
("test_mod", wrap_pymodule!(test_mod)(py)),
]
.into_py_dict_bound(py);
py.run_bound(TEST_CODE, Some(&d), None)?;
py.run_bound(TEST_CODE, Some(&d), None)?;
Ok(())
})
}
#[pymodule]
fn cvars_mod(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
#![allow(deprecated)]
#[pyfunction]
fn async_callback(py: Python, callback: PyObject) -> PyResult> {
pyo3_async_runtimes::tokio::future_into_py(py, async move {
Python::with_gil(|py| {
pyo3_async_runtimes::tokio::into_future(callback.bind(py).call0()?)
})?
.await?;
Ok(())
})
}
m.add_function(wrap_pyfunction!(async_callback, m)?)?;
Ok(())
}
#[cfg(feature = "unstable-streams")]
const TOKIO_TEST_MOD: &str = r#"
import asyncio
async def gen():
for i in range(10):
await asyncio.sleep(0.1)
yield i
"#;
#[cfg(feature = "unstable-streams")]
#[pyo3_async_runtimes::tokio::test]
async fn test_async_gen_v1() -> PyResult<()> {
let stream = Python::with_gil(|py| {
let test_mod = PyModule::from_code_bound(
py,
TOKIO_TEST_MOD,
"test_rust_coroutine/tokio_test_mod.py",
"tokio_test_mod",
)?;
pyo3_async_runtimes::tokio::into_stream_v1(test_mod.call_method0("gen")?)
})?;
let vals = stream
.map(|item| Python::with_gil(|py| -> PyResult { Ok(item?.bind(py).extract()?) }))
.try_collect::>()
.await?;
assert_eq!((0..10).collect::>(), vals);
Ok(())
}
#[cfg(feature = "unstable-streams")]
#[pyo3_async_runtimes::tokio::test]
async fn test_async_gen_v2() -> PyResult<()> {
let stream = Python::with_gil(|py| {
let test_mod = PyModule::from_code_bound(
py,
TOKIO_TEST_MOD,
"test_rust_coroutine/tokio_test_mod.py",
"tokio_test_mod",
)?;
pyo3_async_runtimes::tokio::into_stream_v2(test_mod.call_method0("gen")?)
})?;
let vals = stream
.map(|item| Python::with_gil(|py| -> PyResult { Ok(item.bind(py).extract()?) }))
.try_collect::>()
.await?;
assert_eq!((0..10).collect::>(), vals);
Ok(())
}
const CONTEXTVARS_CODE: &str = r#"
cx = contextvars.ContextVar("cx")
async def contextvars_test():
assert cx.get() == "foobar"
async def main():
cx.set("foobar")
await cvars_mod.async_callback(contextvars_test)
asyncio.run(main())
"#;
#[pyo3_async_runtimes::tokio::test]
fn test_contextvars() -> PyResult<()> {
Python::with_gil(|py| {
let d = [
("asyncio", py.import_bound("asyncio")?.into()),
("contextvars", py.import_bound("contextvars")?.into()),
("cvars_mod", wrap_pymodule!(cvars_mod)(py)),
]
.into_py_dict_bound(py);
py.run_bound(CONTEXTVARS_CODE, Some(&d), None)?;
py.run_bound(CONTEXTVARS_CODE, Some(&d), None)?;
Ok(())
})
}
pyo3-async-runtimes-0.22.0/pytests/tokio_run_forever/mod.rs 0000644 0000000 0000000 00000002512 10461020230 0022157 0 ustar 0000000 0000000 use std::time::Duration;
use pyo3::prelude::*;
fn dump_err(py: Python<'_>, e: PyErr) {
// We can't display Python exceptions via std::fmt::Display,
// so print the error here manually.
e.print_and_set_sys_last_vars(py);
}
pub(super) fn test_main() {
Python::with_gil(|py| {
let asyncio = py.import_bound("asyncio")?;
let event_loop = asyncio.call_method0("new_event_loop")?;
asyncio.call_method1("set_event_loop", (&event_loop,))?;
let event_loop_hdl = PyObject::from(event_loop.clone());
pyo3_async_runtimes::tokio::get_runtime().spawn(async move {
tokio::time::sleep(Duration::from_secs(1)).await;
Python::with_gil(|py| {
event_loop_hdl
.bind(py)
.call_method1(
"call_soon_threadsafe",
(event_loop_hdl
.bind(py)
.getattr("stop")
.map_err(|e| dump_err(py, e))
.unwrap(),),
)
.map_err(|e| dump_err(py, e))
.unwrap();
})
});
event_loop.call_method0("run_forever")?;
Ok(())
})
.map_err(|e| Python::with_gil(|py| dump_err(py, e)))
.unwrap();
}
pyo3-async-runtimes-0.22.0/src/async_std.rs 0000644 0000000 0000000 00000063501 10461020230 0016707 0 ustar 0000000 0000000 //! async-std-runtime PyO3 Asyncio functions specific to the async-std runtime
//!
//! Items marked with
//! unstable-streams
//! are only available when the `unstable-streams` Cargo feature is enabled:
//!
//! ```toml
//! [dependencies.pyo3-async-runtimes]
//! version = "0.22"
//! features = ["unstable-streams"]
//! ```
use async_std::task;
use futures::FutureExt;
use pyo3::prelude::*;
use std::{any::Any, cell::RefCell, future::Future, panic::AssertUnwindSafe, pin::Pin};
use crate::{
generic::{self, ContextExt, JoinError, LocalContextExt, Runtime, SpawnLocalExt},
TaskLocals,
};
/// attributes
/// re-exports for macros
#[cfg(feature = "attributes")]
pub mod re_exports {
/// re-export spawn_blocking for use in `#[test]` macro without external dependency
pub use async_std::task::spawn_blocking;
}
/// attributes Provides the boilerplate for the `async-std` runtime and runs an async fn as main
#[cfg(feature = "attributes")]
pub use pyo3_async_runtimes_macros::async_std_main as main;
/// attributes
/// testing
/// Registers an `async-std` test with the `pyo3-asyncio` test harness
#[cfg(all(feature = "attributes", feature = "testing"))]
pub use pyo3_async_runtimes_macros::async_std_test as test;
struct AsyncStdJoinErr(Box);
impl JoinError for AsyncStdJoinErr {
fn is_panic(&self) -> bool {
true
}
fn into_panic(self) -> Box {
self.0
}
}
async_std::task_local! {
static TASK_LOCALS: RefCell