Search code examples
pythonmultithreadingpysidesignals-slotsqthread

Python + Pyside + QThreads emit signal and segmentation fault


Hello I'm new in python and PySide, and after hours of research I'm try to develop a simple GUI to show some data from API service.

I program is "simple", I implemented Qthread and have worker thread that make the request to api and emits signal to Main thread with QObject as argument.

The main thread receives the signal and update the GUI.

The problem is i have segmentation fault error when run the program.

Before implement the api request i try simple pass a number as string and works perfectly.

I think my error comes when my main thread try to access the GObject and my worker thread also try to access that object.

Heres my code:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
from PySide import QtGui
from PySide import QtCore
import urllib2
import json
import datetime
import time
from termcolor import colored
from blessings import Terminal


class MySig(QtCore.QObject):
    sig = QtCore.Signal(QtCore.QObject)

class MyThread(QtCore.QThread):

    def __init__(self, parent=None):
        QtCore.QThread.__init__(self, parent)
        self.exiting = 10
        self.signal = MySig()


    def callAping(self, jsonrpc_req):
        url = "https://api.betfair.com/exchange/betting/json-rpc/v1"
        headers = { 'X-Application' : '***********', 'X-Authentication' : '**************************' ,'content-type' : 'application/json' }
        try:
            req = urllib2.Request(url, jsonrpc_req, headers)
            response = urllib2.urlopen(req)
            jsonResponse = response.read()
            return jsonResponse
        except urllib2.URLError:
            print 'Oops no service available at ' + str(url)
            exit()
        except urllib2.HTTPError:
            print 'Oops not a valid operation from the service ' + str(url)
            exit()

    def getMarketBookBestOffers(self):

        marketId = "1.116260985"
        market_book_req = '{"jsonrpc": "2.0", "method": "SportsAPING/v1.0/listMarketBook", "params": {"marketIds":["' + marketId + '"],"priceProjection":{"priceData":["EX_BEST_OFFERS"]}}, "id": 1}'
        """
        print  market_book_req
        """
        market_book_response = self.callAping(market_book_req)
        """
        print market_book_response
        """
        market_book_loads = json.loads(market_book_response)
        try:
            market_book_result = market_book_loads['result']
            return market_book_result
        except:
            print  'Exception from API-NG' + str(market_book_result['error'])
            exit()


    def run(self):
        while True:
            market_book_result = self.getMarketBookBestOffers()
            self.signal.sig.emit(market_book_result)
            time.sleep(0.5)


class Example(QtGui.QWidget):

    def __init__(self):
        super(Example, self).__init__()
        self.initUI()


    def initUI(self):

        self.selid1 = QtGui.QLabel('id', self)
        self.price11 = QtGui.QLabel('0.0', self)
        self.price12 = QtGui.QLabel('0.0', self)

        self.hbox1=QtGui.QHBoxLayout()
        self.hbox1.addWidget(self.selid1)
        self.hbox1.addWidget(self.price11)
        self.hbox1.addWidget(self.price12)

        self.selid2 = QtGui.QLabel('id', self)
        self.price21 = QtGui.QLabel('0.0', self)
        self.price22 = QtGui.QLabel('0.0', self)

        self.hbox2=QtGui.QHBoxLayout()
        self.hbox2.addWidget(self.selid2)
        self.hbox2.addWidget(self.price21)
        self.hbox2.addWidget(self.price22)

        self.selid3 = QtGui.QLabel('id', self)
        self.price31 = QtGui.QLabel('0.0', self)
        self.price32 = QtGui.QLabel('0.0', self)

        self.hbox3=QtGui.QHBoxLayout()
        self.hbox3.addWidget(self.selid3)
        self.hbox3.addWidget(self.price31)
        self.hbox3.addWidget(self.price32)

        self.vbox=QtGui.QVBoxLayout()
        self.vbox.addLayout(self.hbox1)
        self.vbox.addLayout(self.hbox2)
        self.vbox.addLayout(self.hbox3)

        self.setLayout(self.vbox)

        self.setGeometry(300, 300, 400, 250)
        self.setWindowTitle('Absolute')

        self.thread = MyThread()
        self.thread.start()
        self.thread.signal.sig.connect(self.changelabel)

    def changelabel(self, datas):       
        if(datas is not None):
            for marketBook in datas:
                runners = marketBook['runners']
                if (runners[0]['status'] == 'ACTIVE'):
                    self.selid1.setText(runners[0]['status'])
                    self.price11.setText(str(runners[0]['ex']['availableToBack'][0]['price']))
                    self.price12.setText(str(runners[0]['ex']['availableToLay'][0]['price']))
                else:
                    self.selid1.setText(runners[0]['status'])

                if (runners[1]['status'] == 'ACTIVE'):
                    self.selid2.setText(runners[1]['status'])
                    self.price21.setText(str(runners[1]['ex']['availableToBack'][0]['price']))
                    self.price22.setText(str(runners[1]['ex']['availableToLay'][0]['price']))
                else:
                    self.selid2.setText(runners[1]['status'])

                if (runners[2]['status'] == 'ACTIVE'):
                    self.selid3.setText(runners[2]['status'])
                    self.price31.setText(str(runners[2]['ex']['availableToBack'][0]['price']))
                    self.price32.setText(str(runners[2]['ex']['availableToLay'][0]['price']))
                else:
                    self.selid3.setText(runners[2]['status'])


def main():

    app = QtGui.QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

Sorry for my English


Solution

  • You do not need the MySig class, and the signal should not be defined to emit a QObject because that does not match the type of object you are emitting.

    I cannot test your example code, but try this:

    class MyThread(QtCore.QThread):
        sig = QtCore.Signal(object)
    
        def __init__(self, parent=None):
            QtCore.QThread.__init__(self, parent)
            self.exiting = 10
        ...
    
        def run(self):
            ...
            self.sig.emit(market_book_result)
        ...
    
    class Example(QtGui.QWidget):
        ...
        def initUI(self):    
            ...
            self.thread = MyThread()
            self.thread.sig.connect(self.changelabel)
            self.thread.start()