Skip to content

Commit

Permalink
Update linter configuration and sys-info output (#200)
Browse files Browse the repository at this point in the history
* improve sys-info

* update linter configuration

* update stubs configuration

* update stubs

* fix parsing of metadata

* fix typo

* Update .pre-commit-config.yaml
  • Loading branch information
mscheltienne authored Sep 5, 2024
1 parent 88c67f7 commit b4d00e4
Show file tree
Hide file tree
Showing 32 changed files with 177 additions and 208 deletions.
19 changes: 2 additions & 17 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
repos:
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
files: mne_icalabel

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.7
rev: v0.6.3
hooks:
- id: ruff
name: ruff linter
args: [--fix]
files: mne_icalabel
args: [--fix, --show-fixes]
- id: ruff-format
name: ruff formatter
files: mne_icalabel

- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
Expand All @@ -23,13 +15,6 @@ repos:
args: [--write-changes]
additional_dependencies: [tomli]

- repo: https://github.com/pycqa/pydocstyle
rev: 6.3.0
hooks:
- id: pydocstyle
files: mne_icalabel
additional_dependencies: [tomli]

- repo: https://github.com/mscheltienne/bibclean
rev: 0.8.0
hooks:
Expand Down
4 changes: 2 additions & 2 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

project = "MNE-ICALabel"
author = "Adam Li, Mathieu Scheltienne"
copyright = (
copyright = ( # noqa: A001
f"2021-{date.today().year}, MNE Developers. "
f"Last updated on {date.today().isoformat()}"
)
Expand Down Expand Up @@ -180,7 +180,7 @@
"EX01", # section 'Examples' not found
"ES01", # no extended summary found
"SA01", # section 'See Also' not found
"RT02", # The first line of the Returns section should contain only the type, unless multiple values are being returned # noqa
"RT02", # The first line of the Returns section should contain only the type, unless multiple values are being returned # noqa: E501
}

numpydoc_validate = True
Expand Down
2 changes: 1 addition & 1 deletion examples/00_iclabel.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""
r"""
.. _tuto-iclabel:
Repairing artifacts with ICA automatically using ICLabel Model
Expand Down
16 changes: 4 additions & 12 deletions mne_icalabel/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
"""Automatic ICA labeling for MEG, EEG and iEEG data."""

from . import annotation # noqa: F401
from . import config # noqa: F401
from . import datasets # noqa: F401
from . import features # noqa: F401
from . import gui # noqa: F401
from . import iclabel # noqa: F401
from . import utils # noqa: F401
from ._version import __version__ # noqa: F401
from .label_components import label_components # noqa: F401
from .utils.config import sys_info # noqa: F401
from . import annotation, config, datasets, features, gui, iclabel, utils
from ._version import __version__
from .label_components import label_components
from .utils.config import sys_info
26 changes: 15 additions & 11 deletions mne_icalabel/annotation/tests/test_bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
raw_fname = op.join(data_path, "test_reduced.edf")


@pytest.fixture(scope="function")
def _tmp_bids_path(tmp_path):
@pytest.fixture
def tmp_bids_path(tmp_path):
"""Create a bids path."""
bids_path = BIDSPath(
subject=subject_id,
session=session_id,
Expand All @@ -35,7 +36,8 @@ def _tmp_bids_path(tmp_path):


@pytest.fixture(scope="session")
def _ica():
def ica():
"""Create an ICA object."""
raw = read_raw_edf(raw_fname, preload=True)
raw.filter(l_freq=1, h_freq=100)
n_components = 5
Expand All @@ -44,8 +46,9 @@ def _ica():
return ica


def test_write_channels_tsv(_ica, _tmp_bids_path):
root = _tmp_bids_path.root
def test_write_channels_tsv(ica: ICA, tmp_bids_path):
"""Test writing components to a channels.tsv file."""
root = tmp_bids_path.root
deriv_root = root / "derivatives" / "ICA"
deriv_fname = BIDSPath(
root=deriv_root,
Expand All @@ -57,10 +60,10 @@ def test_write_channels_tsv(_ica, _tmp_bids_path):
suffix="channels",
extension=".tsv",
)
_ica = _ica.copy()
_ica.labels_["ecg"] = [0]
ica = ica.copy()
ica.labels_["ecg"] = [0]

write_components_tsv(_ica, deriv_fname)
write_components_tsv(ica, deriv_fname)

assert deriv_fname.fpath.exists()
expected_json = deriv_fname.copy().update(extension=".json")
Expand All @@ -72,8 +75,9 @@ def test_write_channels_tsv(_ica, _tmp_bids_path):
assert ch_tsv["ic_type"].values[0] == "ecg"


def test_mark_components(_ica, _tmp_bids_path):
root = _tmp_bids_path.root
def test_mark_components(ica, tmp_bids_path):
"""Test marking components."""
root = tmp_bids_path.root
deriv_root = root / "derivatives" / "ICA"
deriv_fname = BIDSPath(
root=deriv_root,
Expand All @@ -85,7 +89,7 @@ def test_mark_components(_ica, _tmp_bids_path):
suffix="channels",
extension=".tsv",
)
write_components_tsv(_ica, deriv_fname)
write_components_tsv(ica, deriv_fname)

# mark components
with pytest.raises(ValueError, match="not a valid label"):
Expand Down
8 changes: 8 additions & 0 deletions mne_icalabel/conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import numpy as np
import pytest
from mne import set_log_level


Expand All @@ -20,3 +22,9 @@ def pytest_configure(config):
if warning_line and not warning_line.startswith("#"):
config.addinivalue_line("filterwarnings", warning_line)
set_log_level("WARNING")


@pytest.fixture(scope="session")
def rng():
"""Return a numpy random generator."""
return np.random.default_rng()
2 changes: 1 addition & 1 deletion mne_icalabel/datasets/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from . import icalabel # noqa: F401
from . import icalabel
2 changes: 1 addition & 1 deletion mne_icalabel/datasets/icalabel/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .icalabel import data_path, has_icalabel_testing_data # noqa: F401
from .icalabel import data_path, has_icalabel_testing_data
4 changes: 1 addition & 3 deletions mne_icalabel/features/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
"""Features for the ICLabel"""

from .topomap import get_topomaps # noqa: F401
from .topomap import get_topomaps
7 changes: 4 additions & 3 deletions mne_icalabel/features/tests/test_topomap.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@


@pytest.mark.filterwarnings("ignore:invalid value encountered in divide:RuntimeWarning")
@pytest.mark.parametrize("ica", (ica, ica_eeg))
@pytest.mark.parametrize("ica", [ica, ica_eeg])
def test_topomap_defaults(ica):
"""Test scalp topography array generation"""
"""Test scalp topography array generation."""
topomaps = get_topomaps(ica, picks=None)
assert isinstance(topomaps, dict)
for topomaps_ in topomaps.values():
Expand All @@ -41,7 +41,8 @@ def test_topomap_defaults(ica):

@pytest.mark.filterwarnings("ignore:invalid value encountered in divide:RuntimeWarning")
@pytest.mark.parametrize(
"picks, res", [(0, 32), ([0, 1, 2], 50), (slice(1, 3), 128), (np.array([1, 2]), 10)]
("picks", "res"),
[(0, 32), ([0, 1, 2], 50), (slice(1, 3), 128), (np.array([1, 2]), 10)],
)
def test_topomap_arguments(picks, res):
"""Test arguments that influence the output shape."""
Expand Down
4 changes: 2 additions & 2 deletions mne_icalabel/gui/_label_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,8 @@ def _update_selected_labels(self) -> None:
self._save_labels() # updates the ICA instance every time

@Slot()
def _reset(self) -> None: # noqa: D401
"""Action of the reset button."""
def _reset(self) -> None:
"""Remove the label from the current component."""
self._reset_buttons()
if self.selected_component in self.selected_labels:
del self.selected_labels[self.selected_component]
Expand Down
2 changes: 1 addition & 1 deletion mne_icalabel/gui/_label_components.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class ICAComponentLabeler(QMainWindow):
"""Update the labels saved."""

def _reset(self) -> None:
"""Action of the reset button."""
"""Remove the label from the current component."""

def _reset_buttons(self) -> None:
"""Reset all buttons."""
Expand Down
1 change: 1 addition & 0 deletions mne_icalabel/gui/tests/test_label_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@


def test_label_components_gui_display():
"""Test that the GUI is displayed correctly."""
ica_ = ica.copy()
gui = label_ica_components(raw, ica_, show=False)
# test setting the label
Expand Down
12 changes: 3 additions & 9 deletions mne_icalabel/iclabel/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
"""ICLabel - An automated electroencephalographic independent component
classifier, dataset, and website.
This is a python implementation of the EEGLAB plugin 'ICLabel'.
"""

from .features import get_iclabel_features # noqa: F401
from .label_components import iclabel_label_components # noqa: F401
from .network import run_iclabel # noqa: F401
from .features import get_iclabel_features
from .label_components import iclabel_label_components
from .network import run_iclabel
14 changes: 2 additions & 12 deletions mne_icalabel/iclabel/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,18 +243,8 @@ def _mergepoints2D(

def _mergesimpts(
data: ArrayLike, tols: list[ArrayLike], mode: str = "average"
) -> ArrayLike: # noqa
"""
Parameters
----------
data : array
tols : list of 3 arrays
mode : str
Returns
-------
array
"""
) -> ArrayLike:
"""Merge similar points."""
data_ = data.copy()[np.argsort(data[:, 0])]
newdata = []
tols_ = np.array(tols)
Expand Down
12 changes: 1 addition & 11 deletions mne_icalabel/iclabel/_utils.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,4 @@ def _mergepoints2D(
def _mergesimpts(
data: ArrayLike, tols: list[ArrayLike], mode: str = "average"
) -> ArrayLike:
"""
Parameters
----------
data : array
tols : list of 3 arrays
mode : str
Returns
-------
array
"""
"""Merge similar points."""
3 changes: 2 additions & 1 deletion mne_icalabel/iclabel/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,8 @@ def _eeg_rpsd_constants(
# possible to reproduce the output in python.
# 'subset' is used to select from arrays and is 0-index in Python while its
# 1-index in MATLAB.
subset = np.random.permutation(range(n_seg)) # 0-index
rng = np.random.default_rng()
subset = rng.permutation(range(n_seg)) # 0-index

return ncomp, nfreqs, n_points, nyquist, index, window, subset

Expand Down
40 changes: 23 additions & 17 deletions mne_icalabel/iclabel/network/tests/test_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ def test_weights_pytorch():

@requires_module("torch")
def test_network_outputs_pytorch():
"""
Compare that the ICLabel network in pytorch and matlab outputs the same
values for a common set of features (input to the forward pass).
"""Compare that the ICLabel network in pytorch and matlab outputs the same values.
Compare the outputs for a common set of features (input to the forward pass).
Notes
-----
Expand Down Expand Up @@ -132,9 +132,9 @@ def test_network_outputs_pytorch():

@requires_module("onnxruntime")
def test_network_outputs_onnx():
"""
Compare that the ICLabel network in onnx and matlab outputs the same
values for a common set of features (input to the forward pass).
"""Compare that the ICLabel network in onnx and matlab outputs the same values.
Compare the outputs for a common set of features (input to the forward pass).
Notes
-----
Expand Down Expand Up @@ -176,7 +176,7 @@ def test_network_outputs_onnx():


@pytest.mark.parametrize(
"eeglab_feature_file, eeglab_feature_formatted_file",
("eeglab_feature_file", "eeglab_feature_formatted_file"),
[
(features_raw_path, features_formatted_raw_path),
(features_epo_path, features_formatted_epo_path),
Expand All @@ -200,18 +200,21 @@ def test_format_input(eeglab_feature_file, eeglab_feature_formatted_file):


@pytest.mark.parametrize(
"eeglab_feature_file, eeglab_output_file",
("eeglab_feature_file", "eeglab_output_file"),
[
(features_raw_path, iclabel_output_raw_path),
(features_epo_path, iclabel_output_epo_path),
],
)
@requires_module("onnxruntime")
def test_run_iclabel_onnx(eeglab_feature_file, eeglab_output_file):
"""Test that the network outputs the same values for the features in
'features_raw_path' and 'features_epo_path' that contains the features
extracted in EEGLAB. This set of feature is compared with the set of
features retrieved in python in 'test_features.py:test_get_features'."""
"""Test that the network outputs the same values as MATLAB.
Test the the network outputs the same values for the features in
'features_raw_path' and 'features_epo_path' that contains the features extracted in
EEGLAB. This set of feature is compared with the set of features retrieved in python
in 'test_features.py:test_get_features'.
"""
from mne_icalabel.iclabel.network.onnx import _run_iclabel

features_eeglab = loadmat(eeglab_feature_file)["features"]
Expand All @@ -230,18 +233,21 @@ def test_run_iclabel_onnx(eeglab_feature_file, eeglab_output_file):


@pytest.mark.parametrize(
"eeglab_feature_file, eeglab_output_file",
("eeglab_feature_file", "eeglab_output_file"),
[
(features_raw_path, iclabel_output_raw_path),
(features_epo_path, iclabel_output_epo_path),
],
)
@requires_module("torch")
def test_run_iclabel_pytorch(eeglab_feature_file, eeglab_output_file):
"""Test that the network outputs the same values for the features in
'features_raw_path' and 'features_epo_path' that contains the features
extracted in EEGLAB. This set of feature is compared with the set of
features retrieved in python in 'test_features.py:test_get_features'."""
"""Test that the network outputs matches MATLAB.
Test that the net work outputs the same values for the features in
'features_raw_path' and 'features_epo_path' that contains the features extracted in
EEGLAB. This set of feature is compared with the set of features retrieved in python
in 'test_features.py:test_get_features'.
"""
from mne_icalabel.iclabel.network.torch import _run_iclabel

features_eeglab = loadmat(eeglab_feature_file)["features"]
Expand Down
4 changes: 2 additions & 2 deletions mne_icalabel/iclabel/network/torch.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ def reshape_concat(self, tensor: torch.Tensor) -> torch.Tensor: # noqa: D102
tensor = tensor.permute((0, 3, 1, 2))
return tensor

def forward(
def forward( # noqa: D102
self, images: torch.Tensor, psds: torch.Tensor, autocorr: torch.Tensor
) -> torch.Tensor: # noqa: D102
) -> torch.Tensor:
out_img = self.img_conv(images)
out_psds = self.psds_conv(psds)
out_autocorr = self.autocorr_conv(autocorr)
Expand Down
Loading

0 comments on commit b4d00e4

Please sign in to comment.