Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ffi cleanup: methodobject to moduleobject #1425

Merged
merged 8 commits into from Feb 14, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions src/derive_utils.rs
Expand Up @@ -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))
Expand Down
34 changes: 30 additions & 4 deletions 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};

Expand All @@ -8,6 +8,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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definition PyCFunction_Check is the same as the new PyCFunction_CheckExact - does it need updating?

Copy link
Contributor Author

@nw0 nw0 Feb 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, thanks. Looks like this one was renamed in Python 3.9, with the new definition of PyCFunction_Check using PyObject_TypeCheck. Updated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like 3.9 introduced the Py_IS_TYPE macro in object.h, which I'll add -- should help catch these changes when eyeballing

Expand Down Expand Up @@ -38,11 +51,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<PyCFunction>;
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,
Expand All @@ -59,6 +75,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,
Expand All @@ -73,17 +93,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;
Expand All @@ -109,6 +131,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;
}
7 changes: 4 additions & 3 deletions src/ffi/mod.rs
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
29 changes: 27 additions & 2 deletions src/ffi/modsupport.rs
Expand Up @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -122,3 +145,5 @@ pub unsafe fn PyModule_FromDefAndSpec(def: *mut PyModuleDef, spec: *mut PyObject
},
)
}

// skipped non-limited _Py_PackageContext
10 changes: 10 additions & 0 deletions src/ffi/moduleobject.rs
Expand Up @@ -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")]
Expand Down Expand Up @@ -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 {
Expand All @@ -85,6 +91,10 @@ pub struct PyModuleDef {
pub m_free: Option<freefunc>,
}

/// 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 {
Comment on lines +97 to 98
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be breaking, but I guess the only user is pyclass.rs and we can remove this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, as I think we're going to do a breaking release next anyway it's fine to just scrap this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davidhewitt You'll do this in #1426 or should I add to this PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think probably simpler for you to do it in this PR so there's no risk of merge conflicts.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually nvm, I see that other than that, this PR is ready to go. I'll merge this PR now and do it in #1426.

m_base: PyModuleDef_HEAD_INIT,
m_name: std::ptr::null(),
Expand Down
1 change: 1 addition & 0 deletions src/pyclass.rs
Expand Up @@ -350,6 +350,7 @@ fn py_class_method_defs<T: PyMethods>() -> (
}

if !defs.is_empty() {
#[allow(deprecated)]
defs.push(ffi::PyMethodDef_INIT);
}

Expand Down
8 changes: 6 additions & 2 deletions src/types/module.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -121,7 +121,11 @@ 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.py()
.from_owned_ptr_or_err::<PyString>(ffi::PyModule_GetFilenameObject(self.as_ptr()))?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏼

.to_str()
}
}

/// Calls a function in the module.
Expand Down