gruns / icecream

🍦 Never use print() to debug again.
MIT License
8.69k stars 184 forks source link

Incompatibility with Qt's PySide #118

Open gjvnq opened 2 years ago

gjvnq commented 2 years ago

When I use ic instead of print, the widget shows up as a black screen instead of none at all.

#!/usr/bin/env python3
import sys
from icecream import ic
import PySide6
from PySide6 import QtWidgets
from PySide6.QtCore import QLibraryInfo, qVersion
from PySide6.QtWidgets import QMainWindow
from PySide6.QtMultimediaWidgets import QVideoWidget

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()

    def showEvent(self, evt):
        # If you replace method2 with method1 or method0, no window will appear for QVideoWidget
        self.method2()

    def method0(self):
        self.setWindowTitle('Method 0')
        camera_view = QVideoWidget()
        camera_view.show()

    def method1(self):
        self.setWindowTitle('Method 1')
        camera_view = QVideoWidget()
        print(camera_view)
        camera_view.show()

    def method2(self):
        self.setWindowTitle('Method 2')
        camera_view = QVideoWidget()
        ic(camera_view)
        camera_view.show()

def main():
    print('Python {}.{}'.format(sys.version_info[0], sys.version_info[1]))
    print(QLibraryInfo.build())
    print(f"PySide6 version: {PySide6.__version__}")

    app = QtWidgets.QApplication(sys.argv)
    window = MyWindow()
    window.show()
    sys.exit(app.exec())

if __name__ == "__main__":
    main()

I suspect that icecream is doing some weird magic that is triggering some function calls that should not have been made.

Bug report on Qt's end: https://bugreports.qt.io/browse/PYSIDE-1866

gjvnq commented 2 years ago

According to a Qt dev:

When constructing a parentless window as shown in the code, it will be destroyed when leaving the function. Apparently the icecream printer keeps a reference somewhere; so the window remains and is shown.

So we have a good idea of what is causing the bug and this seems to imply that icecream is likely to have memory leak problems.

gjvnq commented 2 years ago

After some testing, I have managed to discover that icecream.py:229 is causing the trouble. The Source.executing method seems to be maintaining a reference to the local variables even its return value is discarded.

gjvnq commented 2 years ago

I discovered that adding gc.collect() at the end of IceCreamDebugger.__call__ solves the problem.

--- a/icecream/icecream.py  2022-03-21 15:00:17.604475128 -0300
+++ b/icecream/icecream.py  2022-03-21 14:59:57.518886105 -0300
@@ -13,6 +13,7 @@

 from __future__ import print_function

+import gc
 import ast
 import inspect
 import pprint
@@ -216,6 +217,7 @@
         else:  # E.g. ic(1, 2, 3).
             passthrough = args

+        gc.collect()
         return passthrough

     def format(self, *args):
gruns commented 2 years ago

@gjvnq wonderful digging and homework. that's extremely helpful. thank you! 🙏

strange. the fact that gc.collect() fixes the issue means there's a reference cycle somewhere. otherwise the reference gc would have freed the objects

@gjvnq sanity check: you're running your pyside+icecream app with cpython, right? or a different python interpreter?

garbage collection can be computationally expensive. we dont want to run a gc sweep after every ic() call. @alexmojaki any idea where there might be a reference cycle in executing?

gjvnq commented 1 year ago

I'm running cpython on a macOS 11 machine.

Em ter., 22 de mar. de 2022 15:23, Ansgar Grunseid @.***> escreveu:

@gjvnq https://github.com/gjvnq wonderful digging and homework. that's extremely helpful. thank you! 🙏

strange. the fact that gc.collect() fixes the issue means there's a reference cycle somewhere. otherwise the reference gc would have freed the objects

@gjvnq https://github.com/gjvnq sanity check: you're running your pyside+icecream app with cpython, right? or a different python interpreter?

garbage collection can be computationally expensive. we dont want to run a gc sweep after every ic() call. @alexmojaki https://github.com/alexmojaki any idea where there might be a reference cycle in executing?

— Reply to this email directly, view it on GitHub https://github.com/gruns/icecream/issues/118#issuecomment-1075476534, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAXIYHEHUJBOVZ53QPCEVMTVBIF2JANCNFSM5RFAZNNQ . You are receiving this because you were mentioned.Message ID: @.***>