From 7413d7da410926d6d61066078957bf1c8a97966b Mon Sep 17 00:00:00 2001 From: c-bata Date: Thu, 13 Apr 2023 19:00:22 +0900 Subject: [PATCH 1/3] Remove user_attr_key attribute from ObjectiveUserAttrRef --- optuna_dashboard/_form_widget.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/optuna_dashboard/_form_widget.py b/optuna_dashboard/_form_widget.py index 5f0c6746..596cd91e 100644 --- a/optuna_dashboard/_form_widget.py +++ b/optuna_dashboard/_form_widget.py @@ -150,14 +150,13 @@ class TextInputWidget: @dataclass class ObjectiveUserAttrRef: key: str - # TODO(c-bata): Remove this attribute - user_attr_key: Optional[str] = None def to_dict(self) -> UserAttrRefJSON: return { "type": "user_attr", "key": self.key, - "user_attr_key": self.user_attr_key, + # Set 'user_attr_key' to simplify the frontend source code. + "user_attr_key": self.key, } @classmethod From 5c43d96236df896045972dde6b4b645168067a52 Mon Sep 17 00:00:00 2001 From: c-bata Date: Thu, 13 Apr 2023 19:27:28 +0900 Subject: [PATCH 2/3] Fix mypy errors --- optuna_dashboard/_form_widget.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/optuna_dashboard/_form_widget.py b/optuna_dashboard/_form_widget.py index 596cd91e..e7e96d30 100644 --- a/optuna_dashboard/_form_widget.py +++ b/optuna_dashboard/_form_widget.py @@ -13,6 +13,7 @@ if TYPE_CHECKING: from typing import Any from typing import Literal from typing import Optional + from typing import Sequence from typing import TypedDict ChoiceWidgetJSON = TypedDict( @@ -53,7 +54,7 @@ if TYPE_CHECKING: "FormWidgetJSON", { "output_type": Literal["objective", "user_attr"], - "widgets": list[ + "widgets": Sequence[ Union[ChoiceWidgetJSON, SliderWidgetJSON, TextInputWidgetJSON, UserAttrRefJSON] ], }, @@ -201,7 +202,7 @@ def register_objective_form_widgets( ) -> None: if len(study.directions) != len(widgets): raise ValueError("The length of actions must be the same with the number of objectives.") - if any(w.user_attr_key is not None for w in widgets): + if any(not isinstance(w, ObjectiveUserAttrRef) and w.user_attr_key is not None for w in widgets): warnings.warn("`user_attr_key` specified, but it will not be used.") form_widgets: FormWidgetJSON = { "output_type": "objective", @@ -213,13 +214,22 @@ def register_objective_form_widgets( def register_user_attr_form_widgets( study: optuna.Study, widgets: list[ObjectiveFormWidget] ) -> None: - if any(w.user_attr_key is None for w in widgets): - raise ValueError("`user_attr_key` is not specified.") - if len(widgets) != len(set(w.user_attr_key for w in widgets)): + user_attr_keys = set() + widget_dicts: list[Union[ChoiceWidgetJSON, SliderWidgetJSON, TextInputWidgetJSON]] = [] + for w in widgets: + if isinstance(w, ObjectiveUserAttrRef): + raise ValueError("ObjectiveUserAttrRef can't be specified in register_user_attr_form_widgets.") + if w.user_attr_key is None: + raise ValueError("`user_attr_key` is not specified.") + user_attr_keys.add(w.user_attr_key) + widget_dicts.append(w.to_dict()) + + if len(widget_dicts) != len(user_attr_keys): raise ValueError("`user_attr_key` must be unique for each widget.") + form_widgets: FormWidgetJSON = { "output_type": "user_attr", - "widgets": [w.to_dict() for w in widgets], + "widgets": widget_dicts, } study._storage.set_study_system_attr(study._study_id, FORM_WIDGETS_KEY, form_widgets) From 6da6480edd74f87e5c2d6bd06ba1e08b3bf1ca42 Mon Sep 17 00:00:00 2001 From: c-bata Date: Thu, 13 Apr 2023 19:30:17 +0900 Subject: [PATCH 3/3] Introduce UserAttrFormWidget type --- optuna_dashboard/_form_widget.py | 13 +++++-------- optuna_dashboard/ts/types/index.d.ts | 20 ++++++++++++++------ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/optuna_dashboard/_form_widget.py b/optuna_dashboard/_form_widget.py index e7e96d30..e78ee4fc 100644 --- a/optuna_dashboard/_form_widget.py +++ b/optuna_dashboard/_form_widget.py @@ -46,10 +46,7 @@ if TYPE_CHECKING: "TextInputWidgetJSON", {"type": Literal["text"], "description": Optional[str], "user_attr_key": Optional[str]}, ) - UserAttrRefJSON = TypedDict( - "UserAttrRefJSON", - {"type": Literal["user_attr"], "key": str, "user_attr_key": Optional[str]}, - ) + UserAttrRefJSON = TypedDict("UserAttrRefJSON", {"type": Literal["user_attr"], "key": str}) FormWidgetJSON = TypedDict( "FormWidgetJSON", { @@ -156,8 +153,6 @@ class ObjectiveUserAttrRef: return { "type": "user_attr", "key": self.key, - # Set 'user_attr_key' to simplify the frontend source code. - "user_attr_key": self.key, } @classmethod @@ -202,7 +197,9 @@ def register_objective_form_widgets( ) -> None: if len(study.directions) != len(widgets): raise ValueError("The length of actions must be the same with the number of objectives.") - if any(not isinstance(w, ObjectiveUserAttrRef) and w.user_attr_key is not None for w in widgets): + if any( + not isinstance(w, ObjectiveUserAttrRef) and w.user_attr_key is not None for w in widgets + ): warnings.warn("`user_attr_key` specified, but it will not be used.") form_widgets: FormWidgetJSON = { "output_type": "objective", @@ -218,7 +215,7 @@ def register_user_attr_form_widgets( widget_dicts: list[Union[ChoiceWidgetJSON, SliderWidgetJSON, TextInputWidgetJSON]] = [] for w in widgets: if isinstance(w, ObjectiveUserAttrRef): - raise ValueError("ObjectiveUserAttrRef can't be specified in register_user_attr_form_widgets.") + raise ValueError("ObjectiveUserAttrRef can't be specified.") if w.user_attr_key is None: raise ValueError("`user_attr_key` is not specified.") user_attr_keys.add(w.user_attr_key) diff --git a/optuna_dashboard/ts/types/index.d.ts b/optuna_dashboard/ts/types/index.d.ts index 9e8b4456..24548a2c 100644 --- a/optuna_dashboard/ts/types/index.d.ts +++ b/optuna_dashboard/ts/types/index.d.ts @@ -157,20 +157,28 @@ type ObjectiveTextInputWidget = { type ObjectiveUserAttrRef = { type: "user_attr" key: string - user_attr_key?: string } -// TODO(kenshin): Rename this type to FormWidget or something. type ObjectiveFormWidget = | ObjectiveChoiceWidget | ObjectiveSliderWidget | ObjectiveTextInputWidget | ObjectiveUserAttrRef -type FormWidgets = { - output_type: "objective" | "user_attr" - widgets: ObjectiveFormWidget[] -} +type UserAttrFormWidget = + | ObjectiveChoiceWidget + | ObjectiveSliderWidget + | ObjectiveTextInputWidget + +type FormWidgets = + | { + output_type: "objective" + widgets: ObjectiveFormWidget[] + } + | { + output_type: "user_attr" + widgets: UserAttrFormWidget[] + } type StudyDetail = { id: number