[PyQt] Object lifetime issues with QWebEngineUrlSchemeHandler and QBuffer

Kovid Goyal kovid at kovidgoyal.net
Wed Sep 14 13:07:49 BST 2016


I found you have to keep a reference to the handler. Rather than making
it global, I simply make it an attribute of the profile object it is
installed on.

You dont need to keep references around to the buffer object and the
byte string, as long as you set its parent to the handler instance. See
vise_scheme.py for an example.

Kovid.


On Wed, Sep 14, 2016 at 09:49:25AM +0200, Florian Bruhin wrote:
> Hey,
> 
> I tried implementing a custom QWebEngineUrlSchemeHandler yesterday,
> and ran into some weird object lifetime issues I can't quite explain.
> 
> The attached request1.py is the one which works fine, and displays
> "Hello World" with a custom test:foo URL.
> 
> 
> In request2.py, I removed a global reference to SchemeHandler, so
> "handler" is local in install_scheme_handler().
> 
> Now, despite setting the parent of SchemeHandler to the QApplication
> instance, it seems to go away somehow and I get an
> "ERR_UNKNOWN_URL_SCHEME" error page.
> 
> Why?
> 
> 
> In request3.py, the global reference is back, but I use a QBuffer to
> which I pass a byte string instead of writing to it in requestStarted.
> Here, I get a segfault:
> 
>     #0  QBuffer::readData (this=0xe06740, data=0x7fffd4013000 "", len=32768) at io/qbuffer.cpp:412
>     #1  0x00007fffecd579ae in ?? () from /usr/lib/python3.5/site-packages/PyQt5/QtCore.so
>     #2  0x00007ffff4ae3e0a in QIODevice::read (this=0xe06740, data=0x7fffd4013000 "", maxSize=32768) at io/qiodevice.cpp:1047
>     #3  0x00007fffe734232a in QtWebEngineCore::URLRequestCustomJob::ReadRawData (this=<optimized out>, buf=0x7fff9c1692c0, bufSize=32768)
>     [...]
> 
> I explicitly keep a reference to both the QBuffer and to the
> underlying byte string, to make sure they never get collected, so why
> is this happening?
> 
> 
> Also, with request1.py, I never delete the QBuffer - when can I do so?
> Should I do job.destroyed.connect(buf.deleteLater)?
> 
> 
> Thanks,
> 
> Florian
> 
> -- 
> http://www.the-compiler.org | me at the-compiler.org (Mail/XMPP)
>    GPG: 916E B0C8 FD55 A072 | http://the-compiler.org/pubkey.asc
>          I love long mails! | http://email.is-not-s.ms/

> from PyQt5.QtWidgets import QApplication
> from PyQt5.QtWebEngineWidgets import QWebEngineProfile, QWebEngineView
> from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler
> from PyQt5.QtCore import QUrl, QBuffer, QIODevice
> 
> 
> handler = None
> 
> 
> class SchemeHandler(QWebEngineUrlSchemeHandler):
> 
>     def requestStarted(self, job):
>         buf = QBuffer(parent=self)
>         buf.open(QIODevice.WriteOnly)
>         buf.write(b'Hello World')
>         buf.seek(0)
>         buf.close()
>         job.reply(b'text/plain', buf)
> 
> 
> def install_scheme_handler():
>     global handler
>     handler = SchemeHandler(QApplication.instance())
>     QWebEngineProfile.defaultProfile().installUrlSchemeHandler(b'test', handler)
> 
> 
> app = QApplication([])
> install_scheme_handler()
> view = QWebEngineView()
> view.show()
> view.load(QUrl('test:foo'))
> app.exec_()

> from PyQt5.QtWidgets import QApplication
> from PyQt5.QtWebEngineWidgets import QWebEngineProfile, QWebEngineView
> from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler
> from PyQt5.QtCore import QUrl, QBuffer, QIODevice
> 
> 
> class SchemeHandler(QWebEngineUrlSchemeHandler):
> 
>     def requestStarted(self, job):
>         buf = QBuffer(parent=self)
>         buf.open(QIODevice.WriteOnly)
>         buf.write(b'Hello World')
>         buf.seek(0)
>         buf.close()
>         job.reply(b'text/plain', buf)
> 
> 
> def install_scheme_handler():
>     handler = SchemeHandler(QApplication.instance())
>     QWebEngineProfile.defaultProfile().installUrlSchemeHandler(b'test', handler)
> 
> 
> app = QApplication([])
> install_scheme_handler()
> view = QWebEngineView()
> view.show()
> view.load(QUrl('test:foo'))
> app.exec_()

> from PyQt5.QtWidgets import QApplication
> from PyQt5.QtWebEngineWidgets import QWebEngineProfile, QWebEngineView
> from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler
> from PyQt5.QtCore import QUrl, QBuffer, QIODevice
> 
> 
> handler = None
> 
> 
> class SchemeHandler(QWebEngineUrlSchemeHandler):
> 
>     def __init__(self, parent=None):
>         super().__init__(parent)
>         self._keep = []
> 
>     def requestStarted(self, job):
>         data = b'Hello World'
>         buf = QBuffer(data, parent=self)
>         self._keep.append(data)
>         self._keep.append(buf)
>         job.reply(b'text/plain', buf)
> 
> 
> def install_scheme_handler():
>     global handler
>     handler = SchemeHandler(QApplication.instance())
>     QWebEngineProfile.defaultProfile().installUrlSchemeHandler(b'test', handler)
> 
> 
> app = QApplication([])
> install_scheme_handler()
> view = QWebEngineView()
> view.show()
> view.load(QUrl('test:foo'))
> app.exec_()




> _______________________________________________
> PyQt mailing list    PyQt at riverbankcomputing.com
> https://www.riverbankcomputing.com/mailman/listinfo/pyqt


-- 
_____________________________________

Dr. Kovid Goyal 
http://www.kovidgoyal.net
http://calibre-ebook.com
_____________________________________


More information about the PyQt mailing list