Problem with MNE when using py2app deployment with alias mode

  • MNE-Python version: 0.23.0
  • Python 3.9
  • operating system: Mac Big Sur

I’m not sure if my question is appropriate for this particular forum as it pertains to MNE and creating a Mac .app with py2app, but my experimentation leads me to believe MNE might be this source of my problem. Moreover, very similar code worked fine before I upgraded to 0.23.0.

I apologize for the length of what appears below.

I’ve created a simple GUI with tkinter, which, in its first stage, has a menu that allows the user to select an .edf file and plot it on a figure canvas using raw.plot. Here’s the source code:

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib import pyplot as plt
import numpy as np
 
from matplotlib.figure import Figure

from tkinter import Tk,filedialog,TOP,Menu

# Main Window
root = Tk()

# File selection
def _open():
    root.filename = filedialog.askopenfilename(initialdir = "Users/fishbacp/Desktop",title = 
   "Select file",filetypes = (("EDF files","*.edf"),("all files","*.*")))
   raw = mne.io.read_raw_edf(root.filename, preload=True)

   # Create raw plot as figure and embed on canvas. 
   fig=raw.plot(show=False,block=True,duration=30)
   canvas = FigureCanvasTkAgg(fig, master=root)
   canvas.draw()
   canvas.get_tk_widget().pack(side=TOP)

# Quit function
def _quit():
    root.quit()
    root.destroy()

# Main pull-down menu options to open file and exit. 
menubar = Menu(root)
filemenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="File", menu=filemenu)
filemenu.add_command(label="Open", command=_open)
filemenu.add_command(label="Exit", command=_quit)
root.config(menu=menubar)

root.mainloop()

The script functions fine. Now I try to create an app using py2app following the basic documentation at https://py2app.readthedocs.io/en/latest/tutorial.html

When developing with alias mode, I obtain the fairly length message below, where MNE is referenced numerous times. However, simply changing
fig=raw.plot(show=False,block=True,duration=30)

above to something simple like

fig = Figure(figsize=(5, 4), dpi=100)
t = np.arange(0, 3, .01)
fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t))

works fine. Here is the error message when developing in alias mode:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/tkinter/__init__.py", line 1892, in __call__
    return self.func(*args)
  File "/Users/fishbacp/Desktop/Python_May_2021/EEG_Canvas_Plot_6_15.py", line 17, in _open
    raw = mne.io.read_raw_edf(root.filename, preload=True)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/mne/io/edf/edf.py", line 1220, in read_raw_edf
    return RawEDF(input_fname=input_fname, eog=eog, misc=misc,
  File "<decorator-gen-197>", line 24, in __init__
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/mne/io/edf/edf.py", line 121, in __init__
    super().__init__(info, preload, filenames=[input_fname],
  File "<decorator-gen-179>", line 24, in __init__
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/mne/io/base.py", line 257, in __init__
    self._preload_data(preload)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/mne/io/base.py", line 537, in _preload_data
    self._data = self._read_segment(
  File "<decorator-gen-181>", line 24, in _read_segment
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/mne/io/base.py", line 422, in _read_segment
    _ReadSegmentFileProtector(self)._read_segment_file(
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/mne/io/base.py", line 2068, in _read_segment_file
    return self.__raw.__class__._read_segment_file(
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/mne/io/edf/edf.py", line 141, in _read_segment_file
    return _read_segment_file(data, idx, fi, start, stop,
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/mne/io/edf/edf.py", line 238, in _read_segment_file
    from scipy.interpolate import interp1d
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/scipy/interpolate/__init__.py", line 165, in <module>
    from .interpolate import *
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/scipy/interpolate/interpolate.py", line 11, in <module>
    import scipy.special as spec
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/scipy/special/__init__.py", line 633, in <module>
    from . import _ufuncs
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 664, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 627, in _load_backward_compatible
  File "/Users/fishbacp/Desktop/Python_May_2021/dist/EEG_Canvas_Plot_6_15.app/Contents/Resources/__boot__.py", line 86, in load_module
    return imp.load_module(
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/imp.py", line 244, in load_module
    return load_package(name, filename)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/imp.py", line 216, in load_package
    return _load(spec)
  File "<frozen importlib._bootstrap>", line 710, in _load
AttributeError: 'NoneType' object has no attribute 'name'

I’ve used py2app quite a bit before, and I recall this script worked fine before upgrading to MNE 0.23.0

In your simple np.arange plotting example, could you add from scipy.interpolate import interp1d and see if it still works? That appears to be what is failing here.

So, I added from scipy.interpolate_import interp1d and saved the functioning script under the name MNE_Forum_6_17.py. (A reasonable name I suppose.)

In this case, I was able to develop the app in alias mode and run it. (Better than before). However, the second stage involves building the app for deployment. No error messages arose in the build process, but trying to run the resulting .app file from the terminal resulted in the fairly lengthy error message below.

Part of the error message states the module scipy.special._ufuncs_cxx cannot be found. But I am able to import it at the shell in Idle and it isn’t necessary to run the script itself. Below is the complete error message. Perhaps my issue is more related to scipy and py2app than MNE?

Traceback (most recent call last):
  File "<frozen zipimport>", line 259, in load_module
  File "scipy/special/_ufuncs.pyc", line 14, in <module>
  File "scipy/special/_ufuncs.pyc", line 10, in __load
  File "imp.pyc", line 342, in load_dynamic
  File "<frozen importlib._bootstrap>", line 711, in _load
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 1116, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "_ufuncs.pyx", line 1, in init scipy.special._ufuncs
ModuleNotFoundError: No module named 'scipy.special._ufuncs_cxx'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/fishbacp/Desktop/Python_May_2021/dist/MNE_Forum_6_16.app/Contents/Resources/__boot__.py", line 115, in <module>
    _run()
  File "/Users/fishbacp/Desktop/Python_May_2021/dist/MNE_Forum_6_16.app/Contents/Resources/__boot__.py", line 84, in _run
    exec(compile(source, path, "exec"), globals(), globals())
  File "/Users/fishbacp/Desktop/Python_May_2021/dist/MNE_Forum_6_16.app/Contents/Resources/MNE_Forum_6_16.py", line 7, in <module>
    from scipy.interpolate import interp1d
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 664, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 627, in _load_backward_compatible
  File "<frozen zipimport>", line 259, in load_module
  File "scipy/interpolate/__init__.pyc", line 165, in <module>
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 664, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 627, in _load_backward_compatible
  File "<frozen zipimport>", line 259, in load_module
  File "scipy/interpolate/interpolate.pyc", line 11, in <module>
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 664, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 627, in _load_backward_compatible
  File "<frozen zipimport>", line 259, in load_module
  File "scipy/special/__init__.pyc", line 633, in <module>
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 664, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 627, in _load_backward_compatible
  File "<frozen zipimport>", line 261, in load_module
KeyError: 'scipy.special._ufuncs'

Not sure, I don’t have any experience with py2app. But yeah, seems like MNE is not the root problem here.