Repository: mne-tools/mne-python

Issue:
MNE Coreg Exception in traits notification handler 
In python 2.7 conda venv `mne coreg` fails to load digitized head points due to 

> Exception occurred in traits notification handler.
> Please check the log file for details.
> Exception occurred in traits notification handler for object: <mne.gui._viewer.PointObject object at 0x7f79eafd7590>, trait: scene, old value: <mayavi.tools.mlab_scene_model.MlabSceneModel object at 0x7f79eb1b6170>, new value: <mayavi.tools.mlab_scene_model.MlabSceneModel object at 0x7f79eb46cf50>
> Traceback (most recent call last):
>   File "/home/ktavabi/miniconda3/envs/andrea-anders/lib/python2.7/site-packages/traits/trait_notifiers.py", line 519, in _dispatch_change_event
>     self.dispatch( handler, *args )
>   File "/home/ktavabi/miniconda3/envs/andrea-anders/lib/python2.7/site-packages/traits/trait_notifiers.py", line 482, in dispatch
>     handler( *args )
>   File "/home/ktavabi/Projects/mne-python/mne/gui/_viewer.py", line 225, in _plot_points
>     if not self.scene.running():
> AttributeError: 'MlabSceneModel' object has no attribute 'running'
> 

cc @larsoner 

![image](https://user-images.githubusercontent.com/4381290/31926205-fb7120a8-b841-11e7-90cf-d45b865c9335.png)



Discussion:

Resolving patch:
diff --git a/mne/gui/_viewer.py b/mne/gui/_viewer.py
--- a/mne/gui/_viewer.py
+++ b/mne/gui/_viewer.py
@@ -127,7 +127,7 @@ class Object(HasPrivateTraits):
     src = Instance(VTKDataSource)
 
     # This should be Tuple, but it is broken on Anaconda as of 2016/12/16
-    color = RGBColor()
+    color = RGBColor((1., 1., 1.))
     point_scale = Float(10, label='Point Scale')
     opacity = Range(low=0., high=1., value=1.)
     visible = Bool(True)
@@ -221,10 +221,8 @@ def _on_hide(self):
     @on_trait_change('scene.activated')
     def _plot_points(self):
         """Add the points to the mayavi pipeline"""
-        from . import _testing_mode
-        if not self.scene.running():
+        if self.scene is None:
             return
-
         if hasattr(self.glyph, 'remove'):
             self.glyph.remove()
         if hasattr(self.src, 'remove'):
@@ -232,8 +230,12 @@ def _plot_points(self):
 
         _toggle_mlab_render(self, False)
         x, y, z = self.points.T
-        scatter = pipeline.scalar_scatter(x, y, z)
-        fig = self.scene.mayavi_scene if not _testing_mode() else None
+        fig = self.scene.mayavi_scene
+        scatter = pipeline.scalar_scatter(x, y, z, fig=fig)
+        if not scatter.running:
+            # this can occur sometimes during testing w/ui.dispose()
+            return
+        # fig.scene.engine.current_object is scatter
         glyph = pipeline.glyph(scatter, color=self.color,
                                figure=fig,
                                scale_factor=self.point_scale, opacity=1.,


Test patch:
diff --git a/mne/gui/tests/test_coreg_gui.py b/mne/gui/tests/test_coreg_gui.py
--- a/mne/gui/tests/test_coreg_gui.py
+++ b/mne/gui/tests/test_coreg_gui.py
@@ -159,50 +159,52 @@ def test_coreg_gui():
         assert_raises(ValueError, mne.gui.coregistration, subject='Elvis',
                       subjects_dir=subjects_dir)
 
-        with warnings.catch_warnings(record=True):  # traits spews warnings
-            warnings.simplefilter('always')
-
-            # avoid modal dialog if SUBJECTS_DIR is set to a directory that
-            # does not contain valid subjects
-            ui, frame = mne.gui.coregistration(subjects_dir='')
-
-            frame.model.mri.subjects_dir = subjects_dir
-            frame.model.mri.subject = 'sample'
-
-            assert_false(frame.model.mri.fid_ok)
-            frame.model.mri.lpa = [[-0.06, 0, 0]]
-            frame.model.mri.nasion = [[0, 0.05, 0]]
-            frame.model.mri.rpa = [[0.08, 0, 0]]
-            assert_true(frame.model.mri.fid_ok)
-            frame.raw_src.file = raw_path
-
-            # grow hair (high-res head has no norms)
-            assert_true(frame.model.mri.use_high_res_head)
-            frame.model.mri.use_high_res_head = False
-            frame.model.grow_hair = 40.
-
-            # scale
-            frame.coreg_panel.n_scale_params = 3
-            frame.coreg_panel.scale_x_inc = True
-            assert_equal(frame.model.scale_x, 1.01)
-            frame.coreg_panel.scale_y_dec = True
-            assert_equal(frame.model.scale_y, 0.99)
-
-            # reset parameters
-            frame.coreg_panel.reset_params = True
-            assert_equal(frame.model.grow_hair, 0)
-            assert_false(frame.model.mri.use_high_res_head)
-
-            # configuration persistence
-            assert_true(frame.model.prepare_bem_model)
-            frame.model.prepare_bem_model = False
-            frame.save_config(home_dir)
-            ui.dispose()
-
-            ui, frame = mne.gui.coregistration(subjects_dir=subjects_dir)
-            assert_false(frame.model.prepare_bem_model)
-            assert_false(frame.model.mri.use_high_res_head)
-            ui.dispose()
+        from pyface.api import GUI
+        gui = GUI()
+
+        # avoid modal dialog if SUBJECTS_DIR is set to a directory that
+        # does not contain valid subjects
+        ui, frame = mne.gui.coregistration(subjects_dir='')
+
+        frame.model.mri.subjects_dir = subjects_dir
+        frame.model.mri.subject = 'sample'
+
+        assert_false(frame.model.mri.fid_ok)
+        frame.model.mri.lpa = [[-0.06, 0, 0]]
+        frame.model.mri.nasion = [[0, 0.05, 0]]
+        frame.model.mri.rpa = [[0.08, 0, 0]]
+        assert_true(frame.model.mri.fid_ok)
+        frame.raw_src.file = raw_path
+
+        # grow hair (high-res head has no norms)
+        assert_true(frame.model.mri.use_high_res_head)
+        frame.model.mri.use_high_res_head = False
+        frame.model.grow_hair = 40.
+
+        # scale
+        frame.coreg_panel.n_scale_params = 3
+        frame.coreg_panel.scale_x_inc = True
+        assert_equal(frame.model.scale_x, 1.01)
+        frame.coreg_panel.scale_y_dec = True
+        assert_equal(frame.model.scale_y, 0.99)
+
+        # reset parameters
+        frame.coreg_panel.reset_params = True
+        assert_equal(frame.model.grow_hair, 0)
+        assert_false(frame.model.mri.use_high_res_head)
+
+        # configuration persistence
+        assert_true(frame.model.prepare_bem_model)
+        frame.model.prepare_bem_model = False
+        frame.save_config(home_dir)
+        ui.dispose()
+        gui.process_events()
+
+        ui, frame = mne.gui.coregistration(subjects_dir=subjects_dir)
+        assert_false(frame.model.prepare_bem_model)
+        assert_false(frame.model.mri.use_high_res_head)
+        ui.dispose()
+        gui.process_events()
     finally:
         del os.environ['_MNE_GUI_TESTING_MODE']
         del os.environ['_MNE_FAKE_HOME_DIR']
diff --git a/mne/gui/tests/test_kit2fiff_gui.py b/mne/gui/tests/test_kit2fiff_gui.py
--- a/mne/gui/tests/test_kit2fiff_gui.py
+++ b/mne/gui/tests/test_kit2fiff_gui.py
@@ -27,9 +27,12 @@
 
 
 def _check_ci():
-    if os.getenv('TRAVIS', 'false').lower() == 'true' and \
-            sys.platform == 'darwin':
-        raise SkipTest('Skipping GUI tests on Travis OSX')
+    osx = (os.getenv('TRAVIS', 'false').lower() == 'true' and
+           sys.platform == 'darwin')
+    win = (os.getenv('APPVEYOR', 'false').lower() == 'true' and
+           sys.platform.startswith('win'))
+    if win or osx:
+        raise SkipTest('Skipping GUI tests on Travis OSX and AppVeyor')
 
 
 @requires_mayavi
@@ -131,25 +134,31 @@ def test_kit2fiff_gui():
     os.environ['_MNE_GUI_TESTING_MODE'] = 'true'
     os.environ['_MNE_FAKE_HOME_DIR'] = home_dir
     try:
-        with warnings.catch_warnings(record=True):  # traits warnings
-            warnings.simplefilter('always')
-            ui, frame = mne.gui.kit2fiff()
-            assert_false(frame.model.can_save)
-            assert_equal(frame.model.stim_threshold, 1.)
-            frame.model.stim_threshold = 10.
-            frame.model.stim_chs = 'save this!'
-            frame.save_config(home_dir)
-            ui.dispose()
-
-            # test setting persistence
-            ui, frame = mne.gui.kit2fiff()
-            assert_equal(frame.model.stim_threshold, 10.)
-            assert_equal(frame.model.stim_chs, 'save this!')
-
-            frame.model.markers.mrk1.file = mrk_pre_path
-            frame.marker_panel.mrk1_obj.label = True
-            frame.marker_panel.mrk1_obj.label = False
-            ui.dispose()
+        from pyface.api import GUI
+        gui = GUI()
+        gui.process_events()
+
+        ui, frame = mne.gui.kit2fiff()
+        assert_false(frame.model.can_save)
+        assert_equal(frame.model.stim_threshold, 1.)
+        frame.model.stim_threshold = 10.
+        frame.model.stim_chs = 'save this!'
+        frame.save_config(home_dir)
+        ui.dispose()
+
+        gui.process_events()
+
+        # test setting persistence
+        ui, frame = mne.gui.kit2fiff()
+        assert_equal(frame.model.stim_threshold, 10.)
+        assert_equal(frame.model.stim_chs, 'save this!')
+
+        frame.model.markers.mrk1.file = mrk_pre_path
+        frame.marker_panel.mrk1_obj.label = True
+        frame.marker_panel.mrk1_obj.label = False
+        ui.dispose()
+
+        gui.process_events()
     finally:
         del os.environ['_MNE_GUI_TESTING_MODE']
         del os.environ['_MNE_FAKE_HOME_DIR']