From d84d0de604719b7708dc92171e8ac3e05f8821dc Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Sat, 13 Feb 2021 15:35:56 +0800 Subject: [PATCH 1/8] ffi cleanup: methodobject to moduleobject --- CHANGELOG.md | 11 +++++++++++ src/derive_utils.rs | 1 + src/ffi/methodobject.rs | 25 ++++++++++++++++++++++--- src/ffi/mod.rs | 7 ++++--- src/ffi/modsupport.rs | 29 +++++++++++++++++++++++++++-- src/ffi/moduleobject.rs | 10 ++++++++++ src/pyclass.rs | 1 + src/types/module.rs | 7 ++++++- 8 files changed, 82 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99a3e73b..802321b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ PyO3 versions, please see the [migration guide](https://pyo3.rs/master/migration The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## Unreleased +### Added +- Add FFI definition `PyCFunction_CheckExact` for Python 3.9 and later. + +### Changed +- Deprecate FFI definition `PyCFunction_Call` for Python 3.9 and later. +- Deprecate FFI definitions `PyModule_GetFilename`, `PyMethodDef_INIT`. + +### Removed +- Remove FFI definition `PyCFunction_ClearFreeList` for Python 3.9 and later. + ## [0.13.2] - 2021-02-12 ### Packaging - Lower minimum supported Rust version to 1.41. [#1421](https://github.com/PyO3/pyo3/pull/1421) diff --git a/src/derive_utils.rs b/src/derive_utils.rs index cd0f5bde..a6c902fb 100644 --- a/src/derive_utils.rs +++ b/src/derive_utils.rs @@ -136,6 +136,7 @@ impl ModuleDef { /// # Safety /// `name` must be a null-terminated string. pub const unsafe fn new(name: &'static str) -> Self { + #[allow(deprecated)] let mut init = ffi::PyModuleDef_INIT; init.m_name = name.as_ptr() as *const _; ModuleDef(UnsafeCell::new(init)) diff --git a/src/ffi/methodobject.rs b/src/ffi/methodobject.rs index fdf1797e..66eb52e9 100644 --- a/src/ffi/methodobject.rs +++ b/src/ffi/methodobject.rs @@ -8,6 +8,12 @@ extern "C" { pub static mut PyCFunction_Type: PyTypeObject; } +#[cfg(Py_3_9)] +#[inline] +pub unsafe fn PyCFunction_CheckExact(op: *mut PyObject) -> c_int { + (Py_TYPE(op) == &mut PyCFunction_Type) as c_int +} + #[inline] pub unsafe fn PyCFunction_Check(op: *mut PyObject) -> c_int { (Py_TYPE(op) == &mut PyCFunction_Type) as c_int @@ -38,11 +44,14 @@ pub type _PyCFunctionFastWithKeywords = unsafe extern "C" fn( kwnames: *mut PyObject, ) -> *mut PyObject; +// skipped PyCMethod (since 3.9) + extern "C" { #[cfg_attr(PyPy, link_name = "PyPyCFunction_GetFunction")] pub fn PyCFunction_GetFunction(f: *mut PyObject) -> Option; pub fn PyCFunction_GetSelf(f: *mut PyObject) -> *mut PyObject; pub fn PyCFunction_GetFlags(f: *mut PyObject) -> c_int; + #[cfg_attr(Py_3_9, deprecated(note = "Python 3.9"))] pub fn PyCFunction_Call( f: *mut PyObject, args: *mut PyObject, @@ -59,6 +68,10 @@ pub struct PyMethodDef { pub ml_doc: *const c_char, } +/// Helper initial value of [`PyMethodDef`] for a Python class. +/// +/// Not present in the Python C API. +#[deprecated(note = "not present in Python headers; to be removed")] pub const PyMethodDef_INIT: PyMethodDef = PyMethodDef { ml_name: std::ptr::null(), ml_meth: None, @@ -73,17 +86,19 @@ impl Default for PyMethodDef { } extern "C" { + #[cfg_attr(PyPy, link_name = "PyPyCFunction_New")] + pub fn PyCFunction_New(ml: *mut PyMethodDef, slf: *mut PyObject) -> *mut PyObject; + #[cfg_attr(PyPy, link_name = "PyPyCFunction_NewEx")] pub fn PyCFunction_NewEx( ml: *mut PyMethodDef, slf: *mut PyObject, module: *mut PyObject, ) -> *mut PyObject; - - #[cfg_attr(PyPy, link_name = "PyPyCFunction_New")] - pub fn PyCFunction_New(ml: *mut PyMethodDef, slf: *mut PyObject) -> *mut PyObject; } +// skipped non-limited / 3.9 PyCMethod_New + /* Flag passed to newmethodobject */ pub const METH_VARARGS: c_int = 0x0001; pub const METH_KEYWORDS: c_int = 0x0002; @@ -109,6 +124,10 @@ be specified alone or with METH_KEYWORDS. */ #[cfg(all(Py_3_7, not(Py_LIMITED_API)))] pub const METH_FASTCALL: c_int = 0x0080; +// skipped METH_STACKLESS +// skipped METH_METHOD + extern "C" { + #[cfg(not(Py_3_9))] pub fn PyCFunction_ClearFreeList() -> c_int; } diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index 855b1e2a..20962ea2 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -127,6 +127,10 @@ mod listobject; mod longobject; pub(crate) mod marshal; mod memoryobject; +mod methodobject; // TODO: incomplete +mod modsupport; // TODO: incomplete +mod moduleobject; // TODO: incomplete + // skipped namespaceobject.h // skipped odictobject.h // skipped opcode.h @@ -174,8 +178,6 @@ mod unicodeobject; // TODO supports PEP-384 only; needs adjustment for Python 3. mod rangeobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod tupleobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 // mod odictobject; TODO new in 3.5 -mod methodobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 -mod moduleobject; mod setobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 // mod classobject; TODO excluded by PEP-384 mod pycapsule; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 @@ -191,7 +193,6 @@ mod pystate; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and #[cfg(Py_LIMITED_API)] mod pyarena {} -mod modsupport; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 #[cfg(not(Py_LIMITED_API))] mod pyarena; // TODO: incomplete mod pythonrun; // TODO some functions need to be moved to pylifecycle diff --git a/src/ffi/modsupport.rs b/src/ffi/modsupport.rs index d2c886f0..62826c60 100644 --- a/src/ffi/modsupport.rs +++ b/src/ffi/modsupport.rs @@ -28,12 +28,32 @@ extern "C" { ) -> c_int; #[cfg_attr(PyPy, link_name = "PyPy_BuildValue")] pub fn Py_BuildValue(arg1: *const c_char, ...) -> *mut PyObject; - #[cfg_attr(PyPy, link_name = "_PyPy_BuildValue_SizeT")] + // #[cfg_attr(PyPy, link_name = "_PyPy_BuildValue_SizeT")] //pub fn _Py_BuildValue_SizeT(arg1: *const c_char, ...) // -> *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPy_VaBuildValue")] + // #[cfg_attr(PyPy, link_name = "PyPy_VaBuildValue")] + + // skipped non-limited _PyArg_UnpackStack + // skipped non-limited _PyArg_NoKeywords + // skipped non-limited _PyArg_NoKwnames + // skipped non-limited _PyArg_NoPositional + // skipped non-limited _PyArg_BadArgument + // skipped non-limited _PyArg_CheckPositional + //pub fn Py_VaBuildValue(arg1: *const c_char, arg2: va_list) // -> *mut PyObject; + + // skipped non-limited _Py_VaBuildStack + // skipped non-limited _PyArg_Parser + + // skipped non-limited _PyArg_ParseTupleAndKeywordsFast + // skipped non-limited _PyArg_ParseStack + // skipped non-limited _PyArg_ParseStackAndKeywords + // skipped non-limited _PyArg_VaParseTupleAndKeywordsFast + // skipped non-limited _PyArg_UnpackKeywords + // skipped non-limited _PyArg_Fini + + // skipped PyModule_AddObjectRef #[cfg_attr(PyPy, link_name = "PyPyModule_AddObject")] pub fn PyModule_AddObject( arg1: *mut PyObject, @@ -49,6 +69,9 @@ extern "C" { arg2: *const c_char, arg3: *const c_char, ) -> c_int; + // skipped non-limited / 3.9 PyModule_AddType + // skipped PyModule_AddIntMacro + // skipped PyModule_AddStringMacro pub fn PyModule_SetDocString(arg1: *mut PyObject, arg2: *const c_char) -> c_int; pub fn PyModule_AddFunctions(arg1: *mut PyObject, arg2: *mut PyMethodDef) -> c_int; pub fn PyModule_ExecDef(module: *mut PyObject, def: *mut PyModuleDef) -> c_int; @@ -122,3 +145,5 @@ pub unsafe fn PyModule_FromDefAndSpec(def: *mut PyModuleDef, spec: *mut PyObject }, ) } + +// skipped non-limited _Py_PackageContext diff --git a/src/ffi/moduleobject.rs b/src/ffi/moduleobject.rs index 1093d28f..d43efa78 100644 --- a/src/ffi/moduleobject.rs +++ b/src/ffi/moduleobject.rs @@ -30,8 +30,12 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyModule_GetName")] pub fn PyModule_GetName(arg1: *mut PyObject) -> *const c_char; #[cfg(not(all(windows, PyPy)))] + #[deprecated(note = "Python 3.2")] pub fn PyModule_GetFilename(arg1: *mut PyObject) -> *const c_char; pub fn PyModule_GetFilenameObject(arg1: *mut PyObject) -> *mut PyObject; + // skipped non-limited _PyModule_Clear + // skipped non-limited _PyModule_ClearDict + // skipped non-limited _PyModuleSpec_IsInitializing #[cfg_attr(PyPy, link_name = "PyPyModule_GetDef")] pub fn PyModule_GetDef(arg1: *mut PyObject) -> *mut PyModuleDef; #[cfg_attr(PyPy, link_name = "PyPyModule_GetState")] @@ -71,6 +75,8 @@ pub struct PyModuleDef_Slot { pub const Py_mod_create: c_int = 1; pub const Py_mod_exec: c_int = 2; +// skipped non-limited _Py_mod_LAST_SLOT + #[repr(C)] #[derive(Copy, Clone)] pub struct PyModuleDef { @@ -85,6 +91,10 @@ pub struct PyModuleDef { pub m_free: Option, } +/// Helper initial value of [`PyModuleDef`] for a Python class. +/// +/// Not present in the Python C API. +#[deprecated(note = "not present in Python headers; to be removed")] pub const PyModuleDef_INIT: PyModuleDef = PyModuleDef { m_base: PyModuleDef_HEAD_INIT, m_name: std::ptr::null(), diff --git a/src/pyclass.rs b/src/pyclass.rs index 2c2fe45d..066ea238 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -350,6 +350,7 @@ fn py_class_method_defs() -> ( } if !defs.is_empty() { + #[allow(deprecated)] defs.push(ffi::PyMethodDef_INIT); } diff --git a/src/types/module.rs b/src/types/module.rs index 11d34f1c..992d7a7e 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -121,7 +121,12 @@ impl PyModule { /// May fail if the module does not have a `__file__` attribute. #[cfg(not(all(windows, PyPy)))] pub fn filename(&self) -> PyResult<&str> { - unsafe { self.str_from_ptr(ffi::PyModule_GetFilename(self.as_ptr())) } + unsafe { + self.str_from_ptr( + #[allow(deprecated)] + ffi::PyModule_GetFilename(self.as_ptr()), + ) + } } /// Calls a function in the module. From d34856ba59d03499e66fafc8e3d0ed41f8cc91dd Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Sat, 13 Feb 2021 15:43:12 +0800 Subject: [PATCH 2/8] CHANGELOG: add PR number --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 802321b2..769d2203 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,14 +7,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased ### Added -- Add FFI definition `PyCFunction_CheckExact` for Python 3.9 and later. +- Add FFI definition `PyCFunction_CheckExact` for Python 3.9 and later. [#1425](https://github.com/PyO3/pyo3/pull/1425) ### Changed -- Deprecate FFI definition `PyCFunction_Call` for Python 3.9 and later. -- Deprecate FFI definitions `PyModule_GetFilename`, `PyMethodDef_INIT`. +- Deprecate FFI definition `PyCFunction_Call` for Python 3.9 and later. [#1425](https://github.com/PyO3/pyo3/pull/1425) +- Deprecate FFI definitions `PyModule_GetFilename`, `PyMethodDef_INIT`. [#1425](https://github.com/PyO3/pyo3/pull/1425) ### Removed -- Remove FFI definition `PyCFunction_ClearFreeList` for Python 3.9 and later. +- Remove FFI definition `PyCFunction_ClearFreeList` for Python 3.9 and later. [#1425](https://github.com/PyO3/pyo3/pull/1425) ## [0.13.2] - 2021-02-12 ### Packaging From b35a6a58b04c581429c5107ccb6149b7b326a210 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Sat, 13 Feb 2021 17:06:20 +0800 Subject: [PATCH 3/8] ffi: methodobject: PyCFunction_Check: fix outdated def --- src/ffi/methodobject.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ffi/methodobject.rs b/src/ffi/methodobject.rs index 66eb52e9..f1aa40bf 100644 --- a/src/ffi/methodobject.rs +++ b/src/ffi/methodobject.rs @@ -1,4 +1,4 @@ -use crate::ffi::object::{PyObject, PyTypeObject, Py_TYPE}; +use crate::ffi::object::{PyObject, PyObject_TypeCheck, PyTypeObject, Py_TYPE}; use std::mem; use std::os::raw::{c_char, c_int}; @@ -16,7 +16,7 @@ pub unsafe fn PyCFunction_CheckExact(op: *mut PyObject) -> c_int { #[inline] pub unsafe fn PyCFunction_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == &mut PyCFunction_Type) as c_int + PyObject_TypeCheck(op, &mut PyCFunction_Type) } pub type PyCFunction = From aaddb20a227a33d441e52054070b0151a565d4fd Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Sat, 13 Feb 2021 17:07:03 +0800 Subject: [PATCH 4/8] CHANGELOG: update as requested --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 769d2203..f941c75a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Deprecate FFI definition `PyCFunction_Call` for Python 3.9 and later. [#1425](https://github.com/PyO3/pyo3/pull/1425) - Deprecate FFI definitions `PyModule_GetFilename`, `PyMethodDef_INIT`. [#1425](https://github.com/PyO3/pyo3/pull/1425) -### Removed +### Fixed - Remove FFI definition `PyCFunction_ClearFreeList` for Python 3.9 and later. [#1425](https://github.com/PyO3/pyo3/pull/1425) ## [0.13.2] - 2021-02-12 From 1c845e7b3b28a74846f25657bceaaefa3409b5f3 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Sat, 13 Feb 2021 17:07:19 +0800 Subject: [PATCH 5/8] PyModule: filename: use non-deprecated function --- src/types/module.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/types/module.rs b/src/types/module.rs index 992d7a7e..3c3e6d0a 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -9,7 +9,7 @@ use crate::ffi; use crate::instance::PyNativeType; use crate::pyclass::PyClass; use crate::type_object::PyTypeObject; -use crate::types::{PyAny, PyDict, PyList}; +use crate::types::{PyAny, PyDict, PyList, PyString}; use crate::types::{PyCFunction, PyTuple}; use crate::{AsPyPointer, IntoPy, Py, PyObject, Python}; use std::ffi::{CStr, CString}; @@ -122,10 +122,9 @@ impl PyModule { #[cfg(not(all(windows, PyPy)))] pub fn filename(&self) -> PyResult<&str> { unsafe { - self.str_from_ptr( - #[allow(deprecated)] - ffi::PyModule_GetFilename(self.as_ptr()), - ) + self.py() + .from_owned_ptr_or_err::(ffi::PyModule_GetFilenameObject(self.as_ptr()))? + .to_str() } } From 96fcfe6e0cb874eeb907feb52c780770c4f25494 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Sat, 13 Feb 2021 17:10:29 +0800 Subject: [PATCH 6/8] ffi: methodobject: PyModule_Check: update for Py39 change --- src/ffi/methodobject.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ffi/methodobject.rs b/src/ffi/methodobject.rs index f1aa40bf..d8f95c4b 100644 --- a/src/ffi/methodobject.rs +++ b/src/ffi/methodobject.rs @@ -14,11 +14,18 @@ pub unsafe fn PyCFunction_CheckExact(op: *mut PyObject) -> c_int { (Py_TYPE(op) == &mut PyCFunction_Type) as c_int } +#[cfg(Py_3_9)] #[inline] pub unsafe fn PyCFunction_Check(op: *mut PyObject) -> c_int { PyObject_TypeCheck(op, &mut PyCFunction_Type) } +#[cfg(not(Py_3_9))] +#[inline] +pub unsafe fn PyCFunction_Check(op: *mut PyObject) -> c_int { + (Py_TYPE(op) == &mut PyCFunction_Type) as c_int +} + pub type PyCFunction = unsafe extern "C" fn(slf: *mut PyObject, args: *mut PyObject) -> *mut PyObject; From 39a29a59f038881dea54063395d44c4e7e564a6d Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Sat, 13 Feb 2021 18:59:33 +0800 Subject: [PATCH 7/8] ffi: methodobject: conditional import for CI --- src/ffi/methodobject.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ffi/methodobject.rs b/src/ffi/methodobject.rs index d8f95c4b..ecfbc81c 100644 --- a/src/ffi/methodobject.rs +++ b/src/ffi/methodobject.rs @@ -1,4 +1,6 @@ -use crate::ffi::object::{PyObject, PyObject_TypeCheck, PyTypeObject, Py_TYPE}; +use crate::ffi::object::{PyObject, PyTypeObject, Py_TYPE}; +#[cfg(Py_3_9)] +use crate::ffi::PyObject_TypeCheck; use std::mem; use std::os::raw::{c_char, c_int}; From 2d7d482d8d183f2c80629b2369f4ad6ac04ec796 Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Sat, 13 Feb 2021 19:06:31 +0800 Subject: [PATCH 8/8] another conditional import fix --- src/types/module.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/types/module.rs b/src/types/module.rs index 3c3e6d0a..71a219a2 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -9,7 +9,7 @@ use crate::ffi; use crate::instance::PyNativeType; use crate::pyclass::PyClass; use crate::type_object::PyTypeObject; -use crate::types::{PyAny, PyDict, PyList, PyString}; +use crate::types::{PyAny, PyDict, PyList}; use crate::types::{PyCFunction, PyTuple}; use crate::{AsPyPointer, IntoPy, Py, PyObject, Python}; use std::ffi::{CStr, CString}; @@ -121,6 +121,7 @@ impl PyModule { /// May fail if the module does not have a `__file__` attribute. #[cfg(not(all(windows, PyPy)))] pub fn filename(&self) -> PyResult<&str> { + use crate::types::PyString; unsafe { self.py() .from_owned_ptr_or_err::(ffi::PyModule_GetFilenameObject(self.as_ptr()))?