Skip to content

Instantly share code, notes, and snippets.

@cpascual
Created April 28, 2016 12:41
Show Gist options
  • Save cpascual/8a90d3464f1819807746812ee56b9319 to your computer and use it in GitHub Desktop.
Save cpascual/8a90d3464f1819807746812ee56b9319 to your computer and use it in GitHub Desktop.
Wrapper to work around signal and method conflicts
class SignalMethodWrapper(object):
"""Object that can act simultaneously as a pyqtBoundSignal and as a callable
method.
It optionally allows to log deprecation messages whe used as a signal
or as a method or both
"""
def __init__(self, pyqtboundsignal, method, alt_sig=None, alt_meth=None,
name='<wrapper>'):
"""
Init for the wrapper.
If alt_sig is passed, the usage of this wrapper as a signal will be
considered deprecated. Similarly for methods if alt_meth is passed.
:param pyqtboundsignal: signal to wrap
:param method: method to wrap
:param alt_sig: name of alternative signal to be suggested
:param alt_meth: name of alternative method to be suggested
:param name: name of the wrapper obj (only used for deprecation message)
"""
self._name = name
self._sig = pyqtboundsignal
self._meth = method
self._alt_sig = alt_sig
self._alt_meth = alt_meth
def __call__(self, *args, **kwargs):
if self._alt_meth:
from taurus.core.util.log import deprecated
deprecated(dep="%s method" % self._name, alt=self._alt_meth)
self._meth(*args, **kwargs)
def __getattr__(self, item):
if self._alt_sig:
from taurus.core.util.log import deprecated
deprecated(dep="%s signal" % self._name, alt=self._alt_sig)
return getattr(self._sig, item)
if __name__ == '__main__':
from taurus.external.qt import Qt
from taurus.qt.qtgui.application import TaurusApplication
import sys
app = TaurusApplication()
# Consider the following case:
# when using old-style signals, it is possible to
# have a MyObj class that uses a signal named "foo" *and* has a method
# named "foo".
# When converting to new-style signals , the signal becomes a member of the
# class and hence the name collides with the method.
#
# The solution is to rename *both* the signal and the method to some private
# names and then wrap the two of them in a SignalMethodWrapper object which
# is inserted as "foo"
class OldC(Qt.QObject):
"""Object using old-style signals"""
def foo(self, p):
print "OLD method _foo", p
def bar(self, p):
print "OLD method bar", p
def test(self):
# call the foo "method" directly
self.foo(1)
#connect the foo "signal" to the bar method
self.connect(self, Qt.SIGNAL('foo'), self.bar)
# connect the foo "signal" to the foo "method" !!!!
self.connect(self, Qt.SIGNAL('foo'), self.foo)
# emit "signal" foo
self.emit(Qt.SIGNAL('foo'), 2)
class NewC(Qt.QObject):
"""Refatored OldC using new-style signals and avooiding name conflict
with a SignalMethodWrapper"""
_fooSig = Qt.pyqtSignal(int)
def __init__(self):
Qt.QObject.__init__(self)
# monkey-patching injection of the fake signal
# note: it cannot be done at class level because C._fooSig is
# properly created only after instantiation of C
self.foo = SignalMethodWrapper(self._fooSig, self._fooMeth,
alt_meth='_foo', alt_sig='baz')
def _fooMeth(self, p):
print "NEW method foo", p
def bar(self, p):
print "NEW method bar", p
def test(self):
# call the foo "method" directly
self.foo(1)
#connect the foo "signal" to the bar method
self.foo.connect(self.bar)
# connect the foo "signal" to the foo "method" !!!!
self.foo.connect(self.foo)
# emit "signal" foo
self.foo.emit(2)
old = OldC()
new = NewC()
Qt.QTimer.singleShot(100, old.test)
Qt.QTimer.singleShot(200, new.test)
Qt.QTimer.singleShot(300, sys.exit)
sys.exit(app.exec_())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment