InsightSoftwareConsortium / itkwidgets

An elegant Python interface for visualization on the web platform to interactively generate insights into multidimensional images, point sets, and geometry.
https://itkwidgets.readthedocs.io/
Apache License 2.0
580 stars 83 forks source link

`master` incompatible with traitlets 5.7.* #588

Closed francesco-ballarin closed 1 year ago

francesco-ballarin commented 1 year ago

Hi, I believe the following change in traitlets, released as part of the 5.7 series https://github.com/ipython/traitlets/commit/f07afea52cf6314bc20571c52409ff6cb115a709#diff-c5d3e26eff54b5559a5eb2dabea191c32d6cbc784ea8d33816ecc2ebdd9d4e38R1348 has broken compatiblity with current master branch.

Sample:

Input:
itkwidgets.view(geometries=pyvista.examples.load_hexbeam())

Traceback:

---------------------------------------------------------------------------
TraitError                                Traceback (most recent call last)
<ipython-input-4-2f6a040def89> in <module>
----> 1 itkwidgets.view(geometries=pyvista.examples.load_hexbeam())

/usr/local/lib/python3.8/dist-packages/itkwidgets/widget_viewer.py in view(image, label_image, label_image_names, label_image_weights, label_image_blend, cmap, lut, select_roi, interpolation, gradient_opacity, opacity_gaussians, channels, slicing_planes, shadow, blend_mode, point_sets, point_set_colors, point_set_opacities, point_set_representations, point_set_sizes, geometries, geometry_colors, geometry_opacities, ui_collapsed, rotate, annotations, axes, mode, **kwargs)
   1088             image = images[0]
   1089 
-> 1090     viewer = Viewer(image=image,
   1091                     label_image=label_image,
   1092                     label_image_names=label_image_names,

/usr/local/lib/python3.8/dist-packages/itkwidgets/widget_viewer.py in __init__(self, **kwargs)
    367             kwargs['interpolation'] = False
    368 
--> 369         super(Viewer, self).__init__(**kwargs)
    370 
    371         if not self.image and not self.label_image:

/usr/lib/python3.8/site-packages/ipywidgets/widgets/widget.py in __init__(self, **kwargs)
    475         """Public constructor"""
    476         self._model_id = kwargs.pop('model_id', None)
--> 477         super(Widget, self).__init__(**kwargs)
    478 
    479         Widget._call_widget_constructed(self)

/usr/lib/python3.8/site-packages/traitlets/traitlets.py in __init__(self, *args, **kwargs)
   1356             for key in changed:
   1357                 value = self._traits[key]._cross_validate(self, getattr(self, key))
-> 1358                 self.set_trait(key, value)
   1359                 changes[key]['new'] = value
   1360             self._cross_validation_lock = False

/usr/lib/python3.8/site-packages/traitlets/traitlets.py in set_trait(self, name, value)
   1736             raise TraitError(f"Class {cls.__name__} does not have a trait named {name}")
   1737         else:
-> 1738             getattr(cls, name).set(self, value)
   1739 
   1740     @classmethod

/usr/local/lib/python3.8/dist-packages/traittypes/traittypes.py in set(self, obj, value)
    106 
    107     def set(self, obj, value):
--> 108         new_value = self._validate(obj, value)
    109         old_value = obj._trait_values.get(self.name, self.default_value)
    110         obj._trait_values[self.name] = new_value

/usr/lib/python3.8/site-packages/traitlets/traitlets.py in _validate(self, obj, value)
    733             return value
    734         if hasattr(self, "validate"):
--> 735             value = self.validate(obj, value)
    736         if obj._cross_validation_lock is False:
    737             value = self._cross_validate(obj, value)

/usr/local/lib/python3.8/dist-packages/ipydatawidgets/ndarray/traits.py in validate(self, obj, value)
     23 
     24     def validate(self, obj, value):
---> 25         value = super(NDArray, self).validate(obj, value)
     26         if value is None or value is Undefined:
     27             return value

/usr/local/lib/python3.8/dist-packages/traittypes/traittypes.py in validate(self, obj, value)
    103         except (ValueError, TypeError) as e:
    104             raise TraitError(e)
--> 105         return super(Array, self).validate(obj, value)
    106 
    107     def set(self, obj, value):

/usr/local/lib/python3.8/dist-packages/traittypes/traittypes.py in validate(self, obj, value)
     74         try:
     75             for validator in self.validators:
---> 76                 value = validator(self, value)
     77             return value
     78         except (ValueError, TypeError) as e:

/usr/local/lib/python3.8/dist-packages/ipydatawidgets/ndarray/traits.py in validator(trait, value)
     38             return value
     39         if len(value.shape) != len(args):
---> 40             raise TraitError('%s shape expected to have %s components, but got %s components' % (
     41                 trait.name, len(args), value.shape))
     42         for i, constraint in enumerate(args):

TraitError: label_image_weights shape expected to have 1 components, but got () components

The error may have to do with the default value of label_image_weights being set to None https://github.com/InsightSoftwareConsortium/itkwidgets/blob/master/itkwidgets/widget_viewer.py#L150

Thanks.

thewtex commented 1 year ago

Perhaps we should pin to traitlets < 5.7 for now.

thewtex commented 1 year ago

Workaround in #590 . A PR to address this for traitlets 5.7+ is welcome. Currently my efforts are focused on 1.X. This will help keep a working install available for the Jupyter Notebook in 0.X.

thewtex commented 1 year ago

Released in 0.32.5