]> skyeroc.xyz Git - obs-ctl/commitdiff
Improve make_pane docstring and function signatures
authorsbkelley <sb24kelley@gmail.com>
Sun, 7 Dec 2025 16:01:14 +0000 (11:01 -0500)
committersbkelley <sb24kelley@gmail.com>
Sun, 7 Dec 2025 16:01:14 +0000 (11:01 -0500)
src/obs_ctl/interface/molecule/settings_block/pane.py
src/obs_ctl/interface/molecule/settings_block/pane.pyi
src/obs_ctl/interface/molecule/settings_block/settings_block.py

index 1607f6de1a74f6cd4401519927c11031c09522e2..8855c6bbde1ad2675a5b8fe268b0535b95012ecc 100644 (file)
@@ -67,7 +67,7 @@ class SettingsWidget(Enum):
 
 
 type MakeWidgetOutputType = tuple[str, SettingsWidget, Any, ParamsType]
-def make_settings_widget(name: str, type: SettingsWidget, default: Any, *args, **kwargs) -> MakeWidgetOutputType:
+def make_pane_widget(name: str, type: SettingsWidget, default: Any, *args, **kwargs) -> MakeWidgetOutputType:
     return (name, type, default, (args, kwargs))
 
 
@@ -76,34 +76,58 @@ type KWArgsType = Mapping[str, Any]
 type ParamsType = tuple[ArgsType, KWArgsType] | None
 type ParamsListType = Sequence[ParamsType]
 type LoopListType = Sequence[MakeWidgetOutputType]
-def make_pane_subclass(
+def make_pane(
         cls_name: str,
-        settings_name_list: list[str] | LoopListType,
+        *args,
+        names_list: list[str] | LoopListType | None=None,
         settings_type_list: list[SettingsWidget] | None=None,
-        settings_default_list: list[Any] | None=None,
-        settings_type_params_list: ParamsListType | None=None,
+        defaults_list: list[Any] | None=None,
+        params_list: ParamsListType | None=None,
         ) -> type[PaneBase]:
     """Creates a new TabPane subclass with cls_name as its name.
-    
-     settings_list should be a list of names for settings.
-     settings_type_list should be a list of pane.SettingsType members
-     settings_default_list should be a list of defaults, for the settings.
-     
-     Returned widget will have appropriate messages for each input field.
-     
-     For example, pane_factory("Settings", ["record_path"], [pane.SettingsType.STRING], [""])
-     will return a TabPane with a Label and an Input box, a reactive attribute "record_path",
-     a watch_record_path function to update the Input value, and an on_record_path_changed
-     function, which emits a RecordPathChanged message containing a value when the user
-     submits the input."""
-    row_height = 1
-    if settings_type_list is None and settings_default_list is None and settings_type_params_list is None:
-        loop_list: LoopListType = settings_name_list # type: ignore
+
+    All the arguments must be keyword arguments, or all of the arguments
+    must be positional pane.make_pane_widget() results.
+
+    If provided:
+        **name_list** must be a list of names for settings.
+        **settings_type_list** must be a list of pane.SettingsType members
+        **default_list** must be a list of defaults, for the settings.
+        **params_list** is optionally a tuple of args and kwarg, passed into
+        the constructor for the particular Textual Widget created.
+        eg: (("foo", "bar"), {"buz":5})
+
+    Returned widget will have appropriate messages for each input field.
+
+    For example:
+    ```python
+        >>> pane_factory("Settings",
+                name_list=["record_path"],
+                settings_type_list=[pane.SettingsType.STRING],
+                defaults_list=[""])
+        ... [TabPane Instance]
+        >>> pane_factory("Settings",
+                pane.make_settings_widget(
+                    "record_path",
+                    pane.SettingsWidget.STRING,
+                    ""))
+        ... [Equivalent (But Not Identical) TabPane Instance]
+    ```
+    The returned a TabPane will have:
+        A reactive attribute "record_path"
+        A watch_record_path function to update the Input's value
+        An on_record_path_changed function, which (upon Input submission) emits ...
+        A RecordPathChanged message containing the submitted value.
+    """
+    # Detect whether this is a "looplist" style input or a parameters style input
+    ROW_HEIGHT = 1
+    if names_list is not None:
+        params_list = params_list if params_list is not None else ( ((), dict()), )
+        loop_list: LoopListType = list(zip_longest(names_list, settings_type_list, defaults_list, params_list)) # type: ignore
     else:
-        settings_type_params_list = settings_type_params_list if settings_type_params_list is not None else ( ((), dict()), )
-        loop_list: LoopListType = list(zip_longest(settings_name_list, settings_type_list, settings_default_list, settings_type_params_list)) # type: ignore
+        loop_list: LoopListType = args # type: ignore
 
-    DEFAULT_CSS = f"Grid {{grid-size:2;grid-rows:{row_height};min-height:{len(loop_list)*row_height}}}"
+    DEFAULT_CSS = f"Grid {{grid-size:2;grid-rows:{ROW_HEIGHT};min-height:{len(loop_list)*ROW_HEIGHT}}}"
 
     def make_watch_reactive(watch_id: str):
         def watch_func(self: PaneBase, value: Any):
@@ -144,7 +168,7 @@ def make_pane_subclass(
     new_dict: dict[str, Any] = dict()
     for setting_name, setting_type, setting_default, _ in loop_list:
         control_setting_id: str = f"{setting_type.widget.__name__.lower()}_{setting_name}"
-        SettingChanged_name: str = f"{snake_to_camel(setting_name)}Changed"
+        SettingChanged_name: str = f"{_snake_to_camel(setting_name)}Changed"
         watch_setting_name: str = f"watch_{setting_name}"
         on_setting_changed_name: str = f"on_{setting_name}_changed"
         # For each desired setting (e.g. 'record_path'):
@@ -172,5 +196,5 @@ def make_pane_subclass(
     new_pane: type[PaneBase] = type(cls_name, (PaneBase,), new_dict)
     return new_pane
 
-def snake_to_camel(string: str):
+def _snake_to_camel(string: str):
     return str.join("", [str.capitalize(x) for x in string.split("_")])
\ No newline at end of file
index 0bc115c1e938bb841e9cc8e57e30dc64e5efb47b..9bc72f0f165f185ce48214ef895cbec6ab2fca72 100644 (file)
@@ -33,18 +33,19 @@ type KWArgsType = Mapping[str, Any]
 type ParamsType = tuple[ArgsType, KWArgsType]
 type ParamsListType = Sequence[ParamsType | None]
 @overload
-def make_pane_subclass(
+def make_pane(
         cls_name: str,
-        settings_list: Sequence[str],
+        *,
+        names_list: Sequence[str],
         settings_type_list: Sequence[SettingsWidget],
         defaults_list: Sequence[Any],
         params_list: ParamsListType | None=None,
         ) -> type[PaneBase]: ...
 @overload
-def make_pane_subclass(
+def make_pane(
         cls_name: str,
-        settings_list: Sequence[MakeWidgetOutputType],
+        *args: MakeWidgetOutputType,
         ) -> type[PaneBase]: ...
 
 type MakeWidgetOutputType = tuple[str, SettingsWidget, Any, ParamsType]
-def make_settings_widget(name: str, type: SettingsWidget, default: Any, *args: Any, **kwargs: Any) -> MakeWidgetOutputType: ...
\ No newline at end of file
+def make_pane_widget(name: str, type: SettingsWidget, default: Any, *args: Any, **kwargs: Any) -> MakeWidgetOutputType: ...
\ No newline at end of file
index f6aeb944f32a915d1a9ef39f3f51aed66aa5271d..2db850107f1a93e357a0a4ce9a762866012281cd 100644 (file)
@@ -6,29 +6,27 @@ from . import pane
 
 logger = getLogger(__name__)
 
-OBSSettingsPane = pane.make_pane_subclass(
+OBSSettingsPane = pane.make_pane(
     "OBSSettingsPane",
-    ["record_path"],
-    [pane.SettingsWidget.STRING],
-    [""],
-    [((), {"compact":True}),]
+    names_list=["record_path"],
+    settings_type_list=[pane.SettingsWidget.STRING],
+    defaults_list=[""],
+    params_list=[((), {"compact":True}),]
 )
 
-OBSWebSocketPane = pane.make_pane_subclass(
+OBSWebSocketPane = pane.make_pane(
     "OBSWebSocketPane",
-    [
-        pane.make_settings_widget("host", pane.SettingsWidget.STRING, "localhost", compact=True),
-        pane.make_settings_widget("port", pane.SettingsWidget.INT, 4455, compact=True),
-        pane.make_settings_widget("password", pane.SettingsWidget.STRING, "", compact=True),
-        pane.make_settings_widget("timeout", pane.SettingsWidget.FLOAT, 1.0, compact=True)
-    ]
+    pane.make_pane_widget("host", pane.SettingsWidget.STRING, "localhost", compact=True),
+    pane.make_pane_widget("port", pane.SettingsWidget.INT, 4455, compact=True),
+    pane.make_pane_widget("password", pane.SettingsWidget.STRING, "", compact=True),
+    pane.make_pane_widget("timeout", pane.SettingsWidget.FLOAT, 1.0, compact=True),
 )
 
-OBSCTLPane = pane.make_pane_subclass(
+OBSCTLPane = pane.make_pane(
     "OBSCTLPane",
-    ["nothing"],
-    [pane.SettingsWidget.STRING],
-    ["zilch"]
+    names_list=["nothing"],
+    settings_type_list=[pane.SettingsWidget.STRING],
+    defaults_list=["zilch"]
 )
 
 class SettingsBlock(Container):