This is a minimal example of project structure required to add a rust extension module in a python project using pyo3 bindings and building using uv+maturin. No useful logic is defined, only a minimum set of configuration.
Find relevant configuration points as follows:
rg my_python_package
rg my_rust_extension
rg CONFIG_NOTEInstall uv.
Since uv provides a build-backend for maturin, nothing extra needs to be done when running code with uv run. For example:
uv run python scripts/example.pyTo manually force uv to build, do: uv sync.
-
There seem to be some situations where caching logic for uv/maturin is fragile. For example when changing name of project folders or the rust extension module. To force a clean rebuild, do:
rm -rf .venv cd rust cargo clean # also find and remove *.so files
-
The name of the rust extension module (the name
my_rust_extensionyou infrom my_python_package import my_rust_extension) is specified in multiple places:
-
pyproject.tomlintool.maturin.module-name -
rust/src/lib.rsin the#[pyo3(name="...")]attribute (or the name of the function) -
__init__.py- this is optional, but helps make usage and naming clear for python user.When these names do not match, python will fail to resolve the import. Note that the suggestion ("likely due to a circular import") is a red herring:
ImportError: cannot import name 'my_rust_extension' from partially initialized module 'my_python_package' (most likely due to a circular import)