Skip to content

Commit d9f891e

Browse files
chkothezm711
andauthored
BrainvisionRawIO: fix handling of broken file references (#1780)
* fix handling of broken file references in brainvisionrawio * brainvisionrawio: using "data" instead of "binary" in warning message * brainvisionrawio: added error message when sidecar file seems to be missing --------- Co-authored-by: Zach McKenzie <[email protected]>
1 parent ab3d0f5 commit d9f891e

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

neo/rawio/brainvisionrawio.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ def _parse_header(self):
5555
marker_filename = self.filename.replace(bname, vhdr_header["Common Infos"]["MarkerFile"])
5656
binary_filename = self.filename.replace(bname, vhdr_header["Common Infos"]["DataFile"])
5757

58+
marker_filename = self._ensure_filename(marker_filename, "marker", "MarkerFile")
59+
binary_filename = self._ensure_filename(binary_filename, "data", "DataFile")
60+
5861
if vhdr_header["Common Infos"]["DataFormat"] != "BINARY":
5962
raise NeoReadWriteError(
6063
f"Only `BINARY` format has been implemented. Current Data Format is {vhdr_header['Common Infos']['DataFormat']}"
@@ -236,6 +239,48 @@ def _rescale_event_timestamp(self, event_timestamps, dtype, event_channel_index)
236239
def _get_analogsignal_buffer_description(self, block_index, seg_index, buffer_id):
237240
return self._buffer_descriptions[block_index][seg_index][buffer_id]
238241

242+
def _ensure_filename(self, filename, kind, entry_name):
243+
if not os.path.exists(filename):
244+
# file not found, subsequent import stage would fail
245+
ext = os.path.splitext(filename)[1]
246+
# Check if we can fall back to a file with the same prefix as the .vhdr.
247+
# This can happen when users rename their files but forget to edit the
248+
# .vhdr file to fix the path reference to the binary and marker files,
249+
# in which case import will fail. These files come in triples, like:
250+
# myfile.vhdr, myfile.eeg and myfile.vmrk; this code will thus pick
251+
# the next best alternative.
252+
alt_name = self.filename.replace(".vhdr", ext)
253+
if os.path.exists(alt_name):
254+
self.logger.warning(
255+
f"The {kind} file {filename} was not found, but found a file whose "
256+
f"prefix matched the .vhdr ({os.path.basename(alt_name)}). Using "
257+
f"this file instead.")
258+
filename = alt_name
259+
else:
260+
# we neither found the file referenced in the .vhdr file nor a file of
261+
# same name as header with the desired extension; most likely a file went
262+
# missing or was renamed in an inconsistent fashion; generate a useful
263+
# error message
264+
header_dname = os.path.dirname(self.filename)
265+
header_bname = os.path.basename(self.filename)
266+
referenced_bname = os.path.basename(filename)
267+
alt_bname = os.path.basename(alt_name)
268+
if alt_bname != referenced_bname:
269+
# this is only needed when the two candidate file names differ
270+
detail = (f" is named either as per the {entry_name}={referenced_bname} "
271+
f"line in the .vhdr file, or")
272+
else:
273+
# we omit it if we can to make it less confusing
274+
detail = ""
275+
self.logger.error(
276+
f"Did not find the {kind} file associated with .vhdr (header) "
277+
f"file {header_bname!r} in folder {header_dname!r}.\n Please make "
278+
f"sure the file{detail} is named the same way as the .vhdr file, but "
279+
f"ending in {ext} (i.e. {alt_bname}).\n The import will likely fail, "
280+
f"but if it goes through, you can ignore this message (the check "
281+
f"can misfire on networked file systems).")
282+
return filename
283+
239284

240285
def read_brainvsion_soup(filename):
241286
with open(filename, "r", encoding="utf8") as f:

0 commit comments

Comments
 (0)