Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ stages:
key: $(testing_version)
path: /home/vsts/mne_data
displayName: 'Cache testing data'
- script: python -c "import mne; mne.datasets.testing.data_path(verbose=True)"
- bash: ./tools/github_actions_download.sh
displayName: 'Get test data'
- script: pytest -m "ultraslowtest or pgtest" --tb=short --cov=mne --cov-report=xml -vv mne
displayName: 'slow and mne-qt-browser tests'
Expand Down Expand Up @@ -188,7 +188,7 @@ stages:
key: $(testing_version)
path: /home/vsts/mne_data
displayName: 'Cache testing data'
- script: python -c "import mne; mne.datasets.testing.data_path(verbose=True)"
- bash: ./tools/github_actions_download.sh
displayName: 'Get test data'
- bash: |
set -eo pipefail
Expand Down Expand Up @@ -285,7 +285,7 @@ stages:
key: $(testing_version)
path: C:\Users\VssAdministrator\mne_data
displayName: 'Cache testing data'
- script: python -c "import mne; mne.datasets.testing.data_path(verbose=True)"
- bash: ./tools/github_actions_download.sh
displayName: 'Get test data'
- script: pytest -m "not (slowtest or pgtest)" --tb=short --cov=mne --cov-report=xml -vv mne
displayName: 'Run tests'
Expand Down
2 changes: 2 additions & 0 deletions mne/commands/tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
from mne.io import read_info, read_raw_fif, show_fiff
from mne.utils import (
ArgvSetter,
_chmod_rw_R,
_record_warnings,
_stamp_to_dt,
requires_freesurfer,
Expand Down Expand Up @@ -207,6 +208,7 @@ def test_make_scalp_surfaces(tmp_path, monkeypatch):
shutil.copy(t1_path, t1_path_new)
shutil.copy(headseg_path, headseg_path_new)
shutil.copy(surf_path, surf_path_new)
_chmod_rw_R(tmp_path)

cmd = (
"-s",
Expand Down
3 changes: 3 additions & 0 deletions mne/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
Bunch,
_assert_no_instances,
_check_qt_version,
_chmod_rw_R,
_pl,
_record_warnings,
_TempDir,
Expand Down Expand Up @@ -771,6 +772,7 @@ def subjects_dir_tmp(tmp_path):
"""Copy MNE-testing-data subjects_dir to a temp dir for manipulation."""
for key in ("sample", "fsaverage"):
shutil.copytree(op.join(subjects_dir, key), str(tmp_path / key))
_chmod_rw_R(tmp_path)
return str(tmp_path)


Expand All @@ -788,6 +790,7 @@ def subjects_dir_tmp_few(tmp_path):
shutil.copytree(
test_path / "subjects" / "sample" / dirname, sample_path / dirname
)
_chmod_rw_R(subjects_path)
return subjects_path


Expand Down
12 changes: 9 additions & 3 deletions mne/io/ctf/tests/test_ctf.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@
from mne.io.tests.test_raw import _test_raw_reader
from mne.tests.test_annotations import _assert_annotations_equal
from mne.transforms import apply_trans
from mne.utils import _clean_names, _record_warnings, _stamp_to_dt, catch_logging
from mne.utils import (
_clean_names,
_record_warnings,
_stamp_to_dt,
catch_logging,
copytree_rw,
)

ctf_dir = testing.data_path(download=False) / "CTF"
ctf_fname_continuous = "testdata_ctf.ds"
Expand Down Expand Up @@ -75,7 +81,7 @@ def test_read_ctf(tmp_path):
# Create a dummy .eeg file so we can test our reading/application of it
os.mkdir(op.join(temp_dir, "randpos"))
ctf_eeg_fname = op.join(temp_dir, "randpos", ctf_fname_catch)
shutil.copytree(op.join(ctf_dir, ctf_fname_catch), ctf_eeg_fname)
copytree_rw(op.join(ctf_dir, ctf_fname_catch), ctf_eeg_fname)
with pytest.warns(RuntimeWarning, match="RMSP .* changed to a MISC ch"):
raw = _test_raw_reader(read_raw_ctf, directory=ctf_eeg_fname)
picks = pick_types(raw.info, meg=False, eeg=True)
Expand Down Expand Up @@ -689,7 +695,7 @@ def _bad_res4_grad_comp(dsdir):
def test_missing_res4(tmp_path):
"""Test that res4 missing is handled gracefully."""
use_ds = tmp_path / ctf_fname_continuous
shutil.copytree(ctf_dir / ctf_fname_continuous, tmp_path / ctf_fname_continuous)
copytree_rw(ctf_dir / ctf_fname_continuous, tmp_path / ctf_fname_continuous)
read_raw_ctf(use_ds)
os.remove(use_ds / (ctf_fname_continuous[:-2] + "meg4"))
with pytest.raises(OSError, match="could not find the following"):
Expand Down
7 changes: 3 additions & 4 deletions mne/io/egi/tests/test_egi.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@


import os
import shutil
from copy import deepcopy
from datetime import datetime, timezone
from pathlib import Path
Expand All @@ -20,7 +19,7 @@
from mne.io import read_evokeds_mff, read_raw_egi, read_raw_fif
from mne.io.egi.egi import _combine_triggers
from mne.io.tests.test_raw import _test_raw_reader
from mne.utils import object_diff
from mne.utils import copytree_rw, object_diff

base_dir = Path(__file__).parent / "data"
egi_fname = base_dir / "test_egi.raw"
Expand Down Expand Up @@ -337,7 +336,7 @@ def test_io_egi_pns_mff(tmp_path):

# EEG missing
new_mff = tmp_path / "temp.mff"
shutil.copytree(egi_mff_pns_fname, new_mff)
copytree_rw(egi_mff_pns_fname, new_mff)
read_raw_egi(new_mff, verbose="error")
os.remove(new_mff / "info1.xml")
os.remove(new_mff / "signal1.bin")
Expand Down Expand Up @@ -593,7 +592,7 @@ def test_set_standard_montage_mff(fname, standard_montage):
def test_egi_mff_bad_xml(tmp_path):
"""Test that corrupt XML files are gracefully handled."""
pytest.importorskip("defusedxml")
mff_fname = shutil.copytree(egi_mff_fname, tmp_path / "test_egi_bad_xml.mff")
mff_fname = copytree_rw(egi_mff_fname, tmp_path / "test_egi_bad_xml.mff")
bad_xml = mff_fname / "bad.xml"
bad_xml.write_text("<foo>", encoding="utf-8")
# Missing coordinate file
Expand Down
6 changes: 3 additions & 3 deletions mne/io/fil/tests/test_fil.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# License: BSD-3-Clause
# Copyright the MNE-Python contributors.

import shutil
from os import remove

import pytest
Expand All @@ -14,6 +13,7 @@
from mne.datasets import testing
from mne.io import read_raw_fil
from mne.io.fil.sensors import _get_pos_units
from mne.utils import copytree_rw

fil_path = testing.data_path(download=False) / "FIL"

Expand Down Expand Up @@ -161,7 +161,7 @@ def test_fil_complete():
def test_fil_no_positions(tmp_path):
"""Test FIL reader in cases where a position file is missing."""
test_path = tmp_path / "FIL"
shutil.copytree(fil_path, test_path)
copytree_rw(fil_path, test_path)

posname = test_path / "sub-noise_ses-001_task-noise220622_run-001_positions.tsv"
binname = test_path / "sub-noise_ses-001_task-noise220622_run-001_meg.bin"
Expand All @@ -179,7 +179,7 @@ def test_fil_no_positions(tmp_path):
def test_fil_bad_channel_spec(tmp_path):
"""Test FIL reader when a bad channel is specified in channels.tsv."""
test_path = tmp_path / "FIL"
shutil.copytree(fil_path, test_path)
copytree_rw(fil_path, test_path)

channame = test_path / "sub-noise_ses-001_task-noise220622_run-001_channels.tsv"
binname = test_path / "sub-noise_ses-001_task-noise220622_run-001_meg.bin"
Expand Down
8 changes: 4 additions & 4 deletions mne/io/nirx/tests/test_nirx.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import datetime as dt
import os
import shutil

import numpy as np
import pytest
Expand All @@ -22,6 +21,7 @@
source_detector_distances,
)
from mne.transforms import _get_trans, apply_trans
from mne.utils import copytree_rw

testing_path = data_path(download=False)
fname_nirx_15_0 = testing_path / "NIRx" / "nirscout" / "nirx_15_0_recording"
Expand Down Expand Up @@ -246,7 +246,7 @@ def test_nirx_missing_warn():
@requires_testing_data
def test_nirx_missing_evt(tmp_path):
"""Test reading NIRX files when missing data."""
shutil.copytree(fname_nirx_15_2_short, str(tmp_path) + "/data/")
copytree_rw(fname_nirx_15_2_short, str(tmp_path) + "/data/")
os.rename(
tmp_path / "data" / "NIRS-2019-08-23_001.evt",
tmp_path / "data" / "NIRS-2019-08-23_001.xxx",
Expand All @@ -259,7 +259,7 @@ def test_nirx_missing_evt(tmp_path):
@requires_testing_data
def test_nirx_dat_warn(tmp_path):
"""Test reading NIRX files when missing data."""
shutil.copytree(fname_nirx_15_2_short, str(tmp_path) + "/data/")
copytree_rw(fname_nirx_15_2_short, str(tmp_path) + "/data/")
os.rename(
tmp_path / "data" / "NIRS-2019-08-23_001.dat",
tmp_path / "data" / "NIRS-2019-08-23_001.tmp",
Expand Down Expand Up @@ -461,7 +461,7 @@ def test_nirx_15_3_short():
def test_locale_encoding(tmp_path):
"""Test NIRx encoding."""
fname = tmp_path / "latin"
shutil.copytree(fname_nirx_15_2, fname)
copytree_rw(fname_nirx_15_2, fname)
hdr_fname = fname / "NIRS-2019-10-02_003.hdr"
hdr = list()
with open(hdr_fname, "rb") as fid:
Expand Down
2 changes: 2 additions & 0 deletions mne/io/persyst/tests/test_persyst.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from mne.datasets.testing import data_path, requires_testing_data
from mne.io import read_raw_persyst
from mne.io.tests.test_raw import _test_raw_reader
from mne.utils import _chmod_rw_R

testing_path = data_path(download=False)
fname_lay = (
Expand Down Expand Up @@ -144,6 +145,7 @@ def test_persyst_moved_file(tmp_path):
new_fname_lay = tmp_path / fname_lay.name
new_fname_dat = tmp_path / fname_dat.name
shutil.copy(fname_lay, new_fname_lay)
_chmod_rw_R(tmp_path)

# original file read should work
read_raw_persyst(fname_lay)
Expand Down
9 changes: 6 additions & 3 deletions mne/io/snirf/tests/test_snirf.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
source_detector_distances,
)
from mne.transforms import _get_trans, apply_trans
from mne.utils import catch_logging
from mne.utils import _chmod_rw_R, catch_logging

testing_path = data_path(download=False)
# SfNIRS files
Expand Down Expand Up @@ -252,8 +252,9 @@ def test_snirf_against_nirx():
@requires_testing_data
def test_snirf_nonstandard(tmp_path):
"""Test custom tags."""
shutil.copy(sfnirs_homer_103_wShort, str(tmp_path) + "/mod.snirf")
fname = str(tmp_path) + "/mod.snirf"
shutil.copy(sfnirs_homer_103_wShort, fname)
_chmod_rw_R(tmp_path)
# Manually mark up the file to match MNE-NIRS custom tags
with h5py.File(fname, "r+") as f:
f.create_dataset("nirs/metaDataTags/middleName", data=[b"X"])
Expand Down Expand Up @@ -287,8 +288,9 @@ def test_snirf_nonstandard(tmp_path):
@requires_testing_data
def test_snirf_empty_landmark_labels(tmp_path):
"""Test reading SNIRF files with empty landmarkLabels (gh-13627)."""
shutil.copy(sfnirs_homer_103_wShort, tmp_path / "empty_labels.snirf")
fname = tmp_path / "empty_labels.snirf"
shutil.copy(sfnirs_homer_103_wShort, fname)
_chmod_rw_R(tmp_path)

# Modify file to have landmarkPos3D but empty/scalar landmarkLabels
with h5py.File(fname, "r+") as f:
Expand Down Expand Up @@ -586,6 +588,7 @@ def test_sample_rate_jitter(tmp_path):
# Create a clean copy and ensure it loads without error
new_file = tmp_path / "snirf_nirsport2_2019.snirf"
copy2(snirf_nirsport2_20219, new_file)
_chmod_rw_R(tmp_path)
read_raw_snirf(new_file)

# Edit the file and add jitter within tolerance (0.99%)
Expand Down
5 changes: 2 additions & 3 deletions mne/source_space/tests/test_source_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
# Copyright the MNE-Python contributors.

from pathlib import Path
from shutil import copytree

import numpy as np
import pytest
Expand Down Expand Up @@ -43,7 +42,7 @@
)
from mne.source_space._source_space import _compare_source_spaces
from mne.surface import _accumulate_normals, _triangle_neighbors
from mne.utils import _record_warnings, requires_mne, run_subprocess
from mne.utils import _record_warnings, copytree_rw, requires_mne, run_subprocess

data_path = testing.data_path(download=False)
subjects_dir = data_path / "subjects"
Expand Down Expand Up @@ -563,7 +562,7 @@ def test_setup_source_space(tmp_path):
def test_setup_source_space_spacing(tmp_path, spacing, monkeypatch):
"""Test setting up surface source spaces using a given spacing."""
pytest.importorskip("nibabel")
copytree(subjects_dir / "sample", tmp_path / "sample")
copytree_rw(subjects_dir / "sample", tmp_path / "sample")
args = [] if spacing == 7 else ["--spacing", str(spacing)]
monkeypatch.setenv("SUBJECTS_DIR", str(tmp_path))
monkeypatch.setenv("SUBJECT", "sample")
Expand Down
2 changes: 2 additions & 0 deletions mne/tests/test_bem.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
from mne.surface import _get_ico_surface, read_surface
from mne.transforms import translation
from mne.utils import (
_chmod_rw_R,
_record_warnings,
catch_logging,
check_version,
Expand Down Expand Up @@ -231,6 +232,7 @@ def test_bem_model_topology(tmp_path):
subjects_dir / "sample" / "bem" / fname,
tmp_path / "foo" / "bem" / fname,
)
_chmod_rw_R(tmp_path)
outer_fname = tmp_path / "foo" / "bem" / "outer_skull.surf"
rr, tris = read_surface(outer_fname)
tris = tris[:-1]
Expand Down
4 changes: 4 additions & 0 deletions mne/utils/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ __all__ = [
"_check_stc_units",
"_check_subject",
"_check_time_format",
"_chmod_rw_R",
"_clean_names",
"_click_ch_name",
"_compute_row_norms",
Expand Down Expand Up @@ -133,6 +134,7 @@ __all__ = [
"compute_corr",
"copy_doc",
"copy_function_doc_to_method_doc",
"copytree_rw",
"create_slices",
"deprecated",
"deprecated_alias",
Expand Down Expand Up @@ -202,6 +204,7 @@ from ._logging import (
)
from ._testing import (
ArgvSetter,
_chmod_rw_R,
_click_ch_name,
_raw_annot,
_TempDir,
Expand All @@ -212,6 +215,7 @@ from ._testing import (
assert_snr,
assert_stcs_equal,
buggy_mkl_svd,
copytree_rw,
has_freesurfer,
has_mne_c,
requires_freesurfer,
Expand Down
21 changes: 21 additions & 0 deletions mne/utils/_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import inspect
import os
import shutil
import sys
import tempfile
import traceback
Expand Down Expand Up @@ -417,3 +418,23 @@ def assert_trans_allclose(actual, desired, dist_tol=0.0, angle_tol=0.0):
f"{1000 * dist:0.3f} > {1000 * dist_tol:0.3f} mm translation"
)
assert angle <= angle_tol, f"{angle:0.3f} > {angle_tol:0.3f}° rotation"


def _chmod_rw_R(path):
assert os.path.isdir(path), f"Expected a directory, got {path}"
os.chmod(path, 0o700 | os.stat(path).st_mode)
for root, dirs, files in os.walk(path):
for name in files:
this_name = os.path.join(root, name)
os.chmod(this_name, 0o600 | os.stat(this_name).st_mode)
for name in dirs:
this_name = os.path.join(root, name)
os.chmod(this_name, 0o770 | os.stat(this_name).st_mode)


def copytree_rw(src, dst):
"""Copy a directory tree and make it read/write."""
assert os.path.isdir(src), f"Expected a directory, got {src}"
shutil.copytree(src, dst)
_chmod_rw_R(dst)
return dst
4 changes: 4 additions & 0 deletions tools/github_actions_download.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@
if [ "${MNE_CI_KIND}" != "minimal" ]; then
python -c 'import mne; mne.datasets.testing.data_path(verbose=True)';
python -c "import mne; mne.datasets.misc.data_path(verbose=True)";
# Make read-only to make sure we don't modify its contents
TESTING_PATH=$(python -c "import mne; print(mne.datasets.testing.data_path(verbose=False))")
echo "Testing data path: $TESTING_PATH"
chmod -R a-w "$TESTING_PATH"
fi
Loading