pyo3 icon indicating copy to clipboard operation
pyo3 copied to clipboard

cargo test fails using uv

Open Cheukting opened this issue 1 month ago • 4 comments

Bug Description

When running cargo test I encounter the following error:

Could not find platform independent libraries <prefix>
Could not find platform dependent libraries <exec_prefix>
Fatal Python error: Failed to import encodings module
Python runtime state: core initialized
ModuleNotFoundError: No module named 'encodings'

While maturin develop works just fine.

Steps to Reproduce

I am using the following set up:

uv 0.9.9 (Homebrew 2025-11-12) Python 3.14.0 maturin 1.10.1 PyO3 0.27

My Cargo.toml:

[package]
name = "py202"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "py202"
crate-type = ["cdylib", "rlib"]

[dependencies]
pyo3 = "0.27.1"
pyo3-async-runtimes = { version = "0.27", features = ["attributes", "tokio-runtime", "testing"] }
tokio = { version = "1", features = ["full"] }

[[test]]
name = "test_py202"
path = "pytests/test.rs"
harness = false

My pyproject.toml:

[build-system]
requires = ["maturin>=1.8,<2.0"]
build-backend = "maturin"

[project]
name = "pyo3_202"
requires-python = ">=3.8"
classifiers = [
    "Programming Language :: Rust",
    "Programming Language :: Python :: Implementation :: CPython",
    "Programming Language :: Python :: Implementation :: PyPy",
]
dynamic = ["version"]

My files:

pytests/test.rs:

mod tests {
    use pyo3::prelude::*;
    use py202::make_order;

    #[pyo3_async_runtimes::tokio::test]
    async fn test_async_sleep() -> PyResult<()> {
        make_order("burger soda burger".to_string()).await;
        Ok(())
    }
}

#[pyo3_async_runtimes::tokio::main]
async fn main() -> pyo3::PyResult<()> {
    pyo3_async_runtimes::testing::main().await
}

src/lib.rs:

use pyo3::{prelude::*, wrap_pyfunction};
use tokio::task::JoinHandle;
use tokio::{
    spawn,
    time::{sleep, Duration},
};


async fn burger() -> () {
    sleep(Duration::from_millis(1000)).await;
    println!("burger made");
}

async fn soda() -> () {
    sleep(Duration::from_millis(100)).await;
    println!("soda pour");
}

pub async fn make_order(input_str: String) -> () {
    let input: Vec<&str> = input_str.split(' ').collect();
    let mut actions: Vec<JoinHandle<()>> = Vec::new();
    for item in input {
        match item {
            // save spawned JoinHandles in 'actions' vec
            "burger" => actions.push(spawn(burger())),
            "soda" => actions.push(spawn(soda())),
            _ => println!("invalid order"),
        }
    }
    for action in actions {
        let _ = action.await;
    }
    println!("order complete");
}

#[pyfunction]
// we use string as input because list in Python is kinda tricky
fn order(py: Python, input_str: String) -> PyResult<Bound<PyAny>> {
    pyo3_async_runtimes::tokio::future_into_py(py, async move {
        make_order(input_str).await;
        Ok(())
    })
}

#[pymodule]
fn py202(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(order, m)?)?;
    Ok(())
}

Backtrace


Your operating system and version

Mac OS 15.6.1

Your Python version (python --version)

3.14.0

Your Rust version (rustc --version)

rustc 1.91.1

Your PyO3 version

0.27.1

How did you install python? Did you use a virtualenv?

uv python install 3.14.0

Additional Info

No response

Cheukting avatar Nov 15 '25 13:11 Cheukting

Yep, I think there's a usability issue here which has been known for a long time and needs some figuring out.

Probably rpath - #5624 is going to help.

I think there are also lots of questions about how we initialize Python, which are related to this, e.g. #1741, #3589, etc. I would love to spend some time to figure this out.

davidhewitt avatar Nov 18 '25 11:11 davidhewitt

Also #5056

davidhewitt avatar Nov 18 '25 12:11 davidhewitt

#5609

davidhewitt avatar Nov 18 '25 12:11 davidhewitt

#4841

davidhewitt avatar Nov 18 '25 12:11 davidhewitt