guiclass throws type error with Optional argument set to None
Describe the bug
None not accepted as Optional type but should be.
To Reproduce Steps to reproduce the behavior:
from magicgui.experimental import guiclass from typing import Optional
@guiclass class Person: name:str age: Optional[int] = None
person = Person('Jane') person.gui.show()
Expected behavior
Works fine as a normal dataclass since Optional type is Union of None. magicgui tries to cast values to float only Same error with Union[ int, None]
Screenshots
TypeError Traceback (most recent call last)
File ~\anaconda3\envs\magicgu\lib\site-packages\magicgui\schema_guiclass.py:249, in GuiBuilder.get(self, instance, owner) 247 if instance is None: 248 return self --> 249 wdg = build_widget(instance) 251 # look for @button-decorated methods 252 # TODO: move inside build_widget? 253 for k, v in vars(owner).items():
File ~\anaconda3\envs\magicgu\lib\site-packages\magicgui\schema_ui_field.py:856, in build_widget(cls_or_instance) 854 values = None if isinstance(cls_or_instance, type) else _get_values(cls_or_instance) 855 fields = get_ui_fields(cls_or_instance) --> 856 return _uifields_to_container(fields, values=values)
File ~\anaconda3\envs\magicgu\lib\site-packages\magicgui\schema_ui_field.py:817, in _uifields_to_container(ui_fields, values, container_kwargs) 812 container = widgets.Container( 813 widgets=[field.create_widget() for field in ui_fields], 814 **(container_kwargs or {}), 815 ) 816 if values is not None: --> 817 container.update(values) 818 return container
File ~\anaconda3\envs\magicgu\lib\site-packages\magicgui\widgets\bases_container_widget.py:445, in ContainerWidget.update(self, mapping, **kwargs) 443 for key, value in chain(items, kwargs.items()): 444 if isinstance(wdg := self._list.get_by_name(key), BaseValueWidget): --> 445 wdg.value = value 446 self.changed.emit(self)
File ~\anaconda3\envs\magicgu\lib\site-packages\magicgui\widgets\bases_value_widget.py:103, in BaseValueWidget.value(self, value) 101 @value.setter 102 def value(self, value: T) -> None: --> 103 return self.set_value(value)
File ~\anaconda3\envs\magicgu\lib\site-packages\magicgui\widgets\bases_ranged_widget.py:124, in RangedWidget.set_value(self, value) 122 """Set widget value, will raise Value error if not within min/max.""" 123 val: tuple[float, ...] = value if isinstance(value, tuple) else (value,) --> 124 if any(float(v) < self.min or float(v) > self.max for v in val): 125 raise ValueError( 126 f"value {value} is outside of the allowed range: " 127 f"({self.min}, {self.max})" 128 ) 129 super().set_value(value)
File ~\anaconda3\envs\magicgu\lib\site-packages\magicgui\widgets\bases_ranged_widget.py:124, in
TypeError: float() argument must be a string or a number, not 'NoneType'
Environment (please complete the following information):
- OS: [Windows]
- backend: [pyqt 5.15.2]
- magicgui version [0.10.1]
hi @neili02, this is essentially the same as https://github.com/pyapp-kit/magicgui/issues/145
basically, it will require some magic, or at the very least the concept of a nullable widget (for every type) that can fallback gracefully to None. And there hasn't been a good PR/proposal for how to deal with this in a general way. Sorry we don't have a better ready-to-go widget solution for optional types