Repository: mne-tools/mne-python

Issue:
De-duplicate channel types
As a follow-up to #4842, we should de-duplicate various definitions of valid channel types. Currently, these can be found in

- `mne.io.pick`: `get_channel_types`, `pick_types`, `_PICK_TYPES_DATA_DICT`, ... There are many more possibly relevant objects, but I need feedback which should be refactored and which should be left as is.
- `mne.io.meas_info`: `_kind_dict`

Anywhere else I forgot?

There should be only one place where valid channel types are defined. I suggest using `mne.io.pick` (currently it is inside `get_channel_types`, but this could be moved to a global dict in this module if desired.


Discussion:
I would also standardize stuff in pick.py

@agramfort did you think of anything in particular in addition to the functions in `pick.py` I mentioned above? I think we should go through the whole module and choose what to refactor and what to leave alone.
did not have time to look yet. Start and we'll see how the diff looks like

@cbrnr I am not sure what you had in mind here? can you point to a code duplication or possible inconsistency?
Currently the mapping between channel type and FIFF constants is implemented multiple times (at least in `mne.io.pick.get_channel_types` and `mne.io.meas_info._kind_dict`). There should be only one place where this  mapping is defined.
indeed !

+1 for using get_channel_types in meas_info and remove _kind_dict

We'll want to do this at the start of a new release cycle rather than right before release so I'm bumping to 0.21

Resolving patch:
diff --git a/mne/channels/channels.py b/mne/channels/channels.py
--- a/mne/channels/channels.py
+++ b/mne/channels/channels.py
@@ -27,7 +27,7 @@
 from ..io.pick import (channel_type, pick_info, pick_types, _picks_by_type,
                        _check_excludes_includes, _contains_ch_type,
                        channel_indices_by_type, pick_channels, _picks_to_idx,
-                       _get_channel_types)
+                       _get_channel_types, get_channel_type_constants)
 from ..io.write import DATE_NONE
 from ..io._digitization import _get_data_as_dict_from_dig
 
@@ -275,41 +275,11 @@ def get_montage(self):
         return montage
 
 
-# XXX Eventually de-duplicate with _kind_dict of mne/io/meas_info.py
-_human2fiff = {'ecg': FIFF.FIFFV_ECG_CH,
-               'eeg': FIFF.FIFFV_EEG_CH,
-               'emg': FIFF.FIFFV_EMG_CH,
-               'eog': FIFF.FIFFV_EOG_CH,
-               'exci': FIFF.FIFFV_EXCI_CH,
-               'ias': FIFF.FIFFV_IAS_CH,
-               'misc': FIFF.FIFFV_MISC_CH,
-               'resp': FIFF.FIFFV_RESP_CH,
-               'seeg': FIFF.FIFFV_SEEG_CH,
-               'stim': FIFF.FIFFV_STIM_CH,
-               'syst': FIFF.FIFFV_SYST_CH,
-               'bio': FIFF.FIFFV_BIO_CH,
-               'ecog': FIFF.FIFFV_ECOG_CH,
-               'fnirs_cw_amplitude': FIFF.FIFFV_FNIRS_CH,
-               'fnirs_od': FIFF.FIFFV_FNIRS_CH,
-               'hbo': FIFF.FIFFV_FNIRS_CH,
-               'hbr': FIFF.FIFFV_FNIRS_CH}
-_human2unit = {'ecg': FIFF.FIFF_UNIT_V,
-               'eeg': FIFF.FIFF_UNIT_V,
-               'emg': FIFF.FIFF_UNIT_V,
-               'eog': FIFF.FIFF_UNIT_V,
-               'exci': FIFF.FIFF_UNIT_NONE,
-               'ias': FIFF.FIFF_UNIT_NONE,
-               'misc': FIFF.FIFF_UNIT_V,
-               'resp': FIFF.FIFF_UNIT_NONE,
-               'seeg': FIFF.FIFF_UNIT_V,
-               'stim': FIFF.FIFF_UNIT_NONE,
-               'syst': FIFF.FIFF_UNIT_NONE,
-               'bio': FIFF.FIFF_UNIT_V,
-               'ecog': FIFF.FIFF_UNIT_V,
-               'fnirs_cw_amplitude': FIFF.FIFF_UNIT_V,
-               'fnirs_od': FIFF.FIFF_UNIT_NONE,
-               'hbo': FIFF.FIFF_UNIT_MOL,
-               'hbr': FIFF.FIFF_UNIT_MOL}
+channel_type_constants = get_channel_type_constants()
+_human2fiff = {k: v.get('kind', FIFF.FIFFV_COIL_NONE) for k, v in
+               channel_type_constants.items()}
+_human2unit = {k: v.get('unit', FIFF.FIFF_UNIT_NONE) for k, v in
+               channel_type_constants.items()}
 _unit2human = {FIFF.FIFF_UNIT_V: 'V',
                FIFF.FIFF_UNIT_T: 'T',
                FIFF.FIFF_UNIT_T_M: 'T/m',
diff --git a/mne/io/meas_info.py b/mne/io/meas_info.py
--- a/mne/io/meas_info.py
+++ b/mne/io/meas_info.py
@@ -17,7 +17,8 @@
 import numpy as np
 from scipy import linalg
 
-from .pick import channel_type, pick_channels, pick_info
+from .pick import (channel_type, pick_channels, pick_info,
+                   get_channel_type_constants)
 from .constants import FIFF, _coord_frame_named
 from .open import fiff_open
 from .tree import dir_tree_find
@@ -40,30 +41,6 @@
 
 b = bytes  # alias
 
-_kind_dict = dict(
-    eeg=(FIFF.FIFFV_EEG_CH, FIFF.FIFFV_COIL_EEG, FIFF.FIFF_UNIT_V),
-    mag=(FIFF.FIFFV_MEG_CH, FIFF.FIFFV_COIL_VV_MAG_T3, FIFF.FIFF_UNIT_T),
-    grad=(FIFF.FIFFV_MEG_CH, FIFF.FIFFV_COIL_VV_PLANAR_T1, FIFF.FIFF_UNIT_T_M),
-    ref_meg=(FIFF.FIFFV_REF_MEG_CH, FIFF.FIFFV_COIL_VV_MAG_T3,
-             FIFF.FIFF_UNIT_T),
-    misc=(FIFF.FIFFV_MISC_CH, FIFF.FIFFV_COIL_NONE, FIFF.FIFF_UNIT_NONE),
-    stim=(FIFF.FIFFV_STIM_CH, FIFF.FIFFV_COIL_NONE, FIFF.FIFF_UNIT_V),
-    eog=(FIFF.FIFFV_EOG_CH, FIFF.FIFFV_COIL_NONE, FIFF.FIFF_UNIT_V),
-    ecg=(FIFF.FIFFV_ECG_CH, FIFF.FIFFV_COIL_NONE, FIFF.FIFF_UNIT_V),
-    emg=(FIFF.FIFFV_EMG_CH, FIFF.FIFFV_COIL_NONE, FIFF.FIFF_UNIT_V),
-    seeg=(FIFF.FIFFV_SEEG_CH, FIFF.FIFFV_COIL_EEG, FIFF.FIFF_UNIT_V),
-    bio=(FIFF.FIFFV_BIO_CH, FIFF.FIFFV_COIL_NONE, FIFF.FIFF_UNIT_V),
-    ecog=(FIFF.FIFFV_ECOG_CH, FIFF.FIFFV_COIL_EEG, FIFF.FIFF_UNIT_V),
-    fnirs_cw_amplitude=(FIFF.FIFFV_FNIRS_CH,
-                        FIFF.FIFFV_COIL_FNIRS_CW_AMPLITUDE, FIFF.FIFF_UNIT_V),
-    fnirs_od=(FIFF.FIFFV_FNIRS_CH, FIFF.FIFFV_COIL_FNIRS_OD,
-              FIFF.FIFF_UNIT_NONE),
-    hbo=(FIFF.FIFFV_FNIRS_CH, FIFF.FIFFV_COIL_FNIRS_HBO, FIFF.FIFF_UNIT_MOL),
-    hbr=(FIFF.FIFFV_FNIRS_CH, FIFF.FIFFV_COIL_FNIRS_HBR, FIFF.FIFF_UNIT_MOL),
-    csd=(FIFF.FIFFV_EEG_CH, FIFF.FIFFV_COIL_EEG_CSD, FIFF.FIFF_UNIT_V_M2),
-)
-
-
 _SCALAR_CH_KEYS = ('scanno', 'logno', 'kind', 'range', 'cal', 'coil_type',
                    'unit', 'unit_mul', 'coord_frame')
 _ALL_CH_KEYS_SET = set(_SCALAR_CH_KEYS + ('loc', 'ch_name'))
@@ -2018,20 +1995,26 @@ def create_info(ch_names, sfreq, ch_types='misc', verbose=None):
                          '(%s != %s) for ch_types=%s'
                          % (len(ch_types), nchan, ch_types))
     info = _empty_info(sfreq)
-    for ci, (name, kind) in enumerate(zip(ch_names, ch_types)):
-        _validate_type(name, 'str', "each entry in ch_names")
-        _validate_type(kind, 'str', "each entry in ch_types")
-        if kind not in _kind_dict:
-            raise KeyError('kind must be one of %s, not %s'
-                           % (list(_kind_dict.keys()), kind))
-        kind = _kind_dict[kind]
+    ch_types_dict = get_channel_type_constants(include_defaults=True)
+    for ci, (ch_name, ch_type) in enumerate(zip(ch_names, ch_types)):
+        _validate_type(ch_name, 'str', "each entry in ch_names")
+        _validate_type(ch_type, 'str', "each entry in ch_types")
+        if ch_type not in ch_types_dict:
+            raise KeyError(f'kind must be one of {list(ch_types_dict)}, '
+                           f'not {ch_type}')
+        this_ch_dict = ch_types_dict[ch_type]
+        kind = this_ch_dict['kind']
+        # handle chpi, where kind is a *list* of FIFF constants:
+        kind = kind[0] if isinstance(kind, (list, tuple)) else kind
         # mirror what tag.py does here
-        coord_frame = _ch_coord_dict.get(kind[0], FIFF.FIFFV_COORD_UNKNOWN)
+        coord_frame = _ch_coord_dict.get(kind, FIFF.FIFFV_COORD_UNKNOWN)
+        coil_type = this_ch_dict.get('coil_type', FIFF.FIFFV_COIL_NONE)
+        unit = this_ch_dict.get('unit', FIFF.FIFF_UNIT_NONE)
         chan_info = dict(loc=np.full(12, np.nan),
                          unit_mul=FIFF.FIFF_UNITM_NONE, range=1., cal=1.,
-                         kind=kind[0], coil_type=kind[1],
-                         unit=kind[2], coord_frame=coord_frame,
-                         ch_name=str(name), scanno=ci + 1, logno=ci + 1)
+                         kind=kind, coil_type=coil_type, unit=unit,
+                         coord_frame=coord_frame, ch_name=str(ch_name),
+                         scanno=ci + 1, logno=ci + 1)
         info['chs'].append(chan_info)
 
     info._update_redundant()
diff --git a/mne/io/pick.py b/mne/io/pick.py
--- a/mne/io/pick.py
+++ b/mne/io/pick.py
@@ -15,51 +15,94 @@
                      _check_option)
 
 
-def get_channel_type_constants():
-    """Return all known channel types.
+def get_channel_type_constants(include_defaults=False):
+    """Return all known channel types, and associated FIFF constants.
+
+    Parameters
+    ----------
+    include_defaults : bool
+        Whether to include default values for "unit" and "coil_type" for all
+        entries (see Notes). Defaults are generally based on values normally
+        present for a VectorView MEG system. Defaults to ``False``.
 
     Returns
     -------
     channel_types : dict
-        The keys contain the channel types, and the values contain the
-        corresponding values in the info['chs'][idx] dictionary.
+        The keys are channel type strings, and the values are dictionaries of
+        FIFF constants for "kind", and possibly "unit" and "coil_type".
+
+    Notes
+    -----
+        Values which might vary within a channel type across real data
+        recordings are excluded unless ``include_defaults=True``. For example,
+        "ref_meg" channels may have coil type
+        ``FIFFV_COIL_MAGNES_OFFDIAG_REF_GRAD``, ``FIFFV_COIL_VV_MAG_T3``, etc
+        (depending on the recording system), so no "coil_type" entry is given
+        for "ref_meg" unless ``include_defaults`` is requested.
     """
-    return dict(grad=dict(kind=FIFF.FIFFV_MEG_CH,
-                          unit=FIFF.FIFF_UNIT_T_M),
-                mag=dict(kind=FIFF.FIFFV_MEG_CH,
-                         unit=FIFF.FIFF_UNIT_T),
+    base = dict(grad=dict(kind=FIFF.FIFFV_MEG_CH, unit=FIFF.FIFF_UNIT_T_M),
+                mag=dict(kind=FIFF.FIFFV_MEG_CH, unit=FIFF.FIFF_UNIT_T),
                 ref_meg=dict(kind=FIFF.FIFFV_REF_MEG_CH),
-                eeg=dict(kind=FIFF.FIFFV_EEG_CH),
+                eeg=dict(kind=FIFF.FIFFV_EEG_CH,
+                         unit=FIFF.FIFF_UNIT_V,
+                         coil_type=FIFF.FIFFV_COIL_EEG),
+                seeg=dict(kind=FIFF.FIFFV_SEEG_CH,
+                          unit=FIFF.FIFF_UNIT_V,
+                          coil_type=FIFF.FIFFV_COIL_EEG),
+                ecog=dict(kind=FIFF.FIFFV_ECOG_CH,
+                          unit=FIFF.FIFF_UNIT_V,
+                          coil_type=FIFF.FIFFV_COIL_EEG),
+                eog=dict(kind=FIFF.FIFFV_EOG_CH, unit=FIFF.FIFF_UNIT_V),
+                emg=dict(kind=FIFF.FIFFV_EMG_CH, unit=FIFF.FIFF_UNIT_V),
+                ecg=dict(kind=FIFF.FIFFV_ECG_CH, unit=FIFF.FIFF_UNIT_V),
+                bio=dict(kind=FIFF.FIFFV_BIO_CH, unit=FIFF.FIFF_UNIT_V),
+                misc=dict(kind=FIFF.FIFFV_MISC_CH, unit=FIFF.FIFF_UNIT_V),
                 stim=dict(kind=FIFF.FIFFV_STIM_CH),
-                eog=dict(kind=FIFF.FIFFV_EOG_CH),
-                emg=dict(kind=FIFF.FIFFV_EMG_CH),
-                ecg=dict(kind=FIFF.FIFFV_ECG_CH),
                 resp=dict(kind=FIFF.FIFFV_RESP_CH),
-                misc=dict(kind=FIFF.FIFFV_MISC_CH),
                 exci=dict(kind=FIFF.FIFFV_EXCI_CH),
-                ias=dict(kind=FIFF.FIFFV_IAS_CH),
                 syst=dict(kind=FIFF.FIFFV_SYST_CH),
-                seeg=dict(kind=FIFF.FIFFV_SEEG_CH),
-                bio=dict(kind=FIFF.FIFFV_BIO_CH),
+                ias=dict(kind=FIFF.FIFFV_IAS_CH),
+                gof=dict(kind=FIFF.FIFFV_GOODNESS_FIT),
+                dipole=dict(kind=FIFF.FIFFV_DIPOLE_WAVE),
                 chpi=dict(kind=[FIFF.FIFFV_QUAT_0, FIFF.FIFFV_QUAT_1,
                                 FIFF.FIFFV_QUAT_2, FIFF.FIFFV_QUAT_3,
                                 FIFF.FIFFV_QUAT_4, FIFF.FIFFV_QUAT_5,
                                 FIFF.FIFFV_QUAT_6, FIFF.FIFFV_HPI_G,
                                 FIFF.FIFFV_HPI_ERR, FIFF.FIFFV_HPI_MOV]),
-                dipole=dict(kind=FIFF.FIFFV_DIPOLE_WAVE),
-                gof=dict(kind=FIFF.FIFFV_GOODNESS_FIT),
-                ecog=dict(kind=FIFF.FIFFV_ECOG_CH),
                 fnirs_cw_amplitude=dict(
                     kind=FIFF.FIFFV_FNIRS_CH,
+                    unit=FIFF.FIFF_UNIT_V,
                     coil_type=FIFF.FIFFV_COIL_FNIRS_CW_AMPLITUDE),
                 fnirs_od=dict(kind=FIFF.FIFFV_FNIRS_CH,
                               coil_type=FIFF.FIFFV_COIL_FNIRS_OD),
                 hbo=dict(kind=FIFF.FIFFV_FNIRS_CH,
+                         unit=FIFF.FIFF_UNIT_MOL,
                          coil_type=FIFF.FIFFV_COIL_FNIRS_HBO),
                 hbr=dict(kind=FIFF.FIFFV_FNIRS_CH,
+                         unit=FIFF.FIFF_UNIT_MOL,
                          coil_type=FIFF.FIFFV_COIL_FNIRS_HBR),
                 csd=dict(kind=FIFF.FIFFV_EEG_CH,
+                         unit=FIFF.FIFF_UNIT_V_M2,
                          coil_type=FIFF.FIFFV_COIL_EEG_CSD))
+    if include_defaults:
+        coil_none = dict(coil_type=FIFF.FIFFV_COIL_NONE)
+        unit_none = dict(unit=FIFF.FIFF_UNIT_NONE)
+        defaults = dict(
+            grad=dict(coil_type=FIFF.FIFFV_COIL_VV_PLANAR_T1),
+            mag=dict(coil_type=FIFF.FIFFV_COIL_VV_MAG_T3),
+            ref_meg=dict(coil_type=FIFF.FIFFV_COIL_VV_MAG_T3,
+                         unit=FIFF.FIFF_UNIT_T),
+            misc=dict(**coil_none, **unit_none),  # NB: overwrites UNIT_V
+            stim=dict(unit=FIFF.FIFF_UNIT_V, **coil_none),
+            eog=coil_none,
+            ecg=coil_none,
+            emg=coil_none,
+            bio=coil_none,
+            fnirs_od=unit_none,
+        )
+        for key, value in defaults.items():
+            base[key].update(value)
+    return base
 
 
 _first_rule = {


Test patch:
diff --git a/mne/channels/tests/test_channels.py b/mne/channels/tests/test_channels.py
--- a/mne/channels/tests/test_channels.py
+++ b/mne/channels/tests/test_channels.py
@@ -114,21 +114,22 @@ def test_set_channel_types():
     # Error Tests
     # Test channel name exists in ch_names
     mapping = {'EEG 160': 'EEG060'}
-    pytest.raises(ValueError, raw.set_channel_types, mapping)
+    with pytest.raises(ValueError, match=r"name \(EEG 160\) doesn't exist"):
+        raw.set_channel_types(mapping)
     # Test change to illegal channel type
     mapping = {'EOG 061': 'xxx'}
-    pytest.raises(ValueError, raw.set_channel_types, mapping)
-    # Test changing type if in proj (avg eeg ref here)
+    with pytest.raises(ValueError, match='cannot change to this channel type'):
+        raw.set_channel_types(mapping)
+    # Test changing type if in proj
     mapping = {'EEG 058': 'ecog', 'EEG 059': 'ecg', 'EEG 060': 'eog',
                'EOG 061': 'seeg', 'MEG 2441': 'eeg', 'MEG 2443': 'eeg',
                'MEG 2442': 'hbo'}
-    pytest.raises(RuntimeError, raw.set_channel_types, mapping)
-    # Test type change
     raw2 = read_raw_fif(raw_fname)
     raw2.info['bads'] = ['EEG 059', 'EEG 060', 'EOG 061']
-    pytest.raises(RuntimeError, raw2.set_channel_types, mapping)  # has prj
+    with pytest.raises(RuntimeError, match='type .* in projector "PCA-v1"'):
+        raw2.set_channel_types(mapping)  # has prj
     raw2.add_proj([], remove_existing=True)
-    with pytest.warns(RuntimeWarning, match='The unit for channel'):
+    with pytest.warns(RuntimeWarning, match='unit for channel.* has changed'):
         raw2 = raw2.set_channel_types(mapping)
     info = raw2.info
     assert info['chs'][372]['ch_name'] == 'EEG 058'
diff --git a/mne/io/array/tests/test_array.py b/mne/io/array/tests/test_array.py
--- a/mne/io/array/tests/test_array.py
+++ b/mne/io/array/tests/test_array.py
@@ -14,7 +14,8 @@
 from mne.io import read_raw_fif
 from mne.io.array import RawArray
 from mne.io.tests.test_raw import _test_raw_reader
-from mne.io.meas_info import create_info, _kind_dict
+from mne.io.meas_info import create_info
+from mne.io.pick import get_channel_type_constants
 from mne.utils import run_tests_if_main
 from mne.channels import make_dig_montage
 
@@ -101,7 +102,8 @@ def test_array_raw():
     types[-1] = 'eog'
     # default type
     info = create_info(ch_names, sfreq)
-    assert_equal(info['chs'][0]['kind'], _kind_dict['misc'][0])
+    assert_equal(info['chs'][0]['kind'],
+                 get_channel_type_constants()['misc']['kind'])
     # use real types
     info = create_info(ch_names, sfreq, types)
     raw2 = _test_raw_reader(RawArray, test_preloading=False,
diff --git a/mne/io/edf/tests/test_edf.py b/mne/io/edf/tests/test_edf.py
--- a/mne/io/edf/tests/test_edf.py
+++ b/mne/io/edf/tests/test_edf.py
@@ -27,9 +27,8 @@
 from mne.io.edf.edf import _read_annotations_edf
 from mne.io.edf.edf import _read_ch
 from mne.io.edf.edf import _parse_prefilter_string
-from mne.io.pick import channel_indices_by_type
+from mne.io.pick import channel_indices_by_type, get_channel_type_constants
 from mne.annotations import events_from_annotations, read_annotations
-from mne.io.meas_info import _kind_dict as _KIND_DICT
 
 
 FILE = inspect.getfile(inspect.currentframe())
@@ -363,7 +362,9 @@ def test_load_generator(fname, recwarn):
 def test_edf_stim_ch_pick_up(test_input, EXPECTED):
     """Test stim_channel."""
     # This is fragile for EEG/EEG-CSD, so just omit csd
-    TYPE_LUT = {v[0]: k for k, v in _KIND_DICT.items() if k != 'csd'}
+    KIND_DICT = get_channel_type_constants()
+    TYPE_LUT = {v['kind']: k for k, v in KIND_DICT.items() if k not in
+                ('csd', 'chpi')}  # chpi not needed, and unhashable (a list)
     fname = op.join(data_dir, 'test_stim_channel.edf')
 
     raw = read_raw_edf(fname, stim_channel=test_input)
diff --git a/mne/io/tests/test_pick.py b/mne/io/tests/test_pick.py
--- a/mne/io/tests/test_pick.py
+++ b/mne/io/tests/test_pick.py
@@ -69,8 +69,8 @@ def _channel_type_old(info, idx):
 
     # iterate through all defined channel types until we find a match with ch
     # go in order from most specific (most rules entries) to least specific
-    channel_types = sorted(
-        get_channel_type_constants().items(), key=lambda x: len(x[1]))[::-1]
+    channel_types = sorted(get_channel_type_constants().items(),
+                           key=lambda x: len(x[1]), reverse=True)
     for t, rules in channel_types:
         for key, vals in rules.items():  # all keys must match the values
             if ch.get(key, None) not in np.array(vals):
@@ -78,7 +78,7 @@ def _channel_type_old(info, idx):
         else:
             return t
 
-    raise ValueError('Unknown channel type for {}'.format(ch["ch_name"]))
+    raise ValueError(f'Unknown channel type for {ch["ch_name"]}')
 
 
 def _assert_channel_types(info):
@@ -112,8 +112,10 @@ def test_pick_refs():
     for info in infos:
         info['bads'] = []
         _assert_channel_types(info)
-        pytest.raises(ValueError, pick_types, info, meg='foo')
-        pytest.raises(ValueError, pick_types, info, ref_meg='foo')
+        with pytest.raises(ValueError, match="'planar2'] or bool, not foo"):
+            pick_types(info, meg='foo')
+        with pytest.raises(ValueError, match="'planar2', 'auto'] or bool,"):
+            pick_types(info, ref_meg='foo')
         picks_meg_ref = pick_types(info, meg=True, ref_meg=True)
         picks_meg = pick_types(info, meg=True, ref_meg=False)
         picks_ref = pick_types(info, meg=False, ref_meg=True)
diff --git a/mne/preprocessing/tests/test_ica.py b/mne/preprocessing/tests/test_ica.py
--- a/mne/preprocessing/tests/test_ica.py
+++ b/mne/preprocessing/tests/test_ica.py
@@ -25,8 +25,7 @@
 from mne.preprocessing.ica import (get_score_funcs, corrmap, _sort_components,
                                    _ica_explained_variance, read_ica_eeglab)
 from mne.io import read_raw_fif, Info, RawArray, read_raw_ctf, read_raw_eeglab
-from mne.io.meas_info import _kind_dict
-from mne.io.pick import _DATA_CH_TYPES_SPLIT
+from mne.io.pick import _DATA_CH_TYPES_SPLIT, get_channel_type_constants
 from mne.io.eeglab.eeglab import _check_load_mat
 from mne.rank import _compute_rank_int
 from mne.utils import catch_logging, requires_sklearn, run_tests_if_main
@@ -1005,7 +1004,7 @@ def test_fit_params(method, tmpdir):
 def test_bad_channels(method, allow_ref_meg):
     """Test exception when unsupported channels are used."""
     _skip_check_picard(method)
-    chs = [i for i in _kind_dict]
+    chs = list(get_channel_type_constants())
     info = create_info(len(chs), 500, chs)
     rng = np.random.RandomState(0)
     data = rng.rand(len(chs), 50)