9898 no_montage = r"ignore:Not setting position of.*channel found in "
9999 r"montage.*:RuntimeWarning:mne" ,
100100 emg_coords_missing = r"ignore:No electrode location info found.*:RuntimeWarning" ,
101- converting_to_edf = r"ignore:Converting data files to EDF format:RuntimeWarning" ,
101+ converting_to_edf = r"ignore:Converting data files to [BE]DF format:RuntimeWarning" ,
102102 channel_mismatch = (
103103 "ignore:Channel mismatch between .*channels\\ .tsv and the raw data file "
104104 "detected\\ .:RuntimeWarning:mne"
105105 ),
106+ edf_date = "ignore:.*limits dates to after 1985-01-01:RuntimeWarning" ,
106107)
107108
108109
@@ -3173,6 +3174,7 @@ def test_coordsystem_json_compliance(
31733174 "sub-pt1_ses-02_task-monitor_acq-ecog_run-01_clip2.lay" ,
31743175 _read_raw_persyst ,
31753176 ),
3177+ ("01" , "Brainvision" , "Analyzer_nV_Export.vhdr" , _read_raw_brainvision ),
31763178 ("03" , "NihonKohden" , "MB0400FU.EEG" , _read_raw_nihon ),
31773179 ("emptyroom" , "MEG/sample" , "sample_audvis_trunc_raw.fif" , _read_raw_fif ),
31783180 ],
@@ -3182,10 +3184,14 @@ def test_coordsystem_json_compliance(
31823184 warning_str ["channel_unit_changed" ],
31833185 warning_str ["edf_warning" ],
31843186 warning_str ["brainvision_unit" ],
3187+ warning_str ["converting_to_edf" ],
3188+ warning_str ["edfblocks" ],
3189+ warning_str ["emg_coords_missing" ],
3190+ warning_str ["edf_date" ],
31853191)
31863192@testing .requires_testing_data
31873193def test_anonymize (subject , dir_name , fname , reader , tmp_path , _bids_validate ):
3188- """Test writing anonymized EDF data."""
3194+ """Test writing anonymized data."""
31893195 raw_fname = op .join (data_path , dir_name , fname )
31903196
31913197 bids_root = tmp_path / "bids1"
@@ -3197,21 +3203,21 @@ def test_anonymize(subject, dir_name, fname, reader, tmp_path, _bids_validate):
31973203 # handle different edge cases
31983204 if subject == "emptyroom" :
31993205 bids_path .update (task = "noise" , session = raw_date , suffix = "meg" , datatype = "meg" )
3200- erm = None
3206+ write_kw = dict (empty_room = None )
3207+ elif dir_name == "Brainvision" : # pretend it's EMG data
3208+ raw .set_channel_types ({ch : "emg" for ch in raw .ch_names })
3209+ raw .set_montage (None )
3210+ bids_path .update (task = "task" , suffix = "emg" , datatype = "emg" )
3211+ write_kw = dict (empty_room = None , emg_placement = "Measured" )
32013212 else :
32023213 bids_path .update (task = "task" , suffix = "eeg" , datatype = "eeg" )
32033214 # make sure anonymization works when also writing empty room file
3204- erm = raw .copy ()
3215+ write_kw = dict ( empty_room = raw .copy () )
32053216 daysback_min , daysback_max = get_anonymization_daysback (raw )
32063217 anonymize = dict (daysback = daysback_min + 1 )
32073218 orig_bids_path = bids_path .copy ()
32083219 bids_path = write_raw_bids (
3209- raw ,
3210- bids_path ,
3211- overwrite = True ,
3212- anonymize = anonymize ,
3213- verbose = False ,
3214- empty_room = erm ,
3220+ raw , bids_path , overwrite = True , anonymize = anonymize , verbose = False , ** write_kw
32153221 )
32163222 # emptyroom recordings' session should match the recording date
32173223 if subject == "emptyroom" :
@@ -3225,7 +3231,8 @@ def test_anonymize(subject, dir_name, fname, reader, tmp_path, _bids_validate):
32253231 assert _raw .info ["meas_date" ].year == 1985
32263232 assert _raw .info ["meas_date" ].month == 1
32273233 assert _raw .info ["meas_date" ].day == 1
3228- assert raw2 .info ["meas_date" ].year < 1925
3234+ year = 1986 if dir_name == "Brainvision" else 1925
3235+ assert raw2 .info ["meas_date" ].year < year
32293236
32303237 # write without source
32313238 scans_fname = BIDSPath (
@@ -3237,7 +3244,12 @@ def test_anonymize(subject, dir_name, fname, reader, tmp_path, _bids_validate):
32373244 )
32383245 anonymize ["keep_source" ] = False
32393246 bids_path = write_raw_bids (
3240- raw , orig_bids_path , overwrite = True , anonymize = anonymize , verbose = False
3247+ raw ,
3248+ orig_bids_path ,
3249+ overwrite = True ,
3250+ anonymize = anonymize ,
3251+ verbose = False ,
3252+ ** write_kw ,
32413253 )
32423254 scans_tsv = _from_tsv (scans_fname )
32433255 assert "source" not in scans_tsv .keys ()
@@ -3249,6 +3261,7 @@ def test_anonymize(subject, dir_name, fname, reader, tmp_path, _bids_validate):
32493261 overwrite = True ,
32503262 anonymize = dict (daysback = daysback_min , keep_source = True ),
32513263 verbose = False ,
3264+ ** write_kw ,
32523265 )
32533266 scans_fname = BIDSPath (
32543267 subject = bids_path .subject ,
@@ -3259,7 +3272,8 @@ def test_anonymize(subject, dir_name, fname, reader, tmp_path, _bids_validate):
32593272 )
32603273 scans_tsv = _from_tsv (scans_fname )
32613274 assert scans_tsv ["source" ] == [Path (f ).name for f in raw .filenames ]
3262- _bids_validate (bids_path .root )
3275+ if dir_name != "Brainvision" : # EMG not yet supported by validator
3276+ _bids_validate (bids_path .root )
32633277
32643278 # update the scans sidecar JSON with information
32653279 scans_json_fpath = scans_fname .copy ().update (extension = ".json" )
@@ -3275,6 +3289,7 @@ def test_anonymize(subject, dir_name, fname, reader, tmp_path, _bids_validate):
32753289 overwrite = True ,
32763290 anonymize = dict (daysback = daysback_min , keep_source = True ),
32773291 verbose = False ,
3292+ ** write_kw ,
32783293 )
32793294 with open (scans_json_fpath ) as fin :
32803295 scans_json = json .load (fin )
@@ -3371,16 +3386,19 @@ def test_sidecar_encoding(_bids_validate, tmp_path):
33713386@testing .requires_testing_data
33723387def test_emg_errors_and_warnings (tmp_path ):
33733388 """Test EMG-specific error/warning raising."""
3374- bids_root = tmp_path / "EDF "
3375- raw_fname = data_path / "EDF " / "test_generator_2.edf "
3389+ bids_root = tmp_path / "EMG_errors "
3390+ raw_fname = data_path / "Brainvision " / "test_NO.vhdr "
33763391 bids_path = _bids_path .copy ().update (root = bids_root , datatype = "emg" )
3377- raw = _read_raw_edf (raw_fname )
3392+ raw = _read_raw_brainvision (raw_fname )
33783393 raw .set_channel_types ({ch : "emg" for ch in raw .ch_names }) # HACK eeg → emg
3379- raw = raw .pick (["emg" ]) # drop misc
3380- good_kwargs = dict (raw = raw , bids_path = bids_path , verbose = False )
3394+ good_kwargs = dict (raw = raw , bids_path = bids_path , verbose = False , overwrite = True )
33813395 with pytest .raises (ValueError , match = "`emg_placement` must be one of" ):
33823396 write_raw_bids (** good_kwargs , emg_placement = "Foo" )
3383- with pytest .warns (RuntimeWarning , match = "add `coordsystem.json` file manually" ):
3397+ with (
3398+ pytest .warns (RuntimeWarning , match = "BDF format requires equal-length data" ),
3399+ pytest .warns (RuntimeWarning , match = "Converting data files to BDF format" ),
3400+ pytest .warns (RuntimeWarning , match = "add `coordsystem.json` file manually" ),
3401+ ):
33843402 write_raw_bids (** good_kwargs , emg_placement = "Other" )
33853403
33863404
@@ -3399,7 +3417,6 @@ def test_convert_emg_formats(tmp_path, dir_name, fmt, fname, reader):
33993417 bids_path = _bids_path .copy ().update (root = bids_root , datatype = "emg" )
34003418 raw = reader (raw_fname )
34013419 raw .set_channel_types ({ch : "emg" for ch in raw .ch_names }) # HACK eeg → emg
3402- raw = raw .pick (["emg" ]) # drop misc
34033420 # test anonymization in one case too, for coverage
34043421 if dir_name == "Brainvision" :
34053422 raw .anonymize ()
@@ -3803,8 +3820,8 @@ def test_write_associated_emptyroom(_bids_validate, tmp_path, empty_room_dtype):
38033820 assert meg_json_data ["AssociatedEmptyRoom" ] == expected_rel
38043821
38053822
3806- def test_preload ( _bids_validate , tmp_path ):
3807- """Test writing custom preloaded raw objects ."""
3823+ def test_preload_errors ( tmp_path ):
3824+ """Test allow_preload error handling ."""
38083825 bids_root = tmp_path / "bids"
38093826 bids_path = _bids_path .copy ().update (root = bids_root )
38103827 sfreq , n_points = 1024.0 , int (1e6 )
@@ -3814,25 +3831,45 @@ def test_preload(_bids_validate, tmp_path):
38143831 raw .orig_format = "single"
38153832 raw .info ["line_freq" ] = 60
38163833
3834+ shared_kwargs = dict (raw = raw , bids_path = bids_path , verbose = False , overwrite = True )
38173835 # reject preloaded by default
38183836 with pytest .raises (ValueError , match = "allow_preload" ):
3819- write_raw_bids (raw , bids_path , verbose = False , overwrite = True )
3837+ write_raw_bids (** shared_kwargs )
38203838
38213839 # preloaded raw must specify format
38223840 with pytest .raises (ValueError , match = "format" ):
3823- write_raw_bids (
3824- raw , bids_path , allow_preload = True , verbose = False , overwrite = True
3825- )
3841+ write_raw_bids (** shared_kwargs , allow_preload = True )
3842+
38263843
3844+ @pytest .mark .filterwarnings (
3845+ warning_str ["edfblocks" ],
3846+ warning_str ["emg_coords_missing" ],
3847+ warning_str ["converting_to_edf" ],
3848+ )
3849+ @pytest .mark .parametrize (
3850+ "format,ch_type" , (("BrainVision" , "eeg" ), ("BDF" , "emg" ), ("EDF" , "seeg" ))
3851+ )
3852+ def test_preload (_bids_validate , tmp_path , format , ch_type ):
3853+ """Test writing custom preloaded raw objects."""
3854+ bids_root = tmp_path / "bids"
3855+ bids_path = _bids_path .copy ().update (root = bids_root )
3856+ sfreq = 1024.0
3857+ info = mne .create_info (["ch1" , "ch2" ], sfreq , ch_type )
3858+ raw = mne .io .RawArray (np .empty ((2 , 100 ), dtype = np .float32 ), info )
3859+ raw .orig_format = "single"
3860+ raw .info ["line_freq" ] = 60
3861+ kw = dict (emg_placement = "Measured" ) if ch_type == "emg" else dict ()
38273862 write_raw_bids (
38283863 raw ,
38293864 bids_path ,
3830- allow_preload = True ,
3831- format = "BrainVision" ,
38323865 verbose = False ,
38333866 overwrite = True ,
3867+ allow_preload = True ,
3868+ format = format ,
3869+ ** kw ,
38343870 )
3835- _bids_validate (bids_root )
3871+ if ch_type != "emg" : # TODO validator support for EMG not available yet
3872+ _bids_validate (bids_root )
38363873
38373874
38383875@pytest .mark .parametrize ("dir_name" , ("tsv_test" , "json_test" ))
0 commit comments