Use pythoncapi-compat to simplify Python C API backwards compatibility

This commit is contained in:
kb1000
2024-02-18 14:08:04 +01:00
committed by Baldur Karlsson
parent d0a24b31cd
commit bb7ec408cb
12 changed files with 1163 additions and 80 deletions
File diff suppressed because it is too large Load Diff
+6 -43
View File
@@ -29,7 +29,8 @@
// must be included first
#include <Python.h>
#include <frameobject.h>
#include "3rdparty/pythoncapi_compat.h"
#ifdef slots_was_defined
#define slots
@@ -72,43 +73,6 @@ PyTypeObject **SbkPySide2_QtWidgetsTypes = NULL;
#include "PythonContext.h"
#include "version.h"
// helpers for new PyFrameObject accessors in newer python versions, that are required starting from
// python 3.11
#if PY_VERSION_HEX < 0x030B0000
// Get the frame's f_globals attribute.
// Return a strong reference
PyObject *PyFrame_GetGlobals(PyFrameObject *frame)
{
PyObject *ret = frame->f_globals;
Py_XINCREF(ret);
return ret;
}
#endif
#if PY_VERSION_HEX < 0x03090000
// Get the frame next outer frame.
// Return a strong reference
PyFrameObject *PyFrame_GetBack(PyFrameObject *frame)
{
PyFrameObject *ret = frame->f_back;
Py_XINCREF(ret);
return ret;
}
// Get the frame code.
// Return a strong reference
PyCodeObject *PyFrame_GetCode(PyFrameObject *frame)
{
PyCodeObject *ret = frame->f_code;
Py_XINCREF(ret);
return ret;
}
#endif
// exported by generated files, used to check interface compliance
bool CheckCoreInterface(rdcstr &log);
bool CheckQtInterface(rdcstr &log);
@@ -883,8 +847,7 @@ void PythonContext::ConvertPyArgs(const ExtensionCallbackData &data,
if(!out)
{
qCritical() << "Couldn't convert" << in << "to python object";
out = Py_None;
Py_XINCREF(out);
out = Py_XNewRef(Py_None);
}
}
@@ -1063,7 +1026,7 @@ QWidget *PythonContext::QWidgetFromPy(PyObject *widget)
if(!initialised())
return NULL;
if(widget == Py_None || widget == NULL)
if(Py_IsNone(widget) || widget == NULL)
return NULL;
if(!SbkPySide2_QtCoreTypes || !SbkPySide2_QtGuiTypes || !SbkPySide2_QtWidgetsTypes)
@@ -1098,7 +1061,7 @@ QStringList PythonContext::completionOptions(QString base)
{
opt = PyObject_CallFunction(completeFunction, "si", input, idx);
if(opt && opt != Py_None)
if(opt && !Py_IsNone(opt))
{
QString optstr = ToQStr(opt);
@@ -1114,7 +1077,7 @@ QStringList PythonContext::completionOptions(QString base)
}
idx++;
} while(opt && opt != Py_None);
} while(opt && !Py_IsNone(opt));
// extra hack, remove the swig object functions/data but ONLY if we find a sure-fire identifier
// (thisown) since otherwise we could remove append from a list object
@@ -273,8 +273,7 @@ PyObject *selfconcat_##unique_name(PyObject *self, PyObject *vals)
if(ret)
{
Py_DECREF(ret);
Py_INCREF(self);
return self;
return Py_NewRef(self);
}
return NULL;
@@ -292,8 +291,7 @@ PyObject *selfrepeat_##unique_name(PyObject *self, Py_ssize_t count)
if(ret)
{
Py_DECREF(ret);
Py_INCREF(self);
return self;
return Py_NewRef(self);
}
return NULL;
+4 -5
View File
@@ -1,4 +1,3 @@
%feature("python:tp_str") ResultDetails "result_str";
%feature("python:tp_repr") ResultDetails "result_str";
@@ -18,7 +17,7 @@ PyObject *__lt__(PyObject *other)
void *resptr = NULL;
ResourceId *id = NULL;
if(other && other != Py_None)
if(other && !Py_IsNone(other))
{
int res = SWIG_ConvertPtr(other, &resptr, SWIGTYPE_p_ResourceId, 0);
if (!SWIG_IsOK(res)) {
@@ -125,7 +124,7 @@ PyObject *__eq__(PyObject *other)
void *resptr = NULL;
Class *id = NULL;
if(other && other != Py_None)
if(other && !Py_IsNone(other))
{
int res = SWIG_ConvertPtr(other, &resptr, SWIGTYPE_p_##Class, 0);
if (!SWIG_IsOK(res)) {
@@ -148,7 +147,7 @@ PyObject *__ne__(PyObject *other)
void *resptr = NULL;
Class *id = NULL;
if(other && other != Py_None)
if(other && !Py_IsNone(other))
{
int res = SWIG_ConvertPtr(other, &resptr, SWIGTYPE_p_##Class, 0);
if (!SWIG_IsOK(res)) {
@@ -202,4 +201,4 @@ DEFINE_SAFE_EQUALITY(ColorBlend)
DEFINE_SAFE_EQUALITY(BoundVBuffer)
DEFINE_SAFE_EQUALITY(VertexInputAttribute)
DEFINE_SAFE_EQUALITY(BoundResource)
DEFINE_SAFE_EQUALITY(BoundResourceArray)
DEFINE_SAFE_EQUALITY(BoundResourceArray)
+1 -1
View File
@@ -38,7 +38,7 @@ static int typeName##_init(PyObject *self, PyObject *args)
PyObject *resultobj = SWIG_NewPointerObj((void *)result, SWIGTYPE_p_##typeName, SWIG_BUILTIN_INIT);
if(resultobj == Py_None)
if(Py_IsNone(resultobj))
{
delete result;
return -1;
@@ -26,6 +26,8 @@
#include <atomic>
#include "3rdparty/pythoncapi_compat.h"
// this is defined elsewhere for managing the opaque global_handle object
extern "C" PyThreadState *GetExecutingThreadState(PyObject *global_handle);
extern "C" PyObject *GetCurrentGlobalHandle();
@@ -178,11 +180,7 @@ inline void get_return(const char *funcname, PyObject *result, PyObject *global_
struct PyObjectRefCounter
{
PyObjectRefCounter(PyObject *o) : obj(o) { Py_INCREF(obj); }
PyObjectRefCounter(const PyObjectRefCounter &o)
{
obj = o.obj;
Py_INCREF(obj);
}
PyObjectRefCounter(const PyObjectRefCounter &o) { obj = Py_NewRef(o.obj); }
~PyObjectRefCounter()
{
// it may not be safe at the point this is destroyed to decref the object. For example if a
@@ -269,8 +267,7 @@ struct ScopedFuncCall
{
ScopedFuncCall(PyObject *h)
{
handle = h;
Py_XINCREF(handle);
handle = Py_XNewRef(h);
gil = PyGILState_Ensure();
}
@@ -288,7 +285,7 @@ template <typename funcType>
funcType ConvertFunc(const char *funcname, PyObject *func, ExceptionHandler exHandle)
{
// allow None to indicate no callback
if(func == Py_None)
if(Py_IsNone(func))
return funcType();
// add a reference to the global object so it stays alive while we execute, in case this is an
@@ -208,7 +208,7 @@ inline bool check_interface(rdcstr &log, swig_type_info **swig_types, size_t num
}
// if it's a callable it's a method, ignore it
if(!PyCallable_Check(value) && !PyType_IsSubtype(value->ob_type, &PyStaticMethod_Type))
if(!PyCallable_Check(value) && !PyType_IsSubtype(Py_TYPE(value), &PyStaticMethod_Type))
{
// some hardcoded exclusions that we allow to break the naming scheme
if(typeName == "KnownShaderTool")
+5 -8
View File
@@ -28,6 +28,8 @@
#include <map>
#include <type_traits>
#include "3rdparty/pythoncapi_compat.h"
// struct to allow partial specialisation for enums
template <typename T, bool isEnum = std::is_enum<T>::value>
struct TypeConversion
@@ -79,17 +81,12 @@ struct TypeConversion<PyObject *, false>
{
static int ConvertFromPy(PyObject *in, PyObject *&out)
{
out = in;
Py_XINCREF(out);
out = Py_XNewRef(in);
return 0;
}
static PyObject *ConvertToPy(PyObject *in)
{
Py_XINCREF(in);
return in;
}
static PyObject *ConvertToPy(PyObject *in) { return Py_XNewRef(in); }
};
// specialisations for pointer types (opaque handles to be moved not copied)
@@ -143,7 +140,7 @@ struct TypeConversion<bool, false>
if(!PyBool_Check(in))
return SWIG_TypeError;
if(in == Py_True)
if(Py_IsTrue(in))
out = true;
else
out = false;
+9 -4
View File
@@ -1,3 +1,4 @@
%module(docstring="This is the API to QRenderDoc's high-level UI panels and functionality.") qrenderdoc
%feature("autodoc", "0");
@@ -8,6 +9,10 @@
#define DOCUMENT3(text1, text2, text3) %feature("docstring") text1 text2 text3
#define DOCUMENT4(text1, text2, text3, text4) %feature("docstring") text1 text2 text3 text4
%header %{
#include "3rdparty/pythoncapi_compat.h"
%}
%begin %{
#undef slots
@@ -51,11 +56,11 @@ TEMPLATE_FIXEDARRAY_DECLARE(rdcfixedarray);
%}
%typemap(in) QWidget * {
if($input == Py_None)
if(Py_IsNone($input))
$1 = NULL;
else
$1 = QWidgetFromPy($input);
if($input && $input != Py_None && !$1)
if($input && !Py_IsNone($input) && !$1)
{
SWIG_exception_fail(SWIG_TypeError, "in method '$symname' QWidget expected for argument $argnum of type '$1_basetype'");
}
@@ -125,7 +130,7 @@ TEMPLATE_FIXEDARRAY_DECLARE(rdcfixedarray);
result = new PythonCaptureViewer(self);
resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ICaptureViewer, SWIG_BUILTIN_INIT | 0);
return resultobj == Py_None ? -1 : 0;
return Py_IsNone(resultobj) ? -1 : 0;
}
SWIGINTERN PyObject *capviewer_deinit(PyObject *self, PyObject *args)
@@ -260,4 +265,4 @@ QWidget *UnwrapBareQWidget(PyObject *obj)
return ret;
}
%}
%}
+7 -3
View File
@@ -20,6 +20,10 @@
#define DOCUMENT3(text1, text2, text3) %feature("docstring") text1 text2 text3
#define DOCUMENT4(text1, text2, text3, text4) %feature("docstring") text1 text2 text3 text4
%header %{
#include "3rdparty/pythoncapi_compat.h"
%}
// include header for typed enums (hopefully using PEP435 enums)
%include <enums.swg>
@@ -470,9 +474,9 @@ extern "C" PyObject *RENDERDOC_DumpObject(PyObject *obj)
void *resptr = NULL;
// for basic types, return the repr directly
if(obj == Py_True ||
obj == Py_False ||
obj == Py_None ||
if(Py_IsTrue(obj) ||
Py_IsFalse(obj) ||
Py_IsNone(obj) ||
PyObject_IsInstance(obj, (PyObject*)&PyFloat_Type) ||
PyObject_IsInstance(obj, (PyObject*)&PyLong_Type) ||
PyObject_IsInstance(obj, (PyObject*)&PyBytes_Type) ||
@@ -24,6 +24,8 @@
#pragma once
#include "3rdparty/pythoncapi_compat.h"
template <typename objType>
inline std::map<const objType *, PyObject *> &obj2py();
@@ -263,7 +265,7 @@ struct TypeConversion<StructuredBufferList, false>
for(int i = 0; i < out.count(); i++)
{
PyObject *elem = PyList_GetItem(in, i);
if(elem == Py_None)
if(Py_IsNone(elem))
{
out[i] = NULL;
}
@@ -389,7 +391,7 @@ struct TypeConversion<StructuredObjectList, false>
for(int i = 0; i < out.count(); i++)
{
PyObject *elem = PyList_GetItem(in, i);
if(elem == Py_None)
if(Py_IsNone(elem))
{
out[i] = NULL;
}
@@ -535,7 +537,7 @@ struct TypeConversion<StructuredChunkList, false>
for(int i = 0; i < out.count(); i++)
{
PyObject *elem = PyList_GetItem(in, i);
if(elem == Py_None)
if(Py_IsNone(elem))
{
out[i] = NULL;
}
+4
View File
@@ -399,6 +399,10 @@ HEADERS += 3rdparty/toolwindowmanager/ToolWindowManager.h \
SOURCES += 3rdparty/flowlayout/FlowLayout.cpp
HEADERS += 3rdparty/flowlayout/FlowLayout.h
# Add pythoncapi-compat
HEADERS += 3rdparty/pythoncapi_compat.h
# Add Scintilla last as it has extra search paths
# Needed for building