[Interest] QWebEngineUrlRequestJob and asynchronous I/O
Jérôme Laheurte
jerome at jeromelaheurte.net
Tue Feb 21 12:58:48 CET 2017
Hello. I already asked this on the PyQt mailing list but I guess it was not the right place; this is more of a Qt problem. I’m trying to implement a custom URI scheme handler, in a context where the underlying data will actually be fetched asynchronously. I reduced the problem to the « minimal » code pasted below (python 3.5, PyQt 5.8/Qt 5.8). Basically the problem is that when I call QWebEngineUrlRequestJob.reply() with an instance of my custom QIODevice, I expect the following:
1. bytesAvailable() is called, returns 0 (no data available yet)
2. The request job waits for readyRead to be emitted
3. The proceeds with bytesAvailable() / readData() until data is exhausted
4. Goto 2, until readChannelFinished is emitted
What actually happens:
1. bytesAvailable() is called, returns 0
2. The request job tries to read 32 Kb nonetheless
3. It gets no data, closes the QIODevice
Did I miss something here ? This happens on both mac OS and Linux. Didn’t try on Windows yet.
TIA
Jérôme Laheurte
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler
class TestIODevice(QtCore.QIODevice):
def __init__(self):
super().__init__()
self.open(self.ReadOnly | self.Unbuffered)
self._data = b''
QtCore.QTimer.singleShot(1000, self._dataReceived)
def _dataReceived(self):
print('== RECV')
self._data = b'foo'
self.readyRead.emit()
def bytesAvailable(self):
count = len(self._data) + super().bytesAvailable()
print('== AVAIL', count)
return count
def isSequential(self):
return True
def readData(self, maxSize):
print('== READ', maxSize)
data, self._data = self._data[:maxSize], self._data[maxSize:]
return data
def close(self):
print('== CLOSE')
super().close()
class TestHandler(QWebEngineUrlSchemeHandler):
def requestStarted(self, request):
self._dev = TestIODevice() # Must keep ref
request.reply(b'text/plain', self._dev)
class TestWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self._view = QWebEngineView(self)
self._handler = TestHandler() # Must keep ref
self._view.page().profile().installUrlSchemeHandler(b'spam', self._handler)
self._view.setHtml('<html><head><title>Test</title></head><body><img src="spam:eggs" /></body></html>')
self.setCentralWidget(self._view)
self.show()
self.raise_()
if __name__ == '__main__':
app = QtWidgets.QApplication([])
win = TestWindow()
app.exec_()
More information about the Interest
mailing list