|
480 | 480 | "first_notebook_cell": ( |
481 | 481 | "# 💡 This cell is automatically added to the start of each notebook.\n" |
482 | 482 | "import micropip\n" |
483 | | - "await micropip.install(['mne', 'pyodide-http'])\n" |
| 483 | + "await micropip.install(['mne'])\n" |
| 484 | + "\n" |
| 485 | + "# Mock lzma since it is missing in Pyodide but required by pooch\n" |
| 486 | + "import sys\n" |
| 487 | + "import types\n" |
| 488 | + "if 'lzma' not in sys.modules:\n" |
| 489 | + " sys.modules['lzma'] = types.ModuleType('lzma')\n" |
484 | 490 | "\n" |
485 | 491 | "# 1. Patch networking so pooch can download datasets\n" |
486 | | - "import pyodide_http\n" |
487 | | - "pyodide_http.patch_all()\n" |
| 492 | + "import pooch\n" |
| 493 | + "import requests\n" |
| 494 | + "import urllib.request\n" |
| 495 | + "import urllib.error\n" |
| 496 | + "import io\n" |
| 497 | + "\n" |
| 498 | + "orig_send = requests.Session.send\n" |
| 499 | + "def pyodide_send(self, request, **kwargs):\n" |
| 500 | + " try:\n" |
| 501 | + " resp = urllib.request.urlopen(request.url)\n" |
| 502 | + " content = resp.read()\n" |
| 503 | + " status = resp.status\n" |
| 504 | + " except urllib.error.HTTPError as e:\n" |
| 505 | + " content = e.read()\n" |
| 506 | + " status = e.code\n" |
| 507 | + " except Exception:\n" |
| 508 | + " return orig_send(self, request, **kwargs)\n" |
| 509 | + " response = requests.Response()\n" |
| 510 | + " response.status_code = status\n" |
| 511 | + " response.url = request.url\n" |
| 512 | + " response.raw = io.BytesIO(content)\n" |
| 513 | + " return response\n" |
| 514 | + "requests.Session.send = pyodide_send\n" |
| 515 | + "\n" |
| 516 | + "# Intercept pooch to provide helpful errors for large OSF datasets\n" |
| 517 | + "orig_pooch_fetch = pooch.Pooch.fetch\n" |
| 518 | + "def pyodide_pooch_fetch(self, fname, processor=None, downloader=None):\n" |
| 519 | + " url = self.get_url(fname)\n" |
| 520 | + " if 'osf.io' in url or 'files.osf.io' in url:\n" |
| 521 | + " raise RuntimeError(\n" |
| 522 | + " f'Cannot download {fname} natively in JupyterLite due to browser CORS restrictions '\n" |
| 523 | + " f'on OSF and memory limits. Please download the dataset locally and upload it '\n" |
| 524 | + " f'into the JupyterLite file browser.'\n" |
| 525 | + " )\n" |
| 526 | + " return orig_pooch_fetch(self, fname, processor=processor, downloader=downloader)\n" |
| 527 | + "pooch.Pooch.fetch = pyodide_pooch_fetch\n" |
488 | 528 | "\n" |
489 | 529 | "# 2. Patch MNEBrowseFigure to auto-display in Pyodide's inline backend\n" |
490 | 530 | "import mne\n" |
491 | | - "import mne.viz.utils\n" |
492 | 531 | "import matplotlib.pyplot as plt\n" |
493 | | - "orig_plt_show = mne.viz.utils.plt_show\n" |
494 | | - "def pyodide_plt_show(*args, **kwargs):\n" |
495 | | - " orig_plt_show(*args, **kwargs)\n" |
| 532 | + "import importlib\n" |
| 533 | + "viz_utils = importlib.import_module('mne.viz.utils')\n" |
| 534 | + "orig_plt_show = viz_utils.plt_show\n" |
| 535 | + "def pyodide_plt_show(fig=None, **kwargs):\n" |
| 536 | + " orig_plt_show(fig, **kwargs)\n" |
496 | 537 | " import IPython.display\n" |
497 | 538 | " IPython.display.display(plt.gcf())\n" |
498 | | - "mne.viz.utils.plt_show = pyodide_plt_show\n" |
| 539 | + "viz_utils.plt_show = pyodide_plt_show\n" |
499 | 540 | ), |
500 | 541 | "doc_module": ("mne",), |
501 | 542 | "reference_url": dict(mne=None), |
|
0 commit comments