Rust bindings for the Python interpreter
Find a file
Omer BenAmram f8bf258602 Support rust extensions for PyPy via cpyext (#393)
* wip

* removed stuff

* removed another change

* implemented minimum amouth of ifdefs to make pypy3 hello world to compile

* implemented minimum amount of ifdefs to make pypy3 hello world to compile

* hacking on build.rs

* compiler is happy!

* few todos remain

* extracted build logic to seperate module

* added pypy test

* finally fixed pypy structs

* removed some todos

* test should now be machine independent

* fixed all pypy3 symbols

* added pypy feature

* removed `is_pypy`

* added pypy2 declerations also

* fix for cpython2

* improved libpypy detection

* added all pypy2 macros

* fixed errneous type

* more fixes

* fix python2 string macros

* modsupport symbol

* fix

* fixed and added many symbols

* fixes

* remove dup

* remove mac-specific config

* fix all name mangling macros

* unite imports

* missing symbol

* fix pybool

* implemented another missing symbol

* it works

* fix merge conflict

* uncomment non default features

* cargo.toml

* Cargo fmt

* small merge fixes

* use newer build version

* whoops

* fix build script

* more build hacks

* some random hiccups

* small fixes

* it builds!

* it builds and runs

* revert everything in FFI2

* revert changes to ffi2

* check python3 for pypy

* tiny fix

* revert ffi2 for real

* revert weird formatting changes

* bring back missing feature

* tiny error

* fix py3.7 issue

* add pypy3.5 6.0 to travis

* remove dbg!

* another tiny fix

* removed some useless annotations, and fixed inlines annotations

* removed `pretty_assertions`

* removed pypy feature from cargo.toml

* fix for Py_CompileStringFlags

* tox runs word_count!

* __dict__ changes are not supported for PyPy

* fix 3.7 and copy comment

* fix test script 😳

* transfer ownership of strings to cpython when possible

* remove cstr! macro

* added missing nuls

* as_bytes() -> b’’ string

* symbol removed by mistake

* properly shim pypy date time API, some tests are passing!

* extension_module tests now not crashing! (some still skipped)

* maybe travis has new pypy version?

* small error on windows (build script)

* fix conditional compilation

* try to make tests run on travis..

* invert condition

* added pytest-faulthandler to facilitate debugging

* correctly name dir

* use full paths

* say —yes to conda

* fix

* syntax error

* change PATH

* fixed a terrible bug with PyTypeObjects in PyPy

* fix PyTypeObject defs

* re-enabled tests!

* all tests are passing!

* make the fix ad-hoc for now

* removed build module

* revert changes that cause an additional GC bug

* prevented buggy test from failing pypy

* removed unused comment

* don’t run coverage on pypy

* removed some erroneous symbols from function calls which are actually macros

* restore py37 pyunicode missing def

* use only `link_name` in PyPy specific declarations

* only setup PyPy when testing against PyPy

* annotation that was eaten during merge

* remove change to  comment by mistake + unnecessary changes to cargo.toml

* xfail dates test only on pypy

* changed comment to be a little more helpful

* cleaned up some warnings

* Update src/ffi3/ceval.rs

Co-Authored-By: omerbenamram <omerbenamram@gmail.com>

* @konstin PR notes

* rustfmt

* some documentation

* if configured via env var only, default to cpython

* remove extra unsafe

* refer users to guide for pypy

* Update guide/src/pypy.md

Co-Authored-By: omerbenamram <omerbenamram@gmail.com>

* Update guide/src/pypy.md

Co-Authored-By: omerbenamram <omerbenamram@gmail.com>

* @konstin applied patch

* check that pypy at least build

* search explicitly for libpypy

* added note about some known unsupported features

* use ld_version

* export PYTHON_SYS_EXECUTABLE to `cargo build` test

* inverted if

* always link pypy dynamically

* remove unused imports

* Apply @kngwyu’s suggestion

* fix tox configuration

* try conda virtualenv

* try to simply not install python at all inside pypy environment

* setup pypy before using “python"

* use system_site_packages

* revert change to .travis

* moved cpyext datetime documentation to module level, and revised it.

* Update src/ffi/datetime.rs

Co-Authored-By: omerbenamram <omerbenamram@gmail.com>

* rustfmt

* Update src/ffi/datetime.rs

Co-Authored-By: omerbenamram <omerbenamram@gmail.com>

* kept only notes that are relevant to users.

* invert if

* use bash and not sh
2019-04-23 13:18:42 +02:00
.github
benches
ci/travis
examples Support rust extensions for PyPy via cpyext (#393) 2019-04-23 13:18:42 +02:00
guide
pyo3-derive-backend
pyo3cls
src
tests
.gitignore
.travis.yml
appveyor.yml
build.rs
Cargo.toml
CHANGELOG.md
Code-of-Conduct.md
Contributing.md
LICENSE
Makefile
README.md
tox.ini

PyO3

Build Status Build Status codecov crates.io Join the dev chat

Rust bindings for Python. This includes running and interacting with python code from a rust binaries as well as writing native python modules.

A comparison with rust-cpython can be found in the guide.

Usage

PyO3 supports Python 3.5 and up. The minimum required rust version is 1.34.0-nightly 2019-02-06.

PyPy is also supported (via cpyext) for Python 3.5 only, targeted PyPy version is 7.0.0. Please refer to the guide for installation instruction against PyPy.

You can either write a native Python module in rust or use Python from a Rust binary.

However, on some OSs, you need some additional packages. E.g. if you are on Ubuntu 18.04, please run

sudo apt install python3-dev python-dev

Using Rust from Python

PyO3 can be used to generate a native python module.

Cargo.toml

[package]
name = "string-sum"
version = "0.1.0"
edition = "2018"

[lib]
name = "string_sum"
crate-type = ["cdylib"]

[dependencies.pyo3]
version = "0.6.0"
features = ["extension-module"]

src/lib.rs

// Not required when using Rust 2018
extern crate pyo3;

use pyo3::prelude::*;
use pyo3::wrap_pyfunction;

#[pyfunction]
/// Formats the sum of two numbers as string
fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
    Ok((a + b).to_string())
}

/// This module is a python module implemented in Rust.
#[pymodule]
fn string_sum(py: Python, m: &PyModule) -> PyResult<()> {
    m.add_wrapped(wrap_pyfunction!(sum_as_string))?;

    Ok(())
}

On Windows and Linux, you can build normally with cargo build --release. On MacOS, you need to set additional linker arguments. One option is to compile with cargo rustc --release -- -C link-arg=-undefined -C link-arg=dynamic_lookup, the other is to create a .cargo/config with the following content:

[target.x86_64-apple-darwin]
rustflags = [
  "-C", "link-arg=-undefined",
  "-C", "link-arg=dynamic_lookup",
]

For developing, you can copy and rename the shared library from the target folder: On MacOS, rename libstring_sum.dylib to string_sum.so, on Windows libstring_sum.dll to string_sum.pyd and on Linux libstring_sum.so to string_sum.so. Then open a Python shell in the same folder and you'll be able to import string_sum.

To build, test and publish your crate as Python module, you can use pyo3-pack or setuptools-rust. You can find an example for setuptools-rust in examples/word-count, while pyo3-pack should work on your crate without any configuration.

Using python from rust

Add pyo3 this to your Cargo.toml:

[dependencies]
pyo3 = "0.6.0-alpha.4"

Example program displaying the value of sys.version:

// Not required when using Rust 2018
extern crate pyo3;

use pyo3::prelude::*;
use pyo3::types::IntoPyDict;

fn main() -> PyResult<()> {
    let gil = Python::acquire_gil();
    let py = gil.python();
    let sys = py.import("sys")?;
    let version: String = sys.get("version")?.extract()?;
    let locals = [("os", py.import("os")?)].into_py_dict(py);
    let code = "os.getenv('USER') or os.getenv('USERNAME') or 'Unknown'";
    let user: String = py.eval(code, None, Some(&locals))?.extract()?;
    println!("Hello {}, I'm Python {}", user, version);
    Ok(())
}

Examples and tooling

License

PyO3 is licensed under the Apache-2.0 license. Python is licensed under the Python License.