Merge pull request #2143 from davidhewitt/pypy-3.9-dev
pypy: support 3.9
This commit is contained in:
commit
1e1d6767d8
|
@ -78,7 +78,16 @@ jobs:
|
|||
fail-fast: false # If one platform fails, allow the rest to keep testing.
|
||||
matrix:
|
||||
rust: [stable]
|
||||
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11-dev", "pypy-3.7-v7.3.7", "pypy-3.8"]
|
||||
python-version: [
|
||||
"3.7",
|
||||
"3.8",
|
||||
"3.9",
|
||||
"3.10",
|
||||
"3.11-dev",
|
||||
"pypy-3.7-v7.3.7",
|
||||
"pypy-3.8",
|
||||
"pypy-3.9"
|
||||
]
|
||||
platform:
|
||||
[
|
||||
{
|
||||
|
@ -108,6 +117,8 @@ jobs:
|
|||
platform: { os: "windows-latest", python-architecture: "x86" }
|
||||
- python-version: pypy-3.8
|
||||
platform: { os: "windows-latest", python-architecture: "x86" }
|
||||
- python-version: pypy-3.9
|
||||
platform: { os: "windows-latest", python-architecture: "x86" }
|
||||
include:
|
||||
# Test minimal supported Rust version
|
||||
- rust: 1.48.0
|
||||
|
|
|
@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Update `inventory` optional dependency to 0.2. [#2019](https://github.com/PyO3/pyo3/pull/2019)
|
||||
- Drop `paste` dependency. [#2081](https://github.com/PyO3/pyo3/pull/2081)
|
||||
- The bindings found `pyo3::ffi` are now a re-export of the new `pyo3-ffi` crate. [#2126](https://github.com/PyO3/pyo3/pull/2126)
|
||||
- Support PyPy 3.9. [#2143](https://github.com/PyO3/pyo3/pull/2143)
|
||||
|
||||
|
||||
### Added
|
||||
|
||||
|
@ -89,6 +91,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Use the Rust function path for `wrap_pymodule!` of a `#[pymodule]` with a `#[pyo3(name = "..")]` attribute, not the Python name. [#2081](https://github.com/PyO3/pyo3/pull/2081)
|
||||
- Fix panic in `#[pyfunction]` generated code when a required argument following an `Option` was not provided. [#2093](https://github.com/PyO3/pyo3/pull/2093)
|
||||
- Fixed undefined behaviour caused by incorrect `ExactSizeIterator` implementations. [#2124](https://github.com/PyO3/pyo3/pull/2124)
|
||||
- Fix missing FFI definition `PyCMethod_New` on Python 3.9 and up. [#2143](https://github.com/PyO3/pyo3/pull/2143)
|
||||
- Add missing FFI definitions `_PyLong_NumBits` and `_PyLong_AsByteArray` on PyPy. [#2146](https://github.com/PyO3/pyo3/pull/2146)
|
||||
- Fix memory leak in implementation of `AsPyPointer` for `Option<T>`. [#2160](https://github.com/PyO3/pyo3/pull/2160)
|
||||
- Fix the signature of `_PyLong_NumBits` [#2161](https://github.com/PyO3/pyo3/pull/2161)
|
||||
|
|
|
@ -1131,7 +1131,16 @@ fn default_lib_name_unix(
|
|||
Some(ld_version) => format!("python{}", ld_version),
|
||||
None => format!("python{}.{}", version.major, version.minor),
|
||||
},
|
||||
PythonImplementation::PyPy => format!("pypy{}-c", version.major),
|
||||
PythonImplementation::PyPy => {
|
||||
if version >= (PythonVersion { major: 3, minor: 9 }) {
|
||||
match ld_version {
|
||||
Some(ld_version) => format!("pypy{}-c", ld_version),
|
||||
None => format!("pypy{}.{}-c", version.major, version.minor),
|
||||
}
|
||||
} else {
|
||||
format!("pypy{}-c", version.major)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1237,6 +1246,11 @@ fn fixup_config_for_abi3(
|
|||
config: &mut InterpreterConfig,
|
||||
abi3_version: Option<PythonVersion>,
|
||||
) -> Result<()> {
|
||||
// PyPy doesn't support abi3; don't adjust the version
|
||||
if config.implementation.is_pypy() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(version) = abi3_version {
|
||||
ensure!(
|
||||
version <= config.version,
|
||||
|
@ -1567,11 +1581,17 @@ mod tests {
|
|||
"python3.7md",
|
||||
);
|
||||
|
||||
// PyPy ignores ldversion
|
||||
// PyPy 3.7 ignores ldversion
|
||||
assert_eq!(
|
||||
super::default_lib_name_unix(PythonVersion { major: 3, minor: 9 }, PyPy, Some("3.7md")),
|
||||
super::default_lib_name_unix(PythonVersion { major: 3, minor: 7 }, PyPy, Some("3.7md")),
|
||||
"pypy3-c",
|
||||
);
|
||||
|
||||
// PyPy 3.9 includes ldversion
|
||||
assert_eq!(
|
||||
super::default_lib_name_unix(PythonVersion { major: 3, minor: 9 }, PyPy, Some("3.9d")),
|
||||
"pypy3.9d-c",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
pyport::PY_SSIZE_T_MAX, vectorcallfunc, PyCallable_Check, PyThreadState, PyThreadState_GET,
|
||||
PyTuple_Check, PyType_HasFeature, Py_TPFLAGS_HAVE_VECTORCALL,
|
||||
};
|
||||
#[cfg(all(Py_3_8, not(PyPy)))]
|
||||
#[cfg(Py_3_8)]
|
||||
use libc::size_t;
|
||||
|
||||
extern "C" {
|
||||
|
@ -101,17 +101,29 @@ pub unsafe fn PyObject_Vectorcall(
|
|||
}
|
||||
|
||||
extern "C" {
|
||||
#[cfg(all(Py_3_8, not(PyPy)))]
|
||||
#[cfg_attr(not(Py_3_9), link_name = "_PyObject_VectorcallDict")]
|
||||
#[cfg(all(PyPy, Py_3_8))]
|
||||
#[cfg_attr(not(Py_3_9), link_name = "_PyPyObject_Vectorcall")]
|
||||
pub fn PyObject_Vectorcall(
|
||||
callable: *mut PyObject,
|
||||
args: *const *mut PyObject,
|
||||
nargsf: size_t,
|
||||
kwnames: *mut PyObject,
|
||||
) -> *mut PyObject;
|
||||
|
||||
#[cfg(all(Py_3_8))]
|
||||
#[cfg_attr(all(not(PyPy), not(Py_3_9)), link_name = "_PyObject_VectorcallDict")]
|
||||
#[cfg_attr(all(PyPy, not(Py_3_9)), link_name = "_PyPyObject_VectorcallDict")]
|
||||
#[cfg_attr(all(PyPy, Py_3_9), link_name = "PyPyObject_VectorcallDict")]
|
||||
pub fn PyObject_VectorcallDict(
|
||||
callable: *mut PyObject,
|
||||
args: *const *mut PyObject,
|
||||
nargsf: size_t,
|
||||
kwargs: *mut PyObject,
|
||||
kwdict: *mut PyObject,
|
||||
) -> *mut PyObject;
|
||||
|
||||
#[cfg(all(Py_3_8, not(PyPy)))]
|
||||
#[cfg_attr(not(Py_3_9), link_name = "_PyVectorcall_Call")]
|
||||
#[cfg(all(Py_3_8))]
|
||||
#[cfg_attr(not(any(Py_3_9, PyPy)), link_name = "_PyVectorcall_Call")]
|
||||
#[cfg_attr(PyPy, link_name = "PyPyVectorcall_Call")]
|
||||
pub fn PyVectorcall_Call(
|
||||
callable: *mut PyObject,
|
||||
tuple: *mut PyObject,
|
||||
|
@ -152,6 +164,12 @@ pub unsafe fn _PyObject_CallNoArg(func: *mut PyObject) -> *mut PyObject {
|
|||
)
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#[cfg(PyPy)]
|
||||
#[link_name = "_PyPyObject_CallNoArg"]
|
||||
pub fn _PyObject_CallNoArg(func: *mut PyObject) -> *mut PyObject;
|
||||
}
|
||||
|
||||
#[cfg(all(Py_3_8, not(PyPy)))]
|
||||
#[inline(always)]
|
||||
pub unsafe fn PyObject_CallOneArg(func: *mut PyObject, arg: *mut PyObject) -> *mut PyObject {
|
||||
|
|
|
@ -117,6 +117,7 @@ pub union PyMethodDefPointer {
|
|||
const _: () =
|
||||
[()][mem::size_of::<PyMethodDefPointer>() - mem::size_of::<Option<extern "C" fn()>>()];
|
||||
|
||||
#[cfg(not(Py_3_9))]
|
||||
extern "C" {
|
||||
#[cfg_attr(PyPy, link_name = "PyPyCFunction_New")]
|
||||
pub fn PyCFunction_New(ml: *mut PyMethodDef, slf: *mut PyObject) -> *mut PyObject;
|
||||
|
@ -129,7 +130,32 @@ extern "C" {
|
|||
) -> *mut PyObject;
|
||||
}
|
||||
|
||||
// skipped non-limited / 3.9 PyCMethod_New
|
||||
#[cfg(Py_3_9)]
|
||||
#[inline]
|
||||
pub unsafe fn PyCFunction_New(ml: *mut PyMethodDef, slf: *mut PyObject) -> *mut PyObject {
|
||||
PyCFunction_NewEx(ml, slf, std::ptr::null_mut())
|
||||
}
|
||||
|
||||
#[cfg(Py_3_9)]
|
||||
#[inline]
|
||||
pub unsafe fn PyCFunction_NewEx(
|
||||
ml: *mut PyMethodDef,
|
||||
slf: *mut PyObject,
|
||||
module: *mut PyObject,
|
||||
) -> *mut PyObject {
|
||||
PyCMethod_New(ml, slf, module, std::ptr::null_mut())
|
||||
}
|
||||
|
||||
#[cfg(Py_3_9)]
|
||||
extern "C" {
|
||||
#[cfg_attr(PyPy, link_name = "PyPyCMethod_New")]
|
||||
pub fn PyCMethod_New(
|
||||
ml: *mut PyMethodDef,
|
||||
slf: *mut PyObject,
|
||||
module: *mut PyObject,
|
||||
cls: *mut PyTypeObject,
|
||||
) -> *mut PyObject;
|
||||
}
|
||||
|
||||
/* Flag passed to newmethodobject */
|
||||
pub const METH_VARARGS: c_int = 0x0001;
|
||||
|
|
|
@ -583,7 +583,7 @@ impl<T> Py<T> {
|
|||
/// This is equivalent to the Python expression `self()`.
|
||||
pub fn call0(&self, py: Python) -> PyResult<PyObject> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(Py_3_9)] {
|
||||
if #[cfg(all(Py_3_9, not(PyPy)))] {
|
||||
// Optimized path on python 3.9+
|
||||
unsafe {
|
||||
PyObject::from_owned_ptr_or_err(py, ffi::PyObject_CallNoArgs(self.as_ptr()))
|
||||
|
@ -636,7 +636,7 @@ impl<T> Py<T> {
|
|||
/// This is equivalent to the Python expression `self.name()`.
|
||||
pub fn call_method0(&self, py: Python, name: &str) -> PyResult<PyObject> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(Py_3_9, not(Py_LIMITED_API)))] {
|
||||
if #[cfg(all(Py_3_9, not(any(Py_LIMITED_API, PyPy))))] {
|
||||
// Optimized path on python 3.9+
|
||||
unsafe {
|
||||
let name = name.into_py(py);
|
||||
|
|
|
@ -218,7 +218,7 @@ fn type_object_creation_failed(py: Python, e: PyErr, name: &'static str) -> ! {
|
|||
/// Additional type initializations necessary before Python 3.10
|
||||
#[cfg(all(not(Py_LIMITED_API), not(Py_3_10)))]
|
||||
unsafe fn tp_init_additional(
|
||||
type_object: *mut ffi::PyTypeObject,
|
||||
_type_object: *mut ffi::PyTypeObject,
|
||||
_tp_doc: &str,
|
||||
#[cfg(not(Py_3_9))] buffer_procs: &ffi::PyBufferProcs,
|
||||
#[cfg(not(Py_3_9))] dict_offset: Option<ffi::Py_ssize_t>,
|
||||
|
@ -236,10 +236,10 @@ unsafe fn tp_init_additional(
|
|||
// heap-types, and it removed the text_signature value from it.
|
||||
// We go in after the fact and replace tp_doc with something
|
||||
// that _does_ include the text_signature value!
|
||||
ffi::PyObject_Free((*type_object).tp_doc as _);
|
||||
ffi::PyObject_Free((*_type_object).tp_doc as _);
|
||||
let data = ffi::PyObject_Malloc(_tp_doc.len());
|
||||
data.copy_from(_tp_doc.as_ptr() as _, _tp_doc.len());
|
||||
(*type_object).tp_doc = data as _;
|
||||
(*_type_object).tp_doc = data as _;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,15 +247,15 @@ unsafe fn tp_init_additional(
|
|||
// Python 3.9, so on older versions we must manually fixup the type object.
|
||||
#[cfg(not(Py_3_9))]
|
||||
{
|
||||
(*(*type_object).tp_as_buffer).bf_getbuffer = buffer_procs.bf_getbuffer;
|
||||
(*(*type_object).tp_as_buffer).bf_releasebuffer = buffer_procs.bf_releasebuffer;
|
||||
(*(*_type_object).tp_as_buffer).bf_getbuffer = buffer_procs.bf_getbuffer;
|
||||
(*(*_type_object).tp_as_buffer).bf_releasebuffer = buffer_procs.bf_releasebuffer;
|
||||
|
||||
if let Some(dict_offset) = dict_offset {
|
||||
(*type_object).tp_dictoffset = dict_offset;
|
||||
(*_type_object).tp_dictoffset = dict_offset;
|
||||
}
|
||||
|
||||
if let Some(weaklist_offset) = weaklist_offset {
|
||||
(*type_object).tp_weaklistoffset = weaklist_offset;
|
||||
(*_type_object).tp_weaklistoffset = weaklist_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -333,7 +333,7 @@ impl PyAny {
|
|||
/// This is equivalent to the Python expression `help()`.
|
||||
pub fn call0(&self) -> PyResult<&PyAny> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(Py_3_9)] {
|
||||
if #[cfg(all(Py_3_9, not(PyPy)))] {
|
||||
// Optimized path on python 3.9+
|
||||
unsafe {
|
||||
self.py().from_owned_ptr_or_err(ffi::PyObject_CallNoArgs(self.as_ptr()))
|
||||
|
@ -461,7 +461,7 @@ impl PyAny {
|
|||
/// ```
|
||||
pub fn call_method0(&self, name: &str) -> PyResult<&PyAny> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(Py_3_9, not(Py_LIMITED_API)))] {
|
||||
if #[cfg(all(Py_3_9, not(any(Py_LIMITED_API, PyPy))))] {
|
||||
// Optimized path on python 3.9+
|
||||
unsafe {
|
||||
let name = name.into_py(self.py());
|
||||
|
|
Loading…
Reference in New Issue