Closed visr closed 18 hours ago
Turns out I somehow deleted all folders in the ribasim_qgis
folder.
I just saw the same thing on first startup of the Ribasim plugin on a clean install. Trying a second time it works. @Huite also sees this sometimes.
QGIS currently uses Qt 5, but is in the progress of upgrading to Qt 6. Would be interesting to see if we can get our hands on a Qt 6 build to see if that fixes this. Though general availability of this will take a while so we should still look into actually fixing this.
QGIS on macOS seems to work fine (for now). Am on 3.36.
Haven't seen this recently, now on 3.36.3. And sometimes using LTR 3.34.7. Post here if you see the issue on this or later releases.
Nevermind, just saw this again on 3.36.3.
I've been seeing these crashes off and on again (also in the brother and sisters plugins). Sometimes, it's the plugin reloader forcing a reload which causes QGIS to crash.
I'm wondering whether it's due to the reference to iface
being stored in the widget. It specifically complains about some access violation in the crash report, mentioning the line where the widget is initialized.
The iface
object is barely used in the plugin, and it can be fetched if needed. Might be worth adjusting a few lines to see if this helps against the crashes.
EDIT: taking a look at this, not sure the iface
can actually be fetched that easily...
Looking at some other popular plugins, storing iface seems common practice. Our problem, and I assume the imod qgis one as well, lies slightly deeper in some widget link/state? I also saw we don't unload everything we load, but that wouldn't explain crashes on starting.
Might be linked to the horrible non-deterministic failings of our QGIS CI?
I think I might have been a bit too hasty at pointing at iface
. In one of the other plugins, relatively many crashes seemed to originate from a line setting the column width of the DatasetTreeWidget, with self.setColumnWidth(0, 1)
. This happens at initialization / reloading. I've removed the line there, and it seems a little more stable, but that's really just a feeling.
I've based the Ribasim plugin off of the qgis-tim one: https://github.com/deltares/qgis-tim The imod-qgis plugin also stores references everywhere: https://github.com/Deltares/imod-qgis
Across these plugins, the reason an iface reference is kept around is for:
My feeling is that the imod-qgis plugin seems to crash a lot less. I've also been getting crashes on innocuous seeming stuff, like creating a vector layer via PyQGIS.
I still don't have a lot of concrete ideas. I suggest we starting logging the crashes here, and including the stacktraces in a spoiler section.
Okay to trigger it was pretty easy: start QGIS, click Ribasim button, click plugin reloader to reload Ribasim plugin, click Ribasim button, crash.
It crashed here on: self.tabwidget.addTab(self.__dataset_widget, "Model")
In the Qt stack trace, it's somewhat interesting that QHeaderView::resizeSections
is mentioned, which I think is also involved with the self.setColumnWidth(0, 1)
above. But I'm still grasping at straws.
Can you try to do the same for the imod plugin? The stacktrace was lacking in the related issue.
I've also seen some (example) plugins having a first run variable, to only initialize GUI elements once, and not on reload? Might be worth investigating. I would love to help some more, but I can't reproduce the crash on my mac (not sure what that says about the bug).
Here's a crash generated from reloading and starting the timeseries widget repeatedly:
One thing to note is that there's double memory management going with these pyqt bindings, the Python interpreter and Qt both allocate and free memory. Sometimes I wonder whether there's some maybe some lag between them. These access violations make me thing the Python things try to access something that isn't there yet or something.
I don't think we're doing anything fishy by the way, I think this is a memory bug or something in QGIS or Qt. Ideally we can find a way to circumvent it.
Indeed, but if we can circumvent it, we can report it (QGIS issue tracker is rife with memory crashes without details). Ideally you would debug the Python plugin , so you can find some specifics.
Other interesting debugging tools are https://github.com/wonder-sk/qgis-first-aid-plugin, or https://gist.github.com/thbaumann/73c873d4c49d8c1add8dc97359cebabe.
Unfortunately, I don't think debugging Python will do much good. We are not getting a Python exception -- I don't think we're even crashing the Python interpreter. And even if were to inspect the Python objects during debugging, you would find nothing amiss. You would have to debug the QGIS C++ application instead, right?
Regardless, I'll try and keep on posting stack traces. Hopefully we can find something of a pattern.
Just updated to QGIS 3.38 RC, got it on first load of the Ribasim plugin. Stacktrace below.
You would have to debug the QGIS C++ application instead, right?
I guess, https://github.com/qgis/QGIS/blob/master/INSTALL.md#4-building-on-windows, but that doesn't seem very straightforward, since they just point to https://github.com/jef-n/OSGeo4W/blob/master/src/qgis-dev/osgeo4w/package.sh for the actual build steps.
## Report Details **Python Stack Trace** ``` Windows fatal exception: access violation Current thread 0x00006b18 (most recent call first): File "C:\Users/visser_mn/AppData/Roaming/QGIS/QGIS3\profiles\default/python/plugins\ribasim_qgis\widgets\ribasim_widget.py", line 47 in __init__ self.tabwidget.addTab(self.__dataset_widget, "Model") File "C:\Users/visser_mn/AppData/Roaming/QGIS/QGIS3\profiles\default/python/plugins\ribasim_qgis\ribasim_qgis.py", line 48 in toggle_ribasim widget = RibasimWidget(self.ribasim_widget, self.iface) ``` **Stack Trace** ``` QHeaderView::resizeSections : QHeaderView::sectionSize : QTreeViewPrivate::updateScrollBars : QTreeView::updateGeometries : PyInit_QtWidgets : QObject::qt_static_metacall : QHeaderView::viewportEvent : QCoreApplicationPrivate::sendThroughObjectEventFilters : QApplicationPrivate::notify_helper : QApplication::notify : QgsApplication::notify : QCoreApplication::notifyInternal2 : QWidgetPrivate::setStyle_helper : QWidgetPrivate::inheritStyle : QWidgetPrivate::setStyle_helper : QWidgetPrivate::inheritStyle : QWidgetPrivate::setStyle_helper : QWidgetPrivate::inheritStyle : QWidgetPrivate::setStyle_helper : QWidgetPrivate::inheritStyle : QWidget::setParent : QWidgetPrivate::setWidgetParentHelper : QLayout::addChildWidget : QStackedLayout::insertWidget : QTabWidget::addTab : PyInit_QtWidgets : PyObject_Call : PyObject_Vectorcall : PyObject_Vectorcall : PyEval_EvalFrameDefault : PyFunction_Vectorcall : PyObject_Call_Prepend : PyObject_Vectorcall : PyObject_Vectorcall : PyEval_EvalFrameDefault : PyFunction_Vectorcall : Py_hashtable_compare_direct : PyObject_Call : PyObject_Call : PyInit_QtCore : PyInit_QtCore : PyInit_QtCore : PyInit_QtCore : QObject::qt_static_metacall : QAction::activate : QAbstractButton::click : QAbstractButton::mouseReleaseEvent : QToolButton::mouseReleaseEvent : QWidget::event : QApplicationPrivate::notify_helper : QApplication::notify : QgsApplication::notify : QCoreApplication::notifyInternal2 : QApplicationPrivate::sendMouseEvent : QSizePolicy::QSizePolicy : QSizePolicy::QSizePolicy : QApplicationPrivate::notify_helper : QApplication::notify : QgsApplication::notify : QCoreApplication::notifyInternal2 : QGuiApplicationPrivate::processMouseEvent : QWindowSystemInterface::sendWindowSystemEvents : QEventDispatcherWin32::processEvents : qt_plugin_query_metadata : QEventLoop::exec : QCoreApplication::exec : main : BaseThreadInitThunk : RtlUserThreadStart : ``` **QGIS Info** QGIS Version: 3.38.0-Grenoble QGIS code revision: 37aa6188bc Compiled against Qt: 5.15.13 Running against Qt: 5.15.13 Compiled against GDAL: 3.9.0 Running against GDAL: 3.9.0 **System Info** CPU Type: x86_64 Kernel Type: winnt Kernel Version: 10.0.19045
You should install a nightly dev build as
Nightlies are debug builds (including debugging output)
Ah, excellent suggestion!
In OSGeo4W description for qgis-dev
it doesn't mention it is a debug build, but there are also separate qgis-*-pdb
for builds with debugging symbols.
Here is a stacktrace on qgis-dev
with qgis-dev-pdb
, giving a few line numbers:
## Report Details **Python Stack Trace** ``` Windows fatal exception: access violation Current thread 0x0000548c (most recent call first): File "C:\Users/visser_mn/AppData/Roaming/QGIS/QGIS3\profiles\default/python/plugins\ribasim_qgis\widgets\ribasim_widget.py", line 47 in __init__ self.tabwidget.addTab(self.__dataset_widget, "Model") File "C:\Users/visser_mn/AppData/Roaming/QGIS/QGIS3\profiles\default/python/plugins\ribasim_qgis\ribasim_qgis.py", line 48 in toggle_ribasim widget = RibasimWidget(self.ribasim_widget, self.iface) ``` **Stack Trace** ``` QHeaderView::resizeSections : QHeaderView::sectionSize : QTreeViewPrivate::updateScrollBars : QTreeView::updateGeometries : PyInit_QtWidgets : QObject::qt_static_metacall : QHeaderView::viewportEvent : QCoreApplicationPrivate::sendThroughObjectEventFilters : QApplicationPrivate::notify_helper : QApplication::notify : QgsApplication::notify qgsapplication.cpp:607 QCoreApplication::notifyInternal2 : QWidgetPrivate::setStyle_helper : QWidgetPrivate::inheritStyle : QWidgetPrivate::setStyle_helper : QWidgetPrivate::inheritStyle : QWidgetPrivate::setStyle_helper : QWidgetPrivate::inheritStyle : QWidgetPrivate::setStyle_helper : QWidgetPrivate::inheritStyle : QWidget::setParent : QWidgetPrivate::setWidgetParentHelper : QLayout::addChildWidget : QStackedLayout::insertWidget : QTabWidget::addTab : PyInit_QtWidgets : PyObject_Call : PyObject_Vectorcall : PyObject_Vectorcall : PyEval_EvalFrameDefault : PyFunction_Vectorcall : PyObject_Call_Prepend : PyObject_Vectorcall : PyObject_Vectorcall : PyEval_EvalFrameDefault : PyFunction_Vectorcall : Py_hashtable_compare_direct : PyObject_Call : PyObject_Call : PyInit_QtCore : PyInit_QtCore : PyInit_QtCore : PyInit_QtCore : QObject::qt_static_metacall : QAction::activate : QAbstractButton::click : QAbstractButton::mouseReleaseEvent : QToolButton::mouseReleaseEvent : QWidget::event : QApplicationPrivate::notify_helper : QApplication::notify : QgsApplication::notify qgsapplication.cpp:607 QCoreApplication::notifyInternal2 : QApplicationPrivate::sendMouseEvent : QSizePolicy::QSizePolicy : QSizePolicy::QSizePolicy : QApplicationPrivate::notify_helper : QApplication::notify : QgsApplication::notify qgsapplication.cpp:607 QCoreApplication::notifyInternal2 : QGuiApplicationPrivate::processMouseEvent : QWindowSystemInterface::sendWindowSystemEvents : QEventDispatcherWin32::processEvents : qt_plugin_query_metadata : QEventLoop::exec : QCoreApplication::exec : main main.cpp:1845 WinMain mainwin.cpp:214 __scrt_common_main_seh exe_common.inl:288 BaseThreadInitThunk : RtlUserThreadStart : ``` **QGIS Info** QGIS Version: 3.37.0-Master QGIS code revision: 684a802617 Compiled against Qt: 5.15.13 Running against Qt: 5.15.13 Compiled against GDAL: 3.10.0dev-5481008668 Running against GDAL: 3.10.0dev-5d4c2d3a3a **System Info** CPU Type: x86_64 Kernel Type: winnt Kernel Version: 10.0.19045
I know have 4 versions installed:
The Ribasim plugin of course doesn't work on the Qt6 version, listed as invalid, but that's unrelated.
It may help to also get debug builds or symbols of Qt5:
5.13.3:
qt5-libs-debug
qt5-libs-debug-symbols
5.15.13:
qt5-libs
qt5-libs-symbols
So it seems it crashes after/on the init (PyInit_QtWidgets
) of the DatasetTreeWidget
in ribasim. On init, it will active a redraw of the child widget(s), calling updateGeometries, which in turn passes the new size to updatescrollbars, which in turn tries to get/set the size of the column headers (AFAIK). So I would advise to play with https://github.com/Deltares/Ribasim/blob/b425aa1e0e85ebf2981d14521579997b3dfd2ce5/ribasim_qgis/widgets/dataset_widget.py#L47-L56.
edit: We might even get away with setting https://doc.qt.io/qt-5/qwidget.html#updatesEnabled-prop on a higher level?
With the help of @evetion I narrowed it down to this line in our code, by repeatedly running pixi run test-ribasim-qgis-ui
:
@Huite what does this do exactly? I don't see the difference when commenting out that line. In these Qt docs it mentions The logical index should exist at the time this function is called.
. Can that be the issue? Or can we call this without the logical index as well?
And as this is C++, shouldn't it be header.setSectionResizeMode(0, QHeaderView.Stretch)
? Would be fun if this all comes down to an off by one.
In the original plugin, the dataset view has multiple columns (a checkbox, the steady-state input, another checkbox, transient input). These aren't relevant to Ribasim, so it can most likely be removed indeed.
In a hobby project (another sibiling for the qgis-tim plugin...), I've removed these lines as well. I've had far, far less crashes: https://github.com/Huite/gflow-plugin/commit/a429dc2b35e7cb7510ff171c5d9bb25f66ad46a4
I should probably adjust the original code in qgis-tim as well: https://github.com/Deltares/QGIS-Tim/blob/2d61c099e8c73e7bcd18e7190a2393d182049a6c/plugin/qgistim/widgets/dataset_widget.py#L76
Since the ColumnCount should probably be set first. (In my defense, the sizing behavior often isn't that predictable and some of this is a result of trial-and-error...)
QGIS LTS 3.28 works, but 3.34.4 and 3.36.0 crash when I try to start the plugin. This doesn't seems to happen all the time, though most times it does.