You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: FigureCanvasQT is seemingly prematurely freed under certain conditions #29618
I'm in the process of updating some code using matplotlib and pyside6. Using version 6.6.0 of PySide there is no error, but on versions 6.7.0 and newer I get an error indicating that the underlying C++ object has been prematurely freed. I've had a hard time identifying the source of the bug. I have opened an issue with pyside, but as I have been unable to recreate the bug without matplotlib components I thought I would open an issue here and see if anyone had any ideas. Sorry to bother, and thanks for the help.
Traceback (most recent call last):
File "/home/ez/test.py", line 20, in
QApplication.instance().processEvents()
File "/home/ez/micromamba/envs/pycodas/lib/python3.11/site-packages/matplotlib/backends/backend_qt.py", line 495, in _draw_idle
if self.height() < 0 or self.width() < 0:
^^^^^^^^^^^^^
RuntimeError: Internal C++ object (FigureCanvasQT) already deleted.
Expected outcome
It shouldn't do anything, maybe briefly display a window, but the error is unexpected. I may just be using something wrong, but this code did run in the past without error
Additional information
I should mention that I copied the entire class definition of FigureCanvasQT into my test file and that runs just fine, which I find somewhat confusing. Though this may be explained by the fact that I am using version 3.9.1 of matplotlib which may differ from the main branch.
It does, I also found that if I manually shut down the application at the end of the function it resolves this. Using pdb in the version where the error is generated, the sys.getrefcount is non zero at the time it is generated. This makes me think you're correct that Qt's GC doesn't agree with python. I have not as of yet however been able to isolate why this is. Thanks for your response!
Is any action needed on the matplotlib side, or can this be closed now? My interpretation is that application code needs to keep Python references to (some?) objects created by Qt until they are no longer used, implicitly or explicitly. Or, is there something that can be done in the matplotlib library to prevent the problem?
@tacaswell‘s example is a workaround, not a solution. There should not hechte need for the user to keep a reference to the canvas. OTOH, _draw_idle should not needed to have to worry about a deleted Qt object. Therefore, I also don‘t see a clear solution in the matplotlib side.
Given the example is rather theoretical and it depends on the Qt version I will close this under the assumption that it‘s an issue between Qt and PyQt. We are happy to reopen if there’s a more realistic example, which hopefully will inform us better about theorizing cause of the issue.
Reading this again, I think the issue is that the QMainWindow that the user is creating is getting deleted by Python [there are no circular refs and it simply goes out of scope] that causes the c++ side of the main window to get cleaned up. I speculate that this in turn cleans up all of the widgets in the window (as without a window they can not do anything!) on the c++ side. We have enough circular references that our Python side objects stick around for a bit (and the signal/slot machinery for draw on show may be enough to keep some non-circular hard-refs around) so we are trying to draw to a non-existent widget in a non existent window.
Agree with Tim's plan to re-open if we have a more realistic example.
The very short version, we have some classes that wrap Matplotlib and are using a pytest extension to manage testing the Qt aspect. On every test this drives to the case where the c++ side is cleaned up, the Python side still exists, and a process_events tries to do one last draw_idle on a non-existent widget.
Activity
tacaswell commentedon Feb 14, 2025
Does
this fix the problem? I suspect that Python and Qt's gcs are having conflicts.
ezra-varady commentedon Feb 14, 2025
It does, I also found that if I manually shut down the application at the end of the function it resolves this. Using pdb in the version where the error is generated, the
sys.getrefcountis non zero at the time it is generated. This makes me think you're correct that Qt's GC doesn't agree with python. I have not as of yet however been able to isolate why this is. Thanks for your response!efiring commentedon Aug 22, 2025
Is any action needed on the matplotlib side, or can this be closed now? My interpretation is that application code needs to keep Python references to (some?) objects created by Qt until they are no longer used, implicitly or explicitly. Or, is there something that can be done in the matplotlib library to prevent the problem?
timhoffm commentedon Aug 22, 2025
@tacaswell‘s example is a workaround, not a solution. There should not hechte need for the user to keep a reference to the canvas. OTOH, _draw_idle should not needed to have to worry about a deleted Qt object. Therefore, I also don‘t see a clear solution in the matplotlib side.
Given the example is rather theoretical and it depends on the Qt version I will close this under the assumption that it‘s an issue between Qt and PyQt. We are happy to reopen if there’s a more realistic example, which hopefully will inform us better about theorizing cause of the issue.
tacaswell commentedon Aug 22, 2025
Reading this again, I think the issue is that the
QMainWindowthat the user is creating is getting deleted by Python [there are no circular refs and it simply goes out of scope] that causes the c++ side of the main window to get cleaned up. I speculate that this in turn cleans up all of the widgets in the window (as without a window they can not do anything!) on the c++ side. We have enough circular references that our Python side objects stick around for a bit (and the signal/slot machinery for draw on show may be enough to keep some non-circular hard-refs around) so we are trying to draw to a non-existent widget in a non existent window.Agree with Tim's plan to re-open if we have a more realistic example.
tacaswell commentedon Aug 29, 2025
I have hit a real-world use case: bluesky/bluesky-widgets#203
The very short version, we have some classes that wrap Matplotlib and are using a pytest extension to manage testing the Qt aspect. On every test this drives to the case where the c++ side is cleaned up, the Python side still exists, and a
process_eventstries to do one lastdraw_idleon a non-existent widget.FIX: be more cautious about checking widget size
FIX: be more cautious about checking widget size