Skip to content

Improve jupyter backends#1139

Merged
prabhuramachandran merged 6 commits into
enthought:masterfrom
prabhuramachandran:improve-jupyter-backends
Mar 28, 2022
Merged

Improve jupyter backends#1139
prabhuramachandran merged 6 commits into
enthought:masterfrom
prabhuramachandran:improve-jupyter-backends

Conversation

@prabhuramachandran
Copy link
Copy Markdown
Member

  • Refactor notebook code and add itkwidgets support. The itkwidgets support allows us to use Mayavi in a headless manner unlike the other backends which require offscreen support.
  • Improve implementation of the different backends.
  • Fix issues with the test backend.
    • mlab.clf() was not clearing the scene.
    • obj.render() was not working correctly.
    • The itkwidgets backend would not work correctly in some cases so we explicitly flush the pipeline before calling view.

The itkwidgets support allows us to use Mayavi in a headless manner
unlike the other backends which require offscreen support.
- `mlab.clf()` was not clearing the scene.
- `obj.render()` was not working correctly.
- The itkwidgets backend would not work correctly in some cases  so we
  explicitly flush the pipeline before calling view.
@rahulporuri rahulporuri self-requested a review March 10, 2022 08:33
Comment thread mayavi/core/engine.py
if preference_manager.root.show_helper_nodes \
and len(self.scenes) == 0:
if (preference_manager.root.show_helper_nodes and
len(self.scenes) == 0):
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.

it looks like all of the changes in this file are cosmetic - two unused variables and a bunch of style changes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, I thought there was an issue there but there wasn't so sent in a separate commit with just PEP8 fixes for that file.

Comment thread mayavi/tools/figure.py
scene = figure
disable_render = scene.scene.disable_render
scene.scene.disable_render = True
if scene.scene is not None:
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.

looks like this is the fix related to the scene not being cleared correctly?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes if you see each commit, the logs will make more sense. This fixes the issue with mlab.clf

m = actor.mapper
if m is not None:
m.update(0)
m.update()
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.

looks like the 0 we were passing before was the arg port - not sure why we don't need to pass it in anymore.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I am not sure, I think this was when there was issues with the old and new pipeline. The current test failures have nothing to do with this. Those have to do with the import of a UI toolkit when tvtk is imported -- this could be in some other library.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I need to see how this build is different from the headless test last Saturday.

Comment thread mayavi/tools/notebook.py


def _ipython_display_(self):
'''Method attached to Mayavi objects.
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.

It was not clear from the code that this special method is what IPython looks for. Ref https://ipython.readthedocs.io/en/stable/config/integrating.html#custom-methods. It'd be nice to document this in the function/method

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I will add a comment.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done in latest commit.

Comment thread mayavi/tools/notebook.py
def __init__(self, width=None, height=None, local=True):
super().__init__(width, height, local)
from mayavi import mlab
mlab.options.backend = 'test'
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.

i'm not sure why we're setting the backend to 'test' here and if this is what we should be shipping.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The test backend does not instantiate a render window. If you do, you cannot run Mayavi in a headless fashion -- say via a remotely hosted jupyter notebook. The name "test" is not ideal but in the interest of backwards compatibility I am not sure we can or should change it.

Also use traitsui-7.2.1 in build to test if failures are related to
this.
@prabhuramachandran
Copy link
Copy Markdown
Member Author

prabhuramachandran commented Mar 10, 2022

@corranwebster -- the only major change I am able to see between the headless test here and the one that was run on schedule from 5 days ago (https://github.com/enthought/mayavi/actions/runs/1937040765) is that traitsui was upgraded to 7.3.0 from 7.2.1. Could it be that simply importing traitsui.api triggers either a wxPython or Qt import before a configure_traits is invoked? This is possibly breaking the tests. I am just pushing a new commit to test this hypothesis. Indeed, that was it, so somehow traitsui 7.3.0 is importing the UI toolkit libraries. Is there a chance this can be fixed in a future traitsui release?

@corranwebster
Copy link
Copy Markdown

Could it be that simply importing traitsui.api triggers either a wxPython or Qt import before a configure_traits is invoked?

Unfortunately the Menu code in API causes the Pyface toolkit to be selected, so you will get a Qt or Wx import when you import traitsui.api. But I am thinking that there may be a regression in the way that Color and Font traits are defined.

@corranwebster
Copy link
Copy Markdown

Quick question: did the version of Pyface also change?

@prabhuramachandran
Copy link
Copy Markdown
Member Author

@corranwebster -- no the earlier code was also on pyface-7.4.1.

@corranwebster
Copy link
Copy Markdown

When I try to replicate the failing test in a Python 3.9 virtualenv (not an EDM env) with no backends installed, I see the following line in the verbose output from doing from tvtk.api import tvtk; p = tvtk.Property():

# /Users/cwebster/p3.9/lib/python3.9/site-packages/pyface/ui/wx/__pycache__/__init__.cpython-39.pyc matches /Users/cwebster/p3.9/lib/python3.9/site-packages/pyface/ui/wx/__init__.py
# code object from '/Users/cwebster/p3.9/lib/python3.9/site-packages/pyface/ui/wx/__pycache__/__init__.cpython-39.pyc'
import 'pyface.ui.wx' # <_frozen_importlib_external.SourceFileLoader object at 0x132cd9bb0>
# /Users/cwebster/p3.9/lib/python3.9/site-packages/pyface/ui/wx/__pycache__/init.cpython-39.pyc matches /Users/cwebster/p3.9/lib/python3.9/site-packages/pyface/ui/wx/init.py
# code object from '/Users/cwebster/p3.9/lib/python3.9/site-packages/pyface/ui/wx/__pycache__/init.cpython-39.pyc'
# destroy pyface.ui.wx.init

and there are similar lines mentioning pyface.qt. However in this environment we can't be importing wx, because it isn't installed. But if I look at sys.modules['wx'] it isn't loaded and the selected toolkit is null as would be expected.

So I think that the failure is because some code is likely trying to load wx (and probably Qt) and failing, but things are showing up in the verbose logs that didn't before. The test probably needs to be refined to do something like inspecting sys.modules rather than just searching the logs.

@prabhuramachandran
Copy link
Copy Markdown
Member Author

@corranwebster -- so sorry I sent you on a wild goose chase! I will look into writing a better and more robust test if that is possible. Thank you very much!

@prabhuramachandran
Copy link
Copy Markdown
Member Author

@corranwebster -- I did some more investigation on this, while the test may not be ideal, it does do its job. It did detect what I think is a regression. If we just do from traitsui.view import View it imports a Qt or wx backend. To see where this actually happens I did some more digging:

  1. I see that the place this first starts is in the import from traitsui.ui import UI
  2. From here I looked at from traitsui.editor import Editor and I found that the culprit is the import from pyface.api import information in editor.py

I sent a simple PR to fix this (enthought/traitsui#1883) and all it requires is delaying the import of information in the error method of the editor. This fixes the problem but you are very likely not going to like my test case at all.

@prabhuramachandran
Copy link
Copy Markdown
Member Author

@rahulporuri -- can you please review this so I can merge it sooner rather than later. I can fix any issues related to the traitsui issue in a later PR.

@prabhuramachandran prabhuramachandran merged commit a0b9f1c into enthought:master Mar 28, 2022
@prabhuramachandran prabhuramachandran deleted the improve-jupyter-backends branch March 28, 2022 07:12
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