Giter Site home page Giter Site logo

pyo3 / maturin Goto Github PK

View Code? Open in Web Editor NEW
3.3K 26.0 219.0 6.64 MB

Build and publish crates with pyo3, cffi and uniffi bindings as well as rust binaries as python packages

Home Page: https://maturin.rs

License: Apache License 2.0

Rust 93.13% Python 4.82% Dockerfile 0.35% Shell 0.78% Jinja 0.45% JavaScript 0.44% CSS 0.03%
pyo3 python wheels cpython packaging pypi cffi pypy uniffi cross-compile

maturin's Introduction

Maturin

formerly pyo3-pack

Maturin User Guide Crates.io PyPI Actions Status FreeBSD discord server

Build and publish crates with pyo3, rust-cpython, cffi and uniffi bindings as well as rust binaries as python packages with minimal configuration. It supports building wheels for python 3.8+ on windows, linux, mac and freebsd, can upload them to pypi and has basic pypy and graalpy support.

Check out the User Guide!

Usage

You can either download binaries from the latest release or install it with pipx:

pipx install maturin

Note

pip install maturin should also work if you don't want to use pipx.

There are four main commands:

  • maturin new creates a new cargo project with maturin configured.
  • maturin publish builds the crate into python packages and publishes them to pypi.
  • maturin build builds the wheels and stores them in a folder (target/wheels by default), but doesn't upload them. It's possible to upload those with twine or maturin upload.
  • maturin develop builds the crate and installs it as a python module directly in the current virtualenv. Note that while maturin develop is faster, it doesn't support all the feature that running pip install after maturin build supports.

pyo3 and rust-cpython bindings are automatically detected. For cffi or binaries, you need to pass -b cffi or -b bin. maturin doesn't need extra configuration files and doesn't clash with an existing setuptools-rust or milksnake configuration. You can even integrate it with testing tools such as tox. There are examples for the different bindings in the test-crates folder.

The name of the package will be the name of the cargo project, i.e. the name field in the [package] section of Cargo.toml. The name of the module, which you are using when importing, will be the name value in the [lib] section (which defaults to the name of the package). For binaries, it's simply the name of the binary generated by cargo.

Python packaging basics

Python packages come in two formats: A built form called wheel and source distributions (sdist), both of which are archives. A wheel can be compatible with any python version, interpreter (cpython and pypy, mainly), operating system and hardware architecture (for pure python wheels), can be limited to a specific platform and architecture (e.g. when using ctypes or cffi) or to a specific python interpreter and version on a specific architecture and operating system (e.g. with pyo3 and rust-cpython).

When using pip install on a package, pip tries to find a matching wheel and install that. If it doesn't find one, it downloads the source distribution and builds a wheel for the current platform, which requires the right compilers to be installed. Installing a wheel is much faster than installing a source distribution as building wheels is generally slow.

When you publish a package to be installable with pip install, you upload it to pypi, the official package repository. For testing, you can use test pypi instead, which you can use with pip install --index-url https://test.pypi.org/simple/. Note that for publishing for linux, you need to use the manylinux docker container, while for publishing from your repository you can use the PyO3/maturin-action github action.

pyo3 and rust-cpython

For pyo3 and rust-cpython, maturin can only build packages for installed python versions. On linux and mac, all python versions in PATH are used. If you don't set your own interpreters with -i, a heuristic is used to search for python installations. On windows all versions from the python launcher (which is installed by default by the python.org installer) and all conda environments except base are used. You can check which versions are picked up with the list-python subcommand.

pyo3 will set the used python interpreter in the environment variable PYTHON_SYS_EXECUTABLE, which can be used from custom build scripts. Maturin can build and upload wheels for pypy with pyo3, even though only pypy3.7-7.3 on linux is tested.

Cffi

Cffi wheels are compatible with all python versions including pypy. If cffi isn't installed and python is running inside a virtualenv, maturin will install it, otherwise you have to install it yourself (pip install cffi).

maturin uses cbindgen to generate a header file, which can be customized by configuring cbindgen through a cbindgen.toml file inside your project root. Alternatively you can use a build script that writes a header file to $PROJECT_ROOT/target/header.h.

Based on the header file maturin generates a module which exports an ffi and a lib object.

Example of a custom build script
use cbindgen;
use std::env;
use std::path::Path;

fn main() {
    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();

    let bindings = cbindgen::Builder::new()
        .with_no_includes()
        .with_language(cbindgen::Language::C)
        .with_crate(crate_dir)
        .generate()
        .unwrap();
    bindings.write_to_file(Path::new("target").join("header.h"));
}

uniffi

uniffi bindings use uniffi-rs to generate Python ctypes bindings from an interface definition file. uniffi wheels are compatible with all python versions including pypy.

Mixed rust/python projects

To create a mixed rust/python project, create a folder with your module name (i.e. lib.name in Cargo.toml) next to your Cargo.toml and add your python sources there:

my-project
├── Cargo.toml
├── my_project
│   ├── __init__.py
│   └── bar.py
├── pyproject.toml
├── README.md
└── src
    └── lib.rs

You can specify a different python source directory in pyproject.toml by setting tool.maturin.python-source, for example

pyproject.toml

[tool.maturin]
python-source = "python"
module-name = "my_project._lib_name"

then the project structure would look like this:

my-project
├── Cargo.toml
├── python
│   └── my_project
│       ├── __init__.py
│       └── bar.py
├── pyproject.toml
├── README.md
└── src
    └── lib.rs

Note

This structure is recommended to avoid a common ImportError pitfall

maturin will add the native extension as a module in your python folder. When using develop, maturin will copy the native library and for cffi also the glue code to your python folder. You should add those files to your gitignore.

With cffi you can do from .my_project import lib and then use lib.my_native_function, with pyo3/rust-cpython you can directly from .my_project import my_native_function.

Example layout with pyo3 after maturin develop:

my-project
├── Cargo.toml
├── my_project
│   ├── __init__.py
│   ├── bar.py
│   └── _lib_name.cpython-36m-x86_64-linux-gnu.so
├── README.md
└── src
    └── lib.rs

When doing this also be sure to set the module name in your code to match the last part of module-name (don't include the package path):

#[pymodule]
#[pyo3(name="_lib_name")]
fn my_lib_name(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
    m.add_class::<MyPythonRustClass>()?;
    Ok(())
}

Python metadata

maturin supports PEP 621, you can specify python package metadata in pyproject.toml. maturin merges metadata from Cargo.toml and pyproject.toml, pyproject.toml takes precedence over Cargo.toml.

To specify python dependencies, add a list dependencies in a [project] section in the pyproject.toml. This list is equivalent to install_requires in setuptools:

[project]
name = "my-project"
dependencies = ["flask~=1.1.0", "toml==0.10.0"]

Pip allows adding so called console scripts, which are shell commands that execute some function in your program. You can add console scripts in a section [project.scripts]. The keys are the script names while the values are the path to the function in the format some.module.path:class.function, where the class part is optional. The function is called with no arguments. Example:

[project.scripts]
get_42 = "my_project:DummyClass.get_42"

You can also specify trove classifiers in your pyproject.toml under project.classifiers:

[project]
name = "my-project"
classifiers = ["Programming Language :: Python"]

Source distribution

maturin supports building through pyproject.toml. To use it, create a pyproject.toml next to your Cargo.toml with the following content:

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

If a pyproject.toml with a [build-system] entry is present, maturin can build a source distribution of your package when --sdist is specified. The source distribution will contain the same files as cargo package. To only build a source distribution, pass --interpreter without any values.

You can then e.g. install your package with pip install .. With pip install . -v you can see the output of cargo and maturin.

You can use the options compatibility, skip-auditwheel, bindings, strip and common Cargo build options such as features under [tool.maturin] the same way you would when running maturin directly. The bindings key is required for cffi and bin projects as those can't be automatically detected. Currently, all builds are in release mode (see this thread for details).

For a non-manylinux build with cffi bindings you could use the following:

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

[tool.maturin]
bindings = "cffi"
compatibility = "linux"

manylinux option is also accepted as an alias of compatibility for backward compatibility with old version of maturin.

To include arbitrary files in the sdist for use during compilation specify include as an array of path globs with format set to sdist:

[tool.maturin]
include = [{ path = "path/**/*", format = "sdist" }]

There's a maturin sdist command for only building a source distribution as workaround for pypa/pip#6041.

Manylinux and auditwheel

For portability reasons, native python modules on linux must only dynamically link a set of very few libraries which are installed basically everywhere, hence the name manylinux. The pypa offers special docker images and a tool called auditwheel to ensure compliance with the manylinux rules. If you want to publish widely usable wheels for linux pypi, you need to use a manylinux docker image.

The Rust compiler since version 1.64 requires at least glibc 2.17, so you need to use at least manylinux2014. For publishing, we recommend enforcing the same manylinux version as the image with the manylinux flag, e.g. use --manylinux 2014 if you are building in quay.io/pypa/manylinux2014_x86_64. The PyO3/maturin-action github action already takes care of this if you set e.g. manylinux: 2014.

maturin contains a reimplementation of auditwheel automatically checks the generated library and gives the wheel the proper platform tag. If your system's glibc is too new or you link other shared libraries, it will assign the linux tag. You can also manually disable those checks and directly use native linux target with --manylinux off.

For full manylinux compliance you need to compile in a CentOS docker container. The pyo3/maturin image is based on the manylinux2014 image, and passes arguments to the maturin binary. You can use it like this:

docker run --rm -v $(pwd):/io ghcr.io/pyo3/maturin build --release  # or other maturin arguments

Note that this image is very basic and only contains python, maturin and stable rust. If you need additional tools, you can run commands inside the manylinux container. See konstin/complex-manylinux-maturin-docker for a small educational example or nanoporetech/fast-ctc-decode for a real world setup.

maturin itself is manylinux compliant when compiled for the musl target.

Examples

  • ballista-python - A Python library that binds to Apache Arrow distributed query engine Ballista
  • chardetng-py - Python binding for the chardetng character encoding detector.
  • connector-x - ConnectorX enables you to load data from databases into Python in the fastest and most memory efficient way
  • datafusion-python - a Python library that binds to Apache Arrow in-memory query engine DataFusion
  • deltalake-python - Native Delta Lake Python binding based on delta-rs with Pandas integration
  • opendal - OpenDAL Python Binding to access data freely
  • orjson - A fast, correct JSON library for Python
  • polars - Fast multi-threaded DataFrame library in Rust | Python | Node.js
  • pydantic-core - Core validation logic for pydantic written in Rust
  • pyrus-cramjam - Thin Python wrapper to de/compression algorithms in Rust
  • pyxel - A retro game engine for Python
  • roapi - ROAPI automatically spins up read-only APIs for static datasets without requiring you to write a single line of code
  • robyn - A fast and extensible async python web server with a Rust runtime
  • ruff - An extremely fast Python linter, written in Rust
  • tantivy-py - Python bindings for Tantivy
  • watchfiles - Simple, modern and high performance file watching and code reload in python
  • wonnx - Wonnx is a GPU-accelerated ONNX inference run-time written 100% in Rust

Contributing

Everyone is welcomed to contribute to maturin! There are many ways to support the project, such as:

  • help maturin users with issues on GitHub and Gitter
  • improve documentation
  • write features and bugfixes
  • publish blogs and examples of how to use maturin

Our contributing notes have more resources if you wish to volunteer time for maturin and are searching where to start.

If you don't have time to contribute yourself but still wish to support the project's future success, some of our maintainers have GitHub sponsorship pages:

License

Licensed under either of:

at your option.

maturin's People

Contributors

badboy avatar bors[bot] avatar cclauss avatar clbarnes avatar davidhewitt avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar hombit avatar hoodmane avatar idavis avatar ijl avatar ischaojie avatar jasperdesutter avatar kngwyu avatar konstin avatar kxepal avatar lenqth avatar mbargull avatar mbrobbel avatar mbway avatar messense avatar mhils avatar niyas-sait avatar paddyhoran avatar pre-commit-ci[bot] avatar programmerjake avatar ravenexp avatar xuanwo avatar yushiomote avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

maturin's Issues

PEP 517 integration

The recent PEP 517 specifies an interface for alternative build systems to be defined, which is exactly what's happening here.

To do that, pyo3-pack would need to provide a very simple Python interface with the following hooks:

  • build_wheel to build a wheel
  • build_sdist to build a gztarred archive of the source code
    (actual semantics are defined in the PEP).

Then, releasing the pyo3-pack module to PyPI would allow users to specify the build system in pyproject.toml, making it easier to build a Rust wheel without setuptools.

publish 0.7.5 completely

It appears as though version 0.7.5 didn't end up on pypi for non-windows platforms:
https://pypi.org/project/maturin/0.7.5/#files

I think there should also be a source package on pypi for those who are using non-x86 platforms, if that's doable (not sure if pypi shows that in the files tab).

Also, 0.7.5 didn't end up on crates.io at all.

__version__

It would be cool if pyo3-pack packages defined their version to be the one from cargo.toml automatically.

In the meanwhile, how would I define such a static string for my pymodule?

Enable cargo feature when building

Tried using

❯ pyo3-pack build -b pyo3 --cargo-extra-args --features bridge-python
error: Found argument '--features' which wasn't expected, or isn't valid in this context

Clarification on the manylinux wheels comliance

Thanks for this very useful package!

Regarding building manylinux1 wheels, the readme states,

The pypa offers a special docker container and a tool called auditwheel to ensure compliance with the manylinux rules. pyo3-pack contains a reimplementation of the most important part of auditwheel that checks the generated library, so there's no need to use external tools. If you want to disable the manylinux compliance checks for some reason, use the --skip-auditwheel flag.

As far as I understand, another requirement of the manylinux policy is that it needs to work with CentOS 5.11 (on which those docker images are based). Does it mean that one has to use these docker images (and install rust nightly there)? The readme sounds like it's not necessary...

Collecting extra file use cases

For some projects it's necessary to add more files than those generated by pyo3-pack. Doing this is more difficult than for pure python projects because we don't have a classic source directory we just copy over. We also can't use cargo's includes/exclude because they might only be valid for the rust package. This issue is meant to collect what cases need to be considered.

If you have a usecase where you need to add extra files, please add it here. Information about whether the file is in the cargo includes/excludes and where it should go when installing the wheel (or where it should be inside the wheel) would be helpful.

Mixed project layout

This layout makes it possible to combine a python project with a native rust extension. The minimal structure would look like the following:

my_proj
  src
    lib.rs
  my_proj
    __init__.py
  Cargo.toml

pyo3-pack would add either the shared library (for pyo3 and rust-cpython) or a folder with the shared library and some glue code (for cffi) in __init__.py in the my_proj/my_proj directoy. The module is named after the lib name in the Cargo.toml.

It should be possible to auto-detect this layout. It would also fix the problem of adding a .pyi file.

manylinux docker image issues

I've tried the official docker image with pyo3 0.6.0, and the master with pyo3 0.7.0 alpha1.

It seems to always complain about missing libpython.

Running it like this:
docker run --rm -v (pwd):/io 10c0135f4da7 build (10c0135f4da7 being master version of docker image)

🔗 Found pyo3 bindings
🐍 Found CPython 3.5m at python3.5, CPython 3.6m at python3.6, CPython 3.7m at python3.7
   Compiling pyo3 v0.7.0-alpha.1
error: could not find native static library `python3.5m`, perhaps an -L flag is missing?


error: aborting due to previous error


error: Could not compile `pyo3`.

To learn more, run the command again with --verbose.
Cargo build finished with "exit code: 101": `cargo rustc --message-format json --manifest-path Cargo.toml --features pyo3/python3 --lib --`
Failed to build a native library through cargo

It seems from a quick glace inside the container that libpython is nowhere to be found.

[root@dca866f6dbb7 /]# find . -iname "*libpython*.so*"
./usr/lib64/libpython2.4.so
./usr/lib64/libpython2.4.so.1.0
[root@dca866f6dbb7 /]#

Am I missing something?

Feature request: option to build no wheels (sdist only)

On CI, where only one python version is available per job, it might be preferable to have one job per wheel. In that case, you wouldn't also want to try (and fail) to deploy one sdist per job. You could read some environment variables and mangle your maturin arguments to do --no-sdist in specific situations, but it might be more ergonomic to run one job which is just an sdist, and one job for each wheel.

I suggest -I (upper-case i)/--sdist-only, as it's the opposite of adding an interpreter to build a wheel for with -i.

pyo3_mixed not working properly on macOS

When running pyo3-pack develop in the test_crates/pyo3-mixed directory, a dynamic library is placed in the site-packages but the python module is left unused. This also holds for pyo3-pack build then pip install target/wheels/* -- the rust extension is able to be imported properly with import pyo3_mixed but the get_42() function call is not available (rust function get_21() works however).

I'm having the same issue with my own project developed with pyo3-pack. I haven't yet had the chance to check running this on linux.

Full PyPy support

pyo3-pack gets basic pypy support from #105, while some things are still missing.

  • Add some automated testing, ideally on ci as pyo3 does.
  • Figure out the best way to deal with manylinux.
  • Add windows support
    • Find a reference how a native pypy wheel on windows should look like: python_Levenshtein-0.10.2-pp38-pypy38_pp73-win_amd64.whl contains Levenshtein.pypy38-pp73-win_amd64.pyd: https://paste.rs/ZAJ
  • Test on mac (done by @messense, it works)
  • Skip pypy wheels when uploading
  • Autodetect pypy binaries, but only for pyo3
  • Look for a better way than using SOABI to determine the native extensions filename since that value isn't define on windows for both cpython and pypy. SOABI is defined on windows for at least pypy 3.7 and later.
  • #460

Support Metadata-Version in package.metadata.pyo3-pack

First off, I have to use artifactory which does not support Metadata-Version higher than 2.0, so this strange feature request stems from that.

In the Python metadata section the docs state "You can use other fields from the python core metadata in the [package.metadata.pyo3-pack] section (...)". I was somehow expecting I could override/set the Metadata-Version in this way by declaring something like:

[package.metadata.pyo3-pack]
metadata-version = "2.0"

Does this make sense to support? If you point me to the right direction I can try to do a PR myself.

Error with passing flag as rustc extra arg.

The Readme says:

--rustc-extra-args <rustc_extra_args>...
           Extra arguments that will be passed to rustc as `cargo rustc [...] -- [arg1] [arg2]`

If I run

pyo3-pack build --rustc-extra-args -Awarnings

I get an error

error: Found argument '-A' which wasn't expected, ...

Is passing flags and options as arguments not supported? Otherwise how am I supposed to pass them?

Specifying python dependencies

Hi! Thanks for the cool project!

Small question: is it possible to specify external python dependencies in a mixed pyo3-pack project layout? If the python part of a mixed project is dependent on some package, let's say external_package==1.0.0, is there any way of specifying this so that the following command:

pip install my_pyo3_package.whl

will automatically pull in the external_package dependency?

I was thinking about something analogous to the scripts definition in Cargo.toml:

[package.metadata.pyo3-pack.requires-dist]
external_package = "==1.0.0"

but could not find it in the docs. Is this possible?

Manylinux2010 does not seem to be correctly supported

I built a wheel for manylinux2010 using pyo3-pack.

After I built it I run auditwheel myself and I was surprised by the result:

fastuuid-0.1.0-cp35-cp35m-manylinux2010_x86_64.whl is consistent with
the following platform tag: "manylinux1_x86_64".

I am building that wheel using the manylinux2010 docker image so I'm supposed to get a manylinux2010 wheel.

Either auditwheel is wrong or we are not doing something we should be doing.
What do you think?

Include files

I'd like to include a file in the built wheel. How about packaging anything in a project's Cargo.toml include array?

pyo3-pack fails if no python3 executable is present

If pyo3-pack develop is called and no interpreter named python3 is present the setup fails:

(venv) PS D:\Entwicklung\Rust\python-extension> pyo3-pack.exe develop
🔗 Found pyo3 bindings
python3 doesn't exist

After creating a copy of python.exe with the name python3.exe the call was successful.

System Information:

  • Windows 10
  • Python 3.7.2 64bit in a virtualenv
  • pyo3-pack 0.6.1

Feature request: Do not build wheels for python versions not supported by package

My computer has more versions of python installed on it than my pyo3-based library supports. maturin build should not build wheels for unsupported python versions. Of course, it's possible to specify exactly which versions to build on every call to maturin build, but that's a relatively static item of metadata which is a good fit for a config file (probably the Cargo.toml, although possibly pyproject.toml).

One option would be to parse the trove classifiers specified in package.metadata.maturin.classifier package.metadata.maturin.requires-python, and build wheels for the intersection of what maturin supports and what is specified there.

Refactor manylinux options

With manylinux 2014 there are now 4 linux flavors (bare linux, manylinux, manylinux200 and manylinux204) and it seems that in the future we will have manylinux releases regularly. To avoid the --manylinux options from becoming overloaded, the --skip-auditwheel should be un-deprecated and the possible values of --manylinux should become off, 1, 2010 and 2014.

platform mismatch for cross compilation

When compiling a cffi crate for a different target through a Cargo environment which has been setup for cross-compilation, maturin fails on a platform check.
I'm trying to build a windows cffi package from a linux build system, but maturin tries to get the windows python.exe, which can easily be overruled by the -i flag. But when passed a linux python version, maturin crashes with this output:

$ maturin build -b cffi --target x86_64-pc-windows-gnu -i python3.7

🍹 Building a mixed python/rust project
💥 maturin failed
  Caused by: Failed to find python interpreter for generating cffi bindings
  Caused by: Failed to get information from the python interpreter at python3.7
  Caused by: sys.platform in python, linux, and the rust target, Target { os: Windows, is_64_bit: true }, don't match ಠ_ಠ

I can manually replace the native.so file within the built wheel by a built windows dll file and it works fine on windows. So I'm guessing this is just a limitation within maturin currently.
This check doesn't seem necessary for me, but could probably be wrong for other use-cases. Does it seem feasible to change this behavior?

Build crate where pyo3 is enabled by a feature

I'm trying to add python bindings to an already-existing crate where I want python to be enabled with a feature that is not enabled by default. I created a minimal example of what I wanted to do:
https://github.com/programmerjake/rust-python-test/tree/7b7ac59c66df8c5b8939361f94f2bc92c53b3c4b

Building using cargo works just fine with:

$ cargo +nightly build --features python-extension

I tried to build it using maturin 0.7.2 running in the repo root directory but it didn't work:

$ maturin build
💥 maturin failed
  Caused by: Couldn't find any bindings; Please specify them with --bindings/-b

I also tried:

$ maturin build --bindings=pyo3
💥 maturin failed
  Caused by: The bindings crate pyo3 was not found in the dependencies list
$ maturin build --bindings=pyo3 --cargo-extra-args="--features python-extension"
💥 maturin failed
  Caused by: The bindings crate pyo3 was not found in the dependencies list
$ maturin build --cargo-extra-args="--features python-extension"
💥 maturin failed
  Caused by: Couldn't find any bindings; Please specify them with --bindings/-b

How do I fix it?

Support non-manylinux Linux builds

Linux builds should be able to target their specific installation rather than the manylinux1 target. Maybe a flag of --env-specific or something better named, which implies --skip-auditwheel, and generates the ...-cp37-cp37m-linux_x86_64.whl tag?

Does not handle conda environments on windows

Many windows users use conda environments to manage their python versions. pyo3-pack does not seem to handle them well.

pyo3-pack develop mentions that I should be in a venv, but I am in a virtual environment. It's just that I am using conda not venv.

pyo3-pack relies on the python launcher, which is not installed with conda (there is a standalone installer but it does not seem to play nice with conda). The information regarding available interpreters can be gotten from conda info -e

Add option to pass python version number

When building through a CI pipeline, it's not possible to pass a version number that has an incremental build number to maturin build.
For my use case, the rust package has version "0.3.0", but the actual python package/wheel should receive "0.3.0.dev50". Simply renaming the file is not enough as the embedded metadata contains the version in some places (including directory name).
Passing the version would need to be dynamic - through environment variable or argument, not in a file like Cargo.toml - because this version is generated by the build pipeline.

Also note that cargo version semantics are different to python, and treats "0.3.0.dev50" as junk.

Windows and Mac testing

pyo3-pack is meant as a replacement for setuptools-rust and is as such feature complete. As I'm working primarily on linux, I did only very limited tests on windows and don't have any mac to test on. It'd appreciate help testing those platforms.

To install pyo3-pack, you can use a prebuilt binary or cargo install pyo3-pack. For testing you can take any pyo3-powered python extension (e.g. hyperjson, pyo3's example or rust-numpy's example), build it, install it with pip and check if you can import it. I'd also be interested in feedback on the user experience (e.g. incomprehensible error message that showed up).

CC @althonos @mre @fafhrd91

Publish 0.6.1 on crates.io

It would be nice if you could publish 0.6.1 on crates.io, right now cargo install pyo3-pack fails because of the yanked structopt version.

Thanks in advance!

Mixed projects PYTHONPATH issue

maturin builds a mixed Rust/Python project if {name}/__init__.py exists, so the PYTHONPATH for the project's name is this directory rather than the installed project. This causes ImportError in tests etc. during development. This affects all mixed projects, so perhaps the detection can instead use _{name}/__init__.py or py{name}/__init__.py? I see that the directory could also be an option in Cargo.toml but I think it would be better to fix by default.

Use [package] name instead of [lib] name

First of all: awesome project !

Now, here's the mostly subjective part: like crates.io, pypi does not have a strong policy on module naming, but the strong consensus is to use kebab case instead of underscore case. There are 3x more packages with kebab case than with underscore case.

Using the name in [lib] will enforce underscore case, since they must be a valid crate identifier, whereas using the name in [package] allows the package developer to choose whatever case he wants.

Improvements for build.rs usage

I have a project that has a custom build.rs script. Ideally, pyo3-pack would be able to pass the information about the interpreter being used to compile the rust crate to the script, so that any additional library needing to include/link to CPython can re-use this information and I don't need to re-compute it.

Perhaps it can be passed as environment variables when invoking cargo?

Unable to pip install mixed layout project

There seems to be a problem with pip installing a mixed layout project where it doesn't place the compiled rust code into the project folder.

I made the following changes to pyo3-pack:

  • in "pyo3-pack/test-crates/pyo3-mixed/pyproject.toml" I changed requires = ["pyo3-pack"] to requires = ["pyo3-pack==0.7.0-beta.7"]
  • in "pyo3-pack/test-crates/pyo3-mixed/rust-toolchain" I changed nightly to nightly-2019-07-01 since I couldn't get mashup to compile on the most recent nightly.

Using this setup I cd'd into the pyo3-mixed test crate and ran pip install .
This runs without an error, however when I open python and try to import pyo3_mixed I get the following error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/pattonw/Work/Packages/pyo3-pack/test-crates/pyo3-mixed/pyo3_mixed/__init__.py", line 2, in <module>
    from .pyo3_mixed import get_21
ModuleNotFoundError: No module named 'pyo3_mixed.pyo3_mixed'

This seems like it can't find the python functions created by rust in they python code directory, so I ran pyo3-pack develop which created the file "pyo3-pack/test-crates/pyo3-imxed/pyo3_mixed/pyo3_mixed.cpython-37m-x86_64-linux-gnu.so"

With this file created, pip install ., import pyo3_mixed, and pyo3_mixed.get_42() all work as expected.

Bug: Cannot install maturin from PyPI

pip install maturin gets

ERROR: Could not find a version that satisfies the requirement maturin (from versions: )
No matching distribution found for maturin

using pip 19.2.3, python 3.7.3. Same result if I look specifically for version 0.7.0, but with from versions: none. If I try to pip install . my package, pip tries to install maturin based on build-system.requires, and hits the same error, but with from versions: 0.7.1b1.

I can cargo install it fine, but then pip can't pick it up from the pyproject.toml.

Readme.md

So I've successfully written and published my first python-rust module with pyo3 and pyo3-pack, and it's been a pretty painless process (and I thank you for that!).
Als, pypi does not show my Readme.md (or an README.md for that matter).

Is this not supported (yet) or am I doing something wrong?

I published with pyo3-pack publish,
this is the github: https://github.com/TyberiusPrime/mbf_gtf
and the pypi packages can be seen here https://pypi.org/project/mbf_gtf/

PEP440 following CI Versions

Maybe I missed this somewhere, but as far as I can tell pyo3-pack has no support for it:

I'm trying to set up a CI pipeline, both for our in-works stuff with snapshot builds, as well as our release pipeline. Unfortunately, I can't seem to make both pip and Cargo happy at the same time.

To start with, let's stick with a definition of a CI generated build ID. It'll be in the format of {YYYY}{MM}{DD}{MonotonicallyIncreasingDailyBuildNumber}, with the build number being left padded to 3 places, e.g. "20190422003", where today's date is 2019-04-22 and we're on the 3rd build of the day. I'll call this {BuildID} in my examples down below.

From what I can tell, Cargo is adamantly opposed to a {Major}.{Minor}.{Patch}.dev{BuildId}, which is a fair enough pre-release format that complies with PEP440 and pip's --pre flag. Example: 2.1.3.dev20190422003

Unfortunately, the Cargo way of doing CI builds is very strictly in the form of {Major}.{Minor}.{Patch}-{SomeAllowableString}{BuildId} , e.g. 2.1.3-dev20190422003. The hyphen is most important, and it's something Cargo does not seem capable of budging on. And since our version is the came as our version in our Cargo.toml, our wheel gets generated as my_artifact_2.1.3-dev20190422003-cp36-cp36m-manylinux1_x86_64.whl. I can publish this to a snapshot repo, but my_artifact_2.1.3-dev... is not going to work with pip's --pre flag; it just ignores it.

If we were in a mono repo this wouldn't even be close to a problem, but we aren't, so it is. It would be great if we could specify some version metadata that would get appended to the version prior to constructing our wheels. I superficially thought I could just rename the wheel and maybe update some metadata in a pinch, but with the sha256 checksums it looked like it wasn't going to be that straight forward.

Is there any way that you can think of to make pip --pre happy AND Cargo? If not, can we add a flag that simply appends a "fixed" string to the version that pyo3-pack is going to generate with (fixed in that it wouldn't need to be anything special to pyo3-pack - just a string append operation, but something I can construct in our build pipeline and pass in)?

Source distribution of pyo3-pack

Would it be possible to provide a source distribution of pyo3-pack? Pipenv cannot install it on NixOS which is not manylinux-compatible.

Custom package namespace

Note I am not talking about the distribution name (packages are names you import, distributions those you pip install).

Distutils based tools support an argument ext_package which makes extension modules installed in a prefix package. Perhaps this could be supported in some way? I don't like polluting the global namespace.

Installation of beta release

Ubuntu 16.04, python 3.7.3, rustc 1.37.0-nightly (02564de47 2019-06-10), cargo 1.37.0-nightly (545f35425 2019-05-23)

  • Installing from source (download github release tarball -> pip install .) says it can't find the build backend (it does seem to rely on itself in the pyproject.toml [1])
  • Trying to pip install from github does the same
  • Installing from the deb places a file called pyo3-pack in /usr/bin/. The file exists, is executable, and is picked up by which. Trying to use it gives "command not found" in zsh and "No such file or directory" in bash
  • Downloading the binary gz and placing it somewhere on the path: same as above

[1] trying to bootstrap with an earlier release doesn't help

Installation of scripts

I have tried out the Python/Rust example in the pyo3_mixed folder and I noticed that maturin develop does not install the script declared in Cargo.toml. Is this the intended behavior?

pyo3-pack does not compile, because structopt 0.2.17 was yanked

error: failed to compile `pyo3-pack v0.6.0`, intermediate artifacts can be found at `/tmp/cargo-installibhtoX`
Caused by:
  failed to select a version for the requirement `structopt = "^0.2.17"`
  candidate versions found which didn't match: 0.2.16, 0.2.15, 0.2.14, ...
  location searched: crates.io index
required by package `pyo3-pack v0.6.0`

See: TeXitoi/structopt#200

Detect cffi and bin targets automatically

Currently, only rust-cpython and pyo3 are automatically detected. For cffi and bin, you need to use the -b flag. In many it should be possible to decide that automatically based on whether the crate has a cdylib or bin target.

Relevant excerpts from cargo metadata for a cffi and a bin crate:

         "targets" : [
            {
               "src_path" : "/home/konsti/bin-test/src/main.rs",
               "edition" : "2018",
               "kind" : [
                  "bin"
               ],
               "crate_types" : [
                  "bin"
               ],
               "name" : "a"
            }
         ]
         "targets" : [
            {
               "crate_types" : [
                  "cdylib"
               ],
               "edition" : "2018",
               "src_path" : "/home/konsti/lib-test/src/lib.rs",
               "name" : "lib-test",
               "kind" : [
                  "cdylib"
               ]
            }
         ],

Trove classifiers

Thoughts on adding support for trove classifiers for pypi?

Possibly something like:

[package.metadata.pyo3-pack.metadata]
classifier = [
    "Programming Language :: Python",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.7",
]

This is somewhat consistent with the [package.metadata.pyo3-pack.scripts] mentioned in the README.

Precompiled 0.6.1 binary not working on Ubuntu 18.04

wget https://github.com/PyO3/maturin/releases/download/v0.6.1/pyo3-pack-v0.6.1-x86_64-unknown-linux-musl.tar.gz
tar -xzf pyo3-pack-v0.6.1-x86_64-unknown-linux-musl.tar.gz
./pyo3-pack

fails with

zsh: no such file or directory: ./pyo3-pack
wget https://github.com/PyO3/maturin/releases/download/v0.7.2/maturin-v0.7.2-x86_64-unknown-linux-musl.tar.gz
tar -xzf maturin-v0.7.2-x86_64-unknown-linux-musl.tar.gz
./maturin

prints usage as expected:

maturin 0.7.2
Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages

USAGE:
    maturin <SUBCOMMAND>

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    build          Build the crate into python packages
    develop        Installs the crate as module in the current virtualenv
    help           Prints this message or the help of the given subcommand(s)
    list-python    Searches and lists the available python installations
    pep517         Backend for the PEP 517 integration. Not for human consumption
    publish        Build and publish the crate as python packages to pypi
    sdist          Build only a source distribution (sdist) without compiling

Fwiw, downloading and installing the .deb file through dpkg leads to the same behaviour.

broken wheels (macOS)

Currently wheels produced with pyo3-pack are not working in macOS (maybe on other platforms as well?).

I initially though this is related to PyO3/pyo3#341, but I've tried reverting to pyo3 0.5.4 and the issue persisted.

I'm using the extension-module feature.

I'm getting the following error:

Python 3.7.3 | packaged by conda-forge | (default, Mar 27 2019, 15:43:19)
[Clang 4.0.1 (tags/RELEASE_401/final)] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import evtx
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: dynamic module does not define module export function (PyInit_evtx)
>>>

And for wheels setuptools-rust with python setup.py bdist_wheel it's working as expected.

Python 3.7.3 | packaged by conda-forge | (default, Mar 27 2019, 15:43:19)
[Clang 4.0.1 (tags/RELEASE_401/final)] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import evtx
>>>

All the code is public at https://github.com/omerbenamram/pyevtx-rs

Any thoughts?

Renaming the project

"pyo3-pack" has become a misleading name for this project, as it can now equally package rust-cpython and cffi projects. Prior to the 0.7 release, I want to rename the project into something that better represents the current features, or at least to a neutral name.

How to generate windows wheels?

Hello, first of all let me tell you this project is really nice, 1 command will produce wheels... Before this I'd tried setuptools-rust and the process was quite tricky :/

Anyway, got a couple of questions, right now I've been able to generate wheels for linux by using the undocummented --release suffix using a command like:

`docker run -it -v `pwd`:/io konstin2/pyo3-pack build`

And the above command has generated me 4 wheels:

pysyntect-0.0.1-cp27-cp27mu-manylinux1_x86_64.whl
pysyntect-0.0.1-cp35-cp35m-manylinux1_x86_64.whl
pysyntect-0.0.1-cp36-cp36m-manylinux1_x86_64.whl
pysyntect-0.0.1-cp37-cp37m-manylinux1_x86_64.whl

1st issue

So far so good... Now I was trying to figure out how to do the same on windows7 but some errors have appeared... take a look:

(py364_32) D:\sources\personal\python\pysyntect>pyo3-pack list-python
Could not find any interpreters, are you sure you have python installed on your PATH?

(py364_32) D:\sources\personal\python\pysyntect>pyo3-pack build
🔗 Found pyo3 bindings
Could not find any interpreters, are you sure you have python installed on your PATH?

As you can see, I'm calling pyo3-pack build from my activated virtualenv (python is on PATH!!!).

2nd issue

I would be interested to generate wheels for windows/linux && cp36-cp36m... that's all, the rest of platforms (cp27,cp35,cp37) are pretty much irrelevant to me, isn't possible to specify that somehow to pyo3-pack?

Thanks in advance!

Ps. Isn't there any irc channel on freenode/moznet to discuss stuff about pyo3, setuptools-rust, pyo3-pack? I see there is gitter... but I prefer using IRC ;)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.