Skip to content

Commit 14203d1

Browse files
Carreaumeeseeksmachine
authored andcommitted
Backport PR ipython#14700: Improve Qt object management and performance
1 parent cd616f4 commit 14203d1

File tree

1 file changed

+15
-17
lines changed
  • IPython/terminal/pt_inputhooks

1 file changed

+15
-17
lines changed

IPython/terminal/pt_inputhooks/qt.py

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
from IPython.external.qt_for_kernel import QtCore, QtGui, enum_helper
44
from IPython import get_ipython
55

6-
# If we create a QApplication, keep a reference to it so that it doesn't get
7-
# garbage collected.
6+
# If we create a QApplication, QEventLoop, or a QTimer, keep a reference to them
7+
# so that they don't get garbage collected or leak memory when created multiple times.
88
_appref = None
9+
_eventloop = None
10+
_timer = None
911
_already_warned = False
1012

1113

@@ -21,7 +23,7 @@ def _reclaim_excepthook():
2123

2224

2325
def inputhook(context):
24-
global _appref
26+
global _appref, _eventloop, _timer
2527
app = QtCore.QCoreApplication.instance()
2628
if not app:
2729
if sys.platform == 'linux':
@@ -48,25 +50,25 @@ def inputhook(context):
4850
except AttributeError: # Only for Qt>=5.14.
4951
pass
5052
_appref = app = QtGui.QApplication([" "])
53+
_eventloop = QtCore.QEventLoop(app)
5154

5255
# "reclaim" IPython sys.excepthook after event loop starts
5356
# without this, it defaults back to BaseIPythonApplication.excepthook
5457
# and exceptions in the Qt event loop are rendered without traceback
5558
# formatting and look like "bug in IPython".
5659
QtCore.QTimer.singleShot(0, _reclaim_excepthook)
5760

58-
event_loop = QtCore.QEventLoop(app)
59-
6061
if sys.platform == 'win32':
6162
# The QSocketNotifier method doesn't appear to work on Windows.
6263
# Use polling instead.
63-
timer = QtCore.QTimer()
64-
timer.timeout.connect(event_loop.quit)
64+
if _timer is None:
65+
_timer = QtCore.QTimer()
66+
_timer.timeout.connect(_eventloop.quit)
6567
while not context.input_is_ready():
66-
# NOTE: run the event loop, and after 50 ms, call `quit` to exit it.
67-
timer.start(50) # 50 ms
68-
_exec(event_loop)
69-
timer.stop()
68+
# NOTE: run the event loop, and after 10 ms, call `quit` to exit it.
69+
_timer.start(10) # 10 ms
70+
_exec(_eventloop)
71+
_timer.stop()
7072
else:
7173
# On POSIX platforms, we can use a file descriptor to quit the event
7274
# loop when there is input ready to read.
@@ -77,14 +79,10 @@ def inputhook(context):
7779
# connect the callback we care about before we turn it on
7880
# lambda is necessary as PyQT inspect the function signature to know
7981
# what arguments to pass to. See https://github.com/ipython/ipython/pull/12355
80-
notifier.activated.connect(lambda: event_loop.exit())
82+
notifier.activated.connect(lambda: _eventloop.exit())
8183
notifier.setEnabled(True)
8284
# only start the event loop we are not already flipped
8385
if not context.input_is_ready():
84-
_exec(event_loop)
86+
_exec(_eventloop)
8587
finally:
8688
notifier.setEnabled(False)
87-
88-
# This makes sure that the event loop is garbage collected.
89-
# See issue 14240.
90-
event_loop.setParent(None)

0 commit comments

Comments
 (0)