Skip to content

Commit 122f268

Browse files
authored
[MRG] handle empty TSVs robustly and warn (#1038)
* handle empty TSVs robustly and warn * add whatsnew * use mne warn, not warnings warn
1 parent be6bd62 commit 122f268

File tree

3 files changed

+25
-4
lines changed

3 files changed

+25
-4
lines changed

doc/whats_new.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ Detailed list of changes
4747

4848
- :func:`~mne_bids.write_raw_bids` now stores participant weight and height in ``participants.tsv``, by `Richard Höchenberger`_ (:gh:`1031`)
4949

50-
- :func:`~mne_bids.write_raw_bids` now supports EGI format by `Anand Saini`_, `Scott Huberty`_ and `Mathieu Scheltienne`_ (:gh:`1006`)
50+
- :func:`~mne_bids.write_raw_bids` now supports EGI format, by `Anand Saini`_, `Scott Huberty`_ and `Mathieu Scheltienne`_ (:gh:`1006`)
51+
52+
- TSV files that are empty (i.e., only a header row is present) are now handled more robustly and a warning is issued, by `Stefan Appelhoff`_ (:gh:`1038`)
5153

5254
🧐 API and behavior changes
5355
^^^^^^^^^^^^^^^^^^^^^^^^^^^

mne_bids/tests/test_tsv_handler.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ def test_tsv_handler(tmp_path):
6363
d = _from_tsv(d_path)
6464
assert d['a'] == ['1', '2', '3', '4']
6565

66+
# test an empty tsv (just headers)
67+
_to_tsv(odict(onset=[], duration=[], trial_type=[]), d_path)
68+
with pytest.warns(RuntimeWarning, match="TSV file is empty"):
69+
d = _from_tsv(d_path)
70+
d = _drop(d, "n/a", "trial_type")
71+
6672

6773
def test_contains_row_different_types():
6874
"""Test that _contains_row() can handle different dtypes without warning.

mne_bids/tsv_handler.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"""Private functions to handle tabular data."""
2-
import numpy as np
32
from collections import OrderedDict
43
from copy import deepcopy
54

5+
from mne.utils import warn
6+
import numpy as np
7+
68

79
def _combine_rows(data1, data2, drop_column=None):
810
"""Add two OrderedDict's together and optionally drop repeated data.
@@ -109,7 +111,10 @@ def _drop(data, values, column):
109111
# Cast `values` to the same dtype as `new_data_col` to avoid a NumPy
110112
# FutureWarning, see
111113
# https://github.com/mne-tools/mne-bids/pull/372
112-
values = np.array(values, dtype=new_data_col.dtype)
114+
dtype = new_data_col.dtype
115+
if new_data_col.shape == (0,):
116+
dtype = np.array(values).dtype
117+
values = np.array(values, dtype=dtype)
113118

114119
mask = np.in1d(new_data_col, values, invert=True)
115120
for key in new_data.keys():
@@ -147,8 +152,16 @@ def _from_tsv(fname, dtypes=None):
147152
if not len(dtypes) == info.shape[1]:
148153
raise ValueError('dtypes length mismatch. Provided: {0}, '
149154
'Expected: {1}'.format(len(dtypes), info.shape[1]))
155+
empty_cols = 0
150156
for i, name in enumerate(column_names):
151-
data_dict[name] = info[:, i].astype(dtypes[i]).tolist()
157+
values = info[:, i].astype(dtypes[i]).tolist()
158+
data_dict[name] = values
159+
if len(values) == 0:
160+
empty_cols += 1
161+
162+
if empty_cols == len(column_names):
163+
warn(f"TSV file is empty: '{fname}'")
164+
152165
return data_dict
153166

154167

0 commit comments

Comments
 (0)