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: Work around MNE change #1128

Merged
merged 4 commits into from
Mar 22, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ The following authors contributed for the first time. Thank you so much! 🤩
The following authors had contributed before. Thank you for sticking around! 🤘

* `Richard Höchenberger`_
* `Eric Larson`_

Detailed list of changes
~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -54,6 +55,7 @@ Detailed list of changes
- Amending a dataset now works in cases where the newly-written data contains additional participant properties (new columns in ``participants.tsv``) not found in the existing dataset, by `Richard Höchenberger`_ (:gh:`1113`)
- Fix ``raw_to_bids`` CLI tool to properly recognize boolean and numeric values for the ``line_freq`` and ``overwrite`` parameters, by `Stefan Appelhoff`_ (:gh:`1125`)
- Fix :func:`~mne_bids.copyfiles.copyfile_eeglab` to prevent data type conversion leading to an ``eeg_checkset`` failure when trying to load the file in EEGLAB, by `Laetitia Fesselier`_ (:gh:`1122`)
- Improve compatibility with latest MNE-Python, by `Eric Larson`_ (:gh:`1128`)

:doc:`Find out what was new in previous releases <whats_new_previous_releases>`

Expand Down
12 changes: 4 additions & 8 deletions mne_bids/dig.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import numpy as np
from mne.io.constants import FIFF
from mne.utils import (logger, _validate_type, _check_option,
has_nibabel, get_subjects_dir)
get_subjects_dir)
from mne.io.pick import _picks_to_idx

from mne_bids.config import (ALLOWED_SPACES, BIDS_COORDINATE_UNITS,
Expand All @@ -25,7 +25,7 @@
BIDS_STANDARD_TEMPLATE_COORDINATE_SYSTEMS)
from mne_bids.tsv_handler import _from_tsv
from mne_bids.utils import (_scale_coord_to_meters, _write_json, _write_tsv,
verbose, warn)
verbose, warn, _import_nibabel)
from mne_bids.path import BIDSPath

data_dir = Path(__file__).parent / 'data'
Expand Down Expand Up @@ -667,9 +667,7 @@ def convert_montage_to_ras(montage, subject, subjects_dir=None, verbose=None):
%(subjects_dir)s
%(verbose)s
"""
if not has_nibabel(): # pragma: no cover
raise ImportError('This function requires nibabel.')
import nibabel as nib
nib = _import_nibabel('converting a montage to RAS')

subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
T1_fname = op.join(subjects_dir, subject, 'mri', 'T1.mgz')
Expand Down Expand Up @@ -712,9 +710,7 @@ def convert_montage_to_mri(montage, subject, subjects_dir=None, verbose=None):
The transformation matrix from ``'ras'`` (``scanner RAS``) to
``'mri'`` (``surface RAS``).
"""
if not has_nibabel(): # pragma: no cover
raise ImportError('This function requires nibabel.')
import nibabel as nib
nib = _import_nibabel('converting a montage to MRI')

subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
T1_fname = op.join(subjects_dir, subject, 'mri', 'T1.mgz')
Expand Down
8 changes: 3 additions & 5 deletions mne_bids/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import mne
from mne import io, read_events, events_from_annotations
from mne.io.pick import pick_channels_regexp
from mne.utils import has_nibabel, logger, get_subjects_dir
from mne.utils import logger, get_subjects_dir
from mne.coreg import fit_matched_points
from mne.transforms import apply_trans

Expand All @@ -27,7 +27,7 @@
from mne_bids.config import (ALLOWED_DATATYPE_EXTENSIONS,
ANNOTATIONS_TO_KEEP,
reader, _map_options)
from mne_bids.utils import _get_ch_type_mapping, verbose, warn
from mne_bids.utils import _get_ch_type_mapping, verbose, warn, _import_nibabel
from mne_bids.path import (BIDSPath, _parse_ext, _find_matching_sidecar,
_infer_datatype, get_bids_path_from_fname)

Expand Down Expand Up @@ -900,9 +900,7 @@ def get_head_mri_trans(bids_path, extra_params=None, t1_bids_path=None,
trans : mne.transforms.Transform
The data transformation matrix from head to MRI coordinates.
"""
if not has_nibabel(): # pragma: no cover
raise ImportError('This function requires nibabel.')
import nibabel as nib
nib = _import_nibabel('get a head to MRI transform')

if not isinstance(bids_path, BIDSPath):
raise RuntimeError('"bids_path" must be a BIDSPath object. Please '
Expand Down
8 changes: 3 additions & 5 deletions mne_bids/tests/test_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import mne
from mne.datasets import testing
from mne.io.constants import FIFF
from mne.utils import requires_nibabel, object_diff, requires_version
from mne.utils import object_diff, requires_version
from mne.utils import assert_dig_allclose, check_version

from mne_bids import BIDSPath
Expand Down Expand Up @@ -209,12 +209,11 @@ def test_read_participants_handedness_and_sex_mapping(hand_bids, hand_mne,
assert raw.info['subject_info']['sex'] is sex_mne


@requires_nibabel()
@pytest.mark.filterwarnings(warning_str['channel_unit_changed'])
@testing.requires_testing_data
def test_get_head_mri_trans(tmp_path):
"""Test getting a trans object from BIDS data."""
import nibabel as nib
nib = pytest.importorskip('nibabel')

event_id = {'Auditory/Left': 1, 'Auditory/Right': 2, 'Visual/Left': 3,
'Visual/Right': 4, 'Smiley': 5, 'Button': 32}
Expand Down Expand Up @@ -1009,13 +1008,12 @@ def test_handle_ieeg_coords_reading(bids_path, tmp_path):
assert ch['ch_name'] not in raw.info['bads']


@requires_nibabel()
@pytest.mark.filterwarnings(warning_str['channel_unit_changed'])
@pytest.mark.parametrize('fname', ['testdata_ctf.ds', 'catch-alp-good-f.ds'])
@testing.requires_testing_data
def test_get_head_mri_trans_ctf(fname, tmp_path):
"""Test getting a trans object from BIDS data in CTF."""
import nibabel as nib
nib = pytest.importorskip('nibabel')

ctf_data_path = op.join(data_path, 'CTF')
raw_ctf_fname = op.join(ctf_data_path, fname)
Expand Down
3 changes: 1 addition & 2 deletions mne_bids/tests/test_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import mne
from mne.io.constants import FIFF
from mne.datasets import testing
from mne.utils import requires_nibabel

from mne_bids import (BIDSPath, write_raw_bids,
write_meg_calibration, write_meg_crosstalk,
Expand Down Expand Up @@ -136,10 +135,10 @@ def test_update_sidecar_jsons(_get_bids_test_dir, _bids_validate,
error_bids_path, _get_sidecar_json_update_file)


@requires_nibabel()
@testing.requires_testing_data
def test_update_anat_landmarks(tmp_path):
"""Test updating the anatomical landmarks of an MRI scan."""
pytest.importorskip('nibabel')
raw_path = data_path / 'MEG' / 'sample' / 'sample_audvis_trunc_raw.fif'
trans_path = Path(str(raw_path).replace('_raw.fif', '-trans.fif'))
t1_path = data_path / 'subjects' / 'sample' / 'mri' / 'T1.mgz'
Expand Down
9 changes: 4 additions & 5 deletions mne_bids/tests/test_write.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

import mne
from mne.datasets import testing
from mne.utils import check_version, requires_nibabel, requires_version
from mne.utils import check_version, requires_version
from mne.io import anonymize_info
from mne.io.constants import FIFF
from mne.io.kit.kit import get_kit_info
Expand Down Expand Up @@ -1983,12 +1983,11 @@ def test_get_anat_landmarks():
mri_voxel_landmarks, landmarks, decimal=5)


@requires_nibabel()
@testing.requires_testing_data
def test_write_anat(_bids_validate, tmp_path):
"""Test writing anatomical data."""
nib = pytest.importorskip('nibabel')
# Get the MNE testing sample data
import nibabel as nib
bids_root = tmp_path / 'bids1'

# Get the T1 weighted MRI data file
Expand Down Expand Up @@ -2199,10 +2198,10 @@ def test_write_raw_no_dig(tmp_path):
assert bids_path_.extension == '.fif'


@requires_nibabel()
@testing.requires_testing_data
def test_write_anat_pathlike(tmp_path):
"""Test writing anatomical data with pathlib.Paths."""
pytest.importorskip('nibabel')
raw_fname = op.join(data_path, 'MEG', 'sample',
'sample_audvis_trunc_raw.fif')
trans_fname = raw_fname.replace('_raw.fif', '-trans.fif')
Expand Down Expand Up @@ -3521,10 +3520,10 @@ def test_write_raw_special_paths(tmp_path, dir_name):
write_raw_bids(raw=raw, bids_path=bids_path)


@requires_nibabel()
@testing.requires_testing_data
def test_anonymize_dataset(_bids_validate, tmpdir):
"""Test creating an anonymized copy of a dataset."""
pytest.importorskip('nibabel')
# Create a non-anonymized dataset
bids_root = tmpdir / 'bids'
bids_path = _bids_path.copy().update(
Expand Down
11 changes: 11 additions & 0 deletions mne_bids/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,17 @@ def _check_datatype(raw, datatype):
'the raw object.')


def _import_nibabel(why='work with MRI data'):
try:
import nibabel # noqa
except ImportError as exc:
raise exc.__class__(
f'nibabel is required to {why} but could not be imported, '
f'got: {exc}') from None
else:
return nibabel


def warn(message, category=RuntimeWarning, module='mne_bids',
ignore_namespaces=('mne', 'mne_bids')): # noqa: D103
_warn(
Expand Down
21 changes: 7 additions & 14 deletions mne_bids/write.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from mne.io import BaseRaw, read_fiducials
from mne.channels.channels import (_unit2human, _get_meg_system)
from mne.chpi import get_chpi_info
from mne.utils import (check_version, has_nibabel, logger, Bunch,
from mne.utils import (check_version, logger, Bunch,
_validate_type, get_subjects_dir, verbose,
ProgressBar)
import mne.preprocessing
Expand All @@ -40,7 +40,8 @@
from mne_bids.utils import (_write_json, _write_tsv, _write_text,
_age_on_date, _infer_eeg_placement_scheme,
_get_ch_type_mapping, _check_anonymize,
_stamp_to_dt, _handle_datatype, warn)
_stamp_to_dt, _handle_datatype, warn,
_import_nibabel)
from mne_bids import (BIDSPath, read_raw_bids, get_anonymization_daysback,
get_bids_path_from_fname)
from mne_bids.path import _parse_ext, _mkdir_p, _path_to_str
Expand Down Expand Up @@ -603,9 +604,7 @@ def _scans_tsv(raw, raw_fname, fname, keep_source, overwrite=False):


def _load_image(image, name='image'):
if not has_nibabel(): # pragma: no cover
raise ImportError('This function requires nibabel.')
import nibabel as nib
nib = _import_nibabel()
if type(image) not in nib.all_image_classes:
try:
image = _path_to_str(image)
Expand Down Expand Up @@ -929,9 +928,7 @@ def _sidecar_json(raw, task, manufacturer, fname, datatype,


def _deface(image, landmarks, deface):
if not has_nibabel(): # pragma: no cover
raise ImportError('This function requires nibabel.')
import nibabel as nib
nib = _import_nibabel('deface MRIs')

inset, theta = (5, 15.)
if isinstance(deface, dict):
Expand Down Expand Up @@ -2028,9 +2025,7 @@ def get_anat_landmarks(image, info, trans, fs_subject, fs_subjects_dir=None):
landmarks : mne.channels.DigMontage
A montage with the landmarks in MRI voxel space.
"""
if not has_nibabel(): # pragma: no cover
raise ImportError('This function requires nibabel.')
import nibabel as nib
nib = _import_nibabel('get anatomical landmarks')
coords_dict, coord_frame = _get_fid_coords(info['dig'])
if coord_frame != FIFF.FIFFV_COORD_HEAD:
raise ValueError('Fiducial coordinates in `info` must be in '
Expand Down Expand Up @@ -2184,9 +2179,7 @@ def write_anat(image, bids_path, landmarks=None, deface=False, overwrite=False,
bids_path : BIDSPath
Path to the written MRI data.
"""
if not has_nibabel(): # pragma: no cover
raise ImportError('This function requires nibabel.')
import nibabel as nib
nib = _import_nibabel('write anatomical MRI data')

write_sidecar = landmarks is not None

Expand Down