diff --git a/CHANGELOG.md b/CHANGELOG.md index 99a3e73b8e2..f941c75a0ea 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. [#1425](https://github.com/PyO3/pyo3/pull/1425) + +### Changed +- 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) + +### 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 ### 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 cd0f5bde1ff..a6c902fb579 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 fdf1797ea2a..ecfbc81c205 100644 --- a/src/ffi/methodobject.rs +++ b/src/ffi/methodobject.rs @@ -1,4 +1,6 @@ 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}; @@ -8,6 +10,19 @@ 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 +} + +#[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 @@ -38,11 +53,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 +77,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 +95,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 +133,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 855b1e2a87f..20962ea2939 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 d2c886f0710..62826c600dc 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 1093d28fa8a..d43efa78e1b 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 2c2fe45db7a..066ea238424 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 11d34f1c59d..71a219a29bb 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())) } + use crate::types::PyString; + unsafe { + self.py() + .from_owned_ptr_or_err::(ffi::PyModule_GetFilenameObject(self.as_ptr()))? + .to_str() + } } /// Calls a function in the module.