@@ -341,68 +341,114 @@ PyObject *PythonQtMemberFunction_Call(PythonQtSlotInfo* info, PyObject* m_self,
341341
342342PyObject *PythonQtSlotFunction_CallImpl (PythonQtClassInfo* classInfo, QObject* objectToCall, PythonQtSlotInfo* info, PyObject *args, PyObject * kw, void * firstArg, void ** directReturnValuePointer, PythonQtPassThisOwnershipType* passThisOwnershipToCPP)
343343{
344- if (kw != NULL && PyDict_Check (kw) && (PyDict_Size (kw) > 0 )) {
345- QString e = QString (" Calling C++ functions with Python keywords is not supported! Function: " ) + info->fullSignature (true ) + " Keywords: " + PythonQtConv::PyObjGetString (kw);
346- PyErr_SetString (PyExc_ValueError, e.toLatin1 ().data ());
347- return NULL ;
348- }
349-
350344 int argc = args?PyTuple_Size (args):0 ;
345+
351346 if (passThisOwnershipToCPP) {
352347 *passThisOwnershipToCPP = IgnoreOwnership;
353348 }
354349
355- #ifdef PYTHONQT_DEBUG
356- std::cout << " called " << info->metaMethod ()->typeName () << " " << info->signature () << std::endl;
357- #endif
358-
359350 PyObject* r = NULL ;
360351 bool ok = false ;
352+
361353 if (directReturnValuePointer) {
362354 *directReturnValuePointer = NULL ;
363355 }
364- if (info->nextInfo ()) {
365- // overloaded slot call, try on all slots with strict conversion first
366- bool strict = true ;
367- PythonQtSlotInfo* i = info;
368- while (i) {
369- bool skipFirst = i->isInstanceDecorator ();
370- if (i->parameterCount ()-1 -(skipFirst?1 :0 ) == argc) {
371- PyErr_Clear ();
372- ok = PythonQtCallSlot (classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer, passThisOwnershipToCPP);
373- if (PyErr_Occurred () || ok) break ;
356+
357+ if ( (kw != NULL && PyDict_Check (kw) && (PyDict_Size (kw) > 0 )) ) {
358+ // -------------------keyword args slot call -------------------------
359+
360+ // keyword arguments are given as dict, must be mapped to arguments in correct order
361+ // very complicated, so call them only on a slot with last variable name kwargs
362+ // slot must be implemented as
363+ // <type> <name>(any number of positional arguments, QVariantMap kwargs)
364+ int numCombinedArgs = argc + 1 ;
365+ PyObject* combinedArgs = PyTuple_New (numCombinedArgs);
366+
367+ for (int i = 0 ; i<argc; i++) {
368+ PyObject* p = PyTuple_GetItem (args,i);
369+ Py_INCREF (p);
370+ PyTuple_SetItem (combinedArgs,i,p);
371+ }
372+
373+ Py_INCREF (kw);
374+ PyTuple_SetItem (combinedArgs, numCombinedArgs - 1 , kw);
375+
376+ bool kwSlotFound = false ;
377+
378+ QList<QByteArray> parameterNames;
379+ PythonQtSlotInfo* slotInfo = info;
380+ static QByteArray kwargs = " kwargs" ;
381+ while (slotInfo) {
382+ parameterNames = slotInfo->metaMethod ()->parameterNames ();
383+ if (!parameterNames.isEmpty () && (parameterNames.last ().constData () == kwargs)) {
384+ kwSlotFound = true ;
385+ break ;
374386 }
375- i = i->nextInfo ();
376- if (!i) {
377- if (strict) {
378- // one more run without being strict
379- strict = false ;
380- i = info;
381- }
387+ }
388+ if (kwSlotFound) {
389+ #ifdef PYTHONQT_DEBUG
390+ std::cout << " called " << slotInfo->metaMethod ()->typeName () << " " << slotInfo->signature ().constData () << std::endl;
391+ #endif
392+
393+ ok = PythonQtCallSlot (classInfo, objectToCall, combinedArgs, false , slotInfo, firstArg, &r, directReturnValuePointer, passThisOwnershipToCPP);
394+ if (!ok && !PyErr_Occurred ()) {
395+ QString e = QString (" Called " ) + info->fullSignature () + " with wrong arguments: " + PythonQtConv::PyObjGetString (args);
396+ PyErr_SetString (PyExc_ValueError, e.toLatin1 ().data ());
382397 }
398+ } else {
399+ QString e = QString (" Called " ) + info->fullSignature () + " with keyword arguments, but called slot does not support kwargs." ;
400+ PyErr_SetString (PyExc_ValueError, e.toLatin1 ().data ());
383401 }
384- if (!ok && !PyErr_Occurred ()) {
385- QString e = QString (" Could not find matching overload for given arguments:\n " + PythonQtConv::PyObjGetString (args) + " \n The following slots are available:\n " );
402+
403+ Py_DECREF (combinedArgs);
404+ } else {
405+ // -------------------Normal slot call -------------------------
406+ if (info->nextInfo ()) {
407+ // overloaded slot call, try on all slots with strict conversion first
408+ bool strict = true ;
386409 PythonQtSlotInfo* i = info;
387410 while (i) {
388- e += QString (i->fullSignature ()) + " \n " ;
411+ bool skipFirst = i->isInstanceDecorator ();
412+ if (i->parameterCount ()-1 -(skipFirst?1 :0 ) == argc) {
413+ PyErr_Clear ();
414+ ok = PythonQtCallSlot (classInfo, objectToCall, args, strict, i, firstArg, &r, directReturnValuePointer, passThisOwnershipToCPP);
415+ if (PyErr_Occurred () || ok) break ;
416+ }
389417 i = i->nextInfo ();
418+ if (!i) {
419+ if (strict) {
420+ // one more run without being strict
421+ strict = false ;
422+ i = info;
423+ }
424+ }
390425 }
391- PyErr_SetString (PyExc_ValueError, e.toLatin1 ().data ());
392- }
393- } else {
394- // simple (non-overloaded) slot call
395- bool skipFirst = info->isInstanceDecorator ();
396- if (info->parameterCount ()-1 -(skipFirst?1 :0 ) == argc) {
397- PyErr_Clear ();
398- ok = PythonQtCallSlot (classInfo, objectToCall, args, false , info, firstArg, &r, directReturnValuePointer, passThisOwnershipToCPP);
399426 if (!ok && !PyErr_Occurred ()) {
400- QString e = QString (" Called " ) + info->fullSignature () + " with wrong arguments: " + PythonQtConv::PyObjGetString (args);
427+ QString e = QString (" Could not find matching overload for given arguments:\n " + PythonQtConv::PyObjGetString (args) + " \n The following slots are available:\n " );
428+ PythonQtSlotInfo* i = info;
429+ while (i) {
430+ e += QString (i->fullSignature ()) + " \n " ;
431+ i = i->nextInfo ();
432+ }
401433 PyErr_SetString (PyExc_ValueError, e.toLatin1 ().data ());
402434 }
403435 } else {
404- QString e = QString (" Called " ) + info->fullSignature () + " with wrong number of arguments: " + PythonQtConv::PyObjGetString (args);
405- PyErr_SetString (PyExc_ValueError, e.toLatin1 ().data ());
436+ // simple (non-overloaded) slot call
437+ bool skipFirst = info->isInstanceDecorator ();
438+ if (info->parameterCount ()-1 -(skipFirst?1 :0 ) == argc) {
439+ PyErr_Clear ();
440+ #ifdef PYTHONQT_DEBUG
441+ std::cout << " called " << info->metaMethod ()->typeName () << " " << info->signature ().constData () << std::endl;
442+ #endif
443+ ok = PythonQtCallSlot (classInfo, objectToCall, args, false , info, firstArg, &r, directReturnValuePointer, passThisOwnershipToCPP);
444+ if (!ok && !PyErr_Occurred ()) {
445+ QString e = QString (" Called " ) + info->fullSignature () + " with wrong arguments: " + PythonQtConv::PyObjGetString (args);
446+ PyErr_SetString (PyExc_ValueError, e.toLatin1 ().data ());
447+ }
448+ } else {
449+ QString e = QString (" Called " ) + info->fullSignature () + " with wrong number of arguments: " + PythonQtConv::PyObjGetString (args);
450+ PyErr_SetString (PyExc_ValueError, e.toLatin1 ().data ());
451+ }
406452 }
407453 }
408454
@@ -734,7 +780,7 @@ static PyObject*
734780meth_richcompare (PythonQtSlotFunctionObject *a, PythonQtSlotFunctionObject *b, int op)
735781{
736782 int x = meth_compare (a, b);
737- bool r;
783+ bool r = false ;
738784 if (op == Py_LT)
739785 r = x < 0 ;
740786 else if (op == Py_LE)
0 commit comments