diff --git a/Architecture.md b/Architecture.md index a4218a7f71f..be9d2b53d82 100644 --- a/Architecture.md +++ b/Architecture.md @@ -37,12 +37,9 @@ automated tooling because: - it gives us best control about how to adapt C conventions to Rust, and - there are many Python interpreter versions we support in a single set of files. -We aim to provide straight-forward Rust wrappers resembling the file structure of -[`cpython/Include`](https://github.com/python/cpython/tree/v3.9.2/Include). +We aim to provide straight-forward Rust wrappers resembling the file structure of [`cpython/Include`](https://github.com/python/cpython/tree/3.13/Include). -However, we still lack some APIs and are continuously updating the module to match -the file contents upstream in CPython. -The tracking issue is [#1289](https://github.com/PyO3/pyo3/issues/1289), and contribution is welcome. +We are continuously updating the module to match the latest CPython version which PyO3 supports (i.e. as of time of writing Python 3.13). The tracking issue is [#1289](https://github.com/PyO3/pyo3/issues/1289), and contribution is welcome. In the [`pyo3-ffi`] crate, there is lots of conditional compilation such as `#[cfg(Py_LIMITED_API)]`, `#[cfg(Py_3_7)]`, and `#[cfg(PyPy)]`. diff --git a/newsfragments/4447.added.md b/newsfragments/4447.added.md new file mode 100644 index 00000000000..a1e6b5eaa39 --- /dev/null +++ b/newsfragments/4447.added.md @@ -0,0 +1 @@ +Add Python 3.13 FFI definitions `PyObject_GetOptionalAttr`, `PyObject_GetOptionalAttrString`, `PyObject_HasAttrWithError`, `PyObject_HasAttrStringWithError`, `Py_CONSTANT_*` constants, `Py_GetConstant`, `Py_GetConstantBorrowed`, and `PyType_GetModuleByDef`. diff --git a/newsfragments/4447.fixed.md b/newsfragments/4447.fixed.md new file mode 100644 index 00000000000..bfc92ae1d26 --- /dev/null +++ b/newsfragments/4447.fixed.md @@ -0,0 +1 @@ +Fix FFI definition `Py_Is` for PyPy on 3.10 to call the function defined by PyPy. diff --git a/newsfragments/4447.removed.md b/newsfragments/4447.removed.md new file mode 100644 index 00000000000..c7451866d83 --- /dev/null +++ b/newsfragments/4447.removed.md @@ -0,0 +1 @@ +Remove private FFI definitions `_Py_IMMORTAL_REFCNT`, `_Py_IsImmortal`, `_Py_TPFLAGS_STATIC_BUILTIN`, `_Py_Dealloc`, `_Py_IncRef`, `_Py_DecRef`. diff --git a/pyo3-ffi/src/abstract_.rs b/pyo3-ffi/src/abstract_.rs index 175f9af734f..1899545011a 100644 --- a/pyo3-ffi/src/abstract_.rs +++ b/pyo3-ffi/src/abstract_.rs @@ -1,23 +1,17 @@ use crate::object::*; use crate::pyport::Py_ssize_t; use std::os::raw::{c_char, c_int}; -use std::ptr; - -extern "C" { - #[cfg(PyPy)] - #[link_name = "PyPyObject_DelAttrString"] - pub fn PyObject_DelAttrString(o: *mut PyObject, attr_name: *const c_char) -> c_int; -} #[inline] -#[cfg(not(PyPy))] +#[cfg(all(not(Py_3_13), not(PyPy)))] // CPython exposed as a function in 3.13, in object.h pub unsafe fn PyObject_DelAttrString(o: *mut PyObject, attr_name: *const c_char) -> c_int { - PyObject_SetAttrString(o, attr_name, ptr::null_mut()) + PyObject_SetAttrString(o, attr_name, std::ptr::null_mut()) } #[inline] +#[cfg(all(not(Py_3_13), not(PyPy)))] // CPython exposed as a function in 3.13, in object.h pub unsafe fn PyObject_DelAttr(o: *mut PyObject, attr_name: *mut PyObject) -> c_int { - PyObject_SetAttr(o, attr_name, ptr::null_mut()) + PyObject_SetAttr(o, attr_name, std::ptr::null_mut()) } extern "C" { diff --git a/pyo3-ffi/src/boolobject.rs b/pyo3-ffi/src/boolobject.rs index 10b5969fa4f..eec9da707a1 100644 --- a/pyo3-ffi/src/boolobject.rs +++ b/pyo3-ffi/src/boolobject.rs @@ -4,12 +4,6 @@ use crate::object::*; use std::os::raw::{c_int, c_long}; use std::ptr::addr_of_mut; -#[cfg_attr(windows, link(name = "pythonXY"))] -extern "C" { - #[cfg_attr(PyPy, link_name = "PyPyBool_Type")] - pub static mut PyBool_Type: PyTypeObject; -} - #[inline] pub unsafe fn PyBool_Check(op: *mut PyObject) -> c_int { (Py_TYPE(op) == addr_of_mut!(PyBool_Type)) as c_int diff --git a/pyo3-ffi/src/cpython/object.rs b/pyo3-ffi/src/cpython/object.rs index 871f3b883d9..23d7f94081e 100644 --- a/pyo3-ffi/src/cpython/object.rs +++ b/pyo3-ffi/src/cpython/object.rs @@ -1,20 +1,23 @@ #[cfg(Py_3_8)] use crate::vectorcallfunc; -#[cfg(Py_3_11)] -use crate::PyModuleDef; 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}; +use std::os::raw::{c_char, c_int, c_uint, c_void}; + +// skipped private _Py_NewReference +// skipped private _Py_NewReferenceNoTotal +// skipped private _Py_ResurrectReference -// skipped _Py_NewReference -// skipped _Py_ForgetReference -// skipped _Py_GetRefTotal +// skipped private _Py_GetGlobalRefTotal +// skipped private _Py_GetRefTotal +// skipped private _Py_GetLegacyRefTotal +// skipped private _PyInterpreterState_GetRefTotal -// skipped _Py_Identifier +// skipped private _Py_Identifier -// skipped _Py_static_string_init -// skipped _Py_static_string -// skipped _Py_IDENTIFIER +// skipped private _Py_static_string_init +// skipped private _Py_static_string +// skipped private _Py_IDENTIFIER #[cfg(not(Py_3_11))] // moved to src/buffer.rs from Python mod bufferinfo { @@ -240,7 +243,10 @@ pub struct PyTypeObject { pub tp_getattro: Option, pub tp_setattro: Option, pub tp_as_buffer: *mut PyBufferProcs, - pub tp_flags: c_ulong, + #[cfg(not(Py_GIL_DISABLED))] + pub tp_flags: std::os::raw::c_ulong, + #[cfg(Py_GIL_DISABLED)] + pub tp_flags: crate::impl_::AtomicCULong, pub tp_doc: *const c_char, pub tp_traverse: Option, pub tp_clear: Option, @@ -292,12 +298,12 @@ pub struct PyTypeObject { #[cfg(Py_3_11)] #[repr(C)] #[derive(Clone)] -pub struct _specialization_cache { - pub getitem: *mut PyObject, +struct _specialization_cache { + getitem: *mut PyObject, #[cfg(Py_3_12)] - pub getitem_version: u32, + getitem_version: u32, #[cfg(Py_3_13)] - pub init: *mut PyObject, + init: *mut PyObject, } #[repr(C)] @@ -316,9 +322,9 @@ pub struct PyHeapTypeObject { #[cfg(Py_3_9)] pub ht_module: *mut object::PyObject, #[cfg(Py_3_11)] - pub _ht_tpname: *mut c_char, + _ht_tpname: *mut c_char, #[cfg(Py_3_11)] - pub _spec_cache: _specialization_cache, + _spec_cache: _specialization_cache, } impl Default for PyHeapTypeObject { @@ -329,82 +335,75 @@ impl Default for PyHeapTypeObject { } #[inline] +#[cfg(not(Py_3_11))] 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 PyMemberDef } -// skipped _PyType_Name -// skipped _PyType_Lookup -// skipped _PyType_LookupId -// skipped _PyObject_LookupSpecial -// skipped _PyType_CalculateMetaclass -// skipped _PyType_GetDocFromInternalDoc -// skipped _PyType_GetTextSignatureFromInternalDoc +// skipped private _PyType_Name +// skipped private _PyType_Lookup +// skipped private _PyType_LookupRef extern "C" { - #[cfg(Py_3_11)] - #[cfg_attr(PyPy, link_name = "PyPyType_GetModuleByDef")] - pub fn PyType_GetModuleByDef(ty: *mut PyTypeObject, def: *mut PyModuleDef) -> *mut PyObject; - #[cfg(Py_3_12)] pub fn PyType_GetDict(o: *mut PyTypeObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyObject_Print")] pub fn PyObject_Print(o: *mut PyObject, fp: *mut ::libc::FILE, flags: c_int) -> c_int; - // skipped _Py_BreakPoint - // skipped _PyObject_Dump - // skipped _PyObject_IsFreed - // skipped _PyObject_IsAbstract + // skipped private _Py_BreakPoint + // skipped private _PyObject_Dump + // skipped _PyObject_GetAttrId - // skipped _PyObject_SetAttrId - // skipped _PyObject_LookupAttr - // skipped _PyObject_LookupAttrId - // skipped _PyObject_GetMethod - #[cfg(not(PyPy))] - pub fn _PyObject_GetDictPtr(obj: *mut PyObject) -> *mut *mut PyObject; - #[cfg(not(PyPy))] - pub fn _PyObject_NextNotImplemented(arg1: *mut PyObject) -> *mut PyObject; + // skipped private _PyObject_GetDictPtr pub fn PyObject_CallFinalizer(arg1: *mut PyObject); #[cfg_attr(PyPy, link_name = "PyPyObject_CallFinalizerFromDealloc")] pub fn PyObject_CallFinalizerFromDealloc(arg1: *mut PyObject) -> c_int; - // skipped _PyObject_GenericGetAttrWithDict - // skipped _PyObject_GenericSetAttrWithDict - // skipped _PyObject_FunctionStr + // skipped private _PyObject_GenericGetAttrWithDict + // skipped private _PyObject_GenericSetAttrWithDict + // skipped private _PyObject_FunctionStr } // skipped Py_SETREF // skipped Py_XSETREF -#[cfg_attr(windows, link(name = "pythonXY"))] -extern "C" { - pub static mut _PyNone_Type: PyTypeObject; - pub static mut _PyNotImplemented_Type: PyTypeObject; -} - -// skipped _Py_SwappedOp +// skipped private _PyObject_ASSERT_FROM +// skipped private _PyObject_ASSERT_WITH_MSG +// skipped private _PyObject_ASSERT +// skipped private _PyObject_ASSERT_FAILED_MSG +// skipped private _PyObject_AssertFailed -// skipped _PyDebugAllocatorStats -// skipped _PyObject_DebugTypeStats -// skipped _PyObject_ASSERT_FROM -// skipped _PyObject_ASSERT_WITH_MSG -// skipped _PyObject_ASSERT -// skipped _PyObject_ASSERT_FAILED_MSG -// skipped _PyObject_AssertFailed -// skipped _PyObject_CheckConsistency +// skipped private _PyTrash_begin +// skipped private _PyTrash_end // skipped _PyTrash_thread_deposit_object // skipped _PyTrash_thread_destroy_chain -// skipped _PyTrash_begin -// skipped _PyTrash_end -// skipped _PyTrash_cond -// skipped PyTrash_UNWIND_LEVEL -// skipped Py_TRASHCAN_BEGIN_CONDITION -// skipped Py_TRASHCAN_END + // skipped Py_TRASHCAN_BEGIN -// skipped Py_TRASHCAN_SAFE_BEGIN -// skipped Py_TRASHCAN_SAFE_END +// skipped Py_TRASHCAN_END + +// skipped PyObject_GetItemData + +// skipped PyObject_VisitManagedDict +// skipped _PyObject_SetManagedDict +// skipped PyObject_ClearManagedDict + +// skipped TYPE_MAX_WATCHERS + +// skipped PyType_WatchCallback +// skipped PyType_AddWatcher +// skipped PyType_ClearWatcher +// skipped PyType_Watch +// skipped PyType_Unwatch + +// skipped PyUnstable_Type_AssignVersionTag + +// skipped PyRefTracerEvent + +// skipped PyRefTracer +// skipped PyRefTracer_SetTracer +// skipped PyRefTracer_GetTracer diff --git a/pyo3-ffi/src/impl_/mod.rs b/pyo3-ffi/src/impl_/mod.rs new file mode 100644 index 00000000000..3058e852e6f --- /dev/null +++ b/pyo3-ffi/src/impl_/mod.rs @@ -0,0 +1,22 @@ +#[cfg(Py_GIL_DISABLED)] +mod atomic_c_ulong { + pub struct GetAtomicCULong(); + + pub trait AtomicCULongType { + type Type; + } + impl AtomicCULongType for GetAtomicCULong<32> { + type Type = std::sync::atomic::AtomicU32; + } + impl AtomicCULongType for GetAtomicCULong<64> { + type Type = std::sync::atomic::AtomicU64; + } + + pub type TYPE = + () * 8 }> as AtomicCULongType>::Type; +} + +/// Typedef for an atomic integer to match the platform-dependent c_ulong type. +#[cfg(Py_GIL_DISABLED)] +#[doc(hidden)] +pub type AtomicCULong = atomic_c_ulong::TYPE; diff --git a/pyo3-ffi/src/lib.rs b/pyo3-ffi/src/lib.rs index 4b5b3e390ad..1e3f804b1f4 100644 --- a/pyo3-ffi/src/lib.rs +++ b/pyo3-ffi/src/lib.rs @@ -292,6 +292,7 @@ pub const fn _cstr_from_utf8_with_nul_checked(s: &str) -> &CStr { use std::ffi::CStr; pub mod compat; +mod impl_; pub use self::abstract_::*; pub use self::bltinmodule::*; diff --git a/pyo3-ffi/src/longobject.rs b/pyo3-ffi/src/longobject.rs index 35a2bc1b0ff..494f86770f4 100644 --- a/pyo3-ffi/src/longobject.rs +++ b/pyo3-ffi/src/longobject.rs @@ -6,12 +6,6 @@ use std::ptr::addr_of_mut; opaque_struct!(PyLongObject); -#[cfg_attr(windows, link(name = "pythonXY"))] -extern "C" { - #[cfg_attr(PyPy, link_name = "PyPyLong_Type")] - pub static mut PyLong_Type: PyTypeObject; -} - #[inline] pub unsafe fn PyLong_Check(op: *mut PyObject) -> c_int { PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_LONG_SUBCLASS) diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index 5e8b6af44a1..deb67caf768 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -15,11 +15,8 @@ opaque_struct!(PyTypeObject); #[cfg(not(Py_LIMITED_API))] pub use crate::cpython::object::PyTypeObject; -// _PyObject_HEAD_EXTRA: conditionally defined in PyObject_HEAD_INIT -// _PyObject_EXTRA_INIT: conditionally defined in PyObject_HEAD_INIT - #[cfg(Py_3_12)] -pub const _Py_IMMORTAL_REFCNT: Py_ssize_t = { +const _Py_IMMORTAL_REFCNT: Py_ssize_t = { if cfg!(target_pointer_width = "64") { c_uint::MAX as Py_ssize_t } else { @@ -29,9 +26,7 @@ pub const _Py_IMMORTAL_REFCNT: Py_ssize_t = { }; #[cfg(Py_GIL_DISABLED)] -pub const _Py_IMMORTAL_REFCNT_LOCAL: u32 = u32::MAX; -#[cfg(Py_GIL_DISABLED)] -pub const _Py_REF_SHARED_SHIFT: isize = 2; +const _Py_IMMORTAL_REFCNT_LOCAL: u32 = u32::MAX; #[allow(clippy::declare_interior_mutable_const)] pub const PyObject_HEAD_INIT: PyObject = PyObject { @@ -66,9 +61,22 @@ pub const PyObject_HEAD_INIT: PyObject = PyObject { // skipped PyObject_VAR_HEAD // skipped Py_INVALID_SIZE +// skipped private _Py_UNOWNED_TID + +#[cfg(Py_GIL_DISABLED)] +const _Py_REF_SHARED_SHIFT: isize = 2; +// skipped private _Py_REF_SHARED_FLAG_MASK + +// skipped private _Py_REF_SHARED_INIT +// skipped private _Py_REF_MAYBE_WEAKREF +// skipped private _Py_REF_QUEUED +// skipped private _Py_REF_MERGED + +// skipped private _Py_REF_SHARED + #[repr(C)] #[derive(Copy, Clone)] -#[cfg(Py_3_12)] +#[cfg(all(Py_3_12, not(Py_GIL_DISABLED)))] /// This union is anonymous in CPython, so the name was given by PyO3 because /// Rust unions need a name. pub union PyObjectObRefcnt { @@ -77,14 +85,14 @@ pub union PyObjectObRefcnt { pub ob_refcnt_split: [crate::PY_UINT32_T; 2], } -#[cfg(Py_3_12)] +#[cfg(all(Py_3_12, not(Py_GIL_DISABLED)))] impl std::fmt::Debug for PyObjectObRefcnt { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", unsafe { self.ob_refcnt }) } } -#[cfg(not(Py_3_12))] +#[cfg(all(not(Py_3_12), not(Py_GIL_DISABLED)))] pub type PyObjectObRefcnt = Py_ssize_t; #[repr(C)] @@ -113,7 +121,7 @@ pub struct PyObject { pub ob_type: *mut PyTypeObject, } -// skipped _PyObject_CAST +// skipped private _PyObject_CAST #[repr(C)] #[derive(Debug)] @@ -123,38 +131,54 @@ pub struct PyVarObject { pub ob_size: Py_ssize_t, } -// skipped _PyVarObject_CAST +// skipped private _PyVarObject_CAST #[inline] +#[cfg(not(all(PyPy, Py_3_10)))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub unsafe fn Py_Is(x: *mut PyObject, y: *mut PyObject) -> c_int { (x == y).into() } -#[inline] -#[cfg(Py_GIL_DISABLED)] -pub unsafe fn Py_REFCNT(ob: *mut PyObject) -> Py_ssize_t { - let local = (*ob).ob_ref_local.load(Relaxed); - if local == _Py_IMMORTAL_REFCNT_LOCAL { - return _Py_IMMORTAL_REFCNT; - } - let shared = (*ob).ob_ref_shared.load(Relaxed); - local as Py_ssize_t + Py_ssize_t::from(shared >> _Py_REF_SHARED_SHIFT) +#[cfg(all(PyPy, Py_3_10))] +#[cfg_attr(docsrs, doc(cfg(all())))] +extern "C" { + #[cfg_attr(PyPy, link_name = "PyPy_Is")] + pub fn Py_Is(x: *mut PyObject, y: *mut PyObject) -> c_int; } -#[inline] -#[cfg(not(Py_GIL_DISABLED))] -#[cfg(Py_3_12)] -pub unsafe fn Py_REFCNT(ob: *mut PyObject) -> Py_ssize_t { - (*ob).ob_refcnt.ob_refcnt -} +// skipped private _Py_GetThreadLocal_Addr + +// skipped private _Py_ThreadId + +// skipped private _Py_IsOwnedByCurrentThread #[inline] -#[cfg(not(Py_3_12))] pub unsafe fn Py_REFCNT(ob: *mut PyObject) -> Py_ssize_t { - #[cfg(not(GraalPy))] - return (*ob).ob_refcnt; - #[cfg(GraalPy)] - return _Py_REFCNT(ob); + #[cfg(Py_GIL_DISABLED)] + { + let local = (*ob).ob_ref_local.load(Relaxed); + if local == _Py_IMMORTAL_REFCNT_LOCAL { + return _Py_IMMORTAL_REFCNT; + } + let shared = (*ob).ob_ref_shared.load(Relaxed); + local as Py_ssize_t + Py_ssize_t::from(shared >> _Py_REF_SHARED_SHIFT) + } + + #[cfg(all(not(Py_GIL_DISABLED), Py_3_12))] + { + (*ob).ob_refcnt.ob_refcnt + } + + #[cfg(all(not(Py_GIL_DISABLED), not(Py_3_12), not(GraalPy)))] + { + (*ob).ob_refcnt + } + + #[cfg(all(not(Py_GIL_DISABLED), not(Py_3_12), GraalPy))] + { + _Py_REFCNT(ob) + } } #[inline] @@ -165,8 +189,13 @@ pub unsafe fn Py_TYPE(ob: *mut PyObject) -> *mut PyTypeObject { return _Py_TYPE(ob); } -// PyLong_Type defined in longobject.rs -// PyBool_Type defined in boolobject.rs +#[cfg_attr(windows, link(name = "pythonXY"))] +extern "C" { + #[cfg_attr(PyPy, link_name = "PyPyLong_Type")] + pub static mut PyLong_Type: PyTypeObject; + #[cfg_attr(PyPy, link_name = "PyPyBool_Type")] + pub static mut PyBool_Type: PyTypeObject; +} #[inline] pub unsafe fn Py_SIZE(ob: *mut PyObject) -> Py_ssize_t { @@ -180,28 +209,31 @@ pub unsafe fn Py_SIZE(ob: *mut PyObject) -> Py_ssize_t { _Py_SIZE(ob) } +#[inline(always)] +#[cfg(all(Py_3_12, not(Py_GIL_DISABLED)))] +unsafe fn _Py_IsImmortal(op: *mut PyObject) -> c_int { + #[cfg(target_pointer_width = "64")] + { + (((*op).ob_refcnt.ob_refcnt as crate::PY_INT32_T) < 0) as c_int + } + + #[cfg(target_pointer_width = "32")] + { + ((*op).ob_refcnt.ob_refcnt == _Py_IMMORTAL_REFCNT) as c_int + } +} + #[inline] pub unsafe fn Py_IS_TYPE(ob: *mut PyObject, tp: *mut PyTypeObject) -> c_int { (Py_TYPE(ob) == tp) as c_int } -#[inline(always)] -#[cfg(all(not(Py_GIL_DISABLED), Py_3_12, target_pointer_width = "64"))] -pub unsafe fn _Py_IsImmortal(op: *mut PyObject) -> c_int { - (((*op).ob_refcnt.ob_refcnt as crate::PY_INT32_T) < 0) as c_int -} - -#[inline(always)] -#[cfg(all(Py_3_12, target_pointer_width = "32"))] -pub unsafe fn _Py_IsImmortal(op: *mut PyObject) -> c_int { - ((*op).ob_refcnt.ob_refcnt == _Py_IMMORTAL_REFCNT) as c_int -} +// skipped _Py_SetRefCnt -// skipped _Py_SET_REFCNT // skipped Py_SET_REFCNT -// skipped _Py_SET_TYPE + // skipped Py_SET_TYPE -// skipped _Py_SET_SIZE + // skipped Py_SET_SIZE pub type unaryfunc = unsafe extern "C" fn(*mut PyObject) -> *mut PyObject; @@ -344,7 +376,7 @@ extern "C" { #[inline] pub unsafe fn PyObject_TypeCheck(ob: *mut PyObject, tp: *mut PyTypeObject) -> c_int { - (Py_TYPE(ob) == tp || PyType_IsSubtype(Py_TYPE(ob), tp) != 0) as c_int + (Py_IS_TYPE(ob, tp) != 0 || PyType_IsSubtype(Py_TYPE(ob), tp) != 0) as c_int } #[cfg_attr(windows, link(name = "pythonXY"))] @@ -401,18 +433,43 @@ extern "C" { arg2: *const c_char, arg3: *mut PyObject, ) -> c_int; + #[cfg(any(Py_3_13, PyPy))] // CPython defined in 3.12 as an inline function in abstract.h + #[cfg_attr(PyPy, link_name = "PyPyObject_DelAttrString")] + pub fn PyObject_DelAttrString(arg1: *mut PyObject, arg2: *const c_char) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyObject_HasAttrString")] pub fn PyObject_HasAttrString(arg1: *mut PyObject, arg2: *const c_char) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyObject_GetAttr")] pub fn PyObject_GetAttr(arg1: *mut PyObject, arg2: *mut PyObject) -> *mut PyObject; + #[cfg(Py_3_13)] + #[cfg_attr(PyPy, link_name = "PyPyObject_GetOptionalAttr")] + pub fn PyObject_GetOptionalAttr( + arg1: *mut PyObject, + arg2: *mut PyObject, + arg3: *mut *mut PyObject, + ) -> c_int; + #[cfg(Py_3_13)] + #[cfg_attr(PyPy, link_name = "PyPyObject_GetOptionalAttrString")] + pub fn PyObject_GetOptionalAttrString( + arg1: *mut PyObject, + arg2: *const c_char, + arg3: *mut *mut PyObject, + ) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyObject_SetAttr")] pub fn PyObject_SetAttr(arg1: *mut PyObject, arg2: *mut PyObject, arg3: *mut PyObject) -> c_int; + #[cfg(any(Py_3_13, PyPy))] // CPython defined in 3.12 as an inline function in abstract.h + #[cfg_attr(PyPy, link_name = "PyPyObject_DelAttr")] + pub fn PyObject_DelAttr(arg1: *mut PyObject, arg2: *mut PyObject) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyObject_HasAttr")] pub fn PyObject_HasAttr(arg1: *mut PyObject, arg2: *mut PyObject) -> c_int; + #[cfg(Py_3_13)] + #[cfg_attr(PyPy, link_name = "PyPyObject_HasAttrWithError")] + pub fn PyObject_HasAttrWithError(arg1: *mut PyObject, arg2: *mut PyObject) -> c_int; + #[cfg(Py_3_13)] + #[cfg_attr(PyPy, link_name = "PyPyObject_HasAttrStringWithError")] + pub fn PyObject_HasAttrStringWithError(arg1: *mut PyObject, arg2: *const c_char) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyObject_SelfIter")] pub fn PyObject_SelfIter(arg1: *mut PyObject) -> *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyObject_GenericGetAttr")] pub fn PyObject_GenericGetAttr(arg1: *mut PyObject, arg2: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyObject_GenericSetAttr")] @@ -422,7 +479,9 @@ extern "C" { arg3: *mut PyObject, ) -> c_int; #[cfg(not(all(Py_LIMITED_API, not(Py_3_10))))] + #[cfg_attr(PyPy, link_name = "PyPyObject_GenericGetDict")] pub fn PyObject_GenericGetDict(arg1: *mut PyObject, arg2: *mut c_void) -> *mut PyObject; + #[cfg_attr(PyPy, link_name = "PyPyObject_GenericSetDict")] pub fn PyObject_GenericSetDict( arg1: *mut PyObject, arg2: *mut PyObject, @@ -450,8 +509,8 @@ extern "C" { // Flag bits for printing: pub const Py_PRINT_RAW: c_int = 1; // No string quotes etc. -#[cfg(all(Py_3_12, not(Py_LIMITED_API)))] -pub const _Py_TPFLAGS_STATIC_BUILTIN: c_ulong = 1 << 1; +// skipped because is a private API +// const _Py_TPFLAGS_STATIC_BUILTIN: c_ulong = 1 << 1; #[cfg(all(Py_3_12, not(Py_LIMITED_API)))] pub const Py_TPFLAGS_MANAGED_WEAKREF: c_ulong = 1 << 3; @@ -480,7 +539,7 @@ pub const Py_TPFLAGS_BASETYPE: c_ulong = 1 << 10; /// Set if the type implements the vectorcall protocol (PEP 590) #[cfg(any(Py_3_12, all(Py_3_8, not(Py_LIMITED_API))))] pub const Py_TPFLAGS_HAVE_VECTORCALL: c_ulong = 1 << 11; -// skipped non-limited _Py_TPFLAGS_HAVE_VECTORCALL +// skipped backwards-compatibility alias _Py_TPFLAGS_HAVE_VECTORCALL /// Set if the type is 'ready' -- fully initialized pub const Py_TPFLAGS_READY: c_ulong = 1 << 12; @@ -526,14 +585,14 @@ pub const Py_TPFLAGS_HAVE_VERSION_TAG: c_ulong = 1 << 18; extern "C" { #[cfg(all(py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API)))] - pub fn _Py_NegativeRefcount(filename: *const c_char, lineno: c_int, op: *mut PyObject); + fn _Py_NegativeRefcount(filename: *const c_char, lineno: c_int, op: *mut PyObject); #[cfg(all(Py_3_12, py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API)))] fn _Py_INCREF_IncRefTotal(); #[cfg(all(Py_3_12, py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API)))] fn _Py_DECREF_DecRefTotal(); #[cfg_attr(PyPy, link_name = "_PyPy_Dealloc")] - pub fn _Py_Dealloc(arg1: *mut PyObject); + fn _Py_Dealloc(arg1: *mut PyObject); #[cfg_attr(PyPy, link_name = "PyPy_IncRef")] #[cfg_attr(GraalPy, link_name = "_Py_IncRef")] @@ -543,18 +602,18 @@ extern "C" { pub fn Py_DecRef(o: *mut PyObject); #[cfg(all(Py_3_10, not(PyPy)))] - pub fn _Py_IncRef(o: *mut PyObject); + fn _Py_IncRef(o: *mut PyObject); #[cfg(all(Py_3_10, not(PyPy)))] - pub fn _Py_DecRef(o: *mut PyObject); + fn _Py_DecRef(o: *mut PyObject); #[cfg(GraalPy)] - pub fn _Py_REFCNT(arg1: *const PyObject) -> Py_ssize_t; + fn _Py_REFCNT(arg1: *const PyObject) -> Py_ssize_t; #[cfg(GraalPy)] - pub fn _Py_TYPE(arg1: *const PyObject) -> *mut PyTypeObject; + fn _Py_TYPE(arg1: *const PyObject) -> *mut PyTypeObject; #[cfg(GraalPy)] - pub fn _Py_SIZE(arg1: *const PyObject) -> Py_ssize_t; + fn _Py_SIZE(arg1: *const PyObject) -> Py_ssize_t; } #[inline(always)] @@ -740,9 +799,39 @@ pub unsafe fn Py_XNewRef(obj: *mut PyObject) -> *mut PyObject { obj } +#[cfg(Py_3_13)] +pub const Py_CONSTANT_NONE: c_uint = 0; +#[cfg(Py_3_13)] +pub const Py_CONSTANT_FALSE: c_uint = 1; +#[cfg(Py_3_13)] +pub const Py_CONSTANT_TRUE: c_uint = 2; +#[cfg(Py_3_13)] +pub const Py_CONSTANT_ELLIPSIS: c_uint = 3; +#[cfg(Py_3_13)] +pub const Py_CONSTANT_NOT_IMPLEMENTED: c_uint = 4; +#[cfg(Py_3_13)] +pub const Py_CONSTANT_ZERO: c_uint = 5; +#[cfg(Py_3_13)] +pub const Py_CONSTANT_ONE: c_uint = 6; +#[cfg(Py_3_13)] +pub const Py_CONSTANT_EMPTY_STR: c_uint = 7; +#[cfg(Py_3_13)] +pub const Py_CONSTANT_EMPTY_BYTES: c_uint = 8; +#[cfg(Py_3_13)] +pub const Py_CONSTANT_EMPTY_TUPLE: c_uint = 9; + +extern "C" { + #[cfg(Py_3_13)] + #[cfg_attr(PyPy, link_name = "PyPy_GetConstant")] + pub fn Py_GetConstant(constant_id: c_uint) -> *mut PyObject; + #[cfg(Py_3_13)] + #[cfg_attr(PyPy, link_name = "PyPy_GetConstantBorrowed")] + pub fn Py_GetConstantBorrowed(constant_id: c_uint) -> *mut PyObject; +} + #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { - #[cfg(not(GraalPy))] + #[cfg(all(not(GraalPy), not(all(Py_3_13, Py_LIMITED_API))))] #[cfg_attr(PyPy, link_name = "_PyPy_NoneStruct")] static mut _Py_NoneStruct: PyObject; @@ -752,8 +841,12 @@ extern "C" { #[inline] pub unsafe fn Py_None() -> *mut PyObject { - #[cfg(not(GraalPy))] + #[cfg(all(not(GraalPy), all(Py_3_13, Py_LIMITED_API)))] + return Py_GetConstantBorrowed(Py_CONSTANT_NONE); + + #[cfg(all(not(GraalPy), not(all(Py_3_13, Py_LIMITED_API))))] return ptr::addr_of_mut!(_Py_NoneStruct); + #[cfg(GraalPy)] return _Py_NoneStructReference; } @@ -767,7 +860,7 @@ pub unsafe fn Py_IsNone(x: *mut PyObject) -> c_int { #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { - #[cfg(not(GraalPy))] + #[cfg(all(not(GraalPy), not(all(Py_3_13, Py_LIMITED_API))))] #[cfg_attr(PyPy, link_name = "_PyPy_NotImplementedStruct")] static mut _Py_NotImplementedStruct: PyObject; @@ -777,8 +870,12 @@ extern "C" { #[inline] pub unsafe fn Py_NotImplemented() -> *mut PyObject { - #[cfg(not(GraalPy))] + #[cfg(all(not(GraalPy), all(Py_3_13, Py_LIMITED_API)))] + return Py_GetConstantBorrowed(Py_CONSTANT_NONE); + + #[cfg(all(not(GraalPy), not(all(Py_3_13, Py_LIMITED_API))))] return ptr::addr_of_mut!(_Py_NotImplementedStruct); + #[cfg(GraalPy)] return _Py_NotImplementedStructReference; } @@ -805,15 +902,17 @@ pub enum PySendResult { // skipped Py_RETURN_RICHCOMPARE #[inline] -#[cfg(Py_LIMITED_API)] -pub unsafe fn PyType_HasFeature(t: *mut PyTypeObject, f: c_ulong) -> c_int { - ((PyType_GetFlags(t) & f) != 0) as c_int -} +pub unsafe fn PyType_HasFeature(ty: *mut PyTypeObject, feature: c_ulong) -> c_int { + #[cfg(Py_LIMITED_API)] + let flags = PyType_GetFlags(ty); -#[inline] -#[cfg(not(Py_LIMITED_API))] -pub unsafe fn PyType_HasFeature(t: *mut PyTypeObject, f: c_ulong) -> c_int { - (((*t).tp_flags & f) != 0) as c_int + #[cfg(all(not(Py_LIMITED_API), Py_GIL_DISABLED))] + let flags = (*ty).tp_flags.load(std::sync::atomic::Ordering::Relaxed); + + #[cfg(all(not(Py_LIMITED_API), not(Py_GIL_DISABLED)))] + let flags = (*ty).tp_flags; + + ((flags & feature) != 0) as c_int } #[inline] @@ -826,7 +925,18 @@ pub unsafe fn PyType_Check(op: *mut PyObject) -> c_int { PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TYPE_SUBCLASS) } +// skipped _PyType_CAST + #[inline] pub unsafe fn PyType_CheckExact(op: *mut PyObject) -> c_int { Py_IS_TYPE(op, ptr::addr_of_mut!(PyType_Type)) } + +extern "C" { + #[cfg(any(Py_3_13, all(Py_3_11, not(Py_LIMITED_API))))] + #[cfg_attr(PyPy, link_name = "PyPyType_GetModuleByDef")] + pub fn PyType_GetModuleByDef( + arg1: *mut crate::PyTypeObject, + arg2: *mut crate::PyModuleDef, + ) -> *mut PyObject; +}