PySide Bugzilla Closed for New Bugs

PySide is now a Qt Add-on and uses the Qt Project's JIRA Bug Tracker instead of this Bugzilla instance. This Bugzilla is left for reference purposes.

Bug 312 - Limit of 50 on dynamic slots
: Limit of 50 on dynamic slots
Status: CLOSED FIXED
Product: PySide
Classification: Unclassified
Component: QtCore
: HEAD
: Other Linux
: P4 enhancement
Assigned To: renato filho
:
:
:
  Show dependency treegraph
 
Reported: 2010-08-24 13:15 EEST by Mikael
Modified: 2011-05-26 17:03 EEST (History)
10 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Mikael 2010-08-24 13:15:09 EEST
Created an application that creates 50 buttons in a list.

Get the following error 7 times:
Fail to add dynamic slot to QObject. PySide support at most 50 dynamic slots.

(Presumably there are 7 other dynamic slots defined earlier in the
application.)

Buttons at the start of the list work, last 7 do not (Segmentation fault).

Limit of 50 seems arbitrary and not sufficient for "real" applications. Suggest
implementation without a set limit.

Workaround exists for this specific case: re-implement using a list.
Comment 1 renato filho 2010-09-15 11:10:34 EEST
The current Qt implementation of metaobject does not allow create a metaobject
with unlimited signals and slots.

Then we implement a dynamic metaobject which support 50 signals and slots, with
 this you can create a QObject and add  up to 50 dynamic signals and others 50
dynamic slots, these is enough to the most of the applications.

The problem you describe here, can be caused because we use only one QObject
(called globalreceiver) to handle all anonymous connections (connections which
is not done with other QObject SLOT, like python functions, lambda functions),
and this implementation only allow 50 anonymous connections. To fix this for
now,  we expand the capacity of global receiver up to 500 dynamics slots, for
now I think this will be enough to any application. We are study a better way
to fix this but this can break the API and we are trying avoid that until to
version 1.0.

I hope this can solve your problem for now, the fix for this was upload to
PySide git on commit:


commit 42f917666904f4eb93002eae2de70d1f225f438f
Author: renatofilho <renato.filho@openbossa.org>
Date:   Tue Sep 14 13:03:39 2010 -0300

Please fell free to comment about that and send  me any example with still
broken after this commit.
Comment 2 Mikael 2010-09-16 00:07:00 EEST
Thanks for a thorough coverage of the issue, even though my Python mindset
cannot really grasp why there is this limitation in the first place.

What's still a bit unclear to me is that in the following scenario:
- shove 50 emails as buttons and connecting their clicked signals to a custom
action
- list is recreated to show latest, updated list of emails whenever there are
new emails
- User can flip through pages of 50 emails to find older emails

Are the dynamic slot spots reused effectively, or does the scenario above
quickly saturate the 500 slots available?
Comment 3 renato filho 2010-09-16 17:14:18 EEST
Now I understand your problem.

I created a unit test for this case, you can check this on:
http://qt.gitorious.org/pyside/pyside/blobs/master/tests/signals/bug_312.py


But after created the unit test I found a bug on disconnection cleanup, I fixed
the bug on PySide commit:

commit 551f6b9c7240d1f68e50edcec0fc41969beaef1d
Author: renatofilho <renato.filho@openbossa.org>
Date:   Thu Sep 16 14:14:45 2010 -0300


In others words, if you connect 50 signals for each message, then when you move
to another page, if you disconnect the signal or destroy the sender object,
these signals will be deallocated and will be available again.

Only avoid have more then 500 anonymous signals connected at the same time.
Comment 4 Mikael 2010-09-17 04:18:09 EEST
Thanks for your hard work.

Does this mean I would need to explicitly destroy the source objects, or is it
enough to "forget about them" i.e. not keep the references? I am worried that
Qt often takes ownership of objects and might not release them. On the other
hand, being forced to be diligent in destroying stuff is not very pythonic.
Comment 5 renato filho 2010-09-17 11:32:04 EEST
If all references to the object was released the object will be destroyed and
the signal disconnected.You do not need explicitly destroy the object.
Comment 6 renato filho 2010-10-18 13:19:44 EEST
changed Importacne to enhancemnt this will be fixed after 1.0
Comment 7 Matti Airas 2010-11-22 15:28:28 EET
Increasing priority to P4. But definitely still post-1.0 stuff. :-)
Comment 8 Matti Airas 2011-03-31 11:31:12 EEST
This was deprioritized to P4 because the bug was regarded as post-1.0 material.
Now that 1.0 has been published for one month already, I'd like to see this
bumped to P3.
Comment 9 Anton Chikin 2011-05-04 16:09:15 EEST
Hi Renato,

I've come across the same issue today.
The message in the output is : 
Fail to add dynamic slot to QObject. PySide support at most 50 dynamic slots.

I am not completely sure where it comes from, investigating now, but are you
sure you've changed the number to 500?
Comment 10 renato filho 2011-05-04 16:18:43 EEST
Hi Aton,

The current situation is that:

PySide support 50 dynamic slots, and 50 dynamic signals for each QObject, and
500 dynamic slots and 500 dynamic signals for global object used when you
connect any QSignal to a python function. Something like that:

myObject.mysignal.connect(pythonFunction)
Comment 11 Anton Chikin 2011-05-04 17:28:24 EEST
Renato,

I've found the place which causes the issue. It is a function with 57 lines
like this : 
QtCore.QObject.connect(self.someAction1, QtCore.SIGNAL("triggered()"),
self.someFunc1)
QtCore.QObject.connect(self.someAction2, QtCore.SIGNAL("triggered()"),
self.someFunc2)
...
I've tried to use new connecting syntax:
self.someAction1.triggered.connect(self.someFunc1)
but it still complains 7 times after 50-th connection.
Comment 12 renato filho 2011-05-04 19:29:31 EEST
Could you send a minimal running example with this bug?

Thanks
Comment 13 Anton Chikin 2011-05-05 00:14:15 EEST
(In reply to comment #12)
> Could you send a minimal running example with this bug?
> 
> Thanks

I've created a sample. Everything is fine with PySide. Somebody put 57 slots in
a single class. Realy huge and bad designed. Sorry.
Comment 14 Luke 2011-05-06 01:03:08 EEST
I am working on porting a large, modular application and have hit the 500
dynamic slot limit, presumably on globalreceiver. Is there a temporary
workaround we could use until a better solution is implemented? 

Perhaps increase the limit on globalreceiver to, say, 50k (Would there be a
performance hit for this?) or just allow the limit to be changed at runtime?
Comment 15 renato filho 2011-05-06 01:11:58 EEST
The big problem here is impossible to change the limit on runtime, for some
problems with Qt way of register slots/signals.

If you want you can change the limit by yourself changing the const
"MAX_GLOBAL_SIGNALS_COUNT" inside of libpyside/dynamicqmetaobject.cpp.


We are trying to find out the best way to fix that, but none solution popped up
yet.
Comment 16 Luke 2011-05-06 01:15:36 EEST
Ok, thanks Renato.
I feel silly making ignorant suggestions, but: why not just create a new
receiver object for each anonymous connection?
Comment 17 renato filho 2011-05-06 15:41:13 EEST
Only question of memory consumption (but this is an alternative).
Comment 18 renato filho 2011-05-11 16:26:17 EEST
The problem was fixed, finally :D

We have discussed with the Qt guys, and finally we found a good solution for
that using a old QMetaObject protocol.

fixed on pyside commit:

commit 78e120ec02e331c6561c3e5e9c63ab0e2dce1aa1
Author: Renato Filho <renato.filho@openbossa.org>
Date:   Tue May 10 16:42:32 2011 -0300
Comment 19 Anton Chikin 2011-05-11 17:14:32 EEST
Woo-hoo! Thank you, guys!
Comment 20 renato filho 2011-05-26 17:03:50 EEST
PySide release 1.0.3