Skip to content

Commit 2f5b45e

Browse files
davidhewittalex
andauthored
ffi: update object.rs for 3.13 (#4447)
* ffi: update `object.rs` for 3.13 * add newsfragment * fixup `_Py_IsImmortal` cfgs * also update `cpython/object.rs` * fix `Py_Is` on PyPy 3.10 * `Py_GetConstant` & `Py_GetConstantBorrowed` are pub * [review] mejrs feedback * correct typo Co-authored-by: Alex Gaynor <[email protected]> * fix freethreaded build --------- Co-authored-by: Alex Gaynor <[email protected]>
1 parent 5cc23d9 commit 2f5b45e

File tree

11 files changed

+279
-165
lines changed

11 files changed

+279
-165
lines changed

Architecture.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,9 @@ automated tooling because:
3737
- it gives us best control about how to adapt C conventions to Rust, and
3838
- there are many Python interpreter versions we support in a single set of files.
3939

40-
We aim to provide straight-forward Rust wrappers resembling the file structure of
41-
[`cpython/Include`](https://github.com/python/cpython/tree/v3.9.2/Include).
40+
We aim to provide straight-forward Rust wrappers resembling the file structure of [`cpython/Include`](https://github.com/python/cpython/tree/3.13/Include).
4241

43-
However, we still lack some APIs and are continuously updating the module to match
44-
the file contents upstream in CPython.
45-
The tracking issue is [#1289](https://github.com/PyO3/pyo3/issues/1289), and contribution is welcome.
42+
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.
4643

4744
In the [`pyo3-ffi`] crate, there is lots of conditional compilation such as `#[cfg(Py_LIMITED_API)]`,
4845
`#[cfg(Py_3_7)]`, and `#[cfg(PyPy)]`.

newsfragments/4447.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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`.

newsfragments/4447.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix FFI definition `Py_Is` for PyPy on 3.10 to call the function defined by PyPy.

newsfragments/4447.removed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove private FFI definitions `_Py_IMMORTAL_REFCNT`, `_Py_IsImmortal`, `_Py_TPFLAGS_STATIC_BUILTIN`, `_Py_Dealloc`, `_Py_IncRef`, `_Py_DecRef`.

pyo3-ffi/src/abstract_.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
11
use crate::object::*;
22
use crate::pyport::Py_ssize_t;
33
use std::os::raw::{c_char, c_int};
4-
use std::ptr;
5-
6-
extern "C" {
7-
#[cfg(PyPy)]
8-
#[link_name = "PyPyObject_DelAttrString"]
9-
pub fn PyObject_DelAttrString(o: *mut PyObject, attr_name: *const c_char) -> c_int;
10-
}
114

125
#[inline]
13-
#[cfg(not(PyPy))]
6+
#[cfg(all(not(Py_3_13), not(PyPy)))] // CPython exposed as a function in 3.13, in object.h
147
pub unsafe fn PyObject_DelAttrString(o: *mut PyObject, attr_name: *const c_char) -> c_int {
15-
PyObject_SetAttrString(o, attr_name, ptr::null_mut())
8+
PyObject_SetAttrString(o, attr_name, std::ptr::null_mut())
169
}
1710

1811
#[inline]
12+
#[cfg(all(not(Py_3_13), not(PyPy)))] // CPython exposed as a function in 3.13, in object.h
1913
pub unsafe fn PyObject_DelAttr(o: *mut PyObject, attr_name: *mut PyObject) -> c_int {
20-
PyObject_SetAttr(o, attr_name, ptr::null_mut())
14+
PyObject_SetAttr(o, attr_name, std::ptr::null_mut())
2115
}
2216

2317
extern "C" {

pyo3-ffi/src/boolobject.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ use crate::object::*;
44
use std::os::raw::{c_int, c_long};
55
use std::ptr::addr_of_mut;
66

7-
#[cfg_attr(windows, link(name = "pythonXY"))]
8-
extern "C" {
9-
#[cfg_attr(PyPy, link_name = "PyPyBool_Type")]
10-
pub static mut PyBool_Type: PyTypeObject;
11-
}
12-
137
#[inline]
148
pub unsafe fn PyBool_Check(op: *mut PyObject) -> c_int {
159
(Py_TYPE(op) == addr_of_mut!(PyBool_Type)) as c_int

pyo3-ffi/src/cpython/object.rs

Lines changed: 65 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
#[cfg(Py_3_8)]
22
use crate::vectorcallfunc;
3-
#[cfg(Py_3_11)]
4-
use crate::PyModuleDef;
53
use crate::{object, PyGetSetDef, PyMemberDef, PyMethodDef, PyObject, Py_ssize_t};
64
use std::mem;
7-
use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void};
5+
use std::os::raw::{c_char, c_int, c_uint, c_void};
6+
7+
// skipped private _Py_NewReference
8+
// skipped private _Py_NewReferenceNoTotal
9+
// skipped private _Py_ResurrectReference
810

9-
// skipped _Py_NewReference
10-
// skipped _Py_ForgetReference
11-
// skipped _Py_GetRefTotal
11+
// skipped private _Py_GetGlobalRefTotal
12+
// skipped private _Py_GetRefTotal
13+
// skipped private _Py_GetLegacyRefTotal
14+
// skipped private _PyInterpreterState_GetRefTotal
1215

13-
// skipped _Py_Identifier
16+
// skipped private _Py_Identifier
1417

15-
// skipped _Py_static_string_init
16-
// skipped _Py_static_string
17-
// skipped _Py_IDENTIFIER
18+
// skipped private _Py_static_string_init
19+
// skipped private _Py_static_string
20+
// skipped private _Py_IDENTIFIER
1821

1922
#[cfg(not(Py_3_11))] // moved to src/buffer.rs from Python
2023
mod bufferinfo {
@@ -240,7 +243,10 @@ pub struct PyTypeObject {
240243
pub tp_getattro: Option<object::getattrofunc>,
241244
pub tp_setattro: Option<object::setattrofunc>,
242245
pub tp_as_buffer: *mut PyBufferProcs,
243-
pub tp_flags: c_ulong,
246+
#[cfg(not(Py_GIL_DISABLED))]
247+
pub tp_flags: std::os::raw::c_ulong,
248+
#[cfg(Py_GIL_DISABLED)]
249+
pub tp_flags: crate::impl_::AtomicCULong,
244250
pub tp_doc: *const c_char,
245251
pub tp_traverse: Option<object::traverseproc>,
246252
pub tp_clear: Option<object::inquiry>,
@@ -292,12 +298,12 @@ pub struct PyTypeObject {
292298
#[cfg(Py_3_11)]
293299
#[repr(C)]
294300
#[derive(Clone)]
295-
pub struct _specialization_cache {
296-
pub getitem: *mut PyObject,
301+
struct _specialization_cache {
302+
getitem: *mut PyObject,
297303
#[cfg(Py_3_12)]
298-
pub getitem_version: u32,
304+
getitem_version: u32,
299305
#[cfg(Py_3_13)]
300-
pub init: *mut PyObject,
306+
init: *mut PyObject,
301307
}
302308

303309
#[repr(C)]
@@ -316,9 +322,9 @@ pub struct PyHeapTypeObject {
316322
#[cfg(Py_3_9)]
317323
pub ht_module: *mut object::PyObject,
318324
#[cfg(Py_3_11)]
319-
pub _ht_tpname: *mut c_char,
325+
_ht_tpname: *mut c_char,
320326
#[cfg(Py_3_11)]
321-
pub _spec_cache: _specialization_cache,
327+
_spec_cache: _specialization_cache,
322328
}
323329

324330
impl Default for PyHeapTypeObject {
@@ -329,82 +335,75 @@ impl Default for PyHeapTypeObject {
329335
}
330336

331337
#[inline]
338+
#[cfg(not(Py_3_11))]
332339
pub unsafe fn PyHeapType_GET_MEMBERS(etype: *mut PyHeapTypeObject) -> *mut PyMemberDef {
333340
let py_type = object::Py_TYPE(etype as *mut object::PyObject);
334341
let ptr = etype.offset((*py_type).tp_basicsize);
335342
ptr as *mut PyMemberDef
336343
}
337344

338-
// skipped _PyType_Name
339-
// skipped _PyType_Lookup
340-
// skipped _PyType_LookupId
341-
// skipped _PyObject_LookupSpecial
342-
// skipped _PyType_CalculateMetaclass
343-
// skipped _PyType_GetDocFromInternalDoc
344-
// skipped _PyType_GetTextSignatureFromInternalDoc
345+
// skipped private _PyType_Name
346+
// skipped private _PyType_Lookup
347+
// skipped private _PyType_LookupRef
345348

346349
extern "C" {
347-
#[cfg(Py_3_11)]
348-
#[cfg_attr(PyPy, link_name = "PyPyType_GetModuleByDef")]
349-
pub fn PyType_GetModuleByDef(ty: *mut PyTypeObject, def: *mut PyModuleDef) -> *mut PyObject;
350-
351350
#[cfg(Py_3_12)]
352351
pub fn PyType_GetDict(o: *mut PyTypeObject) -> *mut PyObject;
353352

354353
#[cfg_attr(PyPy, link_name = "PyPyObject_Print")]
355354
pub fn PyObject_Print(o: *mut PyObject, fp: *mut ::libc::FILE, flags: c_int) -> c_int;
356355

357-
// skipped _Py_BreakPoint
358-
// skipped _PyObject_Dump
359-
// skipped _PyObject_IsFreed
360-
// skipped _PyObject_IsAbstract
356+
// skipped private _Py_BreakPoint
357+
// skipped private _PyObject_Dump
358+
361359
// skipped _PyObject_GetAttrId
362-
// skipped _PyObject_SetAttrId
363-
// skipped _PyObject_LookupAttr
364-
// skipped _PyObject_LookupAttrId
365-
// skipped _PyObject_GetMethod
366360

367-
#[cfg(not(PyPy))]
368-
pub fn _PyObject_GetDictPtr(obj: *mut PyObject) -> *mut *mut PyObject;
369-
#[cfg(not(PyPy))]
370-
pub fn _PyObject_NextNotImplemented(arg1: *mut PyObject) -> *mut PyObject;
361+
// skipped private _PyObject_GetDictPtr
371362
pub fn PyObject_CallFinalizer(arg1: *mut PyObject);
372363
#[cfg_attr(PyPy, link_name = "PyPyObject_CallFinalizerFromDealloc")]
373364
pub fn PyObject_CallFinalizerFromDealloc(arg1: *mut PyObject) -> c_int;
374365

375-
// skipped _PyObject_GenericGetAttrWithDict
376-
// skipped _PyObject_GenericSetAttrWithDict
377-
// skipped _PyObject_FunctionStr
366+
// skipped private _PyObject_GenericGetAttrWithDict
367+
// skipped private _PyObject_GenericSetAttrWithDict
368+
// skipped private _PyObject_FunctionStr
378369
}
379370

380371
// skipped Py_SETREF
381372
// skipped Py_XSETREF
382373

383-
#[cfg_attr(windows, link(name = "pythonXY"))]
384-
extern "C" {
385-
pub static mut _PyNone_Type: PyTypeObject;
386-
pub static mut _PyNotImplemented_Type: PyTypeObject;
387-
}
388-
389-
// skipped _Py_SwappedOp
374+
// skipped private _PyObject_ASSERT_FROM
375+
// skipped private _PyObject_ASSERT_WITH_MSG
376+
// skipped private _PyObject_ASSERT
377+
// skipped private _PyObject_ASSERT_FAILED_MSG
378+
// skipped private _PyObject_AssertFailed
390379

391-
// skipped _PyDebugAllocatorStats
392-
// skipped _PyObject_DebugTypeStats
393-
// skipped _PyObject_ASSERT_FROM
394-
// skipped _PyObject_ASSERT_WITH_MSG
395-
// skipped _PyObject_ASSERT
396-
// skipped _PyObject_ASSERT_FAILED_MSG
397-
// skipped _PyObject_AssertFailed
398-
// skipped _PyObject_CheckConsistency
380+
// skipped private _PyTrash_begin
381+
// skipped private _PyTrash_end
399382

400383
// skipped _PyTrash_thread_deposit_object
401384
// skipped _PyTrash_thread_destroy_chain
402-
// skipped _PyTrash_begin
403-
// skipped _PyTrash_end
404-
// skipped _PyTrash_cond
405-
// skipped PyTrash_UNWIND_LEVEL
406-
// skipped Py_TRASHCAN_BEGIN_CONDITION
407-
// skipped Py_TRASHCAN_END
385+
408386
// skipped Py_TRASHCAN_BEGIN
409-
// skipped Py_TRASHCAN_SAFE_BEGIN
410-
// skipped Py_TRASHCAN_SAFE_END
387+
// skipped Py_TRASHCAN_END
388+
389+
// skipped PyObject_GetItemData
390+
391+
// skipped PyObject_VisitManagedDict
392+
// skipped _PyObject_SetManagedDict
393+
// skipped PyObject_ClearManagedDict
394+
395+
// skipped TYPE_MAX_WATCHERS
396+
397+
// skipped PyType_WatchCallback
398+
// skipped PyType_AddWatcher
399+
// skipped PyType_ClearWatcher
400+
// skipped PyType_Watch
401+
// skipped PyType_Unwatch
402+
403+
// skipped PyUnstable_Type_AssignVersionTag
404+
405+
// skipped PyRefTracerEvent
406+
407+
// skipped PyRefTracer
408+
// skipped PyRefTracer_SetTracer
409+
// skipped PyRefTracer_GetTracer

pyo3-ffi/src/impl_/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#[cfg(Py_GIL_DISABLED)]
2+
mod atomic_c_ulong {
3+
pub struct GetAtomicCULong<const WIDTH: usize>();
4+
5+
pub trait AtomicCULongType {
6+
type Type;
7+
}
8+
impl AtomicCULongType for GetAtomicCULong<32> {
9+
type Type = std::sync::atomic::AtomicU32;
10+
}
11+
impl AtomicCULongType for GetAtomicCULong<64> {
12+
type Type = std::sync::atomic::AtomicU64;
13+
}
14+
15+
pub type TYPE =
16+
<GetAtomicCULong<{ std::mem::size_of::<std::os::raw::c_ulong>() * 8 }> as AtomicCULongType>::Type;
17+
}
18+
19+
/// Typedef for an atomic integer to match the platform-dependent c_ulong type.
20+
#[cfg(Py_GIL_DISABLED)]
21+
#[doc(hidden)]
22+
pub type AtomicCULong = atomic_c_ulong::TYPE;

pyo3-ffi/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ pub const fn _cstr_from_utf8_with_nul_checked(s: &str) -> &CStr {
292292
use std::ffi::CStr;
293293

294294
pub mod compat;
295+
mod impl_;
295296

296297
pub use self::abstract_::*;
297298
pub use self::bltinmodule::*;

pyo3-ffi/src/longobject.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,6 @@ use std::ptr::addr_of_mut;
66

77
opaque_struct!(PyLongObject);
88

9-
#[cfg_attr(windows, link(name = "pythonXY"))]
10-
extern "C" {
11-
#[cfg_attr(PyPy, link_name = "PyPyLong_Type")]
12-
pub static mut PyLong_Type: PyTypeObject;
13-
}
14-
159
#[inline]
1610
pub unsafe fn PyLong_Check(op: *mut PyObject) -> c_int {
1711
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_LONG_SUBCLASS)

0 commit comments

Comments
 (0)