Repository: mne-tools/mne-python

Issue:
can't read new brainvision markers?

When reading a brainvision file (available [here](https://osf.io/5qbr3/?show=revision), after extracting 
- `EEG_data/EEG_excluded.zip/vic0001.vhdr` 
- `EEG_data/hdr_mrk_files/vic0001.vmrk` 
- `EEG_data/hdr_mrk_files/vic0001.vhdr`
)

The following command
```python
raw = mne.io.read_raw_brainvision('vic0001.vhdr')
```

leads to
```
ValueError: MNE-Python currently only supports marker versions 1.0 and 2.0, got unparsable '[Marker Infos]'. 
Contact MNE-Python developers for support.
```

I am thus contacting MNE-Python developers for support :]


Discussion:
Wow, you just won the best issue number jackpot 😄!

It seems like the first line is missing:

```
Brain Vision Data Exchange Marker File, Version 1.0
```

Otherwise, the format looks identical to what we can read, so I'm guessing that this line (1) is either not mandatory or (2) has been removed during export (by BV Analyzer).
ping @sappelhoff WDYT?
According to the official specs, this line is required: https://www.brainproducts.com/filedownload.php?path=products/more/BVCDF-1.0_DocVersion-2.5_2019-12-12.pdf (page 12).
> Wow, you just won the best issue number jackpot 😄!

haha nice!


I guess we could just `warn` in this case that the file might not work correctly. It seems like a bug with whatever wrote this file that the given line is missing
I can do that if no one else beats me to it.
Go for it!

Resolving patch:
diff --git a/mne/io/brainvision/brainvision.py b/mne/io/brainvision/brainvision.py
--- a/mne/io/brainvision/brainvision.py
+++ b/mne/io/brainvision/brainvision.py
@@ -299,22 +299,24 @@ def _read_annotations_brainvision(fname, sfreq='auto'):
     return annotations
 
 
-_data_err = """\
-MNE-Python currently only supports %s versions 1.0 and 2.0, got unparsable \
-%r. Contact MNE-Python developers for support."""
-# optional space, optional Core, Version/Header, optional comma, 1/2
-_data_re = r'Brain ?Vision( Core)? Data Exchange %s File,? Version %s\.0'
-
-
 def _check_bv_version(header, kind):
     """Check the header version."""
+    _data_err = """\
+    MNE-Python currently only supports %s versions 1.0 and 2.0, got unparsable\
+     %r. Contact MNE-Python developers for support."""
+    # optional space, optional Core, Version/Header, optional comma, 1/2
+    _data_re = r'Brain ?Vision( Core)? Data Exchange %s File,? Version %s\.0'
+
     assert kind in ('header', 'marker')
+
+    if header == '':
+        warn(f'Missing header in {kind} file.')
     for version in range(1, 3):
         this_re = _data_re % (kind.capitalize(), version)
         if re.search(this_re, header) is not None:
             return version
     else:
-        raise ValueError(_data_err % (kind, header))
+        warn(_data_err % (kind, header))
 
 
 _orientation_dict = dict(MULTIPLEXED='F', VECTORIZED='C')


Test patch:
diff --git a/mne/io/brainvision/tests/test_brainvision.py b/mne/io/brainvision/tests/test_brainvision.py
--- a/mne/io/brainvision/tests/test_brainvision.py
+++ b/mne/io/brainvision/tests/test_brainvision.py
@@ -201,8 +201,10 @@ def test_vhdr_codepage_ansi(tmp_path):
     b'BrainVision Data Exchange %s File Version 1.0\n',
     # 2.0, space, core, comma
     b'Brain Vision Core Data Exchange %s File, Version 2.0\n',
-    # bad
+    # unsupported version
     b'Brain Vision Core Data Exchange %s File, Version 3.0\n',
+    # missing header
+    b'\n',
 ])
 def test_vhdr_versions(tmp_path, header):
     """Test BV reading with different header variants."""
@@ -217,23 +219,34 @@ def test_vhdr_versions(tmp_path, header):
             for line in fin:
                 # Common Infos section
                 if line.startswith(b'Brain'):
-                    line = header % b'Header'
+                    if header != b'\n':
+                        line = header % b'Header'
+                    else:
+                        line = header
                 fout.write(line)
     with open(use_vmrk_path, 'wb') as fout:
         with open(vmrk_path, 'rb') as fin:
             for line in fin:
                 # Common Infos section
                 if line.startswith(b'Brain'):
-                    line = header % b'Marker'
+                    if header != b'\n':
+                        line = header % b'Marker'
+                    else:
+                        line = header
                 fout.write(line)
 
-    if b'3.0' in header:  # bad case
-        with pytest.raises(ValueError, match=r'3\.0.*Contact MNE-Python'):
+    if (b'3.0' in header):  # unsupported version
+        with pytest.warns(RuntimeWarning, match=r'3\.0.*Contact MNE-Python'):
             read_raw_brainvision(use_vhdr_path)
         return
-    raw = read_raw_brainvision(use_vhdr_path)
-    data_new, _ = raw[:]
-    assert_allclose(data_new, data_expected, atol=1e-15)
+    elif header == b'\n':  # no version header
+        with pytest.warns(RuntimeWarning, match='Missing header'):
+            read_raw_brainvision(use_vhdr_path)
+        return
+    else:
+        raw = read_raw_brainvision(use_vhdr_path)
+        data_new, _ = raw[:]
+        assert_allclose(data_new, data_expected, atol=1e-15)
 
 
 @pytest.mark.parametrize('data_sep', (b' ', b',', b'+'))