From 5d7dfe2e95fc45b6ef05b426ffc5646a3990503c Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Fri, 21 Jul 2023 13:35:53 +0100 Subject: [PATCH 1/3] update pydebug.rs for Python 3.12 --- newsfragments/3336.added.md | 1 + newsfragments/3336.changed.md | 1 + pyo3-ffi/src/cpython/pydebug.rs | 37 ++++++++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 newsfragments/3336.added.md create mode 100644 newsfragments/3336.changed.md diff --git a/newsfragments/3336.added.md b/newsfragments/3336.added.md new file mode 100644 index 00000000..d625be00 --- /dev/null +++ b/newsfragments/3336.added.md @@ -0,0 +1 @@ +Add FFI symbol `Py_GETENV`. diff --git a/newsfragments/3336.changed.md b/newsfragments/3336.changed.md new file mode 100644 index 00000000..b178cc04 --- /dev/null +++ b/newsfragments/3336.changed.md @@ -0,0 +1 @@ +Deprecate FFI definitions which are deprecated in Python 3.12. diff --git a/pyo3-ffi/src/cpython/pydebug.rs b/pyo3-ffi/src/cpython/pydebug.rs index 1ebda05e..a42848e8 100644 --- a/pyo3-ffi/src/cpython/pydebug.rs +++ b/pyo3-ffi/src/cpython/pydebug.rs @@ -1,37 +1,72 @@ -use std::os::raw::c_int; +use std::os::raw::{c_char, c_int}; #[cfg(not(Py_LIMITED_API))] #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { + #[deprecated(note = "Python 3.12")] #[cfg_attr(PyPy, link_name = "PyPy_DebugFlag")] pub static mut Py_DebugFlag: c_int; + #[deprecated(note = "Python 3.12")] #[cfg_attr(PyPy, link_name = "PyPy_VerboseFlag")] pub static mut Py_VerboseFlag: c_int; + #[deprecated(note = "Python 3.12")] pub static mut Py_QuietFlag: c_int; + #[deprecated(note = "Python 3.12")] #[cfg_attr(PyPy, link_name = "PyPy_InteractiveFlag")] pub static mut Py_InteractiveFlag: c_int; + #[deprecated(note = "Python 3.12")] #[cfg_attr(PyPy, link_name = "PyPy_InspectFlag")] pub static mut Py_InspectFlag: c_int; + #[deprecated(note = "Python 3.12")] #[cfg_attr(PyPy, link_name = "PyPy_OptimizeFlag")] pub static mut Py_OptimizeFlag: c_int; + #[deprecated(note = "Python 3.12")] #[cfg_attr(PyPy, link_name = "PyPy_NoSiteFlag")] pub static mut Py_NoSiteFlag: c_int; + #[deprecated(note = "Python 3.12")] #[cfg_attr(PyPy, link_name = "PyPy_BytesWarningFlag")] pub static mut Py_BytesWarningFlag: c_int; + #[deprecated(note = "Python 3.12")] #[cfg_attr(PyPy, link_name = "PyPy_UseClassExceptionsFlag")] pub static mut Py_UseClassExceptionsFlag: c_int; + #[deprecated(note = "Python 3.12")] #[cfg_attr(PyPy, link_name = "PyPy_FrozenFlag")] pub static mut Py_FrozenFlag: c_int; + #[deprecated(note = "Python 3.12")] #[cfg_attr(PyPy, link_name = "PyPy_IgnoreEnvironmentFlag")] pub static mut Py_IgnoreEnvironmentFlag: c_int; + #[deprecated(note = "Python 3.12")] #[cfg_attr(PyPy, link_name = "PyPy_DontWriteBytecodeFlag")] pub static mut Py_DontWriteBytecodeFlag: c_int; + #[deprecated(note = "Python 3.12")] #[cfg_attr(PyPy, link_name = "PyPy_NoUserSiteDirectory")] pub static mut Py_NoUserSiteDirectory: c_int; + #[deprecated(note = "Python 3.12")] pub static mut Py_UnbufferedStdioFlag: c_int; #[cfg_attr(PyPy, link_name = "PyPy_HashRandomizationFlag")] pub static mut Py_HashRandomizationFlag: c_int; + #[deprecated(note = "Python 3.12")] pub static mut Py_IsolatedFlag: c_int; #[cfg(windows)] + #[deprecated(note = "Python 3.12")] + pub static mut Py_LegacyWindowsFSEncodingFlag: c_int; + #[cfg(windows)] + #[deprecated(note = "Python 3.12")] pub static mut Py_LegacyWindowsStdioFlag: c_int; } + +extern "C" { + #[cfg(Py_3_11)] + pub fn Py_GETENV(name: *const c_char) -> *mut c_char; +} + +#[cfg(not(Py_3_11))] +#[inline(always)] +pub unsafe fn Py_GETENV(name: *const c_char) -> *mut c_char { + #[allow(deprecated)] + if Py_IgnoreEnvironmentFlag != 0 { + std::ptr::null_mut() + } else { + libc::getenv(name) + } +} From acb1bf7c0a93e933612cb1a12217d98c6e77f9ce Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Fri, 21 Jul 2023 13:41:34 +0100 Subject: [PATCH 2/3] update fileobject.rs for Python 3.12 --- pyo3-ffi/src/fileobject.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyo3-ffi/src/fileobject.rs b/pyo3-ffi/src/fileobject.rs index 525a7f10..91618ab7 100644 --- a/pyo3-ffi/src/fileobject.rs +++ b/pyo3-ffi/src/fileobject.rs @@ -26,10 +26,13 @@ extern "C" { #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { + #[deprecated(note = "Python 3.12")] pub static mut Py_FileSystemDefaultEncoding: *const c_char; + #[deprecated(note = "Python 3.12")] pub static mut Py_FileSystemDefaultEncodeErrors: *const c_char; + #[deprecated(note = "Python 3.12")] pub static mut Py_HasFileSystemDefaultEncoding: c_int; - // skipped Python 3.7 / ex-non-limited Py_UTF8Mode + // skipped 3.12-deprecated Py_UTF8Mode } // skipped _PyIsSelectable_fd From b0f5901ce37ace7d9b9bd21b645aa205c1f0cd2d Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Fri, 21 Jul 2023 13:54:16 +0100 Subject: [PATCH 3/3] update structmember.rs for Python 3.12 --- pyo3-ffi-check/macro/src/lib.rs | 4 ++ pyo3-ffi-check/wrapper.h | 1 + pyo3-ffi/src/cpython/object.rs | 15 +++--- pyo3-ffi/src/descrobject.rs | 61 ++++++++++++++++++++++- pyo3-ffi/src/lib.rs | 1 + pyo3-ffi/src/structmember.rs | 87 ++++++++++----------------------- 6 files changed, 97 insertions(+), 72 deletions(-) diff --git a/pyo3-ffi-check/macro/src/lib.rs b/pyo3-ffi-check/macro/src/lib.rs index e572a9ad..e3d442c3 100644 --- a/pyo3-ffi-check/macro/src/lib.rs +++ b/pyo3-ffi-check/macro/src/lib.rs @@ -152,6 +152,10 @@ pub fn for_all_fields(input: proc_macro::TokenStream) -> proc_macro::TokenStream // PyObject since 3.12 implements ob_refcnt as a union; bindgen creates // an anonymous name for the field Ident::new("__bindgen_anon_1", Span::call_site()) + } else if struct_name == "PyMemberDef" && field_name == "type_code" { + // the field name in the C API is `type`, but that's a keyword in Rust + // so PyO3 picked type_code, bindgen picked type_ + Ident::new("type_", Span::call_site()) } else { field_ident.clone() }; diff --git a/pyo3-ffi-check/wrapper.h b/pyo3-ffi-check/wrapper.h index 0750f8dc..b91582e1 100644 --- a/pyo3-ffi-check/wrapper.h +++ b/pyo3-ffi-check/wrapper.h @@ -1,3 +1,4 @@ #include "Python.h" #include "datetime.h" #include "frameobject.h" +#include "structmember.h" diff --git a/pyo3-ffi/src/cpython/object.rs b/pyo3-ffi/src/cpython/object.rs index abf8f1dc..423af03a 100644 --- a/pyo3-ffi/src/cpython/object.rs +++ b/pyo3-ffi/src/cpython/object.rs @@ -1,7 +1,6 @@ -use crate::object; #[cfg(Py_3_8)] use crate::vectorcallfunc; -use crate::{PyObject, Py_ssize_t}; +use crate::{object, PyGetSetDef, PyMemberDef, PyMethodDef, PyObject, Py_ssize_t}; use std::mem; use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void}; @@ -247,9 +246,9 @@ pub struct PyTypeObject { pub tp_weaklistoffset: Py_ssize_t, pub tp_iter: Option, pub tp_iternext: Option, - pub tp_methods: *mut crate::methodobject::PyMethodDef, - pub tp_members: *mut crate::structmember::PyMemberDef, - pub tp_getset: *mut crate::descrobject::PyGetSetDef, + pub tp_methods: *mut PyMethodDef, + pub tp_members: *mut PyMemberDef, + pub tp_getset: *mut PyGetSetDef, pub tp_base: *mut PyTypeObject, pub tp_dict: *mut object::PyObject, pub tp_descr_get: Option, @@ -327,12 +326,10 @@ impl Default for PyHeapTypeObject { } #[inline] -pub unsafe fn PyHeapType_GET_MEMBERS( - etype: *mut PyHeapTypeObject, -) -> *mut crate::structmember::PyMemberDef { +pub unsafe fn PyHeapType_GET_MEMBERS(etype: *mut PyHeapTypeObject) -> *mut PyMemberDef { let py_type = object::Py_TYPE(etype as *mut object::PyObject); let ptr = etype.offset((*py_type).tp_basicsize); - ptr as *mut crate::structmember::PyMemberDef + ptr as *mut PyMemberDef } // skipped _PyType_Name diff --git a/pyo3-ffi/src/descrobject.rs b/pyo3-ffi/src/descrobject.rs index c6f099b5..8bae0a88 100644 --- a/pyo3-ffi/src/descrobject.rs +++ b/pyo3-ffi/src/descrobject.rs @@ -1,6 +1,6 @@ use crate::methodobject::PyMethodDef; use crate::object::{PyObject, PyTypeObject}; -use crate::structmember::PyMemberDef; +use crate::Py_ssize_t; use std::os::raw::{c_char, c_int, c_void}; use std::ptr; @@ -62,3 +62,62 @@ extern "C" { pub fn PyDictProxy_New(arg1: *mut PyObject) -> *mut PyObject; pub fn PyWrapper_New(arg1: *mut PyObject, arg2: *mut PyObject) -> *mut PyObject; } + +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct PyMemberDef { + pub name: *const c_char, + pub type_code: c_int, + pub offset: Py_ssize_t, + pub flags: c_int, + pub doc: *const c_char, +} + +impl Default for PyMemberDef { + fn default() -> PyMemberDef { + PyMemberDef { + name: ptr::null_mut(), + type_code: 0, + offset: 0, + flags: 0, + doc: ptr::null_mut(), + } + } +} + +/* Types */ +pub const Py_T_SHORT: c_int = 0; +pub const Py_T_INT: c_int = 1; +pub const Py_T_LONG: c_int = 2; +pub const Py_T_FLOAT: c_int = 3; +pub const Py_T_DOUBLE: c_int = 4; +pub const Py_T_STRING: c_int = 5; +#[deprecated(note = "Use Py_T_OBJECT_EX instead")] +pub const _Py_T_OBJECT: c_int = 6; +pub const Py_T_CHAR: c_int = 7; +pub const Py_T_BYTE: c_int = 8; +pub const Py_T_UBYTE: c_int = 9; +pub const Py_T_USHORT: c_int = 10; +pub const Py_T_UINT: c_int = 11; +pub const Py_T_ULONG: c_int = 12; +pub const Py_T_STRING_INPLACE: c_int = 13; +pub const Py_T_BOOL: c_int = 14; +pub const Py_T_OBJECT_EX: c_int = 16; +pub const Py_T_LONGLONG: c_int = 17; +pub const Py_T_ULONGLONG: c_int = 18; +pub const Py_T_PYSSIZET: c_int = 19; +#[deprecated(note = "Value is always none")] +pub const _Py_T_NONE: c_int = 20; + +/* Flags */ +pub const Py_READONLY: c_int = 1; +#[cfg(Py_3_10)] +pub const Py_AUDIT_READ: c_int = 2; // Added in 3.10, harmless no-op before that +#[deprecated] +pub const _Py_WRITE_RESTRICTED: c_int = 4; // Deprecated, no-op. Do not reuse the value. +pub const Py_RELATIVE_OFFSET: c_int = 8; + +extern "C" { + pub fn PyMember_GetOne(addr: *const c_char, l: *mut PyMemberDef) -> *mut PyObject; + pub fn PyMember_SetOne(addr: *mut c_char, l: *mut PyMemberDef, value: *mut PyObject) -> c_int; +} diff --git a/pyo3-ffi/src/lib.rs b/pyo3-ffi/src/lib.rs index caf50ce2..cae3001d 100644 --- a/pyo3-ffi/src/lib.rs +++ b/pyo3-ffi/src/lib.rs @@ -407,6 +407,7 @@ mod warnings; mod weakrefobject; // Additional headers that are not exported by Python.h +#[deprecated(note = "Python 3.12")] pub mod structmember; // "Limited API" definitions matching Python's `include/cpython` directory. diff --git a/pyo3-ffi/src/structmember.rs b/pyo3-ffi/src/structmember.rs index 81912042..afae165c 100644 --- a/pyo3-ffi/src/structmember.rs +++ b/pyo3-ffi/src/structmember.rs @@ -1,70 +1,33 @@ -use crate::object::PyObject; -use crate::pyport::Py_ssize_t; -use std::os::raw::{c_char, c_int}; -use std::ptr; +use std::os::raw::c_int; -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct PyMemberDef { - pub name: *const c_char, - pub type_code: c_int, - pub offset: Py_ssize_t, - pub flags: c_int, - pub doc: *const c_char, -} +pub use crate::PyMemberDef; -impl Default for PyMemberDef { - fn default() -> PyMemberDef { - PyMemberDef { - name: ptr::null_mut(), - type_code: 0, - offset: 0, - flags: 0, - doc: ptr::null_mut(), - } - } -} +pub use crate::Py_T_BOOL as T_BOOL; +pub use crate::Py_T_BYTE as T_BYTE; +pub use crate::Py_T_CHAR as T_CHAR; +pub use crate::Py_T_DOUBLE as T_DOUBLE; +pub use crate::Py_T_FLOAT as T_FLOAT; +pub use crate::Py_T_INT as T_INT; +pub use crate::Py_T_LONG as T_LONG; +pub use crate::Py_T_LONGLONG as T_LONGLONG; +pub use crate::Py_T_OBJECT_EX as T_OBJECT_EX; +pub use crate::Py_T_SHORT as T_SHORT; +pub use crate::Py_T_STRING as T_STRING; +pub use crate::Py_T_STRING_INPLACE as T_STRING_INPLACE; +pub use crate::Py_T_UBYTE as T_UBYTE; +pub use crate::Py_T_UINT as T_UINT; +pub use crate::Py_T_ULONG as T_ULONG; +pub use crate::Py_T_ULONGLONG as T_ULONGLONG; +pub use crate::Py_T_USHORT as T_USHORT; +#[allow(deprecated)] +pub use crate::_Py_T_OBJECT as T_OBJECT; -/* Types */ -pub const T_SHORT: c_int = 0; -pub const T_INT: c_int = 1; -pub const T_LONG: c_int = 2; -pub const T_FLOAT: c_int = 3; -pub const T_DOUBLE: c_int = 4; -pub const T_STRING: c_int = 5; -pub const T_OBJECT: c_int = 6; -/* XXX the ordering here is weird for binary compatibility */ -pub const T_CHAR: c_int = 7; /* 1-character string */ -pub const T_BYTE: c_int = 8; /* 8-bit signed int */ -/* unsigned variants: */ -pub const T_UBYTE: c_int = 9; -pub const T_USHORT: c_int = 10; -pub const T_UINT: c_int = 11; -pub const T_ULONG: c_int = 12; - -/* Added by Jack: strings contained in the structure */ -pub const T_STRING_INPLACE: c_int = 13; - -/* Added by Lillo: bools contained in the structure (assumed char) */ -pub const T_BOOL: c_int = 14; - -pub const T_OBJECT_EX: c_int = 16; /* Like T_OBJECT, but raises AttributeError - when the value is NULL, instead of - converting to None. */ - -pub const T_LONGLONG: c_int = 17; -pub const T_ULONGLONG: c_int = 18; - -pub const T_PYSSIZET: c_int = 19; /* Py_ssize_t */ -pub const T_NONE: c_int = 20; /* Value is always None */ +pub use crate::Py_T_PYSSIZET as T_PYSSIZET; +#[allow(deprecated)] +pub use crate::_Py_T_NONE as T_NONE; /* Flags */ -pub const READONLY: c_int = 1; +pub use crate::Py_READONLY as READONLY; pub const READ_RESTRICTED: c_int = 2; pub const PY_WRITE_RESTRICTED: c_int = 4; pub const RESTRICTED: c_int = READ_RESTRICTED | PY_WRITE_RESTRICTED; - -extern "C" { - pub fn PyMember_GetOne(addr: *const c_char, l: *mut PyMemberDef) -> *mut PyObject; - pub fn PyMember_SetOne(addr: *mut c_char, l: *mut PyMemberDef, value: *mut PyObject) -> c_int; -}