Repository: mne-tools/mne-python

Issue:
Read empty txt annotations
Hi

If the .txt annotation file is empty it gives a ValueError: not enough values to unpack (expected 3, got 0)

Sometimes, at least for me, it is useful to write empty files to keep track of steps already done. 
A simple option would be to add a try and except assigning empty values to the onset duration and desc.

What do you think?

This issue is similar to #6209


Discussion:
@AdoNunes please provide a basic code snippet we could use to replicate the error and make later a test. thanks
The snippet:

```
from mne.annotations import Annotations,  _read_annotations_txt                                                                                                                                                      
Annot = Annotations([],[],[])                                                                                                                                                           
Annot.save('filename.txt')                                                                                                                                                                
_read_annotations_txt('filename.txt')
```
   
This seems to happen only for .txt

@agramfort in these cases, should I just do a PR directly or always first create an issue?


Resolving patch:
diff --git a/mne/annotations.py b/mne/annotations.py
--- a/mne/annotations.py
+++ b/mne/annotations.py
@@ -9,7 +9,7 @@
 from copy import deepcopy
 from itertools import takewhile
 import collections
-
+import warnings
 import numpy as np
 
 from .utils import (_pl, check_fname, _validate_type, verbose, warn, logger,
@@ -736,11 +736,18 @@ def is_orig_time(x):
 
 
 def _read_annotations_txt(fname):
-    onset, duration, desc = np.loadtxt(fname, delimiter=',',
-                                       dtype=np.bytes_, unpack=True)
-    onset = [float(o.decode()) for o in onset]
-    duration = [float(d.decode()) for d in duration]
-    desc = [str(d.decode()).strip() for d in desc]
+    with warnings.catch_warnings(record=True):
+        warnings.simplefilter("ignore")
+        out = np.loadtxt(fname, delimiter=',',
+                         dtype=np.bytes_, unpack=True)
+    if len(out) == 0:
+        onset, duration, desc = [], [], []
+    else:
+        onset, duration, desc = out
+
+    onset = [float(o.decode()) for o in np.atleast_1d(onset)]
+    duration = [float(d.decode()) for d in np.atleast_1d(duration)]
+    desc = [str(d.decode()).strip() for d in np.atleast_1d(desc)]
     return onset, duration, desc
 
 


Test patch:
diff --git a/mne/tests/test_annotations.py b/mne/tests/test_annotations.py
--- a/mne/tests/test_annotations.py
+++ b/mne/tests/test_annotations.py
@@ -854,6 +854,45 @@ def test_read_annotation_txt_orig_time(
     assert_array_equal(annot.description, ['AA', 'BB'])
 
 
+@pytest.fixture(scope='session')
+def dummy_annotation_txt_one_segment(tmpdir_factory):
+    """Create empty TXT annotations."""
+    content = ("# MNE-Annotations\n"
+               "# onset, duration, description\n"
+               "3.14, 42, AA")
+    fname = tmpdir_factory.mktemp('data').join('one-annotations.txt')
+    fname.write(content)
+    return fname
+
+
+def test_read_annotation_txt_one_segment(
+        dummy_annotation_txt_one_segment):
+    """Test empty TXT input/output."""
+    annot = read_annotations(str(dummy_annotation_txt_one_segment))
+    assert_array_equal(annot.onset, 3.14)
+    assert_array_equal(annot.duration, 42)
+    assert_array_equal(annot.description, 'AA')
+
+
+@pytest.fixture(scope='session')
+def dummy_annotation_txt_file_empty(tmpdir_factory):
+    """Create empty TXT annotations."""
+    content = ("# MNE-Annotations\n"
+               "# onset, duration, description\n")
+    fname = tmpdir_factory.mktemp('data').join('empty-annotations.txt')
+    fname.write(content)
+    return fname
+
+
+def test_read_annotation_txt_empty(
+        dummy_annotation_txt_file_empty):
+    """Test empty TXT input/output."""
+    annot = read_annotations(str(dummy_annotation_txt_file_empty))
+    assert_array_equal(annot.onset, np.array([], dtype=np.float64))
+    assert_array_equal(annot.duration, np.array([], dtype=np.float64))
+    assert_array_equal(annot.description, np.array([], dtype='<U1'))
+
+
 def test_annotations_simple_iteration():
     """Test indexing Annotations."""
     NUM_ANNOT = 5