Skip to content

Commit

Permalink
Added basic Jupyter tests and fix issues
Browse files Browse the repository at this point in the history
  • Loading branch information
astrofrog committed May 23, 2024
1 parent 51a5d22 commit 806deee
Show file tree
Hide file tree
Showing 13 changed files with 134 additions and 89 deletions.
9 changes: 9 additions & 0 deletions glue_vispy_viewers/common/qt/data_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,19 @@
class BaseVispyViewer(BaseVispyViewerMixin, DataViewer):

_options_cls = VispyOptionsWidget
tools = BaseVispyViewerMixin.tools
subtools = {'save': ['vispy:save']}

_toolbar_cls = VispyQtToolbar

# If imageio is available, we can add the record icon
try:
import imageio # noqa
except ImportError:
pass
else:
tools.insert(1, 'vispy:record')

Check warning on line 32 in glue_vispy_viewers/common/qt/data_viewer.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/data_viewer.py#L32

Added line #L32 was not covered by tests

def __init__(self, session, state=None, parent=None):
super().__init__(session, state=state, parent=parent)
self.setup_widget_and_callbacks()
Expand Down
83 changes: 83 additions & 0 deletions glue_vispy_viewers/common/qt/tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import os

Check warning on line 1 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L1

Added line #L1 was not covered by tests

from qtpy import QtGui, compat

Check warning on line 3 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L3

Added line #L3 was not covered by tests

from glue.viewers.common.tool import Tool, CheckableTool

Check warning on line 5 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L5

Added line #L5 was not covered by tests

from glue.config import viewer_tool

Check warning on line 7 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L7

Added line #L7 was not covered by tests

from vispy import app, io

Check warning on line 9 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L9

Added line #L9 was not covered by tests

RECORD_START_ICON = os.path.join(os.path.dirname(__file__), 'glue_record_start.png')
RECORD_STOP_ICON = os.path.join(os.path.dirname(__file__), 'glue_record_stop.png')

Check warning on line 12 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L11-L12

Added lines #L11 - L12 were not covered by tests


@viewer_tool
class SaveTool(Tool):

Check warning on line 16 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L15-L16

Added lines #L15 - L16 were not covered by tests

icon = 'glue_filesave'
tool_id = 'vispy:save'
action_text = 'Save the figure to a file'
tool_tip = 'Save the figure to a file'

Check warning on line 21 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L18-L21

Added lines #L18 - L21 were not covered by tests

def activate(self):
outfile, file_filter = compat.getsavefilename(caption='Save File',

Check warning on line 24 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L23-L24

Added lines #L23 - L24 were not covered by tests
filters='PNG Files (*.png);;'
'JPEG Files (*.jpeg);;'
'TIFF Files (*.tiff);;',
selectedfilter='PNG Files (*.png);;')

# This indicates that the user cancelled
if not outfile:
return
img = self.viewer._vispy_widget.canvas.render()
try:
file_filter = str(file_filter).split()[0]
io.imsave(outfile, img, format=file_filter)
except ImportError:

Check warning on line 37 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L31-L37

Added lines #L31 - L37 were not covered by tests
# TODO: give out a window to notify that only .png file format is supported
if '.' not in outfile:
outfile += '.png'
io.write_png(outfile, img)

Check warning on line 41 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L39-L41

Added lines #L39 - L41 were not covered by tests


@viewer_tool
class RecordTool(CheckableTool):

Check warning on line 45 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L44-L45

Added lines #L44 - L45 were not covered by tests

icon = RECORD_START_ICON
tool_id = 'vispy:record'
action_text = 'Record an animation'
tool_tip = 'Start/Stop the recording'

Check warning on line 50 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L47-L50

Added lines #L47 - L50 were not covered by tests

def __init__(self, viewer):
super(RecordTool, self).__init__(viewer=viewer)
self.record_timer = app.Timer(connect=self.record)
self.writer = None
self.next_action = 'start'

Check warning on line 56 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L52-L56

Added lines #L52 - L56 were not covered by tests

def activate(self):

Check warning on line 58 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L58

Added line #L58 was not covered by tests

# pop up a window for file saving
outfile, file_filter = compat.getsavefilename(caption='Save Animation',

Check warning on line 61 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L61

Added line #L61 was not covered by tests
filters='GIF Files (*.gif);;')

# if outfile is not set, the user cancelled
if outfile:
import imageio
self.set_icon(RECORD_STOP_ICON)
self.writer = imageio.get_writer(outfile)
self.record_timer.start(0.1)

Check warning on line 69 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L65-L69

Added lines #L65 - L69 were not covered by tests

def deactivate(self):

Check warning on line 71 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L71

Added line #L71 was not covered by tests

self.record_timer.stop()
if self.writer is not None:
self.writer.close()
self.set_icon(RECORD_START_ICON)

Check warning on line 76 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L73-L76

Added lines #L73 - L76 were not covered by tests

def set_icon(self, icon):
self.viewer.toolbar.actions[self.tool_id].setIcon(QtGui.QIcon(icon))

Check warning on line 79 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L78-L79

Added lines #L78 - L79 were not covered by tests

def record(self, event):
im = self.viewer._vispy_widget.canvas.render()
self.writer.append_data(im)

Check warning on line 83 in glue_vispy_viewers/common/qt/tools.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/common/qt/tools.py#L81-L83

Added lines #L81 - L83 were not covered by tests
77 changes: 1 addition & 76 deletions glue_vispy_viewers/common/tools.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import os

from qtpy import QtGui, compat

from glue.viewers.common.tool import Tool, CheckableTool

from glue.config import viewer_tool

from vispy import app, io
from vispy import app


RECORD_START_ICON = os.path.join(os.path.dirname(__file__), 'glue_record_start.png')
RECORD_STOP_ICON = os.path.join(os.path.dirname(__file__), 'glue_record_stop.png')
ROTATE_ICON = os.path.join(os.path.dirname(__file__), 'glue_rotate.png')


Expand All @@ -28,77 +24,6 @@ def activate(self):
self.viewer.state.reset_limits()


@viewer_tool
class SaveTool(Tool):

icon = 'glue_filesave'
tool_id = 'vispy:save'
action_text = 'Save the figure to a file'
tool_tip = 'Save the figure to a file'

def activate(self):
outfile, file_filter = compat.getsavefilename(caption='Save File',
filters='PNG Files (*.png);;'
'JPEG Files (*.jpeg);;'
'TIFF Files (*.tiff);;',
selectedfilter='PNG Files (*.png);;')

# This indicates that the user cancelled
if not outfile:
return
img = self.viewer._vispy_widget.canvas.render()
try:
file_filter = str(file_filter).split()[0]
io.imsave(outfile, img, format=file_filter)
except ImportError:
# TODO: give out a window to notify that only .png file format is supported
if '.' not in outfile:
outfile += '.png'
io.write_png(outfile, img)


@viewer_tool
class RecordTool(CheckableTool):

icon = RECORD_START_ICON
tool_id = 'vispy:record'
action_text = 'Record an animation'
tool_tip = 'Start/Stop the recording'

def __init__(self, viewer):
super(RecordTool, self).__init__(viewer=viewer)
self.record_timer = app.Timer(connect=self.record)
self.writer = None
self.next_action = 'start'

def activate(self):

# pop up a window for file saving
outfile, file_filter = compat.getsavefilename(caption='Save Animation',
filters='GIF Files (*.gif);;')

# if outfile is not set, the user cancelled
if outfile:
import imageio
self.set_icon(RECORD_STOP_ICON)
self.writer = imageio.get_writer(outfile)
self.record_timer.start(0.1)

def deactivate(self):

self.record_timer.stop()
if self.writer is not None:
self.writer.close()
self.set_icon(RECORD_START_ICON)

def set_icon(self, icon):
self.viewer.toolbar.actions[self.tool_id].setIcon(QtGui.QIcon(icon))

def record(self, event):
im = self.viewer._vispy_widget.canvas.render()
self.writer.append_data(im)


@viewer_tool
class RotateTool(CheckableTool):

Expand Down
8 changes: 0 additions & 8 deletions glue_vispy_viewers/common/vispy_data_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,6 @@ class BaseVispyViewerMixin:

tools = ['vispy:reset', 'vispy:rotate']

# If imageio is available, we can add the record icon
try:
import imageio # noqa
except ImportError:
pass
else:
tools.insert(1, 'vispy:record')

def setup_widget_and_callbacks(self):

self._vispy_widget = VispyWidgetHelper(viewer_state=self.state)
Expand Down
14 changes: 12 additions & 2 deletions glue_vispy_viewers/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
else:
GLUEQT_INSTALLED = True

try:
import glue_jupyter # noqa
except ImportError:
GLUEJUPYTER_INSTALLED = False
else:
GLUEJUPYTER_INSTALLED = True

Check warning on line 21 in glue_vispy_viewers/conftest.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/conftest.py#L21

Added line #L21 was not covered by tests

try:
import objgraph
except ImportError:
Expand Down Expand Up @@ -44,8 +51,11 @@ def pytest_unconfigure(config):


def pytest_ignore_collect(collection_path, path, config):
if path.isdir() and "qt" in collection_path.parts:
return not GLUEQT_INSTALLED
if path.isdir():
if "qt" in collection_path.parts:
return not GLUEQT_INSTALLED
if "jupyter" in collection_path.parts:
return not GLUEJUPYTER_INSTALLED


def pytest_runtest_setup(item):
Expand Down
2 changes: 1 addition & 1 deletion glue_vispy_viewers/scatter/jupyter/scatter_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class JupyterVispyScatterViewer(VispyScatterViewerMixin, IPyWidgetView):

def __init__(self, *args, **kwargs):

Check warning on line 17 in glue_vispy_viewers/scatter/jupyter/scatter_viewer.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/scatter/jupyter/scatter_viewer.py#L17

Added line #L17 was not covered by tests
# Vispy and jupyter_rfb don't work correctly on Linux unless DISPLAY is set
if 'DISPLAY' not in os:
if 'DISPLAY' not in os.environ:
os.environ['DISPLAY'] = ':0'
super().__init__(*args, **kwargs)
self.setup_widget_and_callbacks()
Expand Down
Empty file.
10 changes: 10 additions & 0 deletions glue_vispy_viewers/scatter/jupyter/tests/test_viewer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from glue.core import Data
from glue_jupyter import jglue
from ..scatter_viewer import JupyterVispyScatterViewer

Check warning on line 3 in glue_vispy_viewers/scatter/jupyter/tests/test_viewer.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/scatter/jupyter/tests/test_viewer.py#L1-L3

Added lines #L1 - L3 were not covered by tests


def test_basic_jupyter_scatter3d():
app = jglue()
data = Data(x=[1, 2, 3], y=[2, 3, 4], z=[5, 6, 7], label="xyz data")
app.add_data(data)
app.new_data_viewer(JupyterVispyScatterViewer, data=data)

Check warning on line 10 in glue_vispy_viewers/scatter/jupyter/tests/test_viewer.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/scatter/jupyter/tests/test_viewer.py#L6-L10

Added lines #L6 - L10 were not covered by tests
Empty file.
11 changes: 11 additions & 0 deletions glue_vispy_viewers/volume/jupyter/tests/test_viewer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import numpy as np
from glue.core import Data
from glue_jupyter import jglue
from ..volume_viewer import JupyterVispyVolumeViewer

Check warning on line 4 in glue_vispy_viewers/volume/jupyter/tests/test_viewer.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/volume/jupyter/tests/test_viewer.py#L1-L4

Added lines #L1 - L4 were not covered by tests


def test_basic_jupyter_volume():
app = jglue()
data = Data(x=np.arange(24).reshape((2, 3, 4)), label="cube data")
app.add_data(data)
app.new_data_viewer(JupyterVispyVolumeViewer, data=data)

Check warning on line 11 in glue_vispy_viewers/volume/jupyter/tests/test_viewer.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/volume/jupyter/tests/test_viewer.py#L7-L11

Added lines #L7 - L11 were not covered by tests
2 changes: 1 addition & 1 deletion glue_vispy_viewers/volume/jupyter/volume_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class JupyterVispyVolumeViewer(VispyVolumeViewerMixin, IPyWidgetView):

def __init__(self, *args, **kwargs):

Check warning on line 16 in glue_vispy_viewers/volume/jupyter/volume_viewer.py

View check run for this annotation

Codecov / codecov/patch

glue_vispy_viewers/volume/jupyter/volume_viewer.py#L16

Added line #L16 was not covered by tests
# Vispy and jupyter_rfb don't work correctly on Linux unless DISPLAY is set
if 'DISPLAY' not in os:
if 'DISPLAY' not in os.environ:
os.environ['DISPLAY'] = ':0'
super().__init__(*args, **kwargs)
self.setup_widget_and_callbacks()
Expand Down
4 changes: 4 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ pyside =
qtpy
glue-qt>=0.1.0
PySide6
jupyter =
glue-jupyter
all =
imageio

Expand All @@ -50,6 +52,8 @@ glue_vispy_viewers.common = *.png
glue_vispy_viewers.common.qt = *.ui
glue_vispy_viewers.scatter.qt = *.ui
glue_vispy_viewers.volume.qt = *.ui
glue_vispy_viewers.scatter.jupyter = *.vue
glue_vispy_viewers.volume.jupyter = *.vue
glue_vispy_viewers.qt.tests = data/*.glu
glue_vispy_viewers.extern = README.md, VISPY_LICENSE
glue_vispy_viewers.extern.vispy = io/_data/*.npy, html/static/js/*.js, app/tests/*.ui
Expand Down
3 changes: 2 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tox]
envlist =
py{38,39,310,311}-{test}-{dev}{,pyqt63,pyside63,pyqt64,pyside64}
py{38,39,310,311}-{test}-{dev}{,pyqt63,pyside63,pyqt64,pyside64,jupyter}
codestyle
requires = pip >= 18.0
setuptools >= 30.3.0
Expand All @@ -22,6 +22,7 @@ extras =
test: test
pyqt63,pyqt64: pyqt
pyside63,pyside64: pyside
jupyter: jupyter
commands =
test: pip freeze
test: pytest --pyargs glue_vispy_viewers --cov glue_vispy_viewers {posargs}
Expand Down

0 comments on commit 806deee

Please sign in to comment.