Maturin expects a particular project layout depending on the contents of the package.
For a pure Rust project, the structure is as expected and what you get from
my-rust-project/ ├── Cargo.toml ├── pyproject.toml # required for maturin configuration └── src ├── lib.rs # default for library crates └── main.rs # default for binary crates
Maturin will add a necessary
__init__.py to the package when building the
wheel. For convenience, this file includes the following:
from .my_project import * __doc__ = my_project.__doc__ if hasattr(my_project, "__all__"): __all__ = my_project.__all__
such that the module functions may be called directly with:
import my_project my_project.foo()
from my_project import my_project
Note: there is currently no way to tell maturin to include extra data (e.g.
package_datain setuptools) for a pure Rust project. Instead, consider using the layout described below for the mixed Rust/Python project.
To create a mixed Rust/Python project, add a directory with your package name
lib.name in your
Cargo.toml) to contain the Python source:
my-rust-and-python-project ├── Cargo.toml ├── my_project # <<< add this directory and put Python code in here │ ├── __init__.py │ └── bar.py ├── pyproject.toml ├── Readme.md └── src └── lib.rs
Note that in a mixed Rust/Python project, maturin does not modify the
__init__.py in the root package, so now to import the rust module in
Python you must use:
from my_project import my_project
You can modify
__init__.py yourself (see above) if you would like to import
functions Rust functions from a higher-level namespace.
Having a directory with
package_name in the root of the project can
occasionally cause confusion as Python allows importing local packages and
modules. A popular way to avoid this is with the
src-layout, where the Python
package is nested within a
src directory. Unfortunately this interferes with
the structure of a typical Rust project. Fortunately, Python is nor particular
about the name of the parent source directory. You tell maturin to use a
different Python source directory in
Cargo.toml by setting
package.metadata.maturin.python-source. For example:
[package.metadata.maturin] python-source = "python"
then the project structure would look like this:
my-rust-and-python-project ├── Cargo.toml ├── python │ └── my_project │ ├── __init__.py │ └── bar.py ├── pyproject.toml ├── README.md └── src └── lib.rs
To distribute typing information, you need to add:
- an empty marker file called
py.typedin the root of the Python package
- inline types in Python files and/or
In a pure Rust project, add type stubs in a
<module_name>.pyi file in the
project root. Maturin will automatically include this file along with the
py.typed file for you.
my-rust-project/ ├── Cargo.toml ├── my_project.pyi # <<< add type stubs for Rust functions in the my_project module here ├── pyproject.toml └── src └── lib.rs
In a mixed Rust/Python project, additional files in the Python source dir (but
.gitignore) will be automatically included in the build outputs
(source distribution and/or wheel). Type information can be therefore added to
the root Python package directory as you might do in a pure Python package.
This requires you to add the
py.typed marker file yourself.
my-project ├── Cargo.toml ├── python │ └── my_project │ ├── __init__.py │ ├── py.typed # <<< add this empty file │ ├── my_project.pyi # <<< add type stubs for Rust functions in the my_project module here │ ├── bar.pyi # <<< add type stubs for bar.py here OR type bar.py inline │ └── bar.py ├── pyproject.toml ├── README.md └── src └── lib.rs
You can add wheel data by creating a
<module_name>.data folder or setting its location as
data in pyproject.toml under
[tool.maturin] or in Cargo.toml under
The data folder may have the following subfolder:
data: The contents of this folder will simply be unpacked into the virtualenv
scripts: Treated similar to entry points, files in there are installed as standalone executable
.hC header files
purelib: This also exists, but seems to be barely used
platlib: This also exists, but seems to be barely used
If you add a symlink in the data directory, we'll include the actual file so you more flexibility