Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAINT: Improve qdarkstyle logic #12491

Merged
merged 5 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading