From f552314b9ab52ece07e9b2cc5efbcdf3fa2b5293 Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Tue, 30 Mar 2021 16:18:22 -0500 Subject: [PATCH 1/3] don't use op.realpath when reading raw --- mne/io/fiff/raw.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mne/io/fiff/raw.py b/mne/io/fiff/raw.py index 2419cbc603e..7f35d6c3bdc 100644 --- a/mne/io/fiff/raw.py +++ b/mne/io/fiff/raw.py @@ -144,7 +144,6 @@ def _read_raw_file(self, fname, allow_maxshield, preload, endings += tuple([f'{e}.gz' for e in endings]) check_fname(fname, 'raw', endings) # filename - fname = op.realpath(fname) ext = os.path.splitext(fname)[1].lower() whole_file = preload if '.gz' in ext else False del ext From 60a05fca38e0f7ae9406657277c3695b6407b04f Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Wed, 31 Mar 2021 12:03:16 -0400 Subject: [PATCH 2/3] BUG: Fix which --- mne/annotations.py | 2 +- mne/io/artemis123/artemis123.py | 3 ++- mne/io/base.py | 2 +- mne/io/boxy/boxy.py | 3 ++- mne/io/ctf/ctf.py | 9 +++---- mne/io/ctf/tests/test_ctf.py | 10 +++++--- mne/io/curry/curry.py | 2 +- mne/io/eeglab/eeglab.py | 9 ++++--- mne/io/egi/egi.py | 4 +-- mne/io/egi/egimff.py | 4 ++- mne/io/eximia/eximia.py | 3 ++- mne/io/fiff/raw.py | 13 +++++----- mne/io/fiff/tests/test_raw_fiff.py | 35 ++++++++++++++++++++++----- mne/io/nedf/nedf.py | 3 ++- mne/io/nihon/nihon.py | 3 ++- mne/io/nirx/nirx.py | 9 ++++--- mne/io/nirx/tests/test_nirx.py | 2 +- mne/io/persyst/persyst.py | 3 ++- mne/io/snirf/_snirf.py | 3 ++- mne/io/tests/test_raw.py | 39 +++++++++++++++++++++++++++--- mne/utils/check.py | 27 +++++++++++++++------ 21 files changed, 133 insertions(+), 55 deletions(-) diff --git a/mne/annotations.py b/mne/annotations.py index ebcf902d80e..dfb7025f320 100644 --- a/mne/annotations.py +++ b/mne/annotations.py @@ -782,7 +782,7 @@ def read_annotations(fname, sfreq='auto', uint16_codec=None): _validate_type(fname, 'path-like', 'fname') fname = _check_fname( fname, overwrite='read', must_exist=True, - allow_dir=str(fname).endswith('.ds'), # allow_dir for CTF + need_dir=str(fname).endswith('.ds'), # for CTF name='fname') name = op.basename(fname) if name.endswith(('fif', 'fif.gz')): diff --git a/mne/io/artemis123/artemis123.py b/mne/io/artemis123/artemis123.py index 06a0b67f909..8b725d7393d 100644 --- a/mne/io/artemis123/artemis123.py +++ b/mne/io/artemis123/artemis123.py @@ -8,7 +8,7 @@ import calendar from .utils import _load_mne_locs, _read_pos -from ...utils import logger, warn, verbose +from ...utils import logger, warn, verbose, _check_fname from ..utils import _read_segments_file from ..base import BaseRaw from ..meas_info import _empty_info @@ -308,6 +308,7 @@ def __init__(self, input_fname, preload=False, verbose=None, from scipy.spatial.distance import cdist from ...chpi import (compute_chpi_amplitudes, compute_chpi_locs, _fit_coil_order_dev_head_trans) + input_fname = _check_fname(input_fname, 'read', True, 'input_fname') fname, ext = op.splitext(input_fname) if ext == '.txt': input_fname = fname + '.bin' diff --git a/mne/io/base.py b/mne/io/base.py index 44b695e0578..aff50a8a625 100644 --- a/mne/io/base.py +++ b/mne/io/base.py @@ -1394,7 +1394,7 @@ def save(self, fname, picks=None, tmin=0, tmax=None, buffer_size_sec=None, or all forms of SSS). It is recommended not to concatenate and then save raw files for this reason. """ - fname = op.realpath(fname) + fname = op.abspath(fname) endings = ('raw.fif', 'raw_sss.fif', 'raw_tsss.fif', '_meg.fif', '_eeg.fif', '_ieeg.fif') endings += tuple([f'{e}.gz' for e in endings]) diff --git a/mne/io/boxy/boxy.py b/mne/io/boxy/boxy.py index a48efd67bf9..2ff5d3eaa4b 100644 --- a/mne/io/boxy/boxy.py +++ b/mne/io/boxy/boxy.py @@ -9,7 +9,7 @@ from ..base import BaseRaw from ..meas_info import create_info from ..utils import _mult_cal_one -from ...utils import logger, verbose, fill_doc +from ...utils import logger, verbose, fill_doc, _check_fname from ...annotations import Annotations @@ -65,6 +65,7 @@ def __init__(self, fname, preload=False, verbose=None): raw_extras = dict() raw_extras['offsets'] = list() # keep track of our offsets sfreq = None + fname = _check_fname(fname, 'read', True, 'fname') with open(fname, 'r') as fid: line_num = 0 i_line = fid.readline() diff --git a/mne/io/ctf/ctf.py b/mne/io/ctf/ctf.py index 5ed7b9ec483..c705af33c7b 100644 --- a/mne/io/ctf/ctf.py +++ b/mne/io/ctf/ctf.py @@ -6,13 +6,12 @@ # License: BSD (3-clause) import os -import os.path as op import numpy as np from .._digitization import _format_dig_points from ...utils import (verbose, logger, _clean_names, fill_doc, _check_option, - _validate_type) + _check_fname) from ..base import BaseRaw from ..utils import _mult_cal_one, _blk_read_lims @@ -91,13 +90,11 @@ class RawCTF(BaseRaw): def __init__(self, directory, system_clock='truncate', preload=False, verbose=None, clean_names=False): # noqa: D102 # adapted from mne_ctf2fiff.c - _validate_type(directory, 'path-like', 'directory') - directory = str(directory) + directory = _check_fname(directory, 'read', True, 'directory', + need_dir=True) if not directory.endswith('.ds'): raise TypeError('directory must be a directory ending with ".ds", ' f'got {directory}') - if not op.isdir(directory): - raise ValueError('directory does not exist: "%s"' % directory) _check_option('system_clock', system_clock, ['ignore', 'truncate']) logger.info('ds directory : %s' % directory) res4 = _read_res4(directory) # Read the magical res4 file diff --git a/mne/io/ctf/tests/test_ctf.py b/mne/io/ctf/tests/test_ctf.py index b7dd0eb6067..7bb938f54ac 100644 --- a/mne/io/ctf/tests/test_ctf.py +++ b/mne/io/ctf/tests/test_ctf.py @@ -220,12 +220,14 @@ def test_read_ctf(tmpdir): assert_allclose(raw.annotations.onset, [2.15]) assert_allclose(raw.annotations.duration, [0.0225]) - pytest.raises(TypeError, read_raw_ctf, 1) - pytest.raises(ValueError, read_raw_ctf, ctf_fname_continuous + 'foo.ds') + with pytest.raises(TypeError, match='path-like'): + read_raw_ctf(1) + with pytest.raises(FileNotFoundError, match='does not exist'): + read_raw_ctf(ctf_fname_continuous + 'foo.ds') # test ignoring of system clock read_raw_ctf(op.join(ctf_dir, ctf_fname_continuous), 'ignore') - pytest.raises(ValueError, read_raw_ctf, - op.join(ctf_dir, ctf_fname_continuous), 'foo') + with pytest.raises(ValueError, match='system_clock'): + read_raw_ctf(op.join(ctf_dir, ctf_fname_continuous), 'foo') @testing.requires_testing_data diff --git a/mne/io/curry/curry.py b/mne/io/curry/curry.py index 829a5278c53..1fe671fcb95 100644 --- a/mne/io/curry/curry.py +++ b/mne/io/curry/curry.py @@ -63,7 +63,7 @@ def _get_curry_file_structure(fname, required=()): """Store paths to a dict and check for required files.""" _msg = "The following required files cannot be found: {0}.\nPlease make " \ "sure all required files are located in the same directory as {1}." - _check_fname(fname, overwrite='read', must_exist=True) + fname = _check_fname(fname, 'read', True, 'fname') # we don't use os.path.splitext to also handle extensions like .cdt.dpa fname_base, ext = fname.split(".", maxsplit=1) diff --git a/mne/io/eeglab/eeglab.py b/mne/io/eeglab/eeglab.py index 61c15823827..a88884220fe 100644 --- a/mne/io/eeglab/eeglab.py +++ b/mne/io/eeglab/eeglab.py @@ -12,7 +12,7 @@ from ..constants import FIFF from ..meas_info import create_info from ..base import BaseRaw -from ...utils import logger, verbose, warn, fill_doc, Bunch +from ...utils import logger, verbose, warn, fill_doc, Bunch, _check_fname from ...channels import make_dig_montage from ...epochs import BaseEpochs from ...event import read_events @@ -22,7 +22,7 @@ CAL = 1e-6 -def _check_fname(fname, dataname): +def _check_eeglab_fname(fname, dataname): """Check whether the filename is valid. Check if the file extension is ``.fdt`` (older ``.dat`` being invalid) or @@ -314,6 +314,7 @@ class RawEEGLAB(BaseRaw): @verbose def __init__(self, input_fname, eog=(), preload=False, uint16_codec=None, verbose=None): # noqa: D102 + input_fname = _check_fname(input_fname, 'read', True, 'input_fname') eeg = _check_load_mat(input_fname, uint16_codec) if eeg.trials != 1: raise TypeError('The number of trials is %d. It must be 1 for raw' @@ -325,7 +326,7 @@ def __init__(self, input_fname, eog=(), # read the data if isinstance(eeg.data, str): - data_fname = _check_fname(input_fname, eeg.data) + data_fname = _check_eeglab_fname(input_fname, eeg.data) logger.info('Reading %s' % data_fname) super(RawEEGLAB, self).__init__( @@ -510,7 +511,7 @@ def __init__(self, input_fname, events=None, event_id=None, tmin=0, '(event id %i)' % (key, val)) if isinstance(eeg.data, str): - data_fname = _check_fname(input_fname, eeg.data) + data_fname = _check_eeglab_fname(input_fname, eeg.data) with open(data_fname, 'rb') as data_fid: data = np.fromfile(data_fid, dtype=np.float32) data = data.reshape((eeg.nbchan, eeg.pnts, eeg.trials), diff --git a/mne/io/egi/egi.py b/mne/io/egi/egi.py index 7267dcbece2..6e3d5652fcc 100644 --- a/mne/io/egi/egi.py +++ b/mne/io/egi/egi.py @@ -14,7 +14,7 @@ from ..utils import _read_segments_file, _create_chs from ..meas_info import _empty_info from ..constants import FIFF -from ...utils import verbose, logger, warn, _validate_type +from ...utils import verbose, logger, warn, _validate_type, _check_fname def _read_header(fid): @@ -152,7 +152,6 @@ def read_raw_egi(input_fname, eog=None, misc=None, """ _validate_type(input_fname, 'path-like', 'input_fname') input_fname = str(input_fname) - if input_fname.endswith('.mff'): return _read_raw_egi_mff(input_fname, eog, misc, include, exclude, preload, channel_naming, verbose) @@ -167,6 +166,7 @@ class RawEGI(BaseRaw): def __init__(self, input_fname, eog=None, misc=None, include=None, exclude=None, preload=False, channel_naming='E%d', verbose=None): # noqa: D102 + input_fname = _check_fname(input_fname, 'read', True, 'input_fname') if eog is None: eog = [] if misc is None: diff --git a/mne/io/egi/egimff.py b/mne/io/egi/egimff.py index ccf1fb5a77d..2b647bea7e8 100644 --- a/mne/io/egi/egimff.py +++ b/mne/io/egi/egimff.py @@ -19,7 +19,7 @@ from ..proj import setup_proj from ..utils import _create_chs, _mult_cal_one from ...annotations import Annotations -from ...utils import verbose, logger, warn, _check_option +from ...utils import verbose, logger, warn, _check_option, _check_fname from ...evoked import EvokedArray @@ -398,6 +398,8 @@ def __init__(self, input_fname, eog=None, misc=None, include=None, exclude=None, preload=False, channel_naming='E%d', verbose=None): """Init the RawMff class.""" + input_fname = _check_fname(input_fname, 'read', True, 'input_fname', + need_dir=True) logger.info('Reading EGI MFF Header from %s...' % input_fname) egi_info = _read_header(input_fname) if eog is None: diff --git a/mne/io/eximia/eximia.py b/mne/io/eximia/eximia.py index 38b57341132..92dbc39531e 100644 --- a/mne/io/eximia/eximia.py +++ b/mne/io/eximia/eximia.py @@ -8,7 +8,7 @@ from ..base import BaseRaw from ..utils import _read_segments_file, _file_size from ..meas_info import create_info -from ...utils import logger, verbose, warn, fill_doc +from ...utils import logger, verbose, warn, fill_doc, _check_fname @fill_doc @@ -52,6 +52,7 @@ class RawEximia(BaseRaw): @verbose def __init__(self, fname, preload=False, verbose=None): + fname = _check_fname(fname, 'read', True, 'fname') data_name = op.basename(fname) logger.info('Loading %s' % data_name) # Create vhdr and vmrk files so that we can use mne_brain_vision2fiff diff --git a/mne/io/fiff/raw.py b/mne/io/fiff/raw.py index 7f35d6c3bdc..8e628a37d18 100644 --- a/mne/io/fiff/raw.py +++ b/mne/io/fiff/raw.py @@ -25,7 +25,7 @@ from ...event import AcqParserFIF from ...utils import (check_fname, logger, verbose, warn, fill_doc, _file_like, - _on_missing) + _on_missing, _check_fname) @fill_doc @@ -75,13 +75,13 @@ class Raw(BaseRaw): def __init__(self, fname, allow_maxshield=False, preload=False, on_split_missing='raise', verbose=None): # noqa: D102 raws = [] - do_check_fname = not _file_like(fname) + do_check_ext = not _file_like(fname) next_fname = fname while next_fname is not None: raw, next_fname, buffer_size_sec = \ self._read_raw_file(next_fname, allow_maxshield, - preload, do_check_fname) - do_check_fname = False + preload, do_check_ext) + do_check_ext = False raws.append(raw) if next_fname is not None: if not op.exists(next_fname): @@ -132,18 +132,19 @@ def __init__(self, fname, allow_maxshield=False, preload=False, @verbose def _read_raw_file(self, fname, allow_maxshield, preload, - do_check_fname=True, verbose=None): + do_check_ext=True, verbose=None): """Read in header information from a raw file.""" logger.info('Opening raw data file %s...' % fname) # Read in the whole file if preload is on and .fif.gz (saves time) if not _file_like(fname): - if do_check_fname: + if do_check_ext: endings = ('raw.fif', 'raw_sss.fif', 'raw_tsss.fif', '_meg.fif', '_eeg.fif', '_ieeg.fif') endings += tuple([f'{e}.gz' for e in endings]) check_fname(fname, 'raw', endings) # filename + fname = _check_fname(fname, 'read', True, 'fname') ext = os.path.splitext(fname)[1].lower() whole_file = preload if '.gz' in ext else False del ext diff --git a/mne/io/fiff/tests/test_raw_fiff.py b/mne/io/fiff/tests/test_raw_fiff.py index 0023492917c..b5c85296a14 100644 --- a/mne/io/fiff/tests/test_raw_fiff.py +++ b/mne/io/fiff/tests/test_raw_fiff.py @@ -11,6 +11,7 @@ import os.path as op import pathlib import pickle +import shutil import sys import numpy as np @@ -28,7 +29,7 @@ compute_proj_raw, pick_types, pick_channels, create_info, pick_info) from mne.utils import (requires_pandas, assert_object_equal, _dt_to_stamp, - requires_mne, run_subprocess, run_tests_if_main, + requires_mne, run_subprocess, assert_and_remove_boundary_annot) from mne.annotations import Annotations @@ -1361,12 +1362,16 @@ def test_add_channels(): @testing.requires_testing_data def test_save(tmpdir): """Test saving raw.""" - raw = read_raw_fif(fif_fname, preload=False) + temp_fname = tmpdir.join('test_raw.fif') + shutil.copyfile(fif_fname, temp_fname) + raw = read_raw_fif(temp_fname, preload=False) # can't write over file being read - pytest.raises(ValueError, raw.save, fif_fname) - raw = read_raw_fif(fif_fname, preload=True) + with pytest.raises(ValueError, match='to the same file'): + raw.save(temp_fname) + raw.load_data() # can't overwrite file without overwrite=True - pytest.raises(IOError, raw.save, fif_fname) + with pytest.raises(IOError, match='file exists'): + raw.save(fif_fname) # test abspath support and annotations orig_time = _dt_to_stamp(raw.info['meas_date'])[0] + raw._first_time @@ -1720,4 +1725,22 @@ def test_bad_acq(fname): assert tag == ent -run_tests_if_main() +@pytest.mark.skipif(sys.platform not in ('darwin', 'linux'), + reason='Needs proper symlinking') +def test_split_symlink(tmpdir): + """Test split files with symlinks.""" + # regression test for gh-9221 + first = str(tmpdir.mkdir('first').join('test_raw.fif')) + raw = read_raw_fif(fif_fname).pick('meg').load_data() + raw.save(first, buffer_size_sec=1, split_size='10MB', verbose=True) + second = first[:-4] + '-1.fif' + assert op.isfile(second) + assert not op.isfile(first[:-4] + '-2.fif') + new_first = tmpdir.mkdir('a').join('test_raw.fif') + new_second = tmpdir.mkdir('b').join('test_raw-1.fif') + shutil.move(first, new_first) + shutil.move(second, new_second) + os.symlink(new_first, first) + os.symlink(new_second, second) + raw_new = read_raw_fif(first) + assert_allclose(raw_new.get_data(), raw.get_data()) diff --git a/mne/io/nedf/nedf.py b/mne/io/nedf/nedf.py index c26a3acf811..70fd2befc4c 100644 --- a/mne/io/nedf/nedf.py +++ b/mne/io/nedf/nedf.py @@ -10,7 +10,7 @@ from ..base import BaseRaw from ..meas_info import create_info from ..utils import _mult_cal_one -from ...utils import warn, verbose +from ...utils import warn, verbose, _check_fname def _getsubnodetext(node, name): @@ -131,6 +131,7 @@ class RawNedf(BaseRaw): """Raw object from NeuroElectrics nedf file.""" def __init__(self, filename, preload=False, verbose=None): + filename = _check_fname(filename, 'read', True, 'filename') with open(filename, mode='rb') as fid: header = fid.read(_HDRLEN) header, dt, dt_last, n_samp, n_full = _parse_nedf_header(header) diff --git a/mne/io/nihon/nihon.py b/mne/io/nihon/nihon.py index 44803250361..b3a7591d4e6 100644 --- a/mne/io/nihon/nihon.py +++ b/mne/io/nihon/nihon.py @@ -8,7 +8,7 @@ import numpy as np -from ...utils import fill_doc, logger, verbose, warn +from ...utils import fill_doc, logger, verbose, warn, _check_fname from ..base import BaseRaw from ..meas_info import create_info from ...annotations import Annotations @@ -308,6 +308,7 @@ class RawNihon(BaseRaw): @verbose def __init__(self, fname, preload=False, verbose=None): + fname = _check_fname(fname, 'read', True, 'fname') fname = _ensure_path(fname) data_name = fname.name logger.info('Loading %s' % data_name) diff --git a/mne/io/nirx/nirx.py b/mne/io/nirx/nirx.py index 88d64987e90..f2d31f17a93 100644 --- a/mne/io/nirx/nirx.py +++ b/mne/io/nirx/nirx.py @@ -16,7 +16,8 @@ from ..meas_info import create_info, _format_dig_points from ...annotations import Annotations from ...transforms import apply_trans, _get_trans -from ...utils import logger, verbose, fill_doc, warn +from ...utils import (logger, verbose, fill_doc, warn, _check_fname, + _validate_type) @fill_doc @@ -69,12 +70,12 @@ def __init__(self, fname, preload=False, verbose=None): from ...externals.pymatreader import read_mat from ...coreg import get_mni_fiducials # avoid circular import prob logger.info('Loading %s' % fname) - + _validate_type(fname, 'path-like', 'fname') + fname = str(fname) if fname.endswith('.hdr'): fname = op.dirname(op.abspath(fname)) - if not op.isdir(fname): - raise FileNotFoundError('The path you specified does not exist.') + fname = _check_fname(fname, 'read', True, 'fname', need_dir=True) # Check if required files exist and store names for later use files = dict() diff --git a/mne/io/nirx/tests/test_nirx.py b/mne/io/nirx/tests/test_nirx.py index 37f329c3212..bdd599cf23b 100644 --- a/mne/io/nirx/tests/test_nirx.py +++ b/mne/io/nirx/tests/test_nirx.py @@ -46,7 +46,7 @@ def test_nirx_hdr_load(): @requires_testing_data def test_nirx_missing_warn(): """Test reading NIRX files when missing data.""" - with pytest.raises(FileNotFoundError, match='The path you'): + with pytest.raises(FileNotFoundError, match='does not exist'): read_raw_nirx(fname_nirx_15_2_short + "1", preload=True) diff --git a/mne/io/persyst/persyst.py b/mne/io/persyst/persyst.py index f3e7f4d768a..1cc83d30ff5 100644 --- a/mne/io/persyst/persyst.py +++ b/mne/io/persyst/persyst.py @@ -13,7 +13,7 @@ from ..meas_info import create_info from ..utils import _mult_cal_one from ...annotations import Annotations -from ...utils import logger, verbose, fill_doc, warn +from ...utils import logger, verbose, fill_doc, warn, _check_fname @fill_doc @@ -65,6 +65,7 @@ class RawPersyst(BaseRaw): @verbose def __init__(self, fname, preload=False, verbose=None): + fname = _check_fname(fname, 'read', True, 'fname') logger.info('Loading %s' % fname) # make sure filename is the Lay file diff --git a/mne/io/snirf/_snirf.py b/mne/io/snirf/_snirf.py index 9a8cab4ba3d..16b7def0f55 100644 --- a/mne/io/snirf/_snirf.py +++ b/mne/io/snirf/_snirf.py @@ -10,7 +10,7 @@ from ..meas_info import create_info from ..utils import _mult_cal_one from ...annotations import Annotations -from ...utils import logger, verbose, fill_doc, warn +from ...utils import logger, verbose, fill_doc, warn, _check_fname from ...utils.check import _require_version from ..constants import FIFF from .._digitization import _make_dig_points @@ -69,6 +69,7 @@ def __init__(self, fname, preload=False, verbose=None): from ...externals.pymatreader.utils import _import_h5py h5py = _import_h5py() + fname = _check_fname(fname, 'read', True, 'fname') logger.info('Loading %s' % fname) with h5py.File(fname, 'r') as dat: diff --git a/mne/io/tests/test_raw.py b/mne/io/tests/test_raw.py index 02a2f1cc1aa..05c1b8a2e23 100644 --- a/mne/io/tests/test_raw.py +++ b/mne/io/tests/test_raw.py @@ -5,12 +5,13 @@ # # License: BSD (3-clause) +from contextlib import redirect_stdout +from io import StringIO +import math +import os from os import path as op from pathlib import Path -import math import re -from contextlib import redirect_stdout -from io import StringIO import pytest import numpy as np @@ -350,6 +351,38 @@ def _test_raw_reader(reader, test_preloading=True, test_kwargs=True, write_hdf5(fname_h5, raw.info) new_info = Info(read_hdf5(fname_h5)) assert object_diff(new_info, raw.info) == '' + + # Make sure that changing directory does not break anything + if test_preloading: + these_kwargs = kwargs.copy() + key = None + for key in ('fname', + 'input_fname', # artemis123 + 'vhdr_fname', # BV + 'pdf_fname', # BTi + 'directory', # CTF + 'filename', # nedf + ): + try: + fname = kwargs[key] + except KeyError: + key = None + else: + break + # len(kwargs) == 0 for the fake arange reader + if len(kwargs): + assert key is not None, sorted(kwargs.keys()) + dirname = op.dirname(fname) + these_kwargs[key] = op.basename(fname) + these_kwargs['preload'] = False + orig_dir = os.getcwd() + try: + os.chdir(dirname) + raw_chdir = reader(**these_kwargs) + finally: + os.chdir(orig_dir) + raw_chdir.load_data() + return raw diff --git a/mne/utils/check.py b/mne/utils/check.py index e5725239186..ca1e879e0e3 100644 --- a/mne/utils/check.py +++ b/mne/utils/check.py @@ -151,21 +151,32 @@ def _check_event_id(event_id, events): def _check_fname(fname, overwrite=False, must_exist=False, name='File', - allow_dir=False): + need_dir=False): """Check for file existence.""" - _validate_type(fname, 'path-like', 'fname') - if op.isfile(fname) or (allow_dir and op.isdir(fname)): + _validate_type(fname, 'path-like', name) + if op.exists(fname): if not overwrite: raise FileExistsError('Destination file exists. Please use option ' '"overwrite=True" to force overwriting.') elif overwrite != 'read': logger.info('Overwriting existing file.') - if must_exist and not os.access(fname, os.R_OK): - raise PermissionError( - '%s does not have read permissions: %s' % (name, fname)) + if must_exist: + if need_dir: + if not op.isdir(fname): + raise IOError( + f'Need a directory for {name} but found a file ' + f'at {fname}') + else: + if not op.isfile(fname): + raise IOError( + f'Need a file for {name} but found a directory ' + f'at {fname}') + if not os.access(fname, os.R_OK): + raise PermissionError( + f'{name} does not have read permissions: {fname}') elif must_exist: - raise FileNotFoundError('%s "%s" does not exist' % (name, fname)) - return str(fname) + raise FileNotFoundError(f'{name} does not exist: {fname}') + return str(op.abspath(fname)) def _check_subject(class_subject, input_subject, raise_error=True, From b092f7742b73c592d713b33b72a3c7efc26a51a6 Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Wed, 31 Mar 2021 14:41:46 -0400 Subject: [PATCH 3/3] FIX: Test --- mne/utils/tests/test_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mne/utils/tests/test_check.py b/mne/utils/tests/test_check.py index 1a62d3597a2..2278d810931 100644 --- a/mne/utils/tests/test_check.py +++ b/mne/utils/tests/test_check.py @@ -35,7 +35,7 @@ def test_check(tmpdir): """Test checking functions.""" pytest.raises(ValueError, check_random_state, 'foo') pytest.raises(TypeError, _check_fname, 1) - _check_fname(Path('./')) + _check_fname(Path('./foo')) fname = str(tmpdir.join('foo')) with open(fname, 'wb'): pass