Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add undefined type #966

Closed
wants to merge 16 commits into from
41 changes: 28 additions & 13 deletions plugins/ui/src/deephaven/ui/_internal/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import sys
from functools import partial
from deephaven.time import to_j_instant, to_j_zdt, to_j_local_date, to_j_local_time
from deephaven.dtypes import ZonedDateTime, Instant

from ..types import (
Date,
Expand All @@ -15,6 +14,7 @@
JavaTime,
LocalDateConvertible,
LocalDate,
Undefined,
)

T = TypeVar("T")
Expand All @@ -36,6 +36,21 @@
}


def is_nullish(value: Any) -> bool:
"""
Check if the value is None or Undefined. Although the `__eq__` method for Undefined exists, Python uses the
`__eq__` method of the left hand side object. If that method is defined, such as afor Java wrapped types, the
behaviour is unexpected.

Args:
value: The value to check.

Returns:
If the value is nullish.
"""
return value is None or value is Undefined


def get_component_name(component: Any) -> str:
"""
Get the name of the component
Expand Down Expand Up @@ -163,7 +178,7 @@ def remove_empty_keys(dict: dict[str, Any]) -> dict[str, Any]:
Returns:
The dict with keys removed.
"""
return {k: v for k, v in dict.items() if v is not None}
return {k: v for k, v in dict.items() if v is not Undefined}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory after this change, this should be the only place that really needs to check for Undefined ... we should be removing it at this point so it shouldn't need to be known at the ElementMessageStream level or anything.



def _wrapped_callable(
Expand Down Expand Up @@ -481,7 +496,7 @@ def _get_first_set_key(props: dict[str, Any], sequence: Sequence[str]) -> str |
The first non-None prop, or None if all props are None.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The first non-None prop, or None if all props are None.
The first non-nullish prop, or None if all props are None.

"""
for key in sequence:
if props.get(key) is not None:
if not is_nullish(props.get(key)):
return key
return None

Expand Down Expand Up @@ -666,11 +681,11 @@ def convert_date_props(
The converted props.
"""
for key in simple_date_props:
if props.get(key) is not None:
if not is_nullish(props.get(key)):
props[key] = _convert_to_java_date(props[key])

for key in date_range_props:
if props.get(key) is not None:
if not is_nullish(props.get(key)):
props[key] = convert_date_range(props[key], _convert_to_java_date)

# the simple props must be converted before this to simplify the callable conversion
Expand All @@ -680,25 +695,25 @@ def convert_date_props(
# Local Dates will default to DAY but we need to default to SECOND for the other types
if (
granularity_key is not None
and props.get(granularity_key) is None
and is_nullish(props.get(granularity_key))
and converter != to_j_local_date
):
props[granularity_key] = "SECOND"

# now that the converter is set, we can convert simple props to strings
# no.w that the converter is set, we can convert simple props to strings
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# no.w that the converter is set, we can convert simple props to strings
# now that the converter is set, we can convert simple props to strings

for key in simple_date_props:
if props.get(key) is not None:
if not is_nullish(props.get(key)):
props[key] = str(props[key])

# and convert the date range props to strings
for key in date_range_props:
if props.get(key) is not None:
if not is_nullish(props.get(key)):
props[key] = convert_date_range(props[key], str)

# wrap the date callable with the convert
# if there are date range props, we need to convert as a date range
for key in callable_date_props:
if props.get(key) is not None:
if not is_nullish(props.get(key)):
if not callable(props[key]):
raise TypeError(f"{key} must be a callable")
if len(date_range_props) > 0:
Expand Down Expand Up @@ -730,20 +745,20 @@ def convert_time_props(
The converted props.
"""
for key in simple_time_props:
if props.get(key) is not None:
if not is_nullish(props.get(key)):
props[key] = _convert_to_java_time(props[key])

# the simple props must be converted before this to simplify the callable conversion
converter = _prioritized_time_callable_converter(props, priority, default_converter)

# now that the converter is set, we can convert simple props to strings
for key in simple_time_props:
if props.get(key) is not None:
if not is_nullish(props.get(key)):
props[key] = str(props[key])

# wrap the date callable with the convert
for key in callable_time_props:
if props.get(key) is not None:
if not is_nullish(props.get(key)):
if not callable(props[key]):
raise TypeError(f"{key} must be a callable")
props[key] = _wrap_time_callable(props[key], converter)
Expand Down
127 changes: 64 additions & 63 deletions plugins/ui/src/deephaven/ui/components/action_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,76 +22,77 @@

from .basic import component_element
from ..elements import Element
from ..types import UndefinedType, Undefined

ActionButtonElement = Element


def action_button(
*children: Any,
type: ButtonType = "button",
on_press: PressEventCallable | None = None,
on_press_start: PressEventCallable | None = None,
on_press_end: PressEventCallable | None = None,
on_press_up: PressEventCallable | None = None,
on_press_change: Callable[[bool], None] | None = None,
on_focus: FocusEventCallable | None = None,
on_blur: FocusEventCallable | None = None,
on_focus_change: Callable[[bool], None] | None = None,
on_key_down: KeyboardEventCallable | None = None,
on_key_up: KeyboardEventCallable | None = None,
auto_focus: bool | None = None,
is_disabled: bool | None = None,
is_quiet: bool | None = None,
static_color: StaticColor | None = None,
flex: LayoutFlex | None = None,
flex_grow: float | None = None,
flex_shrink: float | None = None,
flex_basis: DimensionValue | None = None,
align_self: AlignSelf | None = None,
justify_self: JustifySelf | None = None,
order: int | None = None,
grid_area: str | None = None,
grid_row: str | None = None,
grid_row_start: str | None = None,
grid_row_end: str | None = None,
grid_column: str | None = None,
grid_column_start: str | None = None,
grid_column_end: str | None = None,
margin: DimensionValue | None = None,
margin_top: DimensionValue | None = None,
margin_bottom: DimensionValue | None = None,
margin_start: DimensionValue | None = None,
margin_end: DimensionValue | None = None,
margin_x: DimensionValue | None = None,
margin_y: DimensionValue | None = None,
width: DimensionValue | None = None,
height: DimensionValue | None = None,
min_width: DimensionValue | None = None,
min_height: DimensionValue | None = None,
max_width: DimensionValue | None = None,
max_height: DimensionValue | None = None,
position: Position | None = None,
top: DimensionValue | None = None,
bottom: DimensionValue | None = None,
start: DimensionValue | None = None,
end: DimensionValue | None = None,
left: DimensionValue | None = None,
right: DimensionValue | None = None,
z_index: int | None = None,
is_hidden: bool | None = None,
id: str | None = None,
exclude_from_tab_order: bool | None = None,
aria_expanded: AriaExpanded | None = None,
aria_haspopup: AriaHasPopup | None = None,
aria_controls: str | None = None,
aria_label: str | None = None,
aria_labelledby: str | None = None,
aria_describedby: str | None = None,
aria_pressed: AriaPressed | None = None,
aria_details: str | None = None,
UNSAFE_class_name: str | None = None,
UNSAFE_style: CSSProperties | None = None,
key: str | None = None,
on_press: PressEventCallable | UndefinedType = Undefined,
on_press_start: PressEventCallable | UndefinedType = Undefined,
on_press_end: PressEventCallable | UndefinedType = Undefined,
on_press_up: PressEventCallable | UndefinedType = Undefined,
on_press_change: Callable[[bool], None] | UndefinedType = Undefined,
on_focus: FocusEventCallable | UndefinedType = Undefined,
on_blur: FocusEventCallable | UndefinedType = Undefined,
on_focus_change: Callable[[bool], None] | UndefinedType = Undefined,
on_key_down: KeyboardEventCallable | UndefinedType = Undefined,
on_key_up: KeyboardEventCallable | UndefinedType = Undefined,
auto_focus: bool | UndefinedType = Undefined,
is_disabled: bool | UndefinedType = Undefined,
is_quiet: bool | UndefinedType = Undefined,
static_color: StaticColor | UndefinedType = Undefined,
flex: LayoutFlex | UndefinedType = Undefined,
flex_grow: float | UndefinedType = Undefined,
flex_shrink: float | UndefinedType = Undefined,
flex_basis: DimensionValue | UndefinedType = Undefined,
align_self: AlignSelf | UndefinedType = Undefined,
justify_self: JustifySelf | UndefinedType = Undefined,
order: int | UndefinedType = Undefined,
grid_area: str | UndefinedType = Undefined,
grid_row: str | UndefinedType = Undefined,
grid_row_start: str | UndefinedType = Undefined,
grid_row_end: str | UndefinedType = Undefined,
grid_column: str | UndefinedType = Undefined,
grid_column_start: str | UndefinedType = Undefined,
grid_column_end: str | UndefinedType = Undefined,
margin: DimensionValue | UndefinedType = Undefined,
margin_top: DimensionValue | UndefinedType = Undefined,
margin_bottom: DimensionValue | UndefinedType = Undefined,
margin_start: DimensionValue | UndefinedType = Undefined,
margin_end: DimensionValue | UndefinedType = Undefined,
margin_x: DimensionValue | UndefinedType = Undefined,
margin_y: DimensionValue | UndefinedType = Undefined,
width: DimensionValue | UndefinedType = Undefined,
height: DimensionValue | UndefinedType = Undefined,
min_width: DimensionValue | UndefinedType = Undefined,
min_height: DimensionValue | UndefinedType = Undefined,
max_width: DimensionValue | UndefinedType = Undefined,
max_height: DimensionValue | UndefinedType = Undefined,
position: Position | UndefinedType = Undefined,
top: DimensionValue | UndefinedType = Undefined,
bottom: DimensionValue | UndefinedType = Undefined,
start: DimensionValue | UndefinedType = Undefined,
end: DimensionValue | UndefinedType = Undefined,
left: DimensionValue | UndefinedType = Undefined,
right: DimensionValue | UndefinedType = Undefined,
z_index: int | UndefinedType = Undefined,
is_hidden: bool | UndefinedType = Undefined,
id: str | UndefinedType = Undefined,
exclude_from_tab_order: bool | UndefinedType = Undefined,
aria_expanded: AriaExpanded | UndefinedType = Undefined,
aria_haspopup: AriaHasPopup | UndefinedType = Undefined,
aria_controls: str | UndefinedType = Undefined,
aria_label: str | UndefinedType = Undefined,
aria_labelledby: str | UndefinedType = Undefined,
aria_describedby: str | UndefinedType = Undefined,
aria_pressed: AriaPressed | UndefinedType = Undefined,
aria_details: str | UndefinedType = Undefined,
UNSAFE_class_name: str | UndefinedType = Undefined,
UNSAFE_style: CSSProperties | UndefinedType = Undefined,
key: str | UndefinedType = Undefined,
) -> ActionButtonElement:
"""
ActionButtons allow users to perform an action. They're used for similar, task-based options within a workflow, and are ideal for interfaces where buttons aren't meant to draw a lot of attention.
Expand Down
Loading
Loading