From 37315d2d0752c23017a35d3a83997e4b283fa031 Mon Sep 17 00:00:00 2001 From: minhtuevo Date: Wed, 20 Nov 2024 23:19:45 -0800 Subject: [PATCH 1/3] Added uniqueness validation to TableView --- fiftyone/operators/types.py | 33 +++++++++++++++++++------ tests/unittests/operators/view_tests.py | 29 ++++++++++++++++++++++ 2 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 tests/unittests/operators/view_tests.py diff --git a/fiftyone/operators/types.py b/fiftyone/operators/types.py index a7c06620e3..34c0c4fde2 100644 --- a/fiftyone/operators/types.py +++ b/fiftyone/operators/types.py @@ -252,6 +252,7 @@ def btn( name, label, icon=None, + icon_variant=None, variant=None, disabled=False, on_click=None, @@ -296,6 +297,7 @@ def btn( btn = Button( href=href, icon=icon, + icon_variant=icon_variant, icon_position=icon_position, disabled=disabled, label=label, @@ -1828,16 +1830,18 @@ class Action(View): on_click: the operator to execute when the action is clicked """ - def __init__(self, **kwargs): + def __init__(self, name, **kwargs): super().__init__(**kwargs) + self.name = name def clone(self): - clone = Action(**self._kwargs) + clone = Action(self.name, **self._kwargs) return clone def to_json(self): - return {**super().to_json()} - + return {**super().to_json(), "name": self.name} + + class Tooltip(View): """A tooltip (currently supported only in a :class:`TableView`). @@ -1847,15 +1851,17 @@ class Tooltip(View): column: the column of the tooltip """ - def __init__(self, **kwargs): + def __init__(self, row, column, **kwargs): super().__init__(**kwargs) + self.row = row + self.column = column def clone(self): - clone = Tooltip(**self._kwargs) + clone = Tooltip(self.row, self. column, **self._kwargs) return clone def to_json(self): - return {**super().to_json()} + return {**super().to_json(), "row": self.row, "column": self.column} class TableView(View): @@ -1876,6 +1882,10 @@ def keys(self): return [column.key for column in self.columns] def add_column(self, key, **kwargs): + for column in self.columns: + if column.key == key: + raise ValueError(f"Column with key '{key}' already exists") + column = Column(key, **kwargs) self.columns.append(column) return column @@ -1883,6 +1893,10 @@ def add_column(self, key, **kwargs): def add_row_action( self, name, on_click, label=None, icon=None, tooltip=None, **kwargs ): + for action in self.row_actions: + if action.name == name: + raise ValueError(f"Action with name '{name}' already exists") + row_action = Action( name=name, on_click=on_click, @@ -1895,6 +1909,10 @@ def add_row_action( return row_action def add_tooltip(self, row, column, value, **kwargs): + for tooltip in self.tooltips: + if tooltip.row == row and tooltip.column == column: + raise ValueError(f"Tooltip for row '{row}' and column '{column}' already exists") + tooltip = Tooltip(row=row, column=column, value=value, **kwargs) self.tooltips.append(tooltip) return tooltip @@ -2293,6 +2311,7 @@ class StatusButtonView(View): """ def __init__(self, **kwargs): + print("Status Button View is new") super().__init__(**kwargs) diff --git a/tests/unittests/operators/view_tests.py b/tests/unittests/operators/view_tests.py new file mode 100644 index 0000000000..2cf9d94dcb --- /dev/null +++ b/tests/unittests/operators/view_tests.py @@ -0,0 +1,29 @@ +import unittest + +from fiftyone.operators.types import TableView + + +class TableViewTests(unittest.TestCase): + def test_table_view_basic(self): + table = TableView() + table.add_column("column1", label="Column 1") + table.add_column("column2", label="Column 2") + assert table.keys() == ["column1", "column2"] + + with self.assertRaises(ValueError): + table.add_column("column1", label="Column 3") + + mock_on_click = lambda: None + + table.add_row_action("action1", on_click=mock_on_click, icon="icon1", color="primary", tooltip="Action 1") + table.add_row_action("action2", on_click=mock_on_click, icon="icon2", color="secondary", tooltip="Action 2") + + with self.assertRaises(ValueError): + table.add_row_action("action1", on_click=mock_on_click, icon="icon3", color="primary", + tooltip="Action 3") + + table.add_tooltip(1, 1, "Tooltip 1") + table.add_tooltip(1, 2, "Tooltip 2") + + with self.assertRaises(ValueError): + table.add_tooltip(1, 1, "Tooltip 3") From 22eb1c3fdba7e34897ab40758a3d05a4a6912f59 Mon Sep 17 00:00:00 2001 From: minhtuevo Date: Wed, 20 Nov 2024 23:26:15 -0800 Subject: [PATCH 2/3] More efficient check --- fiftyone/operators/types.py | 20 +++++++++------ .../{view_tests.py => types_tests.py} | 25 ++++++++++++++++--- 2 files changed, 33 insertions(+), 12 deletions(-) rename tests/unittests/operators/{view_tests.py => types_tests.py} (54%) diff --git a/fiftyone/operators/types.py b/fiftyone/operators/types.py index 34c0c4fde2..1539a45d27 100644 --- a/fiftyone/operators/types.py +++ b/fiftyone/operators/types.py @@ -252,7 +252,6 @@ def btn( name, label, icon=None, - icon_variant=None, variant=None, disabled=False, on_click=None, @@ -297,7 +296,6 @@ def btn( btn = Button( href=href, icon=icon, - icon_variant=icon_variant, icon_position=icon_position, disabled=disabled, label=label, @@ -1857,7 +1855,7 @@ def __init__(self, row, column, **kwargs): self.column = column def clone(self): - clone = Tooltip(self.row, self. column, **self._kwargs) + clone = Tooltip(self.row, self.column, **self._kwargs) return clone def to_json(self): @@ -1877,6 +1875,7 @@ def __init__(self, **kwargs): self.columns = kwargs.get("columns", []) self.row_actions = kwargs.get("row_actions", []) self.tooltips = kwargs.get("tooltips", []) + self._tooltip_map = {} def keys(self): return [column.key for column in self.columns] @@ -1907,14 +1906,16 @@ def add_row_action( ) self.row_actions.append(row_action) return row_action - + def add_tooltip(self, row, column, value, **kwargs): - for tooltip in self.tooltips: - if tooltip.row == row and tooltip.column == column: - raise ValueError(f"Tooltip for row '{row}' and column '{column}' already exists") + if (row, column) in self._tooltip_map: + raise ValueError( + f"Tooltip for row '{row}' and column '{column}' already exists" + ) tooltip = Tooltip(row=row, column=column, value=value, **kwargs) self.tooltips.append(tooltip) + self._tooltip_map[(row, column)] = tooltip return tooltip def clone(self): @@ -1922,6 +1923,10 @@ def clone(self): clone.columns = [column.clone() for column in self.columns] clone.row_actions = [action.clone() for action in self.row_actions] clone.tooltips = [tooltip.clone() for tooltip in self.tooltips] + clone._tooltip_map = { + (tooltip.row, tooltip.column): tooltip + for tooltip in clone.tooltips + } return clone def to_json(self): @@ -2311,7 +2316,6 @@ class StatusButtonView(View): """ def __init__(self, **kwargs): - print("Status Button View is new") super().__init__(**kwargs) diff --git a/tests/unittests/operators/view_tests.py b/tests/unittests/operators/types_tests.py similarity index 54% rename from tests/unittests/operators/view_tests.py rename to tests/unittests/operators/types_tests.py index 2cf9d94dcb..88945ec92c 100644 --- a/tests/unittests/operators/view_tests.py +++ b/tests/unittests/operators/types_tests.py @@ -15,12 +15,29 @@ def test_table_view_basic(self): mock_on_click = lambda: None - table.add_row_action("action1", on_click=mock_on_click, icon="icon1", color="primary", tooltip="Action 1") - table.add_row_action("action2", on_click=mock_on_click, icon="icon2", color="secondary", tooltip="Action 2") + table.add_row_action( + "action1", + on_click=mock_on_click, + icon="icon1", + color="primary", + tooltip="Action 1", + ) + table.add_row_action( + "action2", + on_click=mock_on_click, + icon="icon2", + color="secondary", + tooltip="Action 2", + ) with self.assertRaises(ValueError): - table.add_row_action("action1", on_click=mock_on_click, icon="icon3", color="primary", - tooltip="Action 3") + table.add_row_action( + "action1", + on_click=mock_on_click, + icon="icon3", + color="primary", + tooltip="Action 3", + ) table.add_tooltip(1, 1, "Tooltip 1") table.add_tooltip(1, 2, "Tooltip 2") From 2a224ab79221dacd5c4fe8a6040d3b5147910798 Mon Sep 17 00:00:00 2001 From: minhtuevo Date: Thu, 21 Nov 2024 00:24:48 -0800 Subject: [PATCH 3/3] Renamed to tableview_tests --- tests/unittests/operators/{types_tests.py => tableview_tests.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/unittests/operators/{types_tests.py => tableview_tests.py} (100%) diff --git a/tests/unittests/operators/types_tests.py b/tests/unittests/operators/tableview_tests.py similarity index 100% rename from tests/unittests/operators/types_tests.py rename to tests/unittests/operators/tableview_tests.py