Is there any solution for the QtWebKit memory leak? - python

Memory size of QtWebKit process increases with every new page load. Cleaning memory cache doesn't help. Does anyone know how to solve it?
This simple example crashes after some time of operation:
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebKitWidgets import QWebView
from PyQt5.QtWebKit import QWebSettings
class Crawler(QWebView):
def __init__(self):
QWebView.__init__(self)
self.settings().setMaximumPagesInCache(0)
self.settings().setObjectCacheCapacities(0, 0, 0)
self.settings().setOfflineStorageDefaultQuota(0)
self.settings().setOfflineWebApplicationCacheQuota(0)
self.settings().setAttribute(QWebSettings.AutoLoadImages, False)
self.loadFinished.connect(self._result_available)
def start(self):
self.load(QUrl('http://stackoverflow.com/'))
def _result_available(self, ok):
print('got it!')
self.settings().clearMemoryCaches() # it doesn't help
self.settings().clearIconDatabase()
self.start() # next try
if __name__ == '__main__':
app = QApplication([])
crawler = Crawler()
crawler.start()
app.exec_()

Reason of memory leak in disabled autoloading of images. It's a bug that will be fixed in next QT version. Removing this line solves the problem for example above:
self.settings().setAttribute(QWebSettings.AutoLoadImages, False)
Second possible reason which can lead to leaks is "Memory leak in GStreamer". It's in process.
Update:
I see people still looking for a solution. I've recently noticed bug with AutoLoadImages=False was not fixed in version Qt 5.2.1, nor in Qt 5.3 RC. New discussion about it has been opened. You can vote for this issue in bugtracker to increase the chances for fix in Qt 5.3.0

Related

PyQt6 QMediaPlayer and QAudioOutput not behaving as expected

I've been having an issue migrating to PyQt6 with QAudioOutput and QMediaPlayer where the QMediaPlayer object seems to not work with any QAudioOutput I make. If I set a QAudioOutput object the video will fail to render and the event loop gets sluggish like buggy things are happening. Also the QMediaPlayer does not seem to be incrementing the QAudioOutput object's reference counter when QMediaPlayer.setAudioOutput is used, because unless I keep a reference to the object myself it gets cleared.
Here is some demo code:
import sys
from PyQt6.QtWidgets import QMainWindow, QApplication
from PyQt6.QtCore import QUrl
from PyQt6.QtMultimedia import QMediaPlayer, QAudioOutput
from PyQt6.QtMultimediaWidgets import QVideoWidget
class MainWin(QMainWindow):
def __init__(self, file_path):
super(MainWin, self).__init__()
self.cent_wid = QVideoWidget()
self.setCentralWidget(self.cent_wid)
self.player = QMediaPlayer()
self.audio_output = QAudioOutput()
#self.player.setAudioOutput(self.audio_output)
self.audio_output.setVolume(1.0)
self.player.setVideoOutput(self.cent_wid)
self.file_path = file_path
def showEvent(self, a0) -> None:
super(MainWin, self).showEvent(a0)
self.player.setSource(QUrl.fromLocalFile(self.file_path))
self.player.play()
if __name__ == '__main__':
app = QApplication([])
frm = MainWin(sys.argv[1])
frm.show()
app.exec()
For me, the above will run and play the video file (first argument for path), but the "player.setAudioOutput" is commented out. If it is uncommented then the player will fail. I've tried manually setting the QAudioDevice and PyQt (6.2.3, 6.2.2). Despite messing around for quite a while I can't get anything to work. Any ideas?
Although not a solution to this problem I have determined that the issue is with the vorbis audio codec on windows. Since Qt dropped DirectShow and only supports WMF this caused an issue on my computer. Unfortunately, I have not been able to get Qt to cooperate with any attempts to install codecs. Not 3rd party codecs or the "Web Media Extensions" from ms store. Below is some code that appears to prove that the vorbis codec is the issue (along with only files needing that codec breaking Qt):
from PyQt6.QtMultimedia import QMediaFormat
mf = QMediaFormat()
for codec in mf.supportedAudioCodecs(QMediaFormat.ConversionMode.Decode):
print(codec.name)

QWebEngineView not loading with default Windows elevation

I'm having a bizarre issue where this simple QWebEngine code runs perfectly fine as a regular user on Windows 10 (loads the page fully), but when I elevate my own default user account it stops loading the page. The progress output will go from 0->100 and not call loadFinished on the browser or show any output on the page. I've tried running it as an elevated standard Administrator built-in account and it seemed to work oddly enough.
Here's the unloaded page:
and here's it working properly:
Running with os.environ["QT_DEBUG_PLUGINS"] = "1" doesn't show any discrepancies between the elevated and non-elevated processes.
import sys
from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.browser = QWebEngineView()
self.browser.setUrl(QUrl('https://www.google.com'))
self.browser.loadProgress.connect(self.on_load_progress)
self.setCentralWidget(self.browser)
self.show()
def on_load_progress(self, progress: int):
print(f'loading progress:[{progress}]...')
app = QApplication(sys.argv)
main_win = MainWindow()
app.exec()
After trying many things and going through many logs, the only partial solution I've found to this problem is adding --no-sandbox to the QApplication argument list to make the Chromium webdriver work at all. For my app this is enough but running without sandboxing is less than ideal for a broader solution.
For those interested I found the answer thanks to this thread (has a lot more relevant info than my descriptions).

PyQt QThread cause main thread to close

Hello i have a problem with creating Thread using the QThread class.
here is my code :
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import QThread
class ScriptRunner(QThread):
def run(self):
print('test')
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = QWidget()
gui.setFixedSize(400, 400)
gui.setVisible(True)
ScriptRunner().start() # this line cause the error
sys.exit(app.exec_())
when i lunch this code without the ScriptRunner().start() line, the gui is working without any problem, but when i do add the line, the gui show up and is hidden very quickly and program is shutdown
I receive this message in the console :
/usr/bin/python3.6 /home/karim/upwork/python-qt-rasp/tests/test.py
QThread: Destroyed while thread is still running
Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
Please change the line:
ScriptRunner().start() # this line cause the error
to:
sr = ScriptRunner()
sr.start()
Tested for PyQt4 though, but works.
EDIT:
Another workaround that worked for me:
Instantiating ScriptRunner as ScriptRunner(gui).start() also works.
The problem was that you must save a reference to the thread that you lunch, in my real world example, i was not saving a reference to the thread in my object, so its was garbage collected by python i think.
self.runner = Runner()

QMediaPlayer state not stopped when status changed to end of media

I have a problem using QMediaPlayer.mediaStatusChanged.
According to Qt5.7 documentation, when media status is changed to EndOfMedia, the QMediaPlayer state should be StoppedState:
Playback has reached the end of the current media. The player is in the StoppedState.
Qt5.7
However, the state is not stopped. Here is a sample that reproduces the issue:
import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import QUrl
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
class MediaPlayer(QMediaPlayer):
default = 'test.mp3'
def __init__(self):
super(MediaPlayer, self).__init__()
self.mediaStatusChanged[QMediaPlayer.MediaStatus].connect(self.media_status_changed)
self.setup_media(self.default)
def setup_media(self, media):
url = QUrl.fromLocalFile(media)
self.setMedia(QMediaContent(url))
def media_status_changed(self, status):
if status == QMediaPlayer.EndOfMedia:
print(self.state() == QMediaPlayer.StoppedState) # I get False
# self.state() is QMediaPlayer.PlayingState
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
m = MediaPlayer()
m.play()
sys.exit(app.exec_())
Does anyone face the same problem?
I can fix the problem with a workaround but I think it may be a Qt problem.
I reported the issue to Qt as it seems to be a Windows only bug :
Possible workarounds to fix the problem :
Force stop before processing
def media_status_changed(self, status):
if status == QMediaPlayer.EndOfMedia:
super(MediaPlayer, self).stop()
# process
Poll until getting StoppedState
def media_status_changed(self, status):
if status == QMediaPlayer.EndOfMedia:
while not (self.state() == QMediaPlayer.StoppedState):
time.sleep(0.1)
# process
I will add here any update regarding the Qt issue.
EDIT: issue updated and fixed in Qt v5.10.1

Can't get my QT Designer UI to run from script

Ok I hope I can make this understandable...
So I created an UI in QT designer - named heatwindow.ui
Next I wrote this following script in a file named heatwindow.py:
from PySide import QtGui, QtCore, QtUiTools
from HeatModel import *
from vsmutils import *
class HeatWindow:
"""Main window class for the Flow application"""
def __init__(self, app):
"""Class constructor"""
# Assign our application instance as a member variable
self.app = app
# Create an instance of our HeatModel class
#self.heatModel = HeatModel()
# Load and show our user interface
self.ui = loadUiWidget('heatwindow.ui')
self.ui.show()
self.ui.raise_()
if __name__ == '__main__':
app = appInstance()
app.Create()
HeatWindow(app)
window = HeatWindow(app)
app.Run()
Ok, so vsmutils is a script that we got from our teacher...
Anyways - my problem is that nothing happens when running the script. Actually it seems the process in Python gets killed entirely, I have to press "Run again this program" (Spyder) in the Console. When debugging it seems this happens after the line
window = HeatWindow(app)
I hope this is enough info to help me, if not please tell what I should add!
Regards
Ok, solved it finally.
So I am going to post how I did it for others to see if they had the same problem... Cause this was just frustrating.
So- I use Windows 7, Python 2.7.6, Spyder... The script crashed all the time when using QT/Pyside. The solution was to delete a file qt.conf that is inside a Python 2.7.6 folder... And now it works... Don't know why though, but it took me 16 hours to find out.

Categories

Resources