-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Feature: Support for file-like objects for EDF/BDF/GDF files #13156
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Hello! 👋 Thanks for opening your first pull request here! ❤️ We will try to get back to you soon. 🚴 |
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few minor comments, once you push and expect tests to pass can you ping me? I'll need to approve the CI workflow manually
@@ -1597,7 +1882,8 @@ def read_raw_edf( | |||
Parameters | |||
---------- | |||
input_fname : path-like | |||
Path to the EDF or EDF+ file. | |||
Path to the EDF or EDF+ file or EDF/EDF+ file itself. If a file-like | |||
object is provided, preload must be used. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
object is provided, preload must be used. | |
object is provided, preload must be used. | |
.. versionchanged:: 1.10 | |
Added support for file-like objects. |
Same in other functions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@larsoner Only for public functions, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah read_raw_*
should have them, classes not as critical
mne/io/edf/edf.py
Outdated
if not _file_like(input_fname): | ||
input_fname = os.path.abspath(input_fname) | ||
ext = os.path.splitext(input_fname)[1][1:].lower() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is 95% the same code 3 places, should move to a helper function to be more DRY
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@larsoner I'm using _check_fname as suggested below, is it enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@larsoner a new function _check_args has been created, I encapsulated the whole conditional in this function.
mne/io/edf/edf.py
Outdated
input_fname = os.path.abspath(input_fname) | ||
ext = os.path.splitext(input_fname)[1][1:].lower() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to prefer pathlib interface, which _check_fname
will provide for you
input_fname = _check_fname(fname=input_fname, overwrite="read", must_exist=True)
now input_fname
is a pathlib.Path
and you can get the extension using a method
@larsoner Pushing the changes |
for more information, see https://pre-commit.ci
@larsoner I took a look at the failing tests, but I don't know the reason they are failing, do you have any clue? Thanks! |
Reference issue (if any)
Feature #8976.
What does this implement/fix?
Added support for file-like objects for EDF/BDF/GDF files.
Additional information
Until today, mne was checking for the file extension to validate file types, we may not have a file name from a binary object, so, if a binary object (file-like) is provided we trust the user (depending on what API function he is using: read_raw_edf, read_raw_gdf, read_raw_bdf). A new enumeration has been declared to propagate the file type to underlying methods:
In the function _read_edf_header a new exception is raised if the header can be properly parsed, informing the user that the file provided is not valid:
In the function _read_gdf_header, a new exception is raised when the version of the document can't be properly parsed, informing the user that the file provided is not valid:
To accommodate this changes the class RawEDF class has been duplicated (RawBDF) to differentiate between BDF and EDF files when the extension is not known. To avoid changes in the file mne-python/mne/io/tests/test_raw.py.
Additionally 4 new tests have been added to the file mne-python/mne/io/edf/tests/test_edf.py and 2 new tests have been added to the file mne-python/mne/io/edf/tests/test_gdf.py, those tests will open a valid file and check for the channels, and open an invalid file and expect an error. For GDF I'm using an empty file (I don't know where to get bad GDF files).
I've created a helper function to open GDF and EDF files under mne-python/mne/_edf/open.py.
To support in memory file-like objects I'm using the workaround mentioned here, the function has been placed in "fixes.py". The calls to numpy.fromfile have then been replaced by calls to the new function read_from_file_or_buffer. The implementation is as follows: