Skip to content

EGI: stabilize mffpy-backed MFF reader#13914

Draft
PragnyaKhandelwal wants to merge 15 commits into
mne-tools:mainfrom
PragnyaKhandelwal:gsoc26-egi-mff-week1
Draft

EGI: stabilize mffpy-backed MFF reader#13914
PragnyaKhandelwal wants to merge 15 commits into
mne-tools:mainfrom
PragnyaKhandelwal:gsoc26-egi-mff-week1

Conversation

@PragnyaKhandelwal
Copy link
Copy Markdown
Contributor

Reference issue (if any)

What does this implement/fix?

  • Ports the EGI MFF reader refactor onto a clean main-based branch.
  • Stabilizes the mffpy backend integration.
  • Restores compatibility helpers needed by current main.
  • Adds/updates EGI MFF test coverage.

Additional information

  • This is Week 1 GSoC work building on the earlier prototype.
  • I validated the targeted EGI tests locally: 1 passed, 23 skipped.

AI assistance

  • I used GitHub Copilot to help draft and review the PR text; I implemented and tested the code changes manually.

@PragnyaKhandelwal
Copy link
Copy Markdown
Contributor Author

Hey @scott-huberty and @drammock! Here is the fresh branch for Phase 1 (superseding #13684).
I've ported over the core helper functions we discussed. I am intentionally keeping this in Draft mode because the CI (specifically Vulture) is currently flagging those new helpers as dead code. I haven't fully wired them into the RawMff runtime execution path yet.
My primary goal for this week before our sync is to complete that wiring and decommission the legacy paths to get the CI green. Just wanted to get the core logic up here so we have a shared workspace!

@scott-huberty
Copy link
Copy Markdown
Contributor

Thanks @PragnyaKhandelwal ! Can you please open a meta-issue on this repo that is titled something like "GSoC 2026: Use mffpy for EGI Reader"? Then you can include one checkbox for each milestone. This can mirror the proposal plan you submitted, but does not need to be as detailed, it can be something like:

  • Task 1 #[PR NUMBER]
  • Task 2

This will help us keep track of the project's progress. Does that work for you?

@PragnyaKhandelwal
Copy link
Copy Markdown
Contributor Author

This will help us keep track of the project's progress. Does that work for you?

Thanks @scott-huberty! I have opened the tracking meta-issue here: #13926
I set it up with the simplified checkboxes matching my timeline phases, and I've already linked this PR to the Phase 1 task.

Copy link
Copy Markdown
Member

@drammock drammock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a few specific comments in-line, but the overall high-level comments:

  • I was expecting this first PR to be mostly about the tests (google doc mentioned there were cross-platform inconsistencies in the tests, and purging legacy helper funcs from the tests) but there's a lot of changed lines in the package code too.
  • the diff is big. I suggest breaking the problem into smaller pieces and doing multiple PRs.
  • It's worth considering an approach where very small pieces of functionality are done in each PR (to keep diffs small / easy to review). For example, one PR might use mffpy to read events (but use legacy code for everything else); the next might use mffpy to also read metadata, and a third might use it to read the actual data samples.

Let's try to work out a more detailed plan at the meeting.

Comment thread mne/io/egi/egimff.py
except (ValueError, AttributeError):
# mffpy has a bug parsing timestamps with 9 decimal places (nanoseconds)
# Workaround: manually parse the timestamp from the info.xml file
import xml.etree.ElementTree as ET
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should use defusedxml.

Comment thread mne/io/egi/egimff.py
try:
return mff_reader.startdatetime
except (ValueError, AttributeError):
# mffpy has a bug parsing timestamps with 9 decimal places (nanoseconds)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. did you open an issue upstream yet?
  2. normally when we need to shim upstream code to work around bugs, we put it in mne/fixes.py and import the function from there. The shim function should have a comment like TODO VERSION ... explaining / linking to upstream issues/PRs so we can easily see when it's OK to remove the shim.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just FYI: Upstream repo is https://github.com/BEL-Public/mffpy

Comment thread mne/io/egi/egimff.py
return datetime.datetime.strptime(time_str, "%Y-%m-%dT%H:%M:%S.%f%z")


def _parse_egi_datetime(time_str):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment: shims go in mne/fixes.py

Comment thread mne/io/egi/egimff.py
fname = op.join(filepath, "coordinates.xml")
if not op.exists(fname):
warn("File coordinates.xml not found, not setting channel locations")
logger.warn("File coordinates.xml not found, not setting channel locations")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert. We have a wrapper that does some clever magic with e.g. the stack level, so that tracebacks are easier to read

Comment thread mne/io/egi/egimff.py
raise RuntimeError(
f"Number of defined channels ({n_chans}) did not match the "
f"expected channels ({summaryinfo['n_channels']})."
f"Number of defined channels ({n_chans}) did not match the expected "
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try to avoid unrelated / cosmetic changes (to keep the diff small). If you must make them, do them in a separate commit (or even separate PR) --- again, for easier review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants