Skip to content

cargo test doesn't work out of the box with uv-managed venvs #73

Description

@jt-hill

cargo test fails when using a uv-managed virtual environment. The README documents workarounds for extension-module linking and pyenv shared libraries, but uv's thin venvs introduce a different chain of issues:

  1. pyo3 doesn't find the venv Python: Without VIRTUAL_ENV or PYO3_PYTHON set, pyo3 discovers the system Python (which may be a different version and lack numpy/pandas).
  2. Test binary can't find libpython: Even with PYO3_PYTHON pointing at the venv, the compiled test binary fails at runtime with libpython3.x.so: cannot open shared object file. uv installs Python to its own managed location, so LD_LIBRARY_PATH must point there.
  3. Embedded Python can't find stdlib: After solving the linking, Python fails with Could not find platform dependent libraries / No module named 'encodings', because uv venvs are thin (they symlink to a uv-managed Python install rather than containing stdlib). PYTHONHOME must be
    set to sys.base_prefix of the uv-managed Python.

The full workaround requires setting three environment variables before cargo test:

VENV_PYTHON=".venv/bin/python"
PYTHON_PREFIX=$($VENV_PYTHON -c "import sys; print(sys.base_prefix)")
PYTHON_VERSION=$($VENV_PYTHON -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')")

PYO3_PYTHON=$VENV_PYTHON \
LD_LIBRARY_PATH="$PYTHON_PREFIX/lib" \
PYTHONHOME="$PYTHON_PREFIX" \
PYTHONPATH=".venv/lib/python$PYTHON_VERSION/site-packages" \
cargo test

The integration tests in tests/ use pyo3's auto-initialize to embed a Python interpreter inside Rust test binaries. This works when the system Python is straightforward, but is inherently fragile with modern Python managers (uv, potentially others) that use thin/symlinked venvs.

The tests are round-tripping through Python to test what are fundamentally Python-level concerns - input type coercion (lists, dicts, iterators, numpy arrays, pandas DataFrames) and the pyo3 binding layer. The actual financial math in src/core/ is pure Rust and already has its own unit tests.

Suggested fix:

Port the integration tests from Rust (tests/.rs with auto-initialize) to Python (tests/.py with pytest). This gives two clean testing tiers:

  • cargo test - pure Rust, tests the financial math in src/core/, no Python dependency, works everywhere
  • maturin develop && pytest - tests the bindings from Python, running in a normal Python process where numpy/pandas are naturally available

This eliminates the need for auto-initialize, the PYO3_PYTHON/LD_LIBRARY_PATH/PYTHONHOME workarounds, and any platform-specific runner scripts. I have a working port if this direction is agreeable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions