Skip to content

Commit 6f42037

Browse files
szz-dvlpre-commit-ci[bot]autofix-ci[bot]larsoner
authored
Feature: Support for file-like objects for EDF/BDF/GDF files (#13156)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Eric Larson <[email protected]>
1 parent 88951b6 commit 6f42037

File tree

7 files changed

+572
-129
lines changed

7 files changed

+572
-129
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added support for file like objects in :func:`read_raw_bdf <mne.io.read_raw_bdf>`, :func:`read_raw_edf <mne.io.read_raw_edf>` and :func:`read_raw_gdf <mne.io.read_raw_gdf>`, by :newcontrib:`Santi Martínez`.

doc/changes/names.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@
283283
.. _Samuel Louviot: https://github.com/Sam54000
284284
.. _Samuel Powell: https://github.com/samuelpowell
285285
.. _Santeri Ruuskanen: https://github.com/ruuskas
286+
.. _Santi Martínez: https://github.com/szz-dvl
286287
.. _Sara Sommariva: https://github.com/sarasommariva
287288
.. _Sawradip Saha: https://sawradip.github.io/
288289
.. _Scott Huberty: https://orcid.org/0000-0003-2637-031X

mne/_edf/open.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Authors: The MNE-Python contributors.
2+
# License: BSD-3-Clause
3+
# Copyright the MNE-Python contributors.
4+
5+
# Maybe we can move this one to utils or something like that.
6+
from pathlib import Path
7+
8+
from mne._fiff.open import _NoCloseRead
9+
10+
from ..utils import _file_like, _validate_type, logger
11+
12+
13+
def _gdf_edf_get_fid(fname, **kwargs):
14+
"""Open a EDF/BDF/GDF file with no additional parsing."""
15+
if _file_like(fname):
16+
logger.debug("Using file-like I/O")
17+
fid = _NoCloseRead(fname)
18+
fid.seek(0)
19+
else:
20+
_validate_type(fname, [Path, str], "fname", extra="or file-like")
21+
logger.debug("Using normal I/O")
22+
fid = open(fname, "rb", **kwargs) # Open in binary mode
23+
return fid

mne/fixes.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
# because this module is imported many places (but not always used)!
1717

1818
import inspect
19+
import io
1920
import operator as operator_module
2021
import os
2122
import warnings
2223
from math import log
2324

2425
import numpy as np
26+
import numpy.typing
2527
from packaging.version import parse
2628

2729
###############################################################################
@@ -733,3 +735,33 @@ def sph_harm_y(n, m, theta, phi, *, diff_n=0):
733735
return special.sph_harm_y(n, m, theta, phi, diff_n=diff_n)
734736
else:
735737
return special.sph_harm(m, n, phi, theta)
738+
739+
740+
###############################################################################
741+
# workaround: Numpy won't allow to read from file-like objects with numpy.fromfile,
742+
# we try to use numpy.fromfile, if a blob is used we use numpy.frombuffer to read
743+
# from the file-like object.
744+
def read_from_file_or_buffer(
745+
file: str | bytes | os.PathLike | io.IOBase,
746+
dtype: numpy.typing.DTypeLike = float,
747+
count: int = -1,
748+
):
749+
"""numpy.fromfile() wrapper, handling io.BytesIO file-like streams.
750+
751+
Numpy requires open files to be actual files on disk, i.e., must support
752+
file.fileno(), so it fails with file-like streams such as io.BytesIO().
753+
754+
If numpy.fromfile() fails due to no file.fileno() support, this wrapper
755+
reads the required bytes from file and redirects the call to
756+
numpy.frombuffer().
757+
758+
See https://github.com/numpy/numpy/issues/2230#issuecomment-949795210
759+
"""
760+
try:
761+
return np.fromfile(file, dtype=dtype, count=count)
762+
except io.UnsupportedOperation as e:
763+
if not (e.args and e.args[0] == "fileno" and isinstance(file, io.IOBase)):
764+
raise # Nothing I can do about it
765+
dtype = np.dtype(dtype)
766+
buffer = file.read(dtype.itemsize * count)
767+
return np.frombuffer(buffer, dtype=dtype, count=count)

0 commit comments

Comments
 (0)