Skip to content

Commit 48cdd8d

Browse files
FIX: guarantee MNE sample data is bundled into JupyterLite build
Two coordinated fixes for the FileNotFoundError on /drive/mne_data that crashes every intro notebook when run in the CircleCI preview. .circleci/config.yml: Add an explicit 'Ensure MNE sample data for JupyterLite' step immediately before 'make html'. The existing circleci_download.sh script only downloads sample data when the modified tutorial files reference it via a text-grep check, so any PR that touches only configuration files (like this one) would result in a cache miss leaving ~/mne_data/MNE-sample-data absent. Without that directory conf.py cannot copy the required files into jupyterlite_contents/, /drive/mne_data never exists in the Pyodide virtual filesystem, and mne.datasets.sample.data_path() throws FileNotFoundError on the first meaningful cell of every tutorial notebook. The new step calls mne.datasets.sample.data_path(update_path=True) unconditionally, downloading the dataset if the cache is cold and skipping silently if it is already present. doc/conf.py: Always create the jupyterlite_contents/mne_data/MNE-sample-data destination directory unconditionally (dst_sample_data.mkdir) before the copy loop runs, so /drive/mne_data is present in the Pyodide kernel's Emscripten virtual filesystem even if no files were copied. Also drop the 'not d.exists()' guard on individual file copies so each incremental Sphinx build refreshes the bundled data files from the current state of ~/mne_data/MNE-sample-data rather than skipping files that were already copied from a previous build run.
1 parent d349a16 commit 48cdd8d

2 files changed

Lines changed: 16 additions & 2 deletions

File tree

.circleci/config.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,16 @@ jobs:
249249
cp junit-results.xml doc/_build/test-results/test-doc/junit.xml;
250250
cp coverage.xml doc/_build/test-results/test-doc/coverage.xml;
251251
fi;
252+
# Ensure the MNE sample dataset is on disk so conf.py can copy the
253+
# required subset into jupyterlite_contents/ for the JupyterLite build.
254+
# circleci_download.sh only fetches sample data when the changed files
255+
# reference it, so a cache miss on a PR that touches only doc/conf.py
256+
# would leave ~/mne_data/MNE-sample-data absent and the notebooks would
257+
# fail at runtime with FileNotFoundError on /drive/mne_data.
258+
- run:
259+
name: Ensure MNE sample data for JupyterLite
260+
command: |
261+
python -c "import mne; mne.datasets.sample.data_path(update_path=True)"
252262
# Build docs
253263
- run:
254264
name: make html

doc/conf.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,14 +479,17 @@
479479
jupyterlite_contents = ["jupyterlite_contents"]
480480
jupyterlite_bind_ipynb_suffix = False
481481

482-
# Automatically inject the required subset of MNE-sample-data into JupyterLite
482+
# Automatically inject the required subset of MNE-sample-data into JupyterLite.
483+
# The destination directory is always created so /drive/mne_data is present in
484+
# the Pyodide kernel's virtual filesystem even when no files have been copied.
483485
src_sample_data = Path(os.path.expanduser("~/mne_data/MNE-sample-data"))
484486
dst_sample_data = (
485487
Path(os.path.abspath(os.path.dirname(__file__)))
486488
/ "jupyterlite_contents"
487489
/ "mne_data"
488490
/ "MNE-sample-data"
489491
)
492+
dst_sample_data.mkdir(parents=True, exist_ok=True)
490493
if src_sample_data.exists():
491494
required_files = [
492495
"version.txt",
@@ -506,10 +509,11 @@
506509
for req in required_files:
507510
s = src_sample_data / req
508511
d = dst_sample_data / req
509-
if s.exists() and not d.exists():
512+
if s.exists():
510513
d.parent.mkdir(parents=True, exist_ok=True)
511514
shutil.copy2(s, d)
512515

516+
513517
# Also inject SSVEP and EEGLAB testing datasets for JupyterLite
514518
mne_data_base = Path(os.path.expanduser("~/mne_data"))
515519
lite_data_base = (

0 commit comments

Comments
 (0)