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

FIX: problem when closing settings fig #85

Merged
merged 32 commits into from
Apr 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
6c40f7f
fix typo in _toggle_help_fig
juangpc Mar 31, 2022
8865cd0
define _fake_click_on_toolbar_action member fcn in PyQtGraphBrowser
juangpc Apr 5, 2022
3da8095
add window title to settings and help windows dialogs
juangpc Apr 5, 2022
89362d4
change order of downsampling methods in settings window
juangpc Apr 5, 2022
4f69bce
add comma as keyboard shortcut for settings window
juangpc Apr 5, 2022
e6462cb
add extra tests for other toolbar menus
juangpc Apr 7, 2022
0edb436
fix conflict Settings window title
juangpc Apr 7, 2022
069a97a
fix conflict Help window title
juangpc Apr 7, 2022
c890cc8
add projections window title
juangpc Apr 7, 2022
d1757a1
update readme markup instructions in repo
juangpc Apr 7, 2022
f7d8d57
add floating point accuracy
juangpc Apr 7, 2022
e73c698
improve test toolbox time span shown
juangpc Apr 7, 2022
7241b84
improve test toolbar channel number shown
juangpc Apr 7, 2022
1ebfdaa
fix problem in test toolbar time span shown
juangpc Apr 7, 2022
5341a2b
fix merge conflict in projector dialog window title
juangpc Apr 7, 2022
70a5a81
fix projection input arg forwarded to parent class
juangpc Apr 7, 2022
01bdf10
delete comma shortcut for settings dialog
juangpc Apr 7, 2022
1420f85
set fig_projections to none after deleting dialog
juangpc Apr 7, 2022
8464bc2
Merge branch 'main' into fix_settings_menu_crash
juangpc Apr 7, 2022
61239ce
improve README markdown file for repo
juangpc Apr 7, 2022
e855ffd
minor edit typo in comment
juangpc Apr 7, 2022
e77d266
fix argument forwarding to superclass projections dialog
juangpc Apr 7, 2022
6375588
fix typo comment kwargs
juangpc Apr 7, 2022
ef7569a
delete fullscreen toolbar action test, no longer there
juangpc Apr 7, 2022
d80e5ac
fix change in name of toolbar actions in test
juangpc Apr 7, 2022
e6ec944
import standard lib first
juangpc Apr 7, 2022
3aefc9d
make compliant with flake8
juangpc Apr 7, 2022
798c39d
revert change order of subsampling methods
juangpc Apr 7, 2022
0408af1
revert change in ProjDialog constructor
juangpc Apr 7, 2022
15c4813
select benchmark funcs with mark not file
juangpc Apr 8, 2022
e8d91bb
improve scroll control test
juangpc Apr 8, 2022
4cb3573
use explicit length sensitivity tests. flake compliance
juangpc Apr 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,12 @@ You can run a benchmark locally with:
pytest -m benchmark mne_qt_browser
```

To run tests, clone mne-python, and then run the PyQtGraph tests with e.g.:
To run the PyQtGraph tests you have to run:
```
pytest mne_qt_browser/tests/test_pg_specific.py
```

Additionally, clone mne-python, and then run:

```console
pytest -m pgtest ../mne-python/mne/viz/tests
Expand Down
19 changes: 14 additions & 5 deletions mne_qt_browser/_pg_figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -1600,10 +1600,10 @@ def __init__(self, main, title='Settings', **kwargs):
self.setLayout(layout)
self.show()

def closeEvent(self):
def closeEvent(self, event):
_disconnect(self.ds_method_cmbx.currentTextChanged)
_disconnect(self.scroll_sensitivity_slider.valueChanged)
super.closeEvent()
super().closeEvent(event)

def _value_changed(self, new_value, value_name):
if value_name == 'downsampling' and new_value == 0:
Expand Down Expand Up @@ -4101,6 +4101,7 @@ def _toggle_proj_fig(self):
ProjDialog(self, name='fig_proj')
else:
self.mne.fig_proj.close()
self.mne.fig_proj = None

def _toggle_all_projs(self):
if self.mne.fig_proj is None:
Expand All @@ -4118,8 +4119,8 @@ def _toggle_settings_fig(self):
if self.mne.fig_settings is None:
SettingsDialog(self, name='fig_settings')
else:
self.mne.fig_help.close()
self.mne.fig_help = None
self.mne.fig_settings.close()
self.mne.fig_settings = None

def _toggle_help_fig(self):
if self.mne.fig_help is None:
Expand Down Expand Up @@ -4562,6 +4563,14 @@ def closeEvent(self, event):
# Make sure it gets deleted after it was closed.
self.deleteLater()

def _fake_click_on_toolbar_action(self, action_name, wait_after=500):
"""Trigger event associated with action 'action_name' in toolbar."""
for action in self.mne.toolbar.actions():
if not action.isSeparator():
if action.iconText() == action_name:
action.trigger()
QTest.qWait(wait_after)


def _get_n_figs():
# Wait for a short time to let the Qt-loop clean up
Expand Down Expand Up @@ -4646,7 +4655,7 @@ def _init_browser(**kwargs):
app_kwargs['splash'] = 'Initializing mne-qt-browser...'
out = _init_mne_qtapp(pg_app=True, **app_kwargs)
if 'splash' in app_kwargs:
kwargs['splash'] = out[1] # returned as secord element
kwargs['splash'] = out[1] # returned as second element
browser = MNEQtBrowser(**kwargs)

return browser
Expand Down
280 changes: 280 additions & 0 deletions mne_qt_browser/tests/test_pg_specific.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# License: BSD-3-Clause

import numpy as np
from PyQt5.QtTest import QTest


def test_annotations_interactions(raw_orig, pg_backend):
Expand Down Expand Up @@ -81,3 +82,282 @@ def test_annotations_interactions(raw_orig, pg_backend):
assert fig.msg_box.informativeText() == 'Start can\'t be bigger or ' \
'equal to Stop!'
fig.msg_box.close()


def test_pg_settings_dialog(raw_orig, pg_backend):
"""Test Settings Dialog toggle on/off for pyqtgraph-backend."""
fig = raw_orig.plot()
fig.test_mode = True
QTest.qWaitForWindowExposed(fig)
QTest.qWait(50)
assert fig.mne.fig_settings is None
fig._fake_click_on_toolbar_action('Settings', wait_after=500)
assert fig.mne.fig_settings is not None
assert pg_backend._get_n_figs() == 2
fig._fake_click_on_toolbar_action('Settings', wait_after=500)
assert pg_backend._get_n_figs() == 1
assert fig.mne.fig_settings is None
fig._fake_click_on_toolbar_action('Settings', wait_after=500)
assert pg_backend._get_n_figs() == 2
assert fig.mne.fig_settings is not None
fig._fake_click_on_toolbar_action('Settings', wait_after=500)
assert pg_backend._get_n_figs() == 1
assert fig.mne.fig_settings is None

fig._fake_click_on_toolbar_action('Settings', wait_after=500)
assert fig.mne.fig_settings is not None
downsampling_control = fig.mne.fig_settings.downsampling_box
assert downsampling_control.value() == fig.mne.downsampling

downsampling_control.setValue(2)
QTest.qWait(100)
assert downsampling_control.value() == 2
assert downsampling_control.value() == fig.mne.downsampling

downsampling_control.setValue(3)
QTest.qWait(100)
assert downsampling_control.value() == 3
assert downsampling_control.value() == fig.mne.downsampling

QTest.qWait(100)
downsampling_method_control = fig.mne.fig_settings.ds_method_cmbx
assert fig.mne.ds_method == downsampling_method_control.currentText()

downsampling_method_control.setCurrentText('mean')
QTest.qWait(100)
assert downsampling_method_control.currentText() == 'mean'
assert fig.mne.ds_method == 'mean'

downsampling_method_control.setCurrentText('subsample')
QTest.qWait(100)
assert downsampling_method_control.currentText() == 'subsample'
assert fig.mne.ds_method == 'subsample'

downsampling_method_control.setCurrentText('peak')
QTest.qWait(100)
assert downsampling_method_control.currentText() == 'peak'
assert fig.mne.ds_method == 'peak'

downsampling_method_control.setCurrentText('invalid_method_name')
QTest.qWait(100)
assert downsampling_method_control.currentText() != 'invalid_method_name'

sensitivity_control = fig.mne.fig_settings.scroll_sensitivity_slider
assert fig.mne.scroll_sensitivity == sensitivity_control.value()

sensitivity_control.setValue(100)
QTest.qWait(100)
assert sensitivity_control.value() == 100
assert fig.mne.scroll_sensitivity == 100

QTest.qWait(100)
sensitivity_values = list(range(sensitivity_control.minimum(),
sensitivity_control.maximum() + 1, 40))
if sensitivity_values[-1] != sensitivity_control.maximum():
sensitivity_values.append(sensitivity_control.maximum())

sensitivities_mne = list()
sensitivities_control = list()
for val in sensitivity_values:
sensitivity_control.setValue(val)
QTest.qWait(50)
sensitivities_mne.append(fig.mne.scroll_sensitivity)
sensitivities_control.append(sensitivity_control.value())
assert sensitivities_mne == sensitivity_values
assert sensitivities_control == sensitivity_values

sensitivity_values = sensitivity_values[::-1]
sensitivities_mne = list()
sensitivities_control = list()
for val in sensitivity_values:
sensitivity_control.setValue(val)
QTest.qWait(50)
sensitivities_mne.append(fig.mne.scroll_sensitivity)
sensitivities_control.append(sensitivity_control.value())
assert sensitivities_mne == sensitivity_values
assert sensitivities_control == sensitivity_values


larsoner marked this conversation as resolved.
Show resolved Hide resolved
def test_pg_help_dialog(raw_orig, pg_backend):
"""Test Settings Dialog toggle on/off for pyqtgraph-backend."""
fig = raw_orig.plot()
fig.test_mode = True
QTest.qWaitForWindowExposed(fig)
QTest.qWait(50)
assert fig.mne.fig_help is None
fig._fake_click_on_toolbar_action('Help', wait_after=500)
assert fig.mne.fig_help is not None
assert pg_backend._get_n_figs() == 2
fig._fake_click_on_toolbar_action('Help', wait_after=500)
assert fig.mne.fig_help is None
assert pg_backend._get_n_figs() == 1
fig._fake_click_on_toolbar_action('Help', wait_after=500)
assert fig.mne.fig_help is not None
assert pg_backend._get_n_figs() == 2
fig._fake_click_on_toolbar_action('Help', wait_after=500)
assert fig.mne.fig_help is None
assert pg_backend._get_n_figs() == 1


def test_pg_toolbar_time_plus_minus(raw_orig, pg_backend):
fig = raw_orig.plot()
fig.test_mode = True
QTest.qWaitForWindowExposed(fig)
assert pg_backend._get_n_figs() == 1

min_duration = 3 * np.diff(fig.mne.inst.times[:2])[0] # hard code.
xmin, xmax = fig.mne.viewbox.viewRange()[0]
while xmax - xmin > min_duration:
fig._fake_click_on_toolbar_action('- Time', wait_after=20)
xmin, xmax = fig.mne.viewbox.viewRange()[0]
assert xmax - xmin == min_duration

eps = 0.01
step = 0.25
fig._fake_click_on_toolbar_action('+ Time', wait_after=100)
xmin_new, xmax_new = fig.mne.viewbox.viewRange()[0]
assert xmax_new - (xmax + (xmax - xmin * step)) < eps

xmin, xmax = fig.mne.viewbox.viewRange()[0]
while xmax + fig.mne.duration * step < fig.mne.xmax:
fig._fake_click_on_toolbar_action('+ Time', wait_after=20)
xmin, xmax = fig.mne.viewbox.viewRange()[0]

fig._fake_click_on_toolbar_action('+ Time', wait_after=200)
fig._fake_click_on_toolbar_action('+ Time', wait_after=200)

xmin, xmax = fig.mne.viewbox.viewRange()[0]
fig._fake_click_on_toolbar_action('+ Time', wait_after=200)
xmin_new, xmax_new = fig.mne.viewbox.viewRange()[0]
assert xmax_new == xmax # no effect after span maxed

step = -0.2
xmin, xmax = fig.mne.viewbox.viewRange()[0]
fig._fake_click_on_toolbar_action('- Time', wait_after=200)
xmin_new, xmax_new = fig.mne.viewbox.viewRange()[0]
assert xmax_new == xmax + ((xmax - xmin) * step)

xmin, xmax = fig.mne.viewbox.viewRange()[0]
fig._fake_click_on_toolbar_action('- Time', wait_after=200)
xmin_new, xmax_new = fig.mne.viewbox.viewRange()[0]
assert xmax_new == xmax + ((xmax - xmin) * step)

for _ in range(7):
fig._fake_click_on_toolbar_action('- Time', wait_after=20)

assert pg_backend._get_n_figs() == 1 # still alive


def test_pg_toolbar_channels_plus_minus(raw_orig, pg_backend):
fig = raw_orig.plot()
fig.test_mode = True
QTest.qWaitForWindowExposed(fig)
assert pg_backend._get_n_figs() == 1

if fig.mne.butterfly is not True:
fig._fake_keypress('b') # toggle butterfly mode
fig._fake_click_on_toolbar_action('- Channels', wait_after=100)
ymin, ymax = fig.mne.viewbox.viewRange()[1]
fig._fake_click_on_toolbar_action('- Channels', wait_after=100)
assert [ymin, ymax] == fig.mne.viewbox.viewRange()[1]
fig._fake_click_on_toolbar_action('+ Channels', wait_after=100)
assert [ymin, ymax] == fig.mne.viewbox.viewRange()[1]

if fig.mne.butterfly is True:
fig._fake_keypress('b') # toggle butterfly off

while ymax - ymin > 2:
fig._fake_click_on_toolbar_action('- Channels', wait_after=40)
ymin, ymax = fig.mne.viewbox.viewRange()[1]
assert ymax - ymin == 2
fig._fake_click_on_toolbar_action('- Channels', wait_after=40)
ymin, ymax = fig.mne.viewbox.viewRange()[1]
assert ymax - ymin == 2

step = 10
fig._fake_click_on_toolbar_action('+ Channels', wait_after=100)
ymin_new, ymax_new = fig.mne.viewbox.viewRange()[1]
assert ymax_new == ymax + step

ymin, ymax = fig.mne.viewbox.viewRange()[1]
fig._fake_click_on_toolbar_action('+ Channels', wait_after=100)
ymin_new, ymax_new = fig.mne.viewbox.viewRange()[1]
assert ymax_new == ymax + step

ymin, ymax = fig.mne.viewbox.viewRange()[1]
fig._fake_click_on_toolbar_action('+ Channels', wait_after=100)
ymin_new, ymax_new = fig.mne.viewbox.viewRange()[1]
assert ymax_new == ymax + step

assert pg_backend._get_n_figs() == 1 # still alive


def test_pg_toolbar_zoom(raw_orig, pg_backend):
fig = raw_orig.plot()
fig.test_mode = True
QTest.qWaitForWindowExposed(fig)
assert pg_backend._get_n_figs() == 1

step = 4 / 5
scale_factor = fig.mne.scale_factor
fig._fake_click_on_toolbar_action('Zoom out', wait_after=100)
scale_factor_new = fig.mne.scale_factor
assert scale_factor_new == scale_factor * step

for _ in range(6):
fig._fake_click_on_toolbar_action('Zoom out', wait_after=100)

step = 5 / 4
scale_factor = fig.mne.scale_factor
fig._fake_click_on_toolbar_action('Zoom in', wait_after=100)
scale_factor_new = fig.mne.scale_factor
assert scale_factor_new == scale_factor * step

for _ in range(6):
fig._fake_click_on_toolbar_action('Zoom in', wait_after=100)

assert pg_backend._get_n_figs() == 1 # still alive


def test_pg_toolbar_annotations(raw_orig, pg_backend):
fig = raw_orig.plot()
fig.test_mode = True
QTest.qWaitForWindowExposed(fig)
assert pg_backend._get_n_figs() == 1

state_annotation_widget = fig.mne.annotation_mode
fig._fake_click_on_toolbar_action('Annotations', wait_after=100)
assert fig.mne.annotation_mode != state_annotation_widget

fig._fake_click_on_toolbar_action('Annotations', wait_after=300)
fig._fake_click_on_toolbar_action('Annotations', wait_after=300)
fig._fake_click_on_toolbar_action('Annotations', wait_after=300)

assert pg_backend._get_n_figs() == 1 # still alive


def test_pg_toolbar_actions(raw_orig, pg_backend):
""" Test toolbar all actions combined.
Toolbar actions here create a separate QDialog window.
We test the state machine for each window toggle button. """
fig = raw_orig.plot()
fig.test_mode = True
QTest.qWaitForWindowExposed(fig)
assert pg_backend._get_n_figs() == 1

fig._fake_click_on_toolbar_action('SSP', wait_after=200)
assert pg_backend._get_n_figs() == 2
fig._fake_click_on_toolbar_action('Settings', wait_after=200)
assert pg_backend._get_n_figs() == 3
fig._fake_click_on_toolbar_action('Settings', wait_after=100)
assert pg_backend._get_n_figs() == 2
fig._fake_click_on_toolbar_action('Help', wait_after=200)
assert pg_backend._get_n_figs() == 3
fig._fake_click_on_toolbar_action('Settings', wait_after=200)
assert pg_backend._get_n_figs() == 4
fig._fake_click_on_toolbar_action('SSP', wait_after=200)
assert pg_backend._get_n_figs() == 3
fig._fake_click_on_toolbar_action('Settings', wait_after=100)
assert pg_backend._get_n_figs() == 2
fig._fake_click_on_toolbar_action('Help', wait_after=100)
assert pg_backend._get_n_figs() == 1