From 51636b43d90bc29996f3bbd8372f333eb1a321d0 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 24 Nov 2023 17:31:10 +0100 Subject: Enable connecting signals to slots with default parameters Find the number of default parameters using PyFunction_GetDefaults() and change the argCount() helper to return the min/max argument count. With that, try to match the slot using the most argument. [ChangeLog][PySide6] It is now possible to connect signals to slots/lambdas with more arguments provided they have default parameters. Fixes: PYSIDE-2524 Change-Id: I134d33e3ee78b62689fa36887a9acd41951c02e1 Reviewed-by: Qt CI Bot Reviewed-by: Shyamnath Premnadh --- sources/pyside6/libpyside/pysidesignal.cpp | 35 +++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 8 deletions(-) (limited to 'sources/pyside6/libpyside/pysidesignal.cpp') diff --git a/sources/pyside6/libpyside/pysidesignal.cpp b/sources/pyside6/libpyside/pysidesignal.cpp index 16e7b8411..0c6a23245 100644 --- a/sources/pyside6/libpyside/pysidesignal.cpp +++ b/sources/pyside6/libpyside/pysidesignal.cpp @@ -441,11 +441,25 @@ static FunctionArgumentsResult extractFunctionArgumentsFromSlot(PyObject *slot) return ret; } -static int argCount(const FunctionArgumentsResult &args) +struct ArgCount +{ + int min; + int max; +}; + +// Return a pair of minimum / arg count "foo(p1, p2=0)" -> {1, 2} +ArgCount argCount(const FunctionArgumentsResult &args) { Q_ASSERT(args.objCode); - return (PepCode_GET_FLAGS(args.objCode) & CO_VARARGS) != 0 - ? -1 : PepCode_GET_ARGCOUNT(args.objCode); + ArgCount result{-1, -1}; + if ((PepCode_GET_FLAGS(args.objCode) & CO_VARARGS) == 0) { + result.min = result.max = PepCode_GET_ARGCOUNT(args.objCode); + if (args.function != nullptr) { + if (auto *defaultArgs = PepFunction_GetDefaults(args.function)) + result.min -= PyTuple_Size(defaultArgs); + } + } + return result; } // Find Signal Instance for argument count. @@ -510,14 +524,19 @@ static PyObject *signalInstanceConnect(PyObject *self, PyObject *args, PyObject PySideSignalInstance *matchedSlot = nullptr; if (args.function != nullptr) { - qsizetype slotArgs = argCount(args); - if (args.isMethod) - slotArgs -= 1; + auto slotArgRange = argCount(args); + if (args.isMethod) { + slotArgRange.min -= 1; + slotArgRange.max -= 1; + } // Get signature args // Iterate the possible types of connection for this signal and compare // it with slot arguments - matchedSlot = findSignalInstance(source, slotArgs); + for (int slotArgs = slotArgRange.max; + slotArgs >= slotArgRange.min && matchedSlot == nullptr; --slotArgs) { + matchedSlot = findSignalInstance(source, slotArgs); + } } // Adding references to pyArgs @@ -1205,7 +1224,7 @@ QByteArray getCallbackSignature(const char *signal, QObject *receiver, qsizetype useSelf = slotArgs.isMethod ? 1 : 0; if (slotArgs.function != nullptr) { - numArgs = argCount(slotArgs); + numArgs = argCount(slotArgs).max; #ifdef PYPY_VERSION } else if (Py_TYPE(callback) == PepBuiltinMethod_TypePtr) { // PYSIDE-535: PyPy has a special builtin method that acts almost like PyCFunction. -- cgit v1.2.3