Occasionally get "QThread: Destroyed while thread is still running" when running multiple threads
-
@gunraidan said in Occasionally get "QThread: Destroyed while thread is still running" when running multiple threads:
Doing the first results in this error:
<PyQt6.QtCore.QJsonValue object at 0x00000182BF9CA570>
I don't see it being an error. ("qt.tlsbackend.ossl: Failed to load libssl/libcrypto." is over to you, you have had that from the start.) So that actually looks good I think, it has found a
QJsonValue
inpokemon_dict["abilities"]
, so it's working.TypeError: the JSON object must be str, bytes or bytearray, not QByteArray
Then you need to convert Qt
QByteArray
to bytes/bytearray, however you do that from PyQt6. -
@JonB said in Occasionally get "QThread: Destroyed while thread is still running" when running multiple threads:
@gunraidan said in Occasionally get "QThread: Destroyed while thread is still running" when running multiple threads:
Doing the first results in this error:
<PyQt6.QtCore.QJsonValue object at 0x00000182BF9CA570>
I don't see it being an error. ("qt.tlsbackend.ossl: Failed to load libssl/libcrypto." is over to you, you have had that from the start.) So that actually looks good I think, it has found a
QJsonValue
inpokemon_dict["abilities"]
, so it's working.TypeError: the JSON object must be str, bytes or bytearray, not QByteArray
Then you need to convert Qt
QByteArray
to bytes/bytearray, however you do that from PyQt6.When I type the following code:
def handle_request(self, reply): er = reply.error() if er == QtNetwork.QNetworkReply.NetworkError.NoError: bytes_string = reply.readAll() pokemon_dict = QtCore.QJsonDocument.fromJson(bytes_string) pokemon_dict = pokemon_dict.object() print(pokemon_dict)
This is the output:
{'abilities': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0A570>, 'base_experience': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0A5E0>, 'forms': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0A650>, 'game_indices': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0A6C0>, 'height': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0A730>, 'held_items': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0A7A0>, 'id': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0A810>, 'is_default': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0A880>, 'location_area_encounters': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0A8F0>, 'moves': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0A960>, 'name': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0A9D0>, 'order': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0AA40>, 'past_types': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0AAB0>, 'species': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0AB20>, 'sprites': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0AB90>, 'stats': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0AC00>, 'types': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0AC70>, 'weight': <PyQt6.QtCore.QJsonValue object at 0x000001EC6DE0ACE0>}
So it does successfully import the data. However, unlike the keys, the values in the dictionary aren't strings but more so strange code. Is there a way to have the values be the same text string found in the api like the keys?
-
@gunraidan
You have to read the QtQJson...
classes documentation and write the code. Btw did you try to see if yourpokemon_dict["abilities"][0]['ability']['name']
works?From Python you might be more comfortable getting the
json
module working. It may integrate more smoothly in Python than the Qt one, if the Qt one doesn't work with yourpokemon_dict["abilities"][0]['ability']['name']
. -
@JonB said in Occasionally get "QThread: Destroyed while thread is still running" when running multiple threads:
@gunraidan
You have to read the QtQJson...
classes documentation and write the code. Btw did you try to see if yourpokemon_dict["abilities"][0]['ability']['name']
works?From Python you might be more comfortable getting the
json
module working. It may integrate more smoothly in Python than the Qt one, if the Qt one doesn't work with yourpokemon_dict["abilities"][0]['ability']['name']
.This is embarrassing but I just realized I quoted you before without putting my code in.
It strongly gives the impression I'm not putting in the effort, which I don't think is accurate.I came up with the following code:
def handle_request(self, reply): er = reply.error() if er == QtNetwork.QNetworkReply.NetworkError.NoError: bytes_string = reply.readAll() pokemon_dict = json.loads(bytes_string) x = QByteArray(pokemon_dict["abilities"][0]['ability']['name']) print(x)
In my head the
json.loads
will load the response into json format and then x will result in that part of the code being transferred to bytes so Python can read it.However, I still get the same error:
Traceback (most recent call last): File "c:\Users\Nader\OneDrive\Documents\Coding\Python\TestNetwork.py", line 44, in handle_request bytes_string = json.loads(reply.readAll()) File "C:\Users\Nader\AppData\Local\Programs\Python\Python310\lib\json\__init__.py", line 339, in loads raise TypeError(f'the JSON object must be str, bytes or bytearray, ' TypeError: the JSON object must be str, bytes or bytearray, not QByteArray
I have gone to the documentation here, but it lists simply the function and no examples of QJson in use (outside of a saved game load which isn't much like I'm doing.)
-
@gunraidan said in Occasionally get "QThread: Destroyed while thread is still running" when running multiple threads:
I have gone to the documentation here, but it lists simply the function and no examples of QJson in use (outside of a saved game load which isn't much like I'm doing.)
Well, that's all you get!
You have attempted to change your code in the light of the error, but unfortunately not the right thing! Please read the message carefully. First:
File "c:\Users\Nader\OneDrive\Documents\Coding\Python\TestNetwork.py", line 44, in handle_request
bytes_string = json.loads(reply.readAll())
Since that clearly shows
bytes_string = json.loads(reply.readAll())
while you claim your code haspokemon_dict = json.loads(bytes_string)
, how can you get that error message from the code you show? I can only conclude that is not the code you have to cause that message. Please don't do this, it makes it very frustrating when people try to help and code/messages are not actually what you claim they are.Second:
File "C:\Users\Nader\AppData\Local\Programs\Python\Python310\lib\json_init_.py", line 339, in loads
raise TypeError(f'the JSON object must be str, bytes or bytearray, '
TypeError: the JSON object must be str, bytes or bytearray, not QByteArray
Read the error message. It tells you it was in the
json.loads(something)
call. It tells you it requires the parameter to be "str, bytes or bytearray", but that it is actually "QByteArray" (as returned fromreadAll()
). And it is apparently not prepared to convert for you. Hence I wrote earlier:TypeError: the JSON object must be str, bytes or bytearray, not QByteArray
Then you need to convert Qt QByteArray to bytes/bytearray, however you do that from PyQt6.
You were supposed to Google to find out how to do that. I don't, I don't use Python. Your putting in
x = QByteArray(...)
after thejson.loads()
call is not going to address this, you need to change what you pass tojson.loads()
.I will have a go at producing something in next post.....
-
@gunraidan
Here is the code (tested PyQt5) for the two possible approaches:import json from PyQt5 import QtCore if __name__ == '__main__': # I put your sample JSON into a file, since they are not arriving at my serial port f = QtCore.QFile("file.json") if not f.open(QtCore.QIODevice.ReadOnly): raise "Whoops" # following line's `readAll()` returns `QByteArray` type, just like when you read from serial port qbytearray = f.readAll() f.close() # Use `json.loads()` approach: # next line converts Qt `QByteArray` type to Python `bytes` type... pythonbytearray = bytes(qbytearray) # ...so that now it is acceptable to `json.loads(...)` pokemon_dict = json.loads(pythonbytearray) x = pokemon_dict["abilities"][0]['ability']['name'] # next line prints `static`, which must be the value there print(x) # Use `QtCore.QJson...` approach: pokemon_dict = QtCore.QJsonDocument.fromJson(qbytearray) x = pokemon_dict["abilities"][0]['ability']['name'].toString() # next line prints `static`, which must be the value there print(x)
As you can see, all you had to discover for Python/PyQt
json.loads(...)
is that you can convert a QtQByteArray
to a Pythonbytes
array viabytes(qByteArrayValue)
.Use either one of these approaches. The
json
modules is slightly better integrated into Python than the QtQJson...
classes (e.g. note theQJson
expression requires thetoString()
at the end, but thejson
one does not), so you may prefer to use the former. On the other hand, whilejson.loads()
requires converting aQByteArray
to abytes
,QJsonDocument.fromJson()
does not. -
@JonB said in Occasionally get "QThread: Destroyed while thread is still running" when running multiple threads:
@gunraidan
Here is the code (tested PyQt5) for the two possible approaches:import json from PyQt5 import QtCore if __name__ == '__main__': # I put your sample JSON into a file, since they are not arriving at my serial port f = QtCore.QFile("file.json") if not f.open(QtCore.QIODevice.ReadOnly): raise "Whoops" # following line's `readAll()` returns `QByteArray` type, just like when you read from serial port qbytearray = f.readAll() f.close() # Use `json.loads()` approach: # next line converts Qt `QByteArray` type to Python `bytes` type... pythonbytearray = bytes(qbytearray) # ...so that now it is acceptable to `json.loads(...)` pokemon_dict = json.loads(pythonbytearray) x = pokemon_dict["abilities"][0]['ability']['name'] # next line prints `static`, which must be the value there print(x) # Use `QtCore.QJson...` approach: pokemon_dict = QtCore.QJsonDocument.fromJson(qbytearray) x = pokemon_dict["abilities"][0]['ability']['name'].toString() # next line prints `static`, which must be the value there print(x)
As you can see, all you had to discover for Python/PyQt
json.loads(...)
is that you can convert a QtQByteArray
to a Pythonbytes
array viabytes(qByteArrayValue)
.Use either one of these approaches. The
json
modules is slightly better integrated into Python than the QtQJson...
classes (e.g. note theQJson
expression requires thetoString()
at the end, but thejson
one does not), so you may prefer to use the former. On the other hand, whilejson.loads()
requires converting aQByteArray
to abytes
,QJsonDocument.fromJson()
does not.Thank you.
The following code:
pokemon_dict = [] json2qt = QtCore.QJsonDocument.fromJson class MainWindow(QWidget): def __init__ (self): super().__init__() self.title = "Window" self.left = 200 self.top = 300 self.width = 300 self.height = 300 self.setWindowTitle(self.title) self.setGeometry(self.left, self.top,self.width, self.height) self.start_button() self.show() def start_button(self): self.s_button = QtWidgets.QPushButton(self) self.s_button.setText('Start') self.s_button.clicked.connect(self.site_request) def site_request(self): url = 'https://pokeapi.co/api/v2/pokemon/pikachu' req = QtNetwork.QNetworkRequest(QUrl(url)) self.nam = QtNetwork.QNetworkAccessManager() self.nam.finished.connect(self.handle_request) self.nam.get(req) def handle_request(self, reply): er = reply.error() if er == QtNetwork.QNetworkReply.NetworkError.NoError: qbyte = reply.readAll() pokemon_dict = json2qt(qbyte) x = pokemon_dict["abilities"][0]['ability']['name'].toString() print(x) else: print ("Error") print(reply.errorString()) if __name__ == '__main__': app = QApplication(sys.argv) ex = MainWindow() code = app.exec() sys.exit(code)
Works as it prints the name: "static".
Thank you for all your help!
One more thing, that you don't have to answer. Do you have any idea what the
qt.tlsbackend.ossl: Failed to load libssl/libcrypto.
could be? It doesn't effect the program at all and I assume has to do with the api's security not being picked up since it references "ssl"?Doing some research of what "libssl and libcrypto are took me to this page.
-
@gunraidan said in Occasionally get "QThread: Destroyed while thread is still running" when running multiple threads:
libssl/libcrypto
It's the OpenSSL library which is needed if you want to access https URLs.
-
@jsulm said in Occasionally get "QThread: Destroyed while thread is still running" when running multiple threads:
OpenSSL library
I followed the directions here to go to this site and download the installer for Windows.
I still get the error though. :(
-
@gunraidan You should rather install OpenSSL through Qt installer/maintenance tool. See https://stackoverflow.com/questions/68624474/how-to-deploy-qt-application-with-openssl
Also, this is only an issue if you want to access HTTPS URLs. For HTTP you do not need OpenSSL.
-
I'm not sure if I should make a new thread or not, so I'll just post this here.
I can't get self.d_name to print after the api function has been called:
from PyQt6 import QtNetwork from PyQt6 import QtCore from PyQt6.QtCore import QUrl from PyQt6.QtGui import* from PyQt6 import QtWidgets from PyQt6.QtWidgets import* import sys json2qt = QtCore.QJsonDocument.fromJson class MainWindow(QWidget): def __init__ (self): super().__init__() self.title = "Window" self.left = 200 self.top = 300 self.width = 300 self.height = 300 self.setWindowTitle(self.title) self.setGeometry(self.left, self.top,self.width, self.height) self.start_button() self.show() def start_button(self): self.s_button = QtWidgets.QPushButton(self) self.s_button.setText('Start') self.s_button.clicked.connect(self.site_request) def site_request(self): url = 'https://pokeapi.co/api/v2/pokemon/pikachu' req = QtNetwork.QNetworkRequest(QUrl(url)) self.nam = QtNetwork.QNetworkAccessManager() self.nam.finished.connect(self.handle_request) self.nam.get(req) def handle_request(self, reply): er = reply.error() if er == QtNetwork.QNetworkReply.NetworkError.NoError: qbyte = reply.readAll() pokemon_dict = json2qt(qbyte) self.d_name = pokemon_dict["abilities"][0]['ability']['name'].toString() else: print ("Error") print(reply.errorString()) def get_all(self): self.site_request() print(self.d_name) if __name__ == '__main__': app = QApplication(sys.argv) ex = MainWindow() code = app.exec() sys.exit(code)
However, when I put self.d_name to print here:
def handle_request(self, reply): er = reply.error() if er == QtNetwork.QNetworkReply.NetworkError.NoError: qbyte = reply.readAll() pokemon_dict = json2qt(qbyte) self.d_name = pokemon_dict["abilities"][0]['ability']['name'].toString() print (self.d_name) else: print ("Error") print(reply.errorString())
It prints out fine.
It should print out either way, it's a "self variable".
Anyone know what I'm doing wrong?
-
@gunraidan
It won't be aboutself
(that bit is fine), it will be about when you try to print the value.Firstly, you have
print(self.d_name)
inside a methodget_all()
. But since your code never actually callsget_all()
....Even if you did call it.
site_request()
callsself.nam.get(req)
. ButQNetworkAccessManager.get()
only initiates a GET request. It does not wait for it to complete and return. Only whenfinished
signal is received andhandle_request()
is called doesself.d_name = ...
get executed. That happens asynchronously at a later time. So trying to access it immediately after callingsite_request()
is too early.