From 6f1fce0ca856734a214d5e98487d5780bcddf249 Mon Sep 17 00:00:00 2001 From: kary zheng Date: Sun, 2 Aug 2026 15:19:48 -0700 Subject: [PATCH 1/2] fix(visualization): define the render_error the table charts already call TablesPlot and FigureFactoryTable both generate a TableChartOperator that calls self.render_error on two reachable branches -- an empty input table, and a value column left with only non-positive or null values -- but neither generated class defined it, so those branches raised AttributeError instead of showing the message they were written to show. Closes #7244 Co-Authored-By: Claude Opus 5 (1M context) --- .../figureFactoryTable/FigureFactoryTableOpDesc.scala | 3 +++ .../operator/visualization/tablesChart/TablesPlotOpDesc.scala | 3 +++ 2 files changed, 6 insertions(+) diff --git a/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/visualization/figureFactoryTable/FigureFactoryTableOpDesc.scala b/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/visualization/figureFactoryTable/FigureFactoryTableOpDesc.scala index ae9f9073e05..c1c94f7b12d 100644 --- a/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/visualization/figureFactoryTable/FigureFactoryTableOpDesc.scala +++ b/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/visualization/figureFactoryTable/FigureFactoryTableOpDesc.scala @@ -104,6 +104,9 @@ class FigureFactoryTableOpDesc extends PythonOperatorDescriptor { | |class TableChartOperator(UDFTableOperator): | + | def render_error(self, error_msg) -> str: + | return f"

Figure Factory Table is not available.

Reason is: {error_msg}

" + | | def process_table(self, table: Table, port: int) -> Iterator[Optional[TableLike]]: | | if table.empty: diff --git a/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/visualization/tablesChart/TablesPlotOpDesc.scala b/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/visualization/tablesChart/TablesPlotOpDesc.scala index bf230162759..7290c057dd4 100644 --- a/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/visualization/tablesChart/TablesPlotOpDesc.scala +++ b/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/visualization/tablesChart/TablesPlotOpDesc.scala @@ -76,6 +76,9 @@ class TablesPlotOpDesc extends PythonOperatorDescriptor { |import plotly.io |class TableChartOperator(UDFTableOperator): | + | def render_error(self, error_msg) -> str: + | return f"

Tables Plot is not available.

Reason is: {error_msg}

" + | | def process_table(self, table: Table, port: int) -> Iterator[Optional[TableLike]]: | | if table.empty: From ad2a4746169882b38deb99950b2c3ed055173e45 Mon Sep 17 00:00:00 2001 From: kary zheng Date: Tue, 4 Aug 2026 15:25:27 -0700 Subject: [PATCH 2/2] test(visualization): guard the render_error definition in each operator's spec Nothing kept the two definitions from being dropped again. Each operator's own spec now asserts its generated class defines render_error and formats the operator's name, which is the shape the branches depend on. Co-Authored-By: Claude Opus 5 (1M context) --- .../FigureFactoryTableOpDescSpec.scala | 11 +++++++++++ .../tablesChart/TablesPlotOpDescSpec.scala | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/visualization/figureFactoryTable/FigureFactoryTableOpDescSpec.scala b/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/visualization/figureFactoryTable/FigureFactoryTableOpDescSpec.scala index 83eeed1f966..9d564fd3581 100644 --- a/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/visualization/figureFactoryTable/FigureFactoryTableOpDescSpec.scala +++ b/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/visualization/figureFactoryTable/FigureFactoryTableOpDescSpec.scala @@ -99,4 +99,15 @@ class FigureFactoryTableOpDescSpec extends AnyFlatSpec with BeforeAndAfter with assert(carries(code, "col_two")) code should include("class TableChartOperator(UDFTableOperator)") } + + it should "define the render_error the empty-table branches call" in { + // Both empty-table branches call self.render_error; without the definition they + // raised AttributeError instead of rendering the message. + withColumns() + val code = opDesc.generatePythonCode() + code should include("def render_error(self, error_msg) -> str:") + code should include( + """return f"

Figure Factory Table is not available.

Reason is: {error_msg}

"""" + ) + } } diff --git a/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/visualization/tablesChart/TablesPlotOpDescSpec.scala b/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/visualization/tablesChart/TablesPlotOpDescSpec.scala index cc191139060..c088cacc672 100644 --- a/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/visualization/tablesChart/TablesPlotOpDescSpec.scala +++ b/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/visualization/tablesChart/TablesPlotOpDescSpec.scala @@ -88,4 +88,15 @@ class TablesPlotOpDescSpec extends AnyFlatSpec with BeforeAndAfter with Matchers ) code should not include "')','" } + + it should "define the render_error the empty-table branches call" in { + // Both empty-table branches call self.render_error; without the definition they + // raised AttributeError instead of rendering the message. + opDesc.includedColumns = List(column("col_one"), column("col_two")) + val code = opDesc.generatePythonCode() + code should include("def render_error(self, error_msg) -> str:") + code should include( + """return f"

Tables Plot is not available.

Reason is: {error_msg}

"""" + ) + } }