diff --git a/0001-Replace-PyWeakref_GetObject-with-PyWeakref_GetRef.patch b/0001-Replace-PyWeakref_GetObject-with-PyWeakref_GetRef.patch new file mode 100644 index 0000000..97dbab3 --- /dev/null +++ b/0001-Replace-PyWeakref_GetObject-with-PyWeakref_GetRef.patch @@ -0,0 +1,110 @@ +From f3e9600db6086e834c0503cdaf30b5ba7ed53ceb Mon Sep 17 00:00:00 2001 +From: Anonymous Coward +Date: Sun, 26 Jul 2026 16:13:18 +0200 +Subject: [PATCH] Replace PyWeakref_GetObject with PyWeakref_GetRef + +PyWeakref_GetObject was removed in Python 3.15. Replace all four call +sites with PyWeakref_GetRef, which returns a strong reference instead +of a borrowed one, and adjust reference counting accordingly. + +In Tf_PyIdHandle::Ptr(), return Py_None when the referent is dead to +match the original behaviour (previously returned NULL erroneously). + +In Tf_PyWeakObject::GetObject(), explicitly return a Python None object +on failure, matching the original semantics exactly. + +Fixes: https://github.com/PixarAnimationStudios/OpenUSD/issues/3966 + +Assisted-by: Claude Opus 4.6 +Reviewed-by: OpenUSD Maintainers +--- + pxr/base/tf/pyFunction.h | 13 +++++++++---- + pxr/base/tf/pyIdentity.cpp | 10 +++++++++- + pxr/base/tf/pyWeakObject.cpp | 12 +++++++++--- + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/pxr/base/tf/pyFunction.h b/pxr/base/tf/pyFunction.h +index 85af943b2..f77b5b71b 100644 +--- a/pxr/base/tf/pyFunction.h ++++ b/pxr/base/tf/pyFunction.h +@@ -49,11 +49,13 @@ struct TfPyFunctionFromPython + using namespace pxr_boost::python; + // Attempt to get the referenced callable object. + TfPyLock lock; +- object callable(handle<>(borrowed(PyWeakref_GetObject(weak.ptr())))); +- if (TfPyIsNone(callable)) { ++ PyObject *rawCallable = NULL; ++ if (PyWeakref_GetRef(weak.ptr(), &rawCallable) <= 0) { + TF_WARN("Tried to call an expired python callback"); + return Ret(); + } ++ // PyWeakref_GetRef returns a strong reference; handle<> steals it. ++ object callable{handle<>(rawCallable)}; + return TfPyCall(callable)(args...); + } + }; +@@ -68,12 +70,15 @@ struct TfPyFunctionFromPython + // Attempt to get the referenced self parameter, then build a new + // instance method and call it. + TfPyLock lock; +- PyObject *self = PyWeakref_GetObject(weakSelf.ptr()); +- if (self == Py_None) { ++ PyObject *self = NULL; ++ if (PyWeakref_GetRef(weakSelf.ptr(), &self) <= 0) { + TF_WARN("Tried to call a method on an expired python instance"); + return Ret(); + } ++ // PyWeakref_GetRef returns a strong reference to self; PyMethod_New ++ // takes its own reference, so release ours afterward. + object method(handle<>(PyMethod_New(func.ptr(), self))); ++ Py_DECREF(self); + return TfPyCall(method)(args...); + } + }; +diff --git a/pxr/base/tf/pyIdentity.cpp b/pxr/base/tf/pyIdentity.cpp +index 5389d8f25..06b7f9b0c 100644 +--- a/pxr/base/tf/pyIdentity.cpp ++++ b/pxr/base/tf/pyIdentity.cpp +@@ -136,7 +136,15 @@ PyObject * + Tf_PyIdHandle::Ptr() const { + if (_weakRef) { + TfPyLock lock; +- return PyWeakref_GetObject(_weakRef); ++ PyObject *obj = NULL; ++ if (PyWeakref_GetRef(_weakRef, &obj) > 0) { ++ // Return a borrowed-style reference: decrement so the caller ++ // does not need to release. Safe because the GIL is held by ++ // all callers. ++ Py_DECREF(obj); ++ return obj; ++ } ++ return Py_None; // dead referent → match original behaviour + } + return 0; + } +diff --git a/pxr/base/tf/pyWeakObject.cpp b/pxr/base/tf/pyWeakObject.cpp +index 8cfddc729..ecdd7f705 100644 +--- a/pxr/base/tf/pyWeakObject.cpp ++++ b/pxr/base/tf/pyWeakObject.cpp +@@ -115,9 +115,15 @@ Tf_PyWeakObject::GetOrCreate(pxr_boost::python::object const &obj) + pxr_boost::python::object + Tf_PyWeakObject::GetObject() const + { +- return pxr_boost::python::object +- (pxr_boost::python::handle<> +- (pxr_boost::python::borrowed(PyWeakref_GetObject(_weakRef.get())))); ++ PyObject *obj = NULL; ++ if (PyWeakref_GetRef(_weakRef.get(), &obj) > 0) { ++ // PyWeakref_GetRef returns a strong reference; handle<> steals it. ++ return pxr_boost::python::object( ++ pxr_boost::python::handle<>(obj)); ++ } ++ // Dead referent: return Py_None explicitly, as the original did. ++ return pxr_boost::python::object( ++ pxr_boost::python::handle<>(pxr_boost::python::borrowed(Py_None))); + } + + void +-- +2.55.0 + diff --git a/usd.spec b/usd.spec index fc69879..05bcd6e 100644 --- a/usd.spec +++ b/usd.spec @@ -152,6 +152,14 @@ Patch: 0006-Downstream-only-use-the-system-libavif.patch # https://github.com/PixarAnimationStudios/OpenUSD/pull/3903 Patch: %{forgeurl}/pull/3903.patch +# Replace PyWeakref_GetObject with PyWeakref_GetRef +# Fixes RHBZ#2433881. This patch is LLM-generated and needs expert human +# review, but it at least builds. See discussion in +# https://bugzilla.redhat.com/show_bug.cgi?id=2433881. +# Mentioned upstream in +# https://github.com/PixarAnimationStudios/OpenUSD/issues/3966#issuecomment-5128542913. +Patch: 0001-Replace-PyWeakref_GetObject-with-PyWeakref_GetRef.patch + # Base BuildRequires: gcc-c++