Skip to content

Commit acc9bbb

Browse files
authored
fix: Allow user overwritte default widget opts (#602)
* fix: Allow user overwritte default widget opts * use Annotated from typing extensions
1 parent 2fa477d commit acc9bbb

File tree

3 files changed

+38
-27
lines changed

3 files changed

+38
-27
lines changed

src/magicgui/type_map/_type_map.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,8 @@ def _pick_widget_type(
214214
raise_on_unknown: bool = True,
215215
) -> WidgetTuple:
216216
"""Pick the appropriate widget type for ``value`` with ``annotation``."""
217-
annotation, _options = _split_annotated_type(annotation)
218-
options = {**_options, **(options or {})}
217+
annotation, options_ = _split_annotated_type(annotation)
218+
options = {**options_, **(options or {})}
219219
choices = options.get("choices")
220220

221221
if is_result and annotation is inspect.Parameter.empty:
@@ -229,9 +229,9 @@ def _pick_widget_type(
229229
):
230230
return widgets.EmptyWidget, {"visible": False, **options}
231231

232-
_type, optional = _type_optional(value, annotation)
232+
type_, optional = _type_optional(value, annotation)
233233
options.setdefault("nullable", optional)
234-
choices = choices or (isinstance(_type, EnumMeta) and _type)
234+
choices = choices or (isinstance(type_, EnumMeta) and type_)
235235
literal_choices, nullable = _literal_choices(annotation)
236236
if literal_choices is not None:
237237
choices = literal_choices
@@ -243,7 +243,7 @@ def _pick_widget_type(
243243
if widget_type == "RadioButton":
244244
widget_type = "RadioButtons"
245245
warnings.warn(
246-
f"widget_type of 'RadioButton' (with dtype {_type}) is"
246+
f"widget_type of 'RadioButton' (with dtype {type_}) is"
247247
" being coerced to 'RadioButtons' due to choices or Enum type.",
248248
stacklevel=2,
249249
)
@@ -252,15 +252,15 @@ def _pick_widget_type(
252252

253253
# look for subclasses
254254
for registered_type in _TYPE_DEFS:
255-
if _type == registered_type or safe_issubclass(_type, registered_type):
256-
_cls, opts = _TYPE_DEFS[registered_type]
257-
return _cls, {**options, **opts}
255+
if type_ == registered_type or safe_issubclass(type_, registered_type):
256+
cls_, opts = _TYPE_DEFS[registered_type]
257+
return cls_, {**options, **opts}
258258

259259
if is_result:
260-
_widget_type = match_return_type(_type)
261-
if _widget_type:
262-
_cls, opts = _widget_type
263-
return _cls, {**options, **opts}
260+
widget_type_ = match_return_type(type_)
261+
if widget_type_:
262+
cls_, opts = widget_type_
263+
return cls_, {**opts, **options}
264264
# Chosen for backwards/test compatibility
265265
return widgets.LineEdit, {"gui_only": True}
266266

@@ -269,14 +269,14 @@ def _pick_widget_type(
269269
wdg = widgets.Select if options.get("allow_multiple") else widgets.ComboBox
270270
return wdg, options
271271

272-
_widget_type = match_type(_type, value)
273-
if _widget_type:
274-
_cls, opts = _widget_type
275-
return _cls, {**options, **opts}
272+
widget_type_ = match_type(type_, value)
273+
if widget_type_:
274+
cls_, opts = widget_type_
275+
return cls_, {**opts, **options}
276276

277277
if raise_on_unknown:
278278
raise ValueError(
279-
f"No widget found for type {_type} and annotation {annotation!r}"
279+
f"No widget found for type {type_} and annotation {annotation!r}"
280280
)
281281

282282
options["visible"] = False
@@ -328,7 +328,7 @@ def get_widget_class(
328328
The WidgetClass, and dict that can be used for params. dict
329329
may be different than the options passed in.
330330
"""
331-
widget_type, _options = _pick_widget_type(
331+
widget_type, options_ = _pick_widget_type(
332332
value, annotation, options, is_result, raise_on_unknown
333333
)
334334

@@ -340,7 +340,7 @@ def get_widget_class(
340340
if not safe_issubclass(widget_class, widgets.bases.Widget):
341341
assert_protocol(widget_class, WidgetProtocol)
342342

343-
return widget_class, _options
343+
return widget_class, options_
344344

345345

346346
def _import_wdg_class(class_name: str) -> WidgetClass:

src/magicgui/widgets/bases/_create_widget.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def create_widget(
9393
assert wdg.value == ""
9494
```
9595
"""
96-
_options = options.copy() if options is not None else {}
96+
options_ = options.copy() if options is not None else {}
9797
kwargs = {
9898
"value": value,
9999
"annotation": annotation,
@@ -109,21 +109,21 @@ def create_widget(
109109
from magicgui.type_map import get_widget_class
110110

111111
if widget_type:
112-
_options["widget_type"] = widget_type
112+
options_["widget_type"] = widget_type
113113
# special case parameters named "password" with annotation of str
114114
if (
115-
not _options.get("widget_type")
115+
not options_.get("widget_type")
116116
and (name or "").lower() == "password"
117117
and annotation is str
118118
):
119-
_options["widget_type"] = "Password"
119+
options_["widget_type"] = "Password"
120120

121121
wdg_class, opts = get_widget_class(
122-
value, annotation, _options, is_result, raise_on_unknown
122+
value, annotation, options_, is_result, raise_on_unknown
123123
)
124124

125125
if issubclass(wdg_class, Widget):
126-
widget = wdg_class(**{**kwargs, **opts, **_options})
126+
widget = wdg_class(**{**kwargs, **opts, **options_})
127127
if param_kind:
128128
widget.param_kind = param_kind # type: ignore
129129
return widget
@@ -133,9 +133,9 @@ def create_widget(
133133
for p in ("Categorical", "Ranged", "Button", "Value", ""):
134134
prot = getattr(protocols, f"{p}WidgetProtocol")
135135
if isinstance(wdg_class, prot):
136-
_options = kwargs.pop("options", None)
136+
options_ = kwargs.pop("options", None)
137137
cls = getattr(bases, f"{p}Widget")
138-
widget = cls(**{**kwargs, **(_options or {}), "widget_type": wdg_class})
138+
widget = cls(**{**kwargs, **(options_ or {}), "widget_type": wdg_class})
139139
if param_kind:
140140
widget.param_kind = param_kind # type: ignore
141141
return widget

tests/test_widgets.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,17 @@ def test_create_widget_annotation(annotation, expected_type):
110110
wdg.close()
111111

112112

113+
def test_create_widget_annotation_overwritte_parrams():
114+
wdg1 = widgets.create_widget(annotation=widgets.ProgressBar)
115+
assert isinstance(wdg1, widgets.ProgressBar)
116+
assert wdg1.visible
117+
wdg2 = widgets.create_widget(
118+
annotation=Annotated[widgets.ProgressBar, {"visible": False}]
119+
)
120+
assert isinstance(wdg2, widgets.ProgressBar)
121+
assert not wdg2.visible
122+
123+
113124
# fmt: off
114125
class MyBadWidget:
115126
"""INCOMPLETE widget implementation and will error."""

0 commit comments

Comments
 (0)