Repository: mne-tools/mne-python

Issue:
path error in setup_volume_source_space
from CircleCI:
```
Traceback (most recent call last):
  File "/home/circleci/project/examples/inverse/mixed_source_space_inverse.py", line 70, in <module>
    vol_src = mne.setup_volume_source_space(
  File "<decorator-gen-148>", line 10, in setup_volume_source_space
  File "/home/circleci/project/mne/source_space.py", line 1545, in setup_volume_source_space
    elif bem is not None and bem.get('is_sphere') is False:
AttributeError: 'MNEPosixPath' object has no attribute 'get'
```
https://github.com/mne-tools/mne-python/pull/10846#discussion_r908372846


Discussion:

Resolving patch:
diff --git a/mne/conftest.py b/mne/conftest.py
--- a/mne/conftest.py
+++ b/mne/conftest.py
@@ -117,6 +117,8 @@ def pytest_configure(config):
     ignore:.*The 'sym_pos' keyword is deprecated.*:DeprecationWarning
     # Should be removable by 2022/07/08, SciPy savemat issue
     ignore:.*elementwise comparison failed; returning scalar in.*:FutureWarning
+    # numba with NumPy dev
+    ignore:`np.MachAr` is deprecated.*:DeprecationWarning
     """.format(first_kind)  # noqa: E501
     for warning_line in warning_lines.split('\n'):
         warning_line = warning_line.strip()
diff --git a/mne/source_space.py b/mne/source_space.py
--- a/mne/source_space.py
+++ b/mne/source_space.py
@@ -23,7 +23,7 @@
                        write_float_matrix, write_int_matrix,
                        write_coord_trans, start_and_end_file, write_id)
 from .io.pick import channel_type, _picks_to_idx
-from .bem import read_bem_surfaces
+from .bem import read_bem_surfaces, ConductorModel
 from .fixes import _get_img_fdata
 from .surface import (read_surface, _create_surf_spacing, _get_ico_surface,
                       _tessellate_sphere_surf, _get_surf_neighbors,
@@ -630,6 +630,7 @@ def read_source_spaces(fname, patch_stats=False, verbose=None):
     write_source_spaces, setup_source_space, setup_volume_source_space
     """
     # be more permissive on read than write (fwd/inv can contain src)
+    fname = _check_fname(fname, overwrite='read', must_exist=True)
     check_fname(fname, 'source space', ('-src.fif', '-src.fif.gz',
                                         '_src.fif', '_src.fif.gz',
                                         '-fwd.fif', '-fwd.fif.gz',
@@ -1372,10 +1373,10 @@ def setup_volume_source_space(subject=None, pos=5.0, mri=None,
         Only used if ``bem`` and ``surface`` are both None. Can also be a
         spherical ConductorModel, which will use the origin and radius.
         None (the default) uses a head-digitization fit.
-    bem : str | None | ConductorModel
+    bem : path-like | None | ConductorModel
         Define source space bounds using a BEM file (specifically the inner
         skull surface) or a ConductorModel for a 1-layer of 3-layers BEM.
-    surface : str | dict | None
+    surface : path-like | dict | None
         Define source space bounds using a FreeSurfer surface file. Can
         also be a dictionary with entries ``'rr'`` and ``'tris'``, such as
         those returned by :func:`mne.read_surface`.
@@ -1453,6 +1454,14 @@ def setup_volume_source_space(subject=None, pos=5.0, mri=None,
     subjects_dir = get_subjects_dir(subjects_dir)
     _validate_type(
         volume_label, (str, list, tuple, dict, None), 'volume_label')
+    _validate_type(bem, ('path-like', ConductorModel, None), 'bem')
+    _validate_type(surface, ('path-like', dict, None), 'surface')
+    if bem is not None and not isinstance(bem, ConductorModel):
+        bem = _check_fname(bem, overwrite='read', must_exist=True,
+                           name='bem filename')
+    if surface is not None and not isinstance(surface, dict):
+        surface = _check_fname(surface, overwrite='read', must_exist=True,
+                               name='surface filename')
 
     if bem is not None and surface is not None:
         raise ValueError('Only one of "bem" and "surface" should be '
@@ -1488,7 +1497,7 @@ def setup_volume_source_space(subject=None, pos=5.0, mri=None,
             # let's make sure we have geom info
             complete_surface_info(surface, copy=False, verbose=False)
             surf_extra = 'dict()'
-        elif isinstance(surface, str):
+        else:
             if not op.isfile(surface):
                 raise IOError('surface file "%s" not found' % surface)
             surf_extra = surface
diff --git a/mne/viz/_3d.py b/mne/viz/_3d.py
--- a/mne/viz/_3d.py
+++ b/mne/viz/_3d.py
@@ -3008,6 +3008,8 @@ def plot_dipole_locations(dipoles, trans=None, subject=None, subjects_dir=None,
     _validate_type(mode, str, 'mode')
     _validate_type(coord_frame, str, 'coord_frame')
     _check_option('mode', mode, ('orthoview', 'outlines', 'arrow', 'sphere'))
+    if mode in ('orthoview', 'outlines'):
+        subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
     kwargs = dict(
         trans=trans, subject=subject, subjects_dir=subjects_dir,
         coord_frame=coord_frame, ax=ax, block=block, show=show, color=color,


Test patch:
diff --git a/mne/decoding/tests/test_search_light.py b/mne/decoding/tests/test_search_light.py
--- a/mne/decoding/tests/test_search_light.py
+++ b/mne/decoding/tests/test_search_light.py
@@ -7,7 +7,7 @@
 import pytest
 
 from mne.utils import requires_sklearn, _record_warnings
-from mne.fixes import _get_args
+from mne.fixes import _get_args, _compare_version
 from mne.decoding.search_light import SlidingEstimator, GeneralizingEstimator
 from mne.decoding.transformer import Vectorizer
 
@@ -27,6 +27,9 @@ def make_data():
 @requires_sklearn
 def test_search_light():
     """Test SlidingEstimator."""
+    import sklearn
+    if _compare_version(sklearn.__version__, '>=', '1.2.dev0'):
+        pytest.skip('Bug in sklearn')
     from sklearn.linear_model import Ridge, LogisticRegression
     from sklearn.pipeline import make_pipeline
     from sklearn.metrics import roc_auc_score, make_scorer
diff --git a/mne/tests/test_source_space.py b/mne/tests/test_source_space.py
--- a/mne/tests/test_source_space.py
+++ b/mne/tests/test_source_space.py
@@ -306,7 +306,7 @@ def test_volume_source_space(tmp_path):
         del src_new
         src_new = read_source_spaces(temp_name)
         _compare_source_spaces(src, src_new, mode='approx')
-    with pytest.raises(IOError, match='surface file.*not found'):
+    with pytest.raises(IOError, match='surface file.*not exist'):
         setup_volume_source_space(
             'sample', surface='foo', mri=fname_mri, subjects_dir=subjects_dir)
     bem['surfs'][-1]['coord_frame'] = FIFF.FIFFV_COORD_HEAD