diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml index 8eea69643f3..9324505bd24 100644 --- a/.github/workflows/test-linux.yml +++ b/.github/workflows/test-linux.yml @@ -39,6 +39,7 @@ jobs: runs-on: ubuntu-latest env: CI: 'true' + QTCONSOLE_TESTING: 'true' CODECOV_TOKEN: "56731c25-9b1f-4340-8b58-35739bfbc52d" OS: 'linux' PYTHON_VERSION: ${{ matrix.PYTHON_VERSION }} diff --git a/.github/workflows/test-mac.yml b/.github/workflows/test-mac.yml index c547934cb14..e17273524ba 100644 --- a/.github/workflows/test-mac.yml +++ b/.github/workflows/test-mac.yml @@ -39,6 +39,7 @@ jobs: runs-on: macos-12 env: CI: 'true' + QTCONSOLE_TESTING: 'true' CODECOV_TOKEN: "56731c25-9b1f-4340-8b58-35739bfbc52d" OS: 'macos' PYTHON_VERSION: ${{ matrix.PYTHON_VERSION }} diff --git a/.github/workflows/test-win.yml b/.github/workflows/test-win.yml index 80f47cad82e..4a45cd7bbec 100644 --- a/.github/workflows/test-win.yml +++ b/.github/workflows/test-win.yml @@ -39,6 +39,7 @@ jobs: runs-on: windows-latest env: CI: 'true' + QTCONSOLE_TESTING: 'true' CODECOV_TOKEN: "56731c25-9b1f-4340-8b58-35739bfbc52d" OS: 'win' PYTHON_VERSION: ${{ matrix.PYTHON_VERSION }} diff --git a/external-deps/qtconsole/.github/workflows/linux-tests.yml b/external-deps/qtconsole/.github/workflows/linux-tests.yml index 5da008d34c4..b00153992f6 100644 --- a/external-deps/qtconsole/.github/workflows/linux-tests.yml +++ b/external-deps/qtconsole/.github/workflows/linux-tests.yml @@ -15,6 +15,7 @@ jobs: runs-on: ubuntu-latest env: CI: True + QTCONSOLE_TESTING: True PYTHON_VERSION: ${{ matrix.PYTHON_VERSION }} RUNNER_OS: 'ubuntu' COVERALLS_REPO_TOKEN: XWVhJf2AsO7iouBLuCsh0pPhwHy81Uz1v @@ -54,7 +55,11 @@ jobs: shell: bash -l {0} run: | pip install -e .[test] - pip install ${{ matrix.QT_LIB }} coveralls pytest-cov + if [ ${{ matrix.QT_LIB }} = "pyqt6" ]; then + pip install pyqt6!=6.4.0 pyqt6-qt6!=6.4.0 coveralls pytest-cov + else + pip install ${{ matrix.QT_LIB }} coveralls pytest-cov + fi - name: Show environment information shell: bash -l {0} run: | diff --git a/external-deps/qtconsole/.github/workflows/macos-tests.yml b/external-deps/qtconsole/.github/workflows/macos-tests.yml index f8a0c51439f..240d8c88873 100644 --- a/external-deps/qtconsole/.github/workflows/macos-tests.yml +++ b/external-deps/qtconsole/.github/workflows/macos-tests.yml @@ -14,6 +14,7 @@ jobs: runs-on: macos-latest env: CI: True + QTCONSOLE_TESTING: True PYTHON_VERSION: ${{ matrix.PYTHON_VERSION }} RUNNER_OS: 'macos' strategy: diff --git a/external-deps/qtconsole/.github/workflows/windows-tests.yml b/external-deps/qtconsole/.github/workflows/windows-tests.yml index b58f19875cf..62adc739e20 100644 --- a/external-deps/qtconsole/.github/workflows/windows-tests.yml +++ b/external-deps/qtconsole/.github/workflows/windows-tests.yml @@ -14,6 +14,7 @@ jobs: runs-on: windows-latest env: CI: True + QTCONSOLE_TESTING: True PYTHON_VERSION: ${{ matrix.PYTHON_VERSION }} RUNNER_OS: 'windows' strategy: diff --git a/external-deps/qtconsole/.gitrepo b/external-deps/qtconsole/.gitrepo index 02c69eb3a1b..f18ce2d0051 100644 --- a/external-deps/qtconsole/.gitrepo +++ b/external-deps/qtconsole/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/jupyter/qtconsole.git branch = master - commit = be40bce4ce01d282a69fe6071e155df66ae4b41b - parent = 4ed1cbe3fcbe0fc224b167e17b4201f61cbdba27 + commit = cce3b656e22b5b84d907888919ef594018f213cb + parent = ae019138bfde5726d96d74b5c0d79c94a492bb5a method = merge cmdver = 0.4.3 diff --git a/external-deps/qtconsole/qtconsole/completion_html.py b/external-deps/qtconsole/qtconsole/completion_html.py index 017f4069fa2..62391112899 100644 --- a/external-deps/qtconsole/qtconsole/completion_html.py +++ b/external-deps/qtconsole/qtconsole/completion_html.py @@ -124,7 +124,7 @@ class CompletionHtml(QtWidgets.QWidget): _slice_start = 0 _slice_len = 4 - def __init__(self, console_widget): + def __init__(self, console_widget, rows=10): """ Create a completion widget that is attached to the specified Qt text edit widget. """ @@ -133,6 +133,7 @@ def __init__(self, console_widget): self._text_edit = console_widget._control self._console_widget = console_widget + self._rows = rows if rows > 0 else 10 self._text_edit.installEventFilter(self) self._sliding_interval = None self._justified_items = None @@ -312,7 +313,7 @@ def show_items(self, cursor, items, prefix_length=0): displaywidth = int(max(10, (width / char_width) - 1)) items_m, ci = text.compute_item_matrix(items, empty=' ', displaywidth=displaywidth) - self._sliding_interval = SlidingInterval(len(items_m)-1) + self._sliding_interval = SlidingInterval(len(items_m)-1, width=self._rows) self._items = items_m self._size = (ci['rows_numbers'], ci['columns_numbers']) diff --git a/external-deps/qtconsole/qtconsole/completion_widget.py b/external-deps/qtconsole/qtconsole/completion_widget.py index 00d6037c15d..26e292caa1b 100644 --- a/external-deps/qtconsole/qtconsole/completion_widget.py +++ b/external-deps/qtconsole/qtconsole/completion_widget.py @@ -15,7 +15,7 @@ class CompletionWidget(QtWidgets.QListWidget): # 'QObject' interface #-------------------------------------------------------------------------- - def __init__(self, console_widget): + def __init__(self, console_widget, height=0): """ Create a completion widget that is attached to the specified Qt text edit widget. """ @@ -24,6 +24,7 @@ def __init__(self, console_widget): super().__init__(parent=console_widget) self._text_edit = text_edit + self._height_max = height if height > 0 else self.sizeHint().height() self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) @@ -104,7 +105,6 @@ def show_items(self, cursor, items, prefix_length=0): """ Shows the completion widget with 'items' at the position specified by 'cursor'. """ - text_edit = self._text_edit point = self._get_top_left_position(cursor) self.clear() path_items = [] @@ -132,15 +132,16 @@ def show_items(self, cursor, items, prefix_length=0): list_item.setText(text) self.addItem(list_item) - height = self.sizeHint().height() if QT6: screen_rect = self.screen().availableGeometry() else: screen_rect = QtWidgets.QApplication.desktop().availableGeometry(self) - if (screen_rect.size().height() + screen_rect.y() - - point.y() - height < 0): - point = text_edit.mapToGlobal(text_edit.cursorRect().topRight()) - point.setY(int(point.y() - height)) + screen_height = screen_rect.height() + height = int(min(self._height_max, screen_height - 50)) # -50px + if ((screen_height - point.y() - height) < 0): + point = self._text_edit.mapToGlobal(self._text_edit.cursorRect().topRight()) + py = point.y() + point.setY(int(py - min(height, py - 10))) # -10px w = (self.sizeHintForColumn(0) + self.verticalScrollBar().sizeHint().width() + 2 * self.frameWidth()) @@ -161,20 +162,7 @@ def show_items(self, cursor, items, prefix_length=0): def _get_top_left_position(self, cursor): """ Get top left position for this widget. """ - point = self._text_edit.cursorRect(cursor).center() - point_size = self._text_edit.font().pointSize() - - if sys.platform == 'darwin': - delta = int((point_size * 1.20) ** 0.98) - elif os.name == 'nt': - delta = int((point_size * 1.20) ** 1.05) - else: - delta = int((point_size * 1.20) ** 0.98) - - y = delta - (point_size / 2) - point.setY(int(point.y() + y)) - point = self._text_edit.mapToGlobal(point) - return point + return self._text_edit.mapToGlobal(self._text_edit.cursorRect().bottomRight()) def _complete_current(self): """ Perform the completion with the currently selected item. @@ -200,6 +188,7 @@ def _update_current(self): # Update widget position cursor = self._text_edit.textCursor() point = self._get_top_left_position(cursor) + point.setY(self.y()) self.move(point) # Update current item diff --git a/external-deps/qtconsole/qtconsole/console_widget.py b/external-deps/qtconsole/qtconsole/console_widget.py index 3652ea76a66..61be6f7df47 100644 --- a/external-deps/qtconsole/qtconsole/console_widget.py +++ b/external-deps/qtconsole/qtconsole/console_widget.py @@ -91,6 +91,16 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ `tab` and arrow keys. """ ) + gui_completion_height = Integer(0, config=True, + help=""" + Set Height for completion. + + 'droplist' + Height in pixels. + 'ncurses' + Maximum number of rows. + """ + ) # NOTE: this value can only be specified during initialization. kind = Enum(['plain', 'rich'], default_value='plain', config=True, help=""" @@ -265,9 +275,9 @@ def __init__(self, parent=None, **kw): self._append_before_prompt_cursor = self._control.textCursor() self._ansi_processor = QtAnsiCodeProcessor() if self.gui_completion == 'ncurses': - self._completion_widget = CompletionHtml(self) + self._completion_widget = CompletionHtml(self, self.gui_completion_height) elif self.gui_completion == 'droplist': - self._completion_widget = CompletionWidget(self) + self._completion_widget = CompletionWidget(self, self.gui_completion_height) elif self.gui_completion == 'plain': self._completion_widget = CompletionPlain(self) @@ -2483,7 +2493,13 @@ def _show_prompt(self, prompt=None, html=False, newline=True, # This is necessary to solve out-of-order insertion of mixed stdin and # stdout stream texts. # Fixes spyder-ide/spyder#17710 - if not sys.platform == 'darwin': + if sys.platform == 'darwin': + # Although this makes our tests hang on Mac, users confirmed that + # it's needed on that platform too. + # Fixes spyder-ide/spyder#19888 + if not os.environ.get('QTCONSOLE_TESTING'): + QtCore.QCoreApplication.processEvents() + else: QtCore.QCoreApplication.processEvents() cursor = self._get_end_cursor() diff --git a/external-deps/qtconsole/qtconsole/qtconsoleapp.py b/external-deps/qtconsole/qtconsole/qtconsoleapp.py index 1d84934487a..326f0adafab 100644 --- a/external-deps/qtconsole/qtconsole/qtconsoleapp.py +++ b/external-deps/qtconsole/qtconsole/qtconsoleapp.py @@ -7,7 +7,6 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. -from distutils.version import LooseVersion import os import signal import sys @@ -416,8 +415,11 @@ def _init_asyncio_patch(self): def initialize(self, argv=None): # Fixes launching issues with Big Sur # https://bugreports.qt.io/browse/QTBUG-87014, fixed in qt 5.15.2 - if sys.platform == 'darwin' and LooseVersion(QT_VERSION) < LooseVersion('5.15.2'): - os.environ['QT_MAC_WANTS_LAYER'] = '1' + if sys.platform == 'darwin': + v_5_15_2 = QtCore.QVersionNumber.fromString('5.15.2')[0] + v_current = QtCore.QVersionNumber.fromString(QT_VERSION)[0] + if v_current < v_5_15_2: + os.environ['QT_MAC_WANTS_LAYER'] = '1' self._init_asyncio_patch() self.init_qt_app() super().initialize(argv)