Search code examples
pythonpython-3.xpyqtpyqt5python-decorators

Python, reference class instance/method in decorated function


I'm having a hard time finding a way to reference class instances in a decorator function.

import json
import time
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from main_UI import Ui_ApplicationWindow
from slack import RTMClient

class WorkerThread(QThread):
  finished = pyqtSignal(str)   

  def __init__(self):
    QThread.__init__(self)  
    self.rtm_client = RTMClient(token="xoxp...") 

  def run(self):     
    self.rtm_client.start()

  @RTMClient.run_on(event="message")
  def say_hello(**payload):
    data = payload['data']
    if (len(data) != 0):
      if "text" in data:          
        text = data['text']         
        self.finished.emit(str(text))  


class ApplicationWindow(QMainWindow):

  def __init__(self):
    super(ApplicationWindow, self).__init__()
    self.ui = Ui_ApplicationWindow()
    self.ui.setupUi(self)   
    self.ui.pushButton.clicked.connect(self.start_rtm)      

  def start_rtm(self):
    self.thread = WorkerThread()
    self.thread.finished.connect(self.update)
    self.thread.start()

  @pyqtSlot(str)
  def update(self, data):
    self.ui.label.setText(data)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWindow = ApplicationWindow()
    myWindow.show()
    app.exec_()

So in say_hello since it can't take self as an argument, I'm not able to use self.finished.emit(text) at the end of the function.

How can I reference a class instance/function using self in say_hello?


Solution

  • No, You can not. Instead of using the @RTMClient.run_on() decorator, use the RTMClient.on() function to register it.

    import threading
    import asyncio
    
    from slack import RTMClient
    
    from PyQt5 import QtCore, QtWidgets
    
    
    class SlackClient(QtCore.QObject):
        textChanged = QtCore.pyqtSignal(str)
    
        def start(self):
            RTMClient.on(event="message", callback=self.say_hello)
            threading.Thread(target=self._start_loop, daemon=True).start()
    
        def _start_loop(self):
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            slack_token = "xoxb-...."
            rtm_client = RTMClient(token=slack_token)
            rtm_client.start()
    
        def say_hello(self, **payload):
            data = payload["data"]
            if data:
                if "text" in data:
                    text = data["text"]
                    self.textChanged.emit(text)
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
    
        client = SlackClient()
    
        button = QtWidgets.QPushButton("Start")
        textedit = QtWidgets.QPlainTextEdit()
    
        button.clicked.connect(client.start)
        client.textChanged.connect(textedit.appendPlainText)
    
        w = QtWidgets.QWidget()
        lay = QtWidgets.QVBoxLayout(w)
        lay.addWidget(button)
        lay.addWidget(textedit)
        w.show()
    
        sys.exit(app.exec_())
    

    Update:

    import sys
    import threading
    import asyncio
    
    from slack import RTMClient
    
    from PyQt5 import QtCore, QtWidgets
    from main_UI import Ui_ApplicationWindow
    
    
    class SlackClient(QtCore.QObject):
        textChanged = QtCore.pyqtSignal(str)
    
        def start(self):
            RTMClient.on(event="message", callback=self.say_hello)
            threading.Thread(target=self._start_loop, daemon=True).start()
    
        def _start_loop(self):
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            slack_token = "xoxb-...."
            rtm_client = RTMClient(token=slack_token)
            rtm_client.start()
    
        def say_hello(self, **payload):
            data = payload["data"]
            if data:
                if "text" in data:
                    text = data["text"]
                    self.textChanged.emit(text)
    
    
    class ApplicationWindow(QtWidgets.QMainWindow):
        def __init__(self):
            super(ApplicationWindow, self).__init__()
            self.ui = Ui_ApplicationWindow()
            self.ui.setupUi(self)
    
            self.client = SlackClient()
            # connections
            self.ui.pushButton.clicked.connect(self.client.start)
            self.client.textChanged.connect(self.ui.label.setText)
    
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        myWindow = ApplicationWindow()
        myWindow.show()
        sys.exit(app.exec_())