From b6b1e69eaae6f06a0a689e247b3423b709b5b2ad Mon Sep 17 00:00:00 2001 From: Steve Kowalik Date: Wed, 9 Sep 2026 15:09:57 +1000 Subject: [PATCH 1/2] Wrap use of PyWeakref_GET_OBJECT if we need it Python 3.15 removes PyWeakref_GET_OBJECT, and the path forward is by using PyWeakref_GetRef, which was only added in Python 3.13. Add a wrapper for it if required, and switch to using PyWeakref_GetRef everywhere that called PyWeakref_GET_OBJECT. --- atom/src/methodwrapper.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/atom/src/methodwrapper.cpp b/atom/src/methodwrapper.cpp index 4bc8cbf5..6a4ec38d 100644 --- a/atom/src/methodwrapper.cpp +++ b/atom/src/methodwrapper.cpp @@ -6,12 +6,22 @@ | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ #include + +#if PY_VERSION_HEX < 0x030D0000 +// Can be removed when Python < 3.13 is no longer supported +static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj) { + PyObject *obj = PyWeakref_GET_OBJECT(ref); + *pobj = obj; + Py_XINCREF(*pobj); + return 1; +} +#endif + #include "methodwrapper.h" #include "catom.h" #include "catompointer.h" #include "packagenaming.h" - namespace atom { @@ -38,10 +48,12 @@ MethodWrapper_dealloc( MethodWrapper* self ) PyObject* MethodWrapper__call__( MethodWrapper* self, PyObject* args, PyObject* kwargs ) { - PyObject* im_self = PyWeakref_GET_OBJECT( self->im_selfref ); + PyObject* raw_im_self = nullptr; + PyWeakref_GetRef( self->im_selfref, &raw_im_self ); + cppy::ptr im_self( raw_im_self ); if( im_self != Py_None ) { - cppy::ptr method( PyMethod_New( self->im_func, im_self ) ); + cppy::ptr method( PyMethod_New( self->im_func, im_self.get() ) ); if( !method ) return 0; return PyObject_Call( method.get(), args, kwargs ); @@ -57,8 +69,12 @@ MethodWrapper_richcompare( MethodWrapper* self, PyObject* other, int op ) { if( PyMethod_Check( other ) && PyMethod_GET_SELF( other ) ) { + PyObject* raw_im_self = nullptr; + PyWeakref_GetRef( self->im_selfref, &raw_im_self ); + cppy::ptr im_self( raw_im_self ); // Automatically handles DECREF when exiting scope + if( ( self->im_func == PyMethod_GET_FUNCTION( other ) ) && - ( PyWeakref_GET_OBJECT( self->im_selfref ) == PyMethod_GET_SELF( other ) ) ) + ( im_self.get() == PyMethod_GET_SELF( other ) ) ) Py_RETURN_TRUE; Py_RETURN_FALSE; } @@ -80,7 +96,10 @@ MethodWrapper_richcompare( MethodWrapper* self, PyObject* other, int op ) int MethodWrapper__bool__( MethodWrapper* self ) { - if( PyWeakref_GET_OBJECT( self->im_selfref ) != Py_None ) + PyObject* raw_im_self = nullptr; + PyWeakref_GetRef( self->im_selfref, &raw_im_self ); + cppy::ptr im_self( raw_im_self ); + if( im_self.get() != Py_None ) return 1; return 0; } From 6f1baadf80ccbd7ef28d3780e91572f1c77e048f Mon Sep 17 00:00:00 2001 From: Steve Kowalik Date: Wed, 9 Sep 2026 17:11:31 +1000 Subject: [PATCH 2/2] Add Python 3.15 to CI and classifiers --- .github/workflows/ci.yml | 2 +- pyproject.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a5451aa..ae5958d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,7 +94,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ['3.10', '3.11', '3.12', '3.13', '3.14-dev'] + python-version: ['3.10', '3.11', '3.12', '3.13', '3.14', '3.15-dev'] steps: - uses: actions/checkout@v5 - name: Get history and tags for SCM versioning to work diff --git a/pyproject.toml b/pyproject.toml index 94b42939..19ab1d4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", "Programming Language :: Python :: Implementation :: CPython", ] dependencies = ["typing_extensions;python_version<'3.11'"]