crash - PySide crashing Python when emitting None between threads -


[edit] not pure duplicate of pyside emit signal causes python crash question. question relates (now) known bug in pyside preventing none being passed across threads. other question relates hooking signals spinner box. i've updated title of question better reflect problem facing. [/edit]

i've banged head against situation pyside behaves subtly different pyqt. well, subtly pyside crashes python whereas pyqt works expect.

under pyside app crashes

i'm new pyside , still new pyqt maybe i'm making basic mistake, damned if can figure out... hoping 1 of fine folks can give pointers!

the full app batch processing tool , cumbersome describe here, i've stripped problem down bare essentials in code-sample below:

import threading  try:     # raise importerror()  # uncomment line show pyqt works correctly     pyside import qtcore, qtgui except importerror:     pyqt4 import qtcore, qtgui     qtcore.signal = qtcore.pyqtsignal     qtcore.slot = qtcore.pyqtslot   class _threadsafecallbackhelper(qtcore.qobject):     finished = qtcore.signal(object)   def dummy():     print "ran dummy"     # return ''  # uncomment show pyside *not* crashing     return none   class batchprocessingwindow(qtgui.qmainwindow):     def __init__(self):         qtgui.qmainwindow.__init__(self, none)          btn = qtgui.qpushbutton('do it', self)         btn.clicked.connect(lambda: self._batchprocess())      def _batchprocess(self):         def postbatch():             pass         helper = _threadsafecallbackhelper()         helper.finished.connect(postbatch)          def cb():             res = dummy()             helper.finished.emit(res)  # `none` crashes python under pyside??!         t = threading.thread(target=cb)         t.start()   if __name__ == '__main__':  # pragma: no cover     app = qtgui.qapplication([])     batchprocessingwindow().show()     app.exec_() 

running displays window "do it" button. clicking crashes python if running under pyside. uncomment importerror on line 4 see pyqt* correctly run dummy function. or uncomment return statement on line 20 see pyside correctly run.

i don't understand why emitting none makes python/pyside fail badly?

the goal offload processing (whatever dummy does) thread, keeping main gui thread responsive. again has worked fine pyqt not pyside.

any , advice super appreciated.

this under:

    python 2.7 (r27:82525, jul  4 2010, 09:01:59) [msc v.1500 32 bit (intel)] on win32      >>> import pyside     >>> pyside.__version_info__     (1, 1, 0, 'final', 1)      >>> pyqt4 import qt     >>> qt.qversion()     '4.8.2' 

so, if argument pyside neglected , bug, might come workaround, right?

by introducing sentinel replace none, , emitting it problem can circumvented, sentinel has swapped none in callbacks , problem bypassed.

good grief though. i'll post code i've ended invite further comments, if got better alternatives or actual solutions give shout. in meantime guess this'll do:

_pyside_none_sentinel = object()   def pyside_none_wrap(var):     """none -> sentinel. wrap around out-of-thread emitting."""     if var none:         return _pyside_none_sentinel     return var   def pyside_none_deco(func):     """sentinel -> none. decorate callbacks react out-of-thread     signal emitting.      modifies function such sentinels passed in     transformed none.     """      def sentinel_guard(arg):         if arg _pyside_none_sentinel:             return none         return arg      def inner(*args, **kwargs):         newargs = map(sentinel_guard, args)         newkwargs = {k: sentinel_guard(v) k, v in kwargs.iteritems()}         return func(*newargs, **newkwargs)      return inner 

modifying original code arrive @ solution:

class _threadsafecallbackhelper(qtcore.qobject):     finished = qtcore.signal(object)   def dummy():     print "ran dummy"     return none   def _batchprocess():     @pyside_none_deco     def postbatch(result):         print "post batch result: %s" % result      helper = _threadsafecallbackhelper()     helper.finished.connect(postbatch)      def cb():         res = dummy()         helper.finished.emit(pyside_none_wrap(res))      t = threading.thread(target=cb)     t.start()   class batchprocessingwindow(qtgui.qdialog):     def __init__(self):         super(batchprocessingwindow, self).__init__(none)          btn = qtgui.qpushbutton('do it', self)         btn.clicked.connect(_batchprocess)   if __name__ == '__main__':  # pragma: no cover     app = qtgui.qapplication([])     window = batchprocessingwindow()     window.show()     sys.exit(app.exec_()) 

i doubt that'll win awards, seem fix issue.


Comments

Popular posts from this blog

how to proxy from https to http with lighttpd -

android - Automated my builds -

python - Flask migration error -