Skip to content

Commit

Permalink
MAINT: Improve qdarkstyle logic (mne-tools#12491)
Browse files Browse the repository at this point in the history
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
larsoner and autofix-ci[bot] authored Mar 12, 2024
1 parent 9006789 commit b752d2a
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 99 deletions.
6 changes: 3 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,12 @@ For full functionality, some functions require:
- `scikit-learn <https://scikit-learn.org/stable/>`__ ≥ 1.0
- `Joblib <https://joblib.readthedocs.io/en/latest/index.html>`__ ≥ 0.15 (for parallelization)
- `mne-qt-browser <https://github.com/mne-tools/mne-qt-browser>`__ ≥ 0.1 (for fast raw data visualization)
- `Qt <https://www.qt.io>`__ ≥ 5.12 via one of the following bindings (for fast raw data visualization and interactive 3D visualization):
- `Qt <https://www.qt.io>`__ ≥ 5.15 via one of the following bindings (for fast raw data visualization and interactive 3D visualization):

- `PyQt6 <https://www.riverbankcomputing.com/software/pyqt/>`__ ≥ 6.0
- `PySide6 <https://doc.qt.io/qtforpython-6/>`__ ≥ 6.0
- `PyQt5 <https://www.riverbankcomputing.com/software/pyqt/>`__ ≥ 5.12
- `PySide2 <https://doc.qt.io/qtforpython-6/gettingstarted/porting_from2.html>`__ ≥ 5.12
- `PyQt5 <https://www.riverbankcomputing.com/software/pyqt/>`__ ≥ 5.15
- `PySide2 <https://doc.qt.io/qtforpython-6/gettingstarted/porting_from2.html>`__ ≥ 5.15

- `Numba <https://numba.pydata.org>`__ ≥ 0.54.0
- `NiBabel <https://nipy.org/nibabel/>`__ ≥ 3.2.1
Expand Down
1 change: 1 addition & 0 deletions doc/changes/devel/12491.dependency.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The minimum supported version of Qt bindings is 5.15, by `Eric Larson`_.
2 changes: 2 additions & 0 deletions mne/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -963,6 +963,8 @@ def pytest_sessionfinish(session, exitstatus):
# get the number to print
files = defaultdict(lambda: 0.0)
for item in session.items:
if _phase_report_key not in item.stash:
continue
report = item.stash[_phase_report_key]
dur = sum(x.duration for x in report.values())
parts = Path(item.nodeid.split(":")[0]).parts
Expand Down
10 changes: 3 additions & 7 deletions mne/gui/tests/test_gui_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@
pytest.importorskip("nibabel")


def test_gui_api(renderer_notebook, nbexec, *, n_warn=0, backend="qt"):
def test_gui_api(renderer_notebook, nbexec, *, backend="qt"):
"""Test GUI API."""
import contextlib
import sys
import warnings

import mne
Expand All @@ -25,7 +24,6 @@ def test_gui_api(renderer_notebook, nbexec, *, n_warn=0, backend="qt"):
except Exception:
# Notebook standalone mode
backend = "notebook"
n_warn = 0
# nbexec does not expose renderer_notebook so I use a
# temporary variable to synchronize the tests
if backend == "notebook":
Expand All @@ -44,8 +42,7 @@ def test_gui_api(renderer_notebook, nbexec, *, n_warn=0, backend="qt"):
with mne.utils._record_warnings() as w:
renderer._window_set_theme("dark")
w = [ww for ww in w if "is not yet supported" in str(ww.message)]
if sys.platform != "darwin": # sometimes this is fine
assert len(w) == n_warn, [ww.message for ww in w]
assert len(w) == 0, [ww.message for ww in w]

# window without 3d plotter
if backend == "qt":
Expand Down Expand Up @@ -387,10 +384,9 @@ def _check_widget_trigger(
def test_gui_api_qt(renderer_interactive_pyvistaqt):
"""Test GUI API with the Qt backend."""
_, api = _check_qt_version(return_api=True)
n_warn = int(api in ("PySide6", "PyQt6"))
# TODO: After merging https://github.com/mne-tools/mne-python/pull/11567
# The Qt CI run started failing about 50% of the time, so let's skip this
# for now.
if api == "PySide6":
pytest.skip("PySide6 causes segfaults on CIs sometimes")
test_gui_api(None, None, n_warn=n_warn, backend="qt")
test_gui_api(None, None, backend="qt")
107 changes: 32 additions & 75 deletions mne/viz/backends/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,84 +274,42 @@ def _qt_detect_theme():
def _qt_get_stylesheet(theme):
_validate_type(theme, ("path-like",), "theme")
theme = str(theme)
orig_theme = theme
system_theme = None
stylesheet = ""
extra_msg = ""
if theme == "auto":
theme = system_theme = _qt_detect_theme()
if theme in ("dark", "light"):
if system_theme is None:
system_theme = _qt_detect_theme()
qt_version, api = _check_qt_version(return_api=True)
# On macOS, we shouldn't need to set anything when the requested theme
# matches that of the current OS state
if sys.platform == "darwin":
extra_msg = f"when in {system_theme} mode on macOS"
# But before 5.13, we need to patch some mistakes
if sys.platform == "darwin" and theme == system_theme:
if theme == "dark" and _compare_version(qt_version, "<", "5.13"):
# Taken using "Digital Color Meter" on macOS 12.2.1 looking at
# Meld, and also adapting (MIT-licensed)
# https://github.com/ColinDuquesnoy/QDarkStyleSheet/blob/master/qdarkstyle/dark/style.qss # noqa: E501
# Something around rgb(51, 51, 51) worked as the bgcolor here,
# but it's easy enough just to set it transparent and inherit
# the bgcolor of the window (which is the same). We also take
# the separator images from QDarkStyle (MIT).
icons_path = _qt_init_icons()
stylesheet = """\
QStatusBar {
border: 1px solid rgb(76, 76, 75);
background: transparent;
}
QStatusBar QLabel {
background: transparent;
}
QToolBar {
background-color: transparent;
border-bottom: 1px solid rgb(99, 99, 99);
}
QToolBar::separator:horizontal {
width: 16px;
image: url("%(icons_path)s/[email protected]");
}
QToolBar::separator:vertical {
height: 16px;
image: url("%(icons_path)s/[email protected]");
}
QToolBar::handle:horizontal {
width: 16px;
image: url("%(icons_path)s/[email protected]");
}
QToolBar::handle:vertical {
height: 16px;
image: url("%(icons_path)s/[email protected]");
}
""" % dict(icons_path=icons_path)
stylesheet = "" # no stylesheet
if theme in ("auto", "dark", "light"):
if theme == "auto":
return stylesheet
assert theme in ("dark", "light")
system_theme = _qt_detect_theme()
if theme == system_theme:
return stylesheet
_, api = _check_qt_version(return_api=True)
# On macOS or Qt 6, we shouldn't need to set anything when the requested
# theme matches that of the current OS state
try:
import qdarkstyle
except ModuleNotFoundError:
logger.info(
f'To use {theme} mode when in {system_theme} mode, "qdarkstyle" has'
"to be installed! You can install it with:\n"
"pip install qdarkstyle\n"
)
else:
# Here we are on non-macOS (or on macOS but our sys theme does not
# match the requested theme)
if api in ("PySide6", "PyQt6"):
if orig_theme != "auto" and not (theme == system_theme == "light"):
warn(
f"Setting theme={repr(theme)} is not yet supported "
f"for {api} in qdarkstyle, it will be ignored"
)
if api in ("PySide6", "PyQt6") and _compare_version(
qdarkstyle.__version__, "<", "3.2.3"
):
warn(
f"Setting theme={repr(theme)} is not supported for {api} in "
f"qdarkstyle {qdarkstyle.__version__}, it will be ignored. "
"Consider upgrading qdarkstyle to >=3.2.3."
)
else:
try:
import qdarkstyle
except ModuleNotFoundError:
logger.info(
f'To use {theme} mode{extra_msg}, "qdarkstyle" has to '
"be installed! You can install it with:\n"
"pip install qdarkstyle\n"
)
else:
klass = getattr(
stylesheet = qdarkstyle.load_stylesheet(
getattr(
getattr(qdarkstyle, theme).palette,
f"{theme.capitalize()}Palette",
)
stylesheet = qdarkstyle.load_stylesheet(klass)
)
return stylesheet
else:
try:
file = open(theme)
Expand All @@ -363,8 +321,7 @@ def _qt_get_stylesheet(theme):
else:
with file as fid:
stylesheet = fid.read()

return stylesheet
return stylesheet


def _should_raise_window():
Expand Down
15 changes: 1 addition & 14 deletions mne/viz/backends/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import platform
from colorsys import rgb_to_hls
from contextlib import nullcontext

import numpy as np
import pytest
Expand Down Expand Up @@ -66,19 +65,7 @@ def test_theme_colors(pg_backend, theme, monkeypatch, tmp_path):
monkeypatch.setattr(darkdetect, "theme", lambda: "light")
raw = RawArray(np.zeros((1, 1000)), create_info(1, 1000.0, "eeg"))
_, api = _check_qt_version(return_api=True)
if api in ("PyQt6", "PySide6"):
if theme == "dark": # we force darkdetect to say the sys is light
ctx = pytest.warns(RuntimeWarning, match="not yet supported")
else:
ctx = nullcontext()
return_early = True
else:
ctx = nullcontext()
return_early = False
with ctx:
fig = raw.plot(theme=theme)
if return_early:
return # we could add a ton of conditionals below, but KISS
fig = raw.plot(theme=theme)
is_dark = _qt_is_dark(fig)
# on Darwin these checks get complicated, so don't bother for now
if platform.system() == "Darwin":
Expand Down

0 comments on commit b752d2a

Please sign in to comment.