From e827e0cf4222456b01b1a728b564fa0642e3ea33 Mon Sep 17 00:00:00 2001 From: mikebender Date: Fri, 12 Jun 2026 11:40:34 -0400 Subject: [PATCH] chore(ui): clean up Element key typing, render signature, and component naming - Change BaseElement key type from str to Key - Remove the unused RenderContext parameter from Element.render() - Rename make_component to component - Remove now-unused RenderContext imports --- .../src/deephaven/ui/components/__init__.py | 2 +- .../ui/src/deephaven/ui/components/basic.py | 25 +++++++++++++++++-- .../src/deephaven/ui/components/calendar.py | 4 +-- .../{make_component.py => component.py} | 2 +- .../src/deephaven/ui/components/date_field.py | 4 +-- .../deephaven/ui/components/date_picker.py | 4 +-- .../ui/components/date_range_picker.py | 4 +-- .../deephaven/ui/components/range_calendar.py | 4 +-- .../ui/src/deephaven/ui/components/router.py | 3 +-- .../ui/src/deephaven/ui/components/table.py | 4 +-- .../src/deephaven/ui/components/time_field.py | 4 +-- .../src/deephaven/ui/elements/BaseElement.py | 9 ++++--- .../ui/elements/ContextProviderElement.py | 4 +-- .../ui/src/deephaven/ui/elements/Element.py | 10 +++----- .../deephaven/ui/elements/FunctionElement.py | 7 ++---- .../src/deephaven/ui/elements/UriElement.py | 3 +-- .../ui/src/deephaven/ui/renderer/Renderer.py | 2 +- plugins/ui/test/deephaven/ui/test_ui_table.py | 2 +- 18 files changed, 55 insertions(+), 42 deletions(-) rename plugins/ui/src/deephaven/ui/components/{make_component.py => component.py} (93%) diff --git a/plugins/ui/src/deephaven/ui/components/__init__.py b/plugins/ui/src/deephaven/ui/components/__init__.py index 26f9eae1b..97677b1c5 100644 --- a/plugins/ui/src/deephaven/ui/components/__init__.py +++ b/plugins/ui/src/deephaven/ui/components/__init__.py @@ -48,7 +48,7 @@ from .list_action_menu import list_action_menu from .list_view import list_view from .logic_button import logic_button -from .make_component import make_component as component +from .component import component from .markdown import markdown from .menu import menu from .menu_trigger import menu_trigger diff --git a/plugins/ui/src/deephaven/ui/components/basic.py b/plugins/ui/src/deephaven/ui/components/basic.py index df61bf591..507213fd4 100644 --- a/plugins/ui/src/deephaven/ui/components/basic.py +++ b/plugins/ui/src/deephaven/ui/components/basic.py @@ -1,14 +1,35 @@ from __future__ import annotations from typing import Any from ..elements import BaseElement, NodeType +from ..types import Key NAME_PREFIX = "deephaven.ui.components." -def component_element(name: str, /, *children: NodeType, **props: Any) -> BaseElement: +def component_element( + name: str, + /, + *children: NodeType, + key: Key | None = None, + _nullable_props: list[str] = [], + **props: Any, +) -> BaseElement: """ Base class for UI elements. All names are automatically prefixed with "deephaven.ui.components.", and all props are automatically camelCased. + + Args: + name: The name of the element, e.g. "button", "input", "my_component", etc. The full name of the element will be "deephaven.ui.components.{name}". + children: The children of the element. + key: The key for the element. + _nullable_props: A list of prop names that can be set to None. + props: The props for the element. """ - return BaseElement(f"{NAME_PREFIX}{name}", *children, **props) + return BaseElement( + f"{NAME_PREFIX}{name}", + *children, + key=key, + _nullable_props=_nullable_props, + **props, + ) diff --git a/plugins/ui/src/deephaven/ui/components/calendar.py b/plugins/ui/src/deephaven/ui/components/calendar.py index 400c54494..e8f0a664a 100644 --- a/plugins/ui/src/deephaven/ui/components/calendar.py +++ b/plugins/ui/src/deephaven/ui/components/calendar.py @@ -17,7 +17,7 @@ from .._internal.utils import create_props, convert_date_props, wrap_local_date_callable from ..types import Date, LocalDateConvertible, Undefined, UndefinedType from .basic import component_element -from .make_component import make_component +from .component import component CalendarElement = Element @@ -74,7 +74,7 @@ def _convert_calendar_props( return props -@make_component +@component def calendar( value: Date | None | UndefinedType = Undefined, default_value: Date | None | UndefinedType = Undefined, diff --git a/plugins/ui/src/deephaven/ui/components/make_component.py b/plugins/ui/src/deephaven/ui/components/component.py similarity index 93% rename from plugins/ui/src/deephaven/ui/components/make_component.py rename to plugins/ui/src/deephaven/ui/components/component.py index 4d045b349..2c52b6777 100644 --- a/plugins/ui/src/deephaven/ui/components/make_component.py +++ b/plugins/ui/src/deephaven/ui/components/component.py @@ -8,7 +8,7 @@ logger = logging.getLogger(__name__) -def make_component(func: Callable[..., Any]): +def component(func: Callable[..., Any]): """ Create a FunctionalElement from the passed in function. diff --git a/plugins/ui/src/deephaven/ui/components/date_field.py b/plugins/ui/src/deephaven/ui/components/date_field.py index 8dafbd244..3c11673a5 100644 --- a/plugins/ui/src/deephaven/ui/components/date_field.py +++ b/plugins/ui/src/deephaven/ui/components/date_field.py @@ -27,7 +27,7 @@ ) from ..types import Date, Granularity, Undefined, UndefinedType from .basic import component_element -from .make_component import make_component +from .component import component from deephaven.time import dh_now DateFieldElement = Element @@ -75,7 +75,7 @@ def _convert_date_field_props( return props -@make_component +@component def date_field( placeholder_value: Date | None = dh_now(), value: Date | None | UndefinedType = Undefined, diff --git a/plugins/ui/src/deephaven/ui/components/date_picker.py b/plugins/ui/src/deephaven/ui/components/date_picker.py index 8520308d9..94232265b 100644 --- a/plugins/ui/src/deephaven/ui/components/date_picker.py +++ b/plugins/ui/src/deephaven/ui/components/date_picker.py @@ -31,7 +31,7 @@ ) from ..types import Date, Granularity, Undefined, UndefinedType from .basic import component_element -from .make_component import make_component +from .component import component DatePickerElement = Element @@ -79,7 +79,7 @@ def _convert_date_picker_props( return props -@make_component +@component def date_picker( placeholder_value: Date | None = None, value: Date | None | UndefinedType = Undefined, diff --git a/plugins/ui/src/deephaven/ui/components/date_range_picker.py b/plugins/ui/src/deephaven/ui/components/date_range_picker.py index acd56feb2..d092c71a8 100644 --- a/plugins/ui/src/deephaven/ui/components/date_range_picker.py +++ b/plugins/ui/src/deephaven/ui/components/date_range_picker.py @@ -31,7 +31,7 @@ ) from ..types import Date, Granularity, DateRange, Undefined, UndefinedType from .basic import component_element -from .make_component import make_component +from .component import component from deephaven.time import dh_now DatePickerElement = Element @@ -78,7 +78,7 @@ def _convert_date_range_picker_props( return props -@make_component +@component def date_range_picker( placeholder_value: Date | None = None, value: DateRange | None | UndefinedType = Undefined, diff --git a/plugins/ui/src/deephaven/ui/components/range_calendar.py b/plugins/ui/src/deephaven/ui/components/range_calendar.py index f006e3f9e..5e4aa51c1 100644 --- a/plugins/ui/src/deephaven/ui/components/range_calendar.py +++ b/plugins/ui/src/deephaven/ui/components/range_calendar.py @@ -23,7 +23,7 @@ UndefinedType, ) from .basic import component_element -from .make_component import make_component +from .component import component RangeCalendarElement = Element @@ -78,7 +78,7 @@ def _convert_range_calendar_props( return props -@make_component +@component def range_calendar( value: DateRange | None | UndefinedType = Undefined, default_value: DateRange | None | UndefinedType = Undefined, diff --git a/plugins/ui/src/deephaven/ui/components/router.py b/plugins/ui/src/deephaven/ui/components/router.py index 7023bb683..ba67227ff 100644 --- a/plugins/ui/src/deephaven/ui/components/router.py +++ b/plugins/ui/src/deephaven/ui/components/router.py @@ -7,8 +7,7 @@ from ..elements import create_context from ..hooks import use_path, use_memo from .route import _Route -from .make_component import make_component as component - +from .component import component # Module-level context for route params _route_params_context = create_context({}) diff --git a/plugins/ui/src/deephaven/ui/components/table.py b/plugins/ui/src/deephaven/ui/components/table.py index b24812bd7..b2ae56afa 100644 --- a/plugins/ui/src/deephaven/ui/components/table.py +++ b/plugins/ui/src/deephaven/ui/components/table.py @@ -18,7 +18,7 @@ SelectionChangeCallback, TableLike, ) -from .._internal import dict_to_react_props, RenderContext +from .._internal import dict_to_react_props logger = logging.getLogger(__name__) @@ -397,6 +397,6 @@ def name(self): def key(self) -> str | None: return self._key - def render(self, context: RenderContext) -> dict[str, Any]: + def render(self) -> dict[str, Any]: logger.debug("Returning props %s", self._props) return dict_to_react_props(self._props) diff --git a/plugins/ui/src/deephaven/ui/components/time_field.py b/plugins/ui/src/deephaven/ui/components/time_field.py index 91d1129d5..dd1da6b01 100644 --- a/plugins/ui/src/deephaven/ui/components/time_field.py +++ b/plugins/ui/src/deephaven/ui/components/time_field.py @@ -27,7 +27,7 @@ ) from ..types import Time, TimeGranularity, Undefined, UndefinedType from .basic import component_element -from .make_component import make_component +from .component import component TimeFieldElement = Element @@ -70,7 +70,7 @@ def _convert_time_field_props( return props -@make_component +@component def time_field( placeholder_value: Time | None = None, value: Time | None | UndefinedType = Undefined, diff --git a/plugins/ui/src/deephaven/ui/elements/BaseElement.py b/plugins/ui/src/deephaven/ui/elements/BaseElement.py index d6cb0c6c4..de3a0167b 100644 --- a/plugins/ui/src/deephaven/ui/elements/BaseElement.py +++ b/plugins/ui/src/deephaven/ui/elements/BaseElement.py @@ -2,7 +2,8 @@ from typing import Any from .Element import Element, NodeType -from .._internal import dict_to_react_props, RenderContext +from .._internal import dict_to_react_props +from ..types import Key class BaseElement(Element): @@ -23,7 +24,7 @@ def __init__( name: str, /, *children: NodeType, - key: str | None = None, + key: Key | None = None, _nullable_props: list[str] = [], **props: Any, ): @@ -47,8 +48,8 @@ def name(self) -> str: return self._name @property - def key(self) -> str | None: + def key(self) -> Key | None: return self._key - def render(self, context: RenderContext) -> dict[str, Any]: + def render(self) -> dict[str, Any]: return self._props diff --git a/plugins/ui/src/deephaven/ui/elements/ContextProviderElement.py b/plugins/ui/src/deephaven/ui/elements/ContextProviderElement.py index 380fe8ae9..c3bbdd2c9 100644 --- a/plugins/ui/src/deephaven/ui/elements/ContextProviderElement.py +++ b/plugins/ui/src/deephaven/ui/elements/ContextProviderElement.py @@ -2,7 +2,7 @@ from typing import Any, Generic, TypeVar from .Element import Element, PropsType -from .._internal import RenderContext, _get_context_stack, get_context +from .._internal import _get_context_stack, get_context T = TypeVar("T") @@ -31,7 +31,7 @@ def __init__(self, context: Context, value: Any, *children: Any): def name(self) -> str: return "deephaven.ui.elements.ContextProviderElement" - def render(self, context: RenderContext) -> PropsType: + def render(self) -> PropsType: self._context._push(self._value) get_context().add_open_cleanup(lambda: self._context._pop()) diff --git a/plugins/ui/src/deephaven/ui/elements/Element.py b/plugins/ui/src/deephaven/ui/elements/Element.py index ebdd74a51..61fc5599b 100644 --- a/plugins/ui/src/deephaven/ui/elements/Element.py +++ b/plugins/ui/src/deephaven/ui/elements/Element.py @@ -1,10 +1,9 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Any, Dict, List, Tuple, Union -from .._internal import RenderContext +from typing import Any, List, Mapping, Tuple, Union -PropsType = Dict[str, Any] +PropsType = Mapping[str, Any] class Element(ABC): @@ -33,14 +32,11 @@ def key(self) -> str | None: return None @abstractmethod - def render(self, context: RenderContext) -> PropsType: + def render(self) -> PropsType: """ Renders this element, and returns the result as a dictionary of props for the element. If you just want to render children, pass back a dict with children only, e.g. { "children": ... } - Args: - context: Deprecated. The context to render the element in. Should already be opened before calling this method. - Returns: The props of this element. """ diff --git a/plugins/ui/src/deephaven/ui/elements/FunctionElement.py b/plugins/ui/src/deephaven/ui/elements/FunctionElement.py index 6b1ea35f9..4ded69000 100644 --- a/plugins/ui/src/deephaven/ui/elements/FunctionElement.py +++ b/plugins/ui/src/deephaven/ui/elements/FunctionElement.py @@ -2,7 +2,6 @@ import logging from typing import Callable from .Element import Element, PropsType -from .._internal import RenderContext logger = logging.getLogger(__name__) @@ -17,6 +16,7 @@ def __init__( Args: name: Name of the component. Typically, the module joined with the name of the function. render: The render function to call when the component needs to be rendered. + key: The key of this element. """ self._name = name self._render = render @@ -30,13 +30,10 @@ def name(self): def key(self) -> str | None: return self._key - def render(self, context: RenderContext) -> PropsType: + def render(self) -> PropsType: """ Render the component. Should only be called when actually rendering the component, e.g. exporting it to the client. - Args: - context: Context to render the component in - Returns: The props of this element. """ diff --git a/plugins/ui/src/deephaven/ui/elements/UriElement.py b/plugins/ui/src/deephaven/ui/elements/UriElement.py index 7eaf53c7f..3160502a8 100644 --- a/plugins/ui/src/deephaven/ui/elements/UriElement.py +++ b/plugins/ui/src/deephaven/ui/elements/UriElement.py @@ -1,7 +1,6 @@ from __future__ import annotations from .Element import Element, PropsType -from .._internal import RenderContext class UriElement(Element): @@ -29,7 +28,7 @@ def name(self) -> str: def key(self) -> str | None: return self._key - def render(self, context: RenderContext) -> PropsType: + def render(self) -> PropsType: return {"uri": self._uri} def __eq__(self, other: object) -> bool: diff --git a/plugins/ui/src/deephaven/ui/renderer/Renderer.py b/plugins/ui/src/deephaven/ui/renderer/Renderer.py index 8f149b566..afea0d013 100644 --- a/plugins/ui/src/deephaven/ui/renderer/Renderer.py +++ b/plugins/ui/src/deephaven/ui/renderer/Renderer.py @@ -120,7 +120,7 @@ def _render_element(element: Element, context: RenderContext) -> RenderedNode: logger.debug("Rendering element %s in context %s", element.name, context) with context.open(): - props = element.render(context) + props = element.render() # We also need to render any elements that are passed in as props (including `children`) props = _render_dict_in_open_context(props, context) diff --git a/plugins/ui/test/deephaven/ui/test_ui_table.py b/plugins/ui/test/deephaven/ui/test_ui_table.py index 37f17dc2a..d8300c361 100644 --- a/plugins/ui/test/deephaven/ui/test_ui_table.py +++ b/plugins/ui/test/deephaven/ui/test_ui_table.py @@ -38,7 +38,7 @@ def expect_render(self, ui_table, expected_props: dict[str, Any]): on_change = Mock() on_queue = Mock() context = RenderContext(_TestRoot(on_change, on_queue)) - result = ui_table.render(context) + result = ui_table.render() self.assertDictEqual(result, result | expected_props)