Skip to content

Commit

Permalink
Experimental support for PyPy 3.6
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhewitt committed Aug 8, 2020
1 parent 9823019 commit d661cc2
Show file tree
Hide file tree
Showing 18 changed files with 216 additions and 179 deletions.
42 changes: 35 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,63 @@ jobs:
strategy:
max-parallel: 12
matrix:
python-version: [3.5, 3.6, 3.7, 3.8]
python-version: [3.5, 3.6, 3.7, 3.8, pypy3]
platform: [
{ os: "macOS-latest", python-architecture: "x64", rust-target: "x86_64-apple-darwin" },
{ os: "windows-latest", python-architecture: "x64", rust-target: "x86_64-pc-windows-msvc" },
{ os: "windows-latest", python-architecture: "x86", rust-target: "i686-pc-windows-msvc" },
]
exclude:
# There is no 64-bit pypy on windows
- python-version: pypy3
platform: { os: "windows-latest", python-architecture: "x64" }


steps:
- uses: actions/checkout@v2

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install Rust
architecture: ${{ matrix.platform.python-architecture }}

- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
default: true
target: ${{ matrix.platform.rust-target }}

- run: rustup set default-host ${{ matrix.platform.rust-target }}

- name: Build without default features
run: cargo build --no-default-features --verbose

- name: Build with default features
run: cargo build --verbose
- name: Install test dependencies
run: cargo build --features "num-bigint num-complex" --verbose

# Run tests (except on PyPy, because no embedding API).
- if: matrix.python-version != 'pypy3'
name: Test
run: cargo test --features "num-bigint num-complex"

- name: Test proc-macro code
shell: bash
run: cd pyo3-derive-backend && cargo test

- name: Install python test dependencies
run: |
python -m pip install -U pip setuptools
pip install setuptools-rust pytest pytest-benchmark tox tox-venv
- name: Test
run: ci/actions/test.sh
- name: Test example extension modules
shell: bash
run: |
for example_dir in examples/*; do
cd $example_dir
tox -c "tox.ini" -e py
cd -
done
env:
RUST_BACKTRACE: 1
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Don't rely on the order of structmembers to compute offsets in PyCell. Related to
[#1058](https://github.com/PyO3/pyo3/pull/1058). [#1059](https://github.com/PyO3/pyo3/pull/1059)
- Allows `&Self` as a `#[pymethods]` argument again. [#1071](https://github.com/PyO3/pyo3/pull/1071)
- Fix best-effort build against PyPy 3.6. #[1092](https://github.com/PyO3/pyo3/pull/1092)

## [0.11.1] - 2020-06-30
### Added
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ A comparison with rust-cpython can be found [in the guide](https://pyo3.rs/maste

PyO3 supports Python 3.5 and up. The minimum required Rust version is 1.39.0.

PyPy is also supported (via cpyext) for Python 3.5 only, targeted PyPy version is 7.0.0.
Building with PyPy is also possible (via cpyext) for Python 3.6, targeted PyPy version is 7.3+.
Please refer to the [pypy section in the guide](https://pyo3.rs/master/pypy.html).

You can either write a native Python module in Rust, or use Python from a Rust binary.
Expand Down
12 changes: 6 additions & 6 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,12 +306,7 @@ fn get_library_link_name(version: &PythonVersion, ld_version: &str) -> String {
Some(minor) => format!("{}", minor),
None => String::new(),
};
match version.implementation {
PythonInterpreterKind::CPython => {
format!("python{}{}", version.major, minor_or_empty_string)
}
PythonInterpreterKind::PyPy => format!("pypy{}-c", version.major),
}
format!("python{}{}", version.major, minor_or_empty_string)
} else {
match version.implementation {
PythonInterpreterKind::CPython => format!("python{}", ld_version),
Expand All @@ -338,6 +333,11 @@ fn get_rustc_link_lib(config: &InterpreterConfig) -> Result<String> {

#[cfg(target_os = "macos")]
fn get_macos_linkmodel(config: &InterpreterConfig) -> Result<String> {
// PyPy 3.6 ships with a shared library, but doesn't have Py_ENABLE_SHARED.
if config.version.implementation == PythonInterpreterKind::PyPy {
return Ok("shared".to_string());
}

let script = r#"
import sysconfig
Expand Down
12 changes: 0 additions & 12 deletions ci/actions/test.sh

This file was deleted.

4 changes: 3 additions & 1 deletion src/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,9 +443,11 @@ impl_native_exception!(
);
impl_native_exception!(PyTimeoutError, TimeoutError, PyExc_TimeoutError);

#[cfg(not(all(windows, PyPy)))]
impl_native_exception!(PyEnvironmentError, EnvironmentError, PyExc_EnvironmentError);
#[cfg(not(all(windows, PyPy)))]
impl_native_exception!(PyIOError, IOError, PyExc_IOError);
#[cfg(target_os = "windows")]
#[cfg(all(windows, not(PyPy)))]
impl_native_exception!(PyWindowsError, WindowsError, PyExc_WindowsError);

impl PyUnicodeDecodeError {
Expand Down
1 change: 1 addition & 0 deletions src/ffi/dictobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::os::raw::{c_char, c_int};

#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
#[cfg_attr(PyPy, link_name = "PyPyDict_Type")]
pub static mut PyDict_Type: PyTypeObject;
pub static mut PyDictIterKey_Type: PyTypeObject;
pub static mut PyDictIterValue_Type: PyTypeObject;
Expand Down
2 changes: 2 additions & 0 deletions src/ffi/longobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ extern "C" {
#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
#[cfg(not(PyPy))]
pub fn _PyLong_NumBits(obj: *mut PyObject) -> c_int;

#[cfg_attr(PyPy, link_name = "_PyPyLong_FromByteArray")]
Expand All @@ -93,6 +94,7 @@ extern "C" {
is_signed: c_int,
) -> *mut PyObject;

#[cfg(not(PyPy))]
pub fn _PyLong_AsByteArray(
v: *mut PyLongObject,
bytes: *mut c_uchar,
Expand Down
4 changes: 2 additions & 2 deletions src/ffi/marshal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use std::os::raw::{c_char, c_int};

#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
#[cfg_attr(PyPy, link_name = "PyMarshal_WriteObjectToString")]
#[cfg_attr(PyPy, link_name = "PyPyMarshal_WriteObjectToString")]
pub fn PyMarshal_WriteObjectToString(object: *mut PyObject, version: c_int) -> *mut PyObject;

#[cfg_attr(PyPy, link_name = "PyMarshal_ReadObjectFromString")]
#[cfg_attr(PyPy, link_name = "PyPyMarshal_ReadObjectFromString")]
pub fn PyMarshal_ReadObjectFromString(data: *const c_char, len: isize) -> *mut PyObject;
}
2 changes: 2 additions & 0 deletions src/ffi/moduleobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ extern "C" {
#[cfg_attr(PyPy, link_name = "PyPyModule_GetDict")]
pub fn PyModule_GetDict(arg1: *mut PyObject) -> *mut PyObject;
pub fn PyModule_GetNameObject(arg1: *mut PyObject) -> *mut PyObject;
#[cfg_attr(PyPy, link_name = "PyPyModule_GetName")]
pub fn PyModule_GetName(arg1: *mut PyObject) -> *const c_char;
#[cfg(not(all(windows, PyPy)))]
pub fn PyModule_GetFilename(arg1: *mut PyObject) -> *const c_char;
pub fn PyModule_GetFilenameObject(arg1: *mut PyObject) -> *mut PyObject;
#[cfg_attr(PyPy, link_name = "PyPyModule_GetDef")]
Expand Down
5 changes: 4 additions & 1 deletion src/ffi/pyerrors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ extern "C" {
#[cfg_attr(PyPy, link_name = "PyPyExc_ImportError")]
pub static mut PyExc_ImportError: *mut PyObject;
#[cfg(Py_3_6)]
#[cfg_attr(PyPy, link_name = "PyPyExc_ModuleNotFoundError")]
pub static mut PyExc_ModuleNotFoundError: *mut PyObject;
#[cfg_attr(PyPy, link_name = "PyPyExc_IndexError")]
pub static mut PyExc_IndexError: *mut PyObject;
Expand Down Expand Up @@ -282,9 +283,11 @@ extern "C" {
#[cfg_attr(PyPy, link_name = "PyPyExc_TimeoutError")]
pub static mut PyExc_TimeoutError: *mut PyObject;

#[cfg(not(all(windows, PyPy)))]
pub static mut PyExc_EnvironmentError: *mut PyObject;
#[cfg(not(all(windows, PyPy)))]
pub static mut PyExc_IOError: *mut PyObject;
#[cfg(windows)]
#[cfg(all(windows, not(PyPy)))]
pub static mut PyExc_WindowsError: *mut PyObject;

pub static mut PyExc_RecursionErrorInst: *mut PyObject;
Expand Down
2 changes: 1 addition & 1 deletion src/ffi/setobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ extern "C" {
pub fn PySet_Pop(set: *mut PyObject) -> *mut PyObject;

#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(PyPy, link_name = "_PySet_NextEntry")]
#[cfg_attr(PyPy, link_name = "_PyPySet_NextEntry")]
pub fn _PySet_NextEntry(
set: *mut PyObject,
pos: *mut Py_ssize_t,
Expand Down
1 change: 1 addition & 0 deletions src/ffi/warnings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::os::raw::{c_char, c_int};

#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
#[cfg_attr(PyPy, link_name = "PyPyErr_WarnEx")]
pub fn PyErr_WarnEx(
category: *mut PyObject,
message: *const c_char,
Expand Down
44 changes: 18 additions & 26 deletions src/types/complex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,15 @@ impl PyComplex {
unsafe { ffi::PyComplex_ImagAsDouble(self.as_ptr()) }
}
/// Returns `|self|`.
#[cfg(not(Py_LIMITED_API))]
#[cfg(not(PyPy))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
pub fn abs(&self) -> c_double {
unsafe {
let val = (*(self.as_ptr() as *mut ffi::PyComplexObject)).cval;
ffi::_Py_c_abs(val)
}
}
/// Returns `self ** other`
#[cfg(not(Py_LIMITED_API))]
#[cfg(not(PyPy))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
pub fn pow(&self, other: &PyComplex) -> &PyComplex {
unsafe {
self.py()
Expand All @@ -52,8 +50,7 @@ impl PyComplex {
}
}

#[cfg(not(Py_LIMITED_API))]
#[cfg(not(PyPy))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
#[inline(always)]
unsafe fn complex_operation(
l: &PyComplex,
Expand All @@ -65,8 +62,7 @@ unsafe fn complex_operation(
ffi::PyComplex_FromCComplex(operation(l_val, r_val))
}

#[cfg(not(Py_LIMITED_API))]
#[cfg(not(PyPy))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
impl<'py> Add for &'py PyComplex {
type Output = &'py PyComplex;
fn add(self, other: &'py PyComplex) -> &'py PyComplex {
Expand All @@ -77,8 +73,7 @@ impl<'py> Add for &'py PyComplex {
}
}

#[cfg(not(Py_LIMITED_API))]
#[cfg(not(PyPy))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
impl<'py> Sub for &'py PyComplex {
type Output = &'py PyComplex;
fn sub(self, other: &'py PyComplex) -> &'py PyComplex {
Expand All @@ -89,8 +84,7 @@ impl<'py> Sub for &'py PyComplex {
}
}

#[cfg(not(Py_LIMITED_API))]
#[cfg(not(PyPy))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
impl<'py> Mul for &'py PyComplex {
type Output = &'py PyComplex;
fn mul(self, other: &'py PyComplex) -> &'py PyComplex {
Expand All @@ -101,8 +95,7 @@ impl<'py> Mul for &'py PyComplex {
}
}

#[cfg(not(Py_LIMITED_API))]
#[cfg(not(PyPy))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
impl<'py> Div for &'py PyComplex {
type Output = &'py PyComplex;
fn div(self, other: &'py PyComplex) -> &'py PyComplex {
Expand All @@ -113,8 +106,7 @@ impl<'py> Div for &'py PyComplex {
}
}

#[cfg(not(Py_LIMITED_API))]
#[cfg(not(PyPy))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
impl<'py> Neg for &'py PyComplex {
type Output = &'py PyComplex;
fn neg(self) -> &'py PyComplex {
Expand All @@ -129,7 +121,7 @@ impl<'py> Neg for &'py PyComplex {
#[cfg(feature = "num-complex")]
mod complex_conversion {
use super::*;
use crate::{FromPyObject, PyAny, PyErr, PyObject, PyResult, ToPyObject};
use crate::{FromPyObject, PyErr, PyNativeType, PyObject, PyResult, ToPyObject};
use num_complex::Complex;

impl PyComplex {
Expand Down Expand Up @@ -161,7 +153,7 @@ mod complex_conversion {
}
}
}
#[cfg(not(Py_LIMITED_API))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
#[allow(clippy::float_cmp)] // The comparison is for an error value
impl<'source> FromPyObject<'source> for Complex<$float> {
fn extract(obj: &'source PyAny) -> PyResult<Complex<$float>> {
Expand All @@ -175,7 +167,7 @@ mod complex_conversion {
}
}
}
#[cfg(Py_LIMITED_API)]
#[cfg(any(Py_LIMITED_API, PyPy))]
#[allow(clippy::float_cmp)] // The comparison is for an error value
impl<'source> FromPyObject<'source> for Complex<$float> {
fn extract(obj: &'source PyAny) -> PyResult<Complex<$float>> {
Expand Down Expand Up @@ -239,7 +231,7 @@ mod test {
assert_approx_eq!(complex.imag(), 1.2);
}

#[cfg(not(Py_LIMITED_API))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
#[test]
fn test_add() {
let gil = Python::acquire_gil();
Expand All @@ -251,7 +243,7 @@ mod test {
assert_approx_eq!(res.imag(), 3.8);
}

#[cfg(not(Py_LIMITED_API))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
#[test]
fn test_sub() {
let gil = Python::acquire_gil();
Expand All @@ -263,7 +255,7 @@ mod test {
assert_approx_eq!(res.imag(), -1.4);
}

#[cfg(not(Py_LIMITED_API))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
#[test]
fn test_mul() {
let gil = Python::acquire_gil();
Expand All @@ -275,7 +267,7 @@ mod test {
assert_approx_eq!(res.imag(), 9.0);
}

#[cfg(not(Py_LIMITED_API))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
#[test]
fn test_div() {
let gil = Python::acquire_gil();
Expand All @@ -287,7 +279,7 @@ mod test {
assert_approx_eq!(res.imag(), -0.850_515_463_917_525_7);
}

#[cfg(not(Py_LIMITED_API))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
#[test]
fn test_neg() {
let gil = Python::acquire_gil();
Expand All @@ -298,7 +290,7 @@ mod test {
assert_approx_eq!(res.imag(), -1.2);
}

#[cfg(not(Py_LIMITED_API))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
#[test]
fn test_abs() {
let gil = Python::acquire_gil();
Expand All @@ -307,7 +299,7 @@ mod test {
assert_approx_eq!(val.abs(), 3.231_098_884_280_702_2);
}

#[cfg(not(Py_LIMITED_API))]
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
#[test]
fn test_pow() {
let gil = Python::acquire_gil();
Expand Down
Loading

0 comments on commit d661cc2

Please sign in to comment.