Skip to content

Commit

Permalink
Merge pull request #1329 from larsoner/vtk
Browse files Browse the repository at this point in the history
MAINT: Require VTK 9+
  • Loading branch information
prabhuramachandran authored Dec 19, 2024
2 parents 455d30b + a48872b commit 8aa0e7e
Show file tree
Hide file tree
Showing 14 changed files with 160 additions and 185 deletions.
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
groups:
actions:
patterns:
- "*"
66 changes: 41 additions & 25 deletions .github/workflows/run-mayavi-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,55 +10,68 @@ jobs:
tests:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-13]
python-version: ['3.9']
qt-api: ['pyqt5']
vtk: ['vtk<9.3']
# Always test against the latest VTK, NumPy, and Qt bindings
os: [ubuntu-latest, windows-latest, macos-13, macos-15]
python-version: ['3.12']
qt-api: ['pyside6'] # prefer the modern bindings
vtk: ['vtk>=9.4'] # always prefer the latest
# Then add some backward compat checks
include:
- python-version: '3.12'
# PyQt6 and vtk 9.3
- python-version: '3.10'
qt-api: 'pyqt6'
os: ubuntu-latest
vtk: 'vtk>=9.3'
- python-version: '3.12'
vtk: 'vtk==9.3'
- python-version: '3.10'
qt-api: 'pyqt6'
os: macos-14 # arm64
vtk: 'vtk>=9.3'
- python-version: '3.12'
vtk: 'vtk==9.3'
- python-version: '3.10'
qt-api: 'pyqt6'
os: windows-latest
vtk: 'vtk>=9.3'
vtk: 'vtk==9.3'
- python-version: '3.11'
qt-api: 'pyqt6'
os: ubuntu-latest
vtk: 'vtk>=9.3'
- python-version: '3.10'
qt-api: 'pyside6'
vtk: 'vtk==9.3'
# PyQt5 and vtk 9.2 (and one oldest Python)
- python-version: '3.9'
qt-api: 'pyqt5'
os: ubuntu-latest
vtk: 'vtk<9.3'
vtk: 'vtk==9.2.5'
- python-version: '3.10'
qt-api: 'pyside6'
qt-api: 'pyqt5'
os: windows-latest
vtk: 'vtk<9.3'
vtk: 'vtk==9.2.5'
- python-version: '3.10'
qt-api: 'pyside6'
os: macos-13
vtk: 'vtk<9.3'
vtk: 'vtk==9.2.5'
# Some old NumPys
- python-version: '3.12'
qt-api: 'pyside6'
os: ubuntu-latest
vtk: 'vtk>=9.3'
vtk: 'vtk==9.3'
numpy: 'numpy==1.26.4'
- python-version: '3.12'
qt-api: 'pyside6'
os: windows-latest
vtk: 'vtk>=9.3'
numpy: 'numpy==2.0.2'
- python-version: '3.12'
qt-api: 'pyside6'
os: windows-latest
vtk: 'vtk>=9.3'
vtk: 'vtk==9.3'
numpy: 'numpy==1.26.4'
# Older Python and VTKs
- python-version: '3.10'
qt-api: 'pyqt5'
os: ubuntu-latest
vtk: 'vtk==9.2.2'
# TVTK tests intermittently segfault on 9.1
# - python-version: '3.9'
# qt-api: 'pyqt5'
# os: ubuntu-latest
# vtk: 'vtk==9.1.0'
- python-version: '3.9'
qt-api: 'pyqt5'
os: ubuntu-latest
vtk: 'vtk==9.0.2' # oldest available on 3.9 which is the oldest Python we support
fail-fast: false
defaults:
run:
Expand All @@ -72,11 +85,14 @@ jobs:
QT_API: ${{ matrix.qt-api }}
TVTK_VERBOSE: 'true'
VTK_PARSER_VERBOSE: 'true'
PYTHONUNBUFFERED: '1'

steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install Linux packages for Qt5/Qt6 support and start Xvfb
uses: pyvista/setup-headless-display-action@main
uses: pyvista/setup-headless-display-action@v3
with:
qt: true
if: startsWith(matrix.os, 'ubuntu')
Expand Down
13 changes: 6 additions & 7 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,11 @@ By itself Mayavi is not a difficult package to install but its dependencies
are unfortunately rather heavy. However, many of these dependencies are now
available as wheels on PyPI. The two critical dependencies are,

1. VTK_
2. A GUI toolkit, either PyQt4_, PySide_, PySide2_, PyQt5_ or wxPython_.
1. VTK_ >= 9.0
2. A GUI toolkit, either PySide6_, PyQt6_, PySide2_, PyQt5_, or wxPython_.

The latest VTK wheels are available on all the major platforms (Windows,
MacOS, and Linux), but only for 64 bit machines. Python 3.x is fully supported
on all these operating systems and Python 2.7.x on MacOS and Linux. If you are
MacOS, and Linux). If you are
out of luck, and your platform is not supported then you will need to install
VTK yourself using your particular distribution as discussed in the `General
Build and Installation instructions
Expand Down Expand Up @@ -133,7 +132,7 @@ If you are unable to do this, read the documentation above and find a way to
install VTK and a suitable UI toolkit and then repeat the above.

If you are interested in the jupyter notebook support as well, do the
following (after ensuring that you have jupyter installed of course.
following (after ensuring that you have jupyter installed of course.
**Note, the Jupyter notebook function is only supported starting mayavi
version 4.5.0**)::

Expand Down Expand Up @@ -200,8 +199,8 @@ Test suite

The basic test suites for tvtk and mayavi can be run using nose::

nosetests -v tvtk/tests
nosetests -v mayavi
pytest -v tvtk/tests
pytest -v mayavi

The integration tests::

Expand Down
16 changes: 4 additions & 12 deletions mayavi/components/ui/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@

from traitsui.api import (View, Group, Item, InstanceEditor,
DropEditor, Tabbed)
from tvtk.api import tvtk
from tvtk.common import vtk_major_version

# The properties view group.
_prop_base_group = Group(Item(name='representation'),
Expand Down Expand Up @@ -48,16 +46,10 @@
)

# The Texture's view group
if vtk_major_version > 7:
_texture_group = Group(Item(name='interpolate'),
Item(name='color_mode'),
Item(name='repeat'),
show_border=True)
else:
_texture_group = Group(Item(name='interpolate'),
Item(name='map_color_scalars_through_lookup_table'),
Item(name='repeat'),
show_border=True)
_texture_group = Group(Item(name='interpolate'),
Item(name='color_mode'),
Item(name='repeat'),
show_border=True)

# The Actor's view group.
_actor_base_group = Group(Item(name='visibility'))
Expand Down
3 changes: 0 additions & 3 deletions mayavi/tests/test_builtin_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from numpy import array

# Enthought library imports.
from tvtk.common import vtk_major_version
from mayavi.core.null_engine import NullEngine
from mayavi.sources.builtin_image import BuiltinImage
from mayavi.modules.surface import Surface
Expand Down Expand Up @@ -40,8 +39,6 @@ def setUp(self):
image_data.data_source.radius = array([80., 80., 80.])
image_data.data_source.center = array([150., 150., 0.])
image_data.data_source.whole_extent = array([10, 245, 10, 245, 0, 0])
if vtk_major_version < 8:
image_data.data_source.set_update_extent_to_whole_extent()

self.e = e
self.scene = e.current_scene
Expand Down
11 changes: 2 additions & 9 deletions mayavi/tools/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

# imports
from tvtk.api import tvtk
from tvtk.common import vtk_major_version
from mayavi.core.scene import Scene
from mayavi.core.registry import registry
from .camera import view
Expand Down Expand Up @@ -313,19 +312,13 @@ def screenshot(figure=None, mode='rgb', antialiased=False):
out = tvtk.UnsignedCharArray()
shape = (y, x, 3)
pixel_getter = figure.scene.render_window.get_pixel_data
if vtk_major_version > 7:
pg_args = (0, 0, x - 1, y - 1, 1, out, 0)
else:
pg_args = (0, 0, x - 1, y - 1, 1, out)
pg_args = (0, 0, x - 1, y - 1, 1, out, 0)

elif mode == 'rgba':
out = tvtk.FloatArray()
shape = (y, x, 4)
pixel_getter = figure.scene.render_window.get_rgba_pixel_data
if vtk_major_version > 7:
pg_args = (0, 0, x - 1, y - 1, 1, out, 0)
else:
pg_args = (0, 0, x - 1, y - 1, 1, out)
pg_args = (0, 0, x - 1, y - 1, 1, out, 0)

else:
raise ValueError('mode type not understood')
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
requires = [
"numpy>=2.0.0rc2,<3",
"setuptools",
"vtk",
"vtk>=9",
"wheel"
]
6 changes: 4 additions & 2 deletions tvtk/code_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
..code-block:: console
$ python -m tvtk.code_gen -szvno $PWD/tvtk
$ VTK_PARSER_VERBOSE=1 python -m tvtk.code_gen -szvno $PWD/tvtk
On failures you can then for example do ``import pdb; pdb.pm()`` to do
post-mortem debugging.
post-mortem debugging. If there are segfaults, the VTK_PARSER_VERBOSE=1 should help
point to the culprit, which often needs to be worked around in
``vtk_parser.py::VTKMethodParser._find_get_set_methods``.
Exceptions to behaviors based on VTK versions and bugs etc. live in ``wrapper_gen.py``
and ``tvtk_parser.py``.
Expand Down
5 changes: 0 additions & 5 deletions tvtk/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
# License: BSD Style.

from contextlib import contextmanager
import string
import re
import vtk

Expand Down Expand Up @@ -67,10 +66,6 @@ def _sanitize_name(name):
return name


def is_version_9():
return vtk_major_version > 8


def configure_connection(obj, inp):
""" Configure topology for vtk pipeline obj."""
if hasattr(inp, 'output_port'):
Expand Down
13 changes: 1 addition & 12 deletions tvtk/tests/test_class_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
"""
import builtins
import sys
import unittest
from contextlib import contextmanager

Expand All @@ -19,8 +18,6 @@
_cache = class_tree.ClassTree(vtk)
_cache.create()

vtk_major_version = vtk.vtkVersion.GetVTKMajorVersion()

def get_level(klass):
"""Gets the inheritance level of a given class."""
if not klass.__bases__:
Expand Down Expand Up @@ -54,15 +51,7 @@ def test_basic_vtk(self):
if (hasattr(vtk, 'vtkTuple')):
names = [x.name for x in t.tree[0]]
names.sort()
if vtk_major_version == 7:
expect = ['object', 'vtkColor3', 'vtkColor4', 'vtkDenseArray',
'vtkQuaternion', 'vtkRect',
'vtkSparseArray', 'vtkTuple',
'vtkTypedArray','vtkVector',
'vtkVector2', 'vtkVector3']
else:
self.assertGreaterEqual(vtk_major_version, 8)
expect = ['object']
expect = ['object']
self.assertEqual(names, expect)
elif (hasattr(vtk, 'vtkVector')):
self.assertEqual(len(t.tree[0]), 11)
Expand Down
24 changes: 21 additions & 3 deletions tvtk/tests/test_tvtk.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
# Copyright (c) 2004-2020, Enthought, Inc.
# License: BSD Style.

import os
import unittest
import pickle
import weakref
Expand Down Expand Up @@ -43,6 +44,9 @@
from tvtk.tvtk_classes import tvtk_helper


on_gha = os.getenv("GITHUB_ACTION", None) is not None


def mysum(arr):
val = arr
while type(val) == numpy.ndarray:
Expand Down Expand Up @@ -818,14 +822,20 @@ def setUpClass(cls):
def test_all_instantiable(self):
"""Test if all the TVTK classes can be instantiated"""
errors = []
if on_gha:
print("\n::group::Instantiating TVTK classes")
for name in self.names:
tvtk_name = get_tvtk_name(name)
tvtk_klass = getattr(tvtk, tvtk_name, None)
if on_gha:
print(tvtk_name)
try:
obj = tvtk_klass()
tvtk_klass()
# TypeError: super(type, obj): obj must be an instance or subtype of type
except (TraitError, KeyError, TypeError):
errors.append(f"\n{name}:\n{indent(traceback.format_exc(), ' ')}")
if on_gha:
print("\n::endgroup::")
if len(errors) > 0:
message = "Not all classes could be instantiated:\n{0}\n"
raise AssertionError(message.format(''.join(errors)))
Expand Down Expand Up @@ -855,6 +865,8 @@ def get_min_max_value(vtk_klass, vtk_attr_name):
except AttributeError:
return None, None

if on_gha:
print("\n::group::TVTK trait ranges")
for name in self.names:
vtk_klass = getattr(vtk, name)
tvtk_klass_name = get_tvtk_name(name)
Expand All @@ -865,11 +877,15 @@ def get_min_max_value(vtk_klass, vtk_attr_name):
'OpenGLRenderWindow',
'RenderWindow']:
continue

if on_gha:
print(tvtk_klass_name)

try:
obj = getattr(tvtk, tvtk_klass_name)()
except Exception:
# testing for instantiation is above
pass
continue

for trait_name in obj.editable_traits():
if trait_name in ['_in_set', '_vtk_obj']:
Expand All @@ -894,6 +910,8 @@ def get_min_max_value(vtk_klass, vtk_attr_name):
setattr(obj, trait_name, (min_value-1, max_value))
with self.assertRaises(TraitError):
setattr(obj, trait_name, (min_value, max_value+1))
if on_gha:
print("::endgroup::")

def test_no_trait_has_ptr_address_as_value(self):
'''Test if none of the TVTK classes' traits has a value of "*_p_void"
Expand Down Expand Up @@ -938,7 +956,7 @@ def test_all_traits_can_be_obtained(self):
obj = getattr(tvtk, tvtk_klass_name)()
except Exception:
# testing for instantiation is above
pass
continue

for trait_name in obj._full_traitnames_list_:
try:
Expand Down
Loading

0 comments on commit 8aa0e7e

Please sign in to comment.