Wednesday 15 January 2014

python - Strange behavior using PyQt4's 'pyqtSlot' decorator before another decorator -



python - Strange behavior using PyQt4's 'pyqtSlot' decorator before another decorator -

i have unusual problem using qtcore.pyqtslot decorator in front end of function decorated different decorator. problem below demonstrates problem. instantiates minimalistic qt programme single button. on pressing button, next happens:

(1) signals 'signal_a' , 'signal_b' connected instances method_a , method_b, respectively.

(2) signal_a , signal_b signals emitted.

(3) expected behavior method_a , method_b executed. however, turns out both signal_a , signal_b trigger method_a, or method_b (oddly, nondeterministic, , different each run of program!).

this appears bug.

the issue nowadays when using pyqt4 bindings qt. not nowadays when using pyside (use '--pyside' parameter verify). have seen problem both in python 2 , 3, , both in windows , linux.

the issue appears related insertion of decorator between '@qtslot' , method definition. 'null_decorator' in test programme should nil (if understanding of decorators correct), behavior of programme changes when remove it.

any help in understanding going on here appreciated.

#! /usr/bin/env python3 import sys, time if "--pyside" not in sys.argv: # default pyqt4 bindings pyqt4 import qtcore, qtgui qtsignal = qtcore.pyqtsignal qtslot = qtcore.pyqtslot else: # alternatively, utilize pyside bindings pyside import qtcore, qtgui qtsignal = qtcore.signal qtslot = qtcore.slot def null_decorator(f): def null_decorator_wrapper(self, *args, **kwargs): homecoming f(self, *args, **kwargs) homecoming null_decorator_wrapper class testclass(qtcore.qobject): def __init__(self, *args, **kwargs): super(testclass, self).__init__(*args, **kwargs) @qtslot() @null_decorator def method_a(self): print("method_a() executing!") @qtslot() @null_decorator def method_b(self): print("method_b() executing!") class demonstrateproblembutton(qtgui.qpushbutton): signal_a = qtsignal() signal_b = qtsignal() def __init__(self, *args, **kwargs): super(demonstrateproblembutton, self).__init__(*args, **kwargs) self.clicked.connect(self.on_clicked) @qtslot() def on_clicked(self): # create testclass instance instance = testclass() # connect signals self.signal_a.connect(instance.method_a) self.signal_b.connect(instance.method_b) # emit signals self.signal_a.emit() self.signal_b.emit() def main(): # instantiate gui application app = qtgui.qapplication(sys.argv) button = demonstrateproblembutton("demonstrate problem") button.show() homecoming qtgui.qapplication.exec_() if __name__ == "__main__": exitcode = main() sys.exit(exitcode)

using null_decorator result in slots having same name (i.e. "null_decorator_wrapper"), , pyqt may not able distinguish between them.

there several ways prepare in example.

firstly, ensure slots have different signatures:

@qtslot() @null_decorator def method_a(self): print("method_a() executing!") @qtslot(int) @null_decorator def method_b(self, foo=0): print("method_b() executing!")

secondly, explicitly specify slot names:

@qtslot(name="method_a") @null_decorator def method_a(self): print("method_a() executing!") @qtslot(name="method_b") @null_decorator def method_b(self, foo=0): print("method_b() executing!")

thirdly, automagically set name in null_decorator:

def null_decorator(f): def null_decorator_wrapper(self, *args, **kwargs): homecoming f(self, *args, **kwargs) null_decorator_wrapper.__name__ = f.__name__ homecoming null_decorator_wrapper

ps: behaviour of pyqtslot decorator stated in pyqt docs (in particular, see description of name parameter), , not bug.

python qt pyqt4 decorator slots

No comments:

Post a Comment