Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAINT: Fixes for VTK-9.4 #1328

Merged
merged 3 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions docs/source/tvtk/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -260,19 +260,17 @@ tvtk wrapper object is created. The following illustrates this::
>>> cs = tvtk.ConeSource()
>>> o = cs.output
>>> m = tvtk.PolyDataMapper()
>>> m.input = o
>>> print(hash(o))
1109012188
>>> print(hash(m.input))
1109012188
>>> m.input_connection = cs.output_port
>>> print(id(o))
126526931186080
>>> print(id(m.input))
126526931186080
>>> del o
>>> print(hash(m.input))
1119694156
>>> print(id(m.input))
126526931186080

Thus, after `o` is garbage collected `m.input` no longer refers to the
original tvtk object and a new one is created. This is very similar
to VTK's behaviour. Changing this behaviour is tricky and there are no
plans currently to change this.
original tvtk object the old one is cached and returned.


tvtk and traits
Expand Down
9 changes: 1 addition & 8 deletions mayavi/components/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,7 @@ def update_data(self):
sends a `data_changed` event.
"""
# Invoke render to update any changes.
from mayavi.modules.outline import Outline
from mayavi.components.glyph import Glyph
#FIXME: A bad hack, but without these checks results in seg fault
input = self.inputs[0]
if isinstance(input, Outline) or isinstance(input, Glyph):
self.mapper.update(0)
else:
self.mapper.update()
self.mapper.update()
self.render()

######################################################################
Expand Down
7 changes: 4 additions & 3 deletions tvtk/code_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def generate_code(self):
# Write the wrapper files.
tree = wrap_gen.get_tree().tree

classes = []
classes = ['vtkObjectBase']
# This is another class we should not wrap and exists
# in version 8.1.0.
ignore = ['vtkOpenGLGL2PSHelperImpl'] + [
Expand All @@ -124,11 +124,12 @@ def generate_code(self):
if (name not in include and not name.startswith('vtk')) or \
name.startswith('vtkQt'):
continue
if not hasattr(vtk, name) or not hasattr(getattr(vtk, name), 'IsA'): # noqa
if not hasattr(vtk, name) or \
not hasattr(getattr(vtk, name), 'AddObserver'): # noqa
# We need to wrap VTK classes that are derived
# from vtkObjectBase, the others are
# straightforward VTK classes that can be used as
# such. All of these have an 'IsA' method so we
# such. All of these have an 'AddObserver' method so we
# check for that. Only the vtkObjectBase
# subclasses support observers etc. and hence only
# those make sense to wrap into TVTK.
Expand Down
10 changes: 5 additions & 5 deletions tvtk/messenger.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def connect(self, obj, event, callback):

"""
typ = type(callback)
key = hash(obj)
key = id(obj)
if not key in self._signals:
self._signals[key] = {}
signals = self._signals[key]
Expand Down Expand Up @@ -200,7 +200,7 @@ def disconnect(self, obj, event=None, callback=None, obj_is_hash=False):
if obj_is_hash:
key = obj
else:
key = hash(obj)
key = id(obj)
if not key in signals:
return
if callback is None:
Expand Down Expand Up @@ -282,11 +282,11 @@ def _get_signals(self, obj):
object.

"""
ret = self._signals.get(hash(obj))
ret = self._signals.get(id(obj))
if ret is None:
raise MessengerError(
"No such object: %s, has registered itself "\
"with the messenger."%obj
"No such object: %s, has registered itself "
"with the messenger." % obj
)
else:
return ret
Expand Down
4 changes: 2 additions & 2 deletions tvtk/pipeline/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ class TVTKLeafNode(TreeNodeObject):
__ = Python

def __hash__(self):
return hash(tvtk.to_vtk(self.object))
return id(tvtk.to_vtk(self.object))

def _get_name(self):
return self.object.__class__.__name__
Expand Down Expand Up @@ -496,7 +496,7 @@ def __del__(self):
pass

def __hash__(self):
return hash(tvtk.to_vtk(self.object))
return id(tvtk.to_vtk(self.object))

def _get_children_from_cache(self):
return [x for x in self.children_cache.values() if x is not None]
Expand Down
4 changes: 2 additions & 2 deletions tvtk/tests/test_messenger.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,12 @@ def foo(self, o, e):
# Test if things behave sanely if a message was sent and one
# of the callbacks has been gc'd.
m = messenger.Messenger()
l1 = len(m._signals[hash(c1)]['foo'])
l1 = len(m._signals[id(c1)]['foo'])
#
del c
messenger.send(c1, 'foo')
#
l2 = len(m._signals[hash(c1)]['foo'])
l2 = len(m._signals[id(c1)]['foo'])
# Since 'c' is gc'd this callback should have been cleared
# out.
self.assertEqual(l2, l1 - 1)
Expand Down
27 changes: 16 additions & 11 deletions tvtk/tests/test_tvtk.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,22 +202,22 @@ def test_help_trait(self):
def test_object_cache(self):
"""Test if object cache works."""
cs = tvtk.ConeSource()
hash1 = hash(cs)
hash1 = id(cs)
o = cs.output
if hasattr(o, 'producer_port'):
src = o.producer_port.producer
else:
src = cs.executive.algorithm
self.assertEqual(src, cs)
self.assertEqual(hash1, hash(src))
self.assertEqual(hash1, id(src))
del cs, src
gc.collect()
# The test sometimes fails as VTK seems to generate objects with the
# same memory address and hash, we try to force it to allocate more
# objects so as to not end up reusing the same address and hash.
# same memory address and hash/id, we try to force it to allocate more
# objects so as to not end up reusing the same address and id.
junk = [tvtk.ConeSource() for i in range(50)]

# Now get another ConeSource and ensure the hash is different.
# Now get another ConeSource and ensure the id is different.
cs = tvtk.ConeSource()
o = cs.output
if hasattr(o, 'producer_port'):
Expand All @@ -230,8 +230,8 @@ def test_object_cache(self):
# For VTK 5.x this test is inconsistent, hence skipeed for 5.x
# See http://review.source.kitware.com/#/c/15095/
##############################################################
self.assertEqual(hash1 != hash(src), True)
self.assertEqual(hash(cs), hash(src))
self.assertEqual(hash1 != id(src), True)
self.assertEqual(id(cs), id(src))

# Test for a bug with collections and the object cache.
r = tvtk.Renderer()
Expand Down Expand Up @@ -565,7 +565,7 @@ def test_information_keys(self):
s = tvtk.StructuredPoints()
x = s.FIELD_ARRAY_TYPE()
y = tvtk.Information()
x.get(y)
y.get(x)

def test_parent_child_bounds(self):
"""CubeAxesActor2D's bounds should be writable."""
Expand Down Expand Up @@ -858,7 +858,13 @@ def get_min_max_value(vtk_klass, vtk_attr_name):
for name in self.names:
vtk_klass = getattr(vtk, name)
tvtk_klass_name = get_tvtk_name(name)

if vtk.vtk_version == '9.4.0':
if tvtk_klass_name.endswith('View'):
continue
if tvtk_klass_name in ['ImageViewer', 'ImageViewer2',
'OpenGLRenderWindow',
'RenderWindow']:
continue
try:
obj = getattr(tvtk, tvtk_klass_name)()
except Exception:
Expand All @@ -882,8 +888,7 @@ def get_min_max_value(vtk_klass, vtk_attr_name):
# tvtk.tvtk_classes.open_gl_cell_grid_render_request.shapes_to_draw
# uses strings
if isinstance(min_value, str):
name = "tvtk.tvtk_classes.open_gl_cell_grid_render_request"
assert name in repr(obj), (obj, trait_name)
assert 'cell_grid_render_request' in repr(obj), (obj, trait_name)
continue
with self.assertRaises(TraitError):
setattr(obj, trait_name, (min_value-1, max_value))
Expand Down
10 changes: 9 additions & 1 deletion tvtk/vtk_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,12 @@
try:
del vtkDGBoundsResponder, vtkDGOpenGLRenderer, vtkDGSidesResponder
except NameError:
pass
pass

if vtk_version == '9.4.0':
# Instantiating these using TVTK causes a crash on VTK 9.4.0 so skipping.
SKIP = ['vtkIOSSReader', 'vtkIOSSCellGridReader']
try:
del vtkIOSSReader, vtkIOSSCellGridReader
except NameError:
pass
3 changes: 3 additions & 0 deletions tvtk/vtk_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,9 @@ def _find_get_set_methods(self, klass, methods):
# These hang on Windows (and maybe Fedora 34)
elif (klass_name in ('vtkDataEncoder', 'vtkWebApplication')):
continue
# This crashes on VTK version 9.4.0
elif (klass_name == 'vtkGenericCell' and method[3:] == 'CellFaces'):
continue
# we can actually process it
elif ('Get' + method[3:]) in methods:
key = method[3:]
Expand Down
22 changes: 20 additions & 2 deletions tvtk/wrapper_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def get_trait_def(value, **kwargs):
Example
-------
>>> get_trait_def([100., 200.], enter_set=True, auto_set=False)
('traits.Array', '', 'auto_set=False, enter_set=True, shape=(2,), dtype=float, value=[100.0, 200.0], cols=2')
('traits.Array', '', 'auto_set=False, enter_set=True, shape=(None,), dtype=float, value=[100.0, 200.0], cols=2')
>>> get_trait_def(100, enter_set=True, auto_set=False)
('traits.Int', '100', 'auto_set=False, enter_set=True')
>>> get_trait_def(u'something', enter_set=True, auto_set=False)
Expand All @@ -80,7 +80,7 @@ def get_trait_def(value, **kwargs):
return 'traits.String', '{!r}'.format(value), kwargs_code

elif type_ in (tuple, list):
shape = (len(value),)
shape = (None,)
dtypes = set(type(element) for element in value)
dtype = dtypes.pop().__name__ if len(dtypes) == 1 else None
if dtype == 'int' and sys.platform.startswith('win'):
Expand Down Expand Up @@ -1654,6 +1654,11 @@ def _write_trait_with_range(self, klass, out, vtk_attr_name):
'vtkLineIntegralConvolution2D.MaxNoiseValue$': (
True, True, '_write_line_integral_conv_2d_max_noise_value'
),
# In VTK 9.4, CellGridSidesQuery's Get/OutputDimensionControl is initialized
# to some random value this happens mostly on MacOS.
'vtkCellGridSidesQuery.OutputDimensionControl$': (
True, True, '_write_cell_grid_sides_query_od_control'
),
# In VTK 9.3, vtkCylinderSource's GetLatLongTesselation gives random values
# https://gitlab.kitware.com/vtk/vtk/-/issues/19252
'vtkCylinderSource.LatLongTessellation$': (
Expand Down Expand Up @@ -1927,6 +1932,19 @@ def _write_line_integral_conv_2d_max_noise_value(
vtk_set_meth = getattr(klass, 'Set' + vtk_attr_name)
self._write_trait(out, name, t_def, vtk_set_meth, mapped=False)

def _write_cell_grid_sides_query_od_control(self, klass, out, vtk_attr_name):
if vtk_attr_name != 'OutputDimensionControl':
raise RuntimeError(f"Wrong attribute name: {vtk_attr_name}")
if vtk_major_version >= 9:
message = ("vtkCellGridSidesQuery: "
"OutputDimensionControl not updatable "
"(VTK 9.4 bug - value not properly initialized)")
print(message)
t_def = 'tvtk_base.true_bool_trait'
name = self._reform_name(vtk_attr_name)
vtk_set_meth = getattr(klass, 'Set' + vtk_attr_name)
self._write_trait(out, name, t_def, vtk_set_meth, mapped=True)

def _write_cylinder_source_lat_long_tessellation(
self, klass, out, vtk_attr_name
):
Expand Down
Loading