This is an automated email from the ASF dual-hosted git repository.

chenli pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git


The following commit(s) were added to refs/heads/main by this push:
     new c240a296f4 feat(backend): Add 'method' type annotation support for 
PyBuilder (#4267)
c240a296f4 is described below

commit c240a296f46b6398505082b247069878701229c7
Author: carloea2 <[email protected]>
AuthorDate: Thu Mar 19 22:35:49 2026 -0700

    feat(backend): Add 'method' type annotation support for PyBuilder (#4267)
    
    ## What changes were proposed in this PR?
    
    This PR adds method-level support for `EncodableStringAnnotation` in
    PyBuilder.
    
    ### Changes
    - Added `ElementType.METHOD` to `EncodableStringAnnotation.java`
    - Updated `EncodableInspector.scala` to recognize annotated methods as
    UI-encodable strings
    - Updated the annotation FQN used in the inspector
    
    ### Effect
    Now PyBuilder correctly handles both:
    - `Holder.uiText`
    - `Holder.uiText()`
    
    when the method is annotated with `@EncodableStringAnnotation`.
    
    Closes #4266
    
    ## How was this PR tested?
    
    Added 2 tests to verify method annotation support:
    - annotated method without parentheses
    - annotated method with parentheses
    
    ### Was this PR authored or co-authored using generative AI tooling?
    No
    
    ---------
    
    Co-authored-by: Xiaozhen Liu <[email protected]>
    Co-authored-by: Chen Li <[email protected]>
---
 .../texera/amber/pybuilder/EncodableInspector.scala      | 16 +++++++++++++---
 .../amber/pybuilder/EncodableStringAnnotation.java       |  3 ++-
 .../amber/pybuilder/PythonTemplateBuilderSpec.scala      | 16 ++++++++++++++++
 3 files changed, 31 insertions(+), 4 deletions(-)

diff --git 
a/common/pybuilder/src/main/scala/org/apache/texera/amber/pybuilder/EncodableInspector.scala
 
b/common/pybuilder/src/main/scala/org/apache/texera/amber/pybuilder/EncodableInspector.scala
index 58bdcb649e..9362016c72 100644
--- 
a/common/pybuilder/src/main/scala/org/apache/texera/amber/pybuilder/EncodableInspector.scala
+++ 
b/common/pybuilder/src/main/scala/org/apache/texera/amber/pybuilder/EncodableInspector.scala
@@ -46,7 +46,7 @@ final class EncodableInspector[C <: blackbox.Context](val c: 
C) {
 
   // Keep this as a string so it also works if the annotation is referenced 
indirectly.
   private val encodableStringAnnotationFqn =
-    "org.apache.texera.amber.EncodableStringAnn"
+    "org.apache.texera.amber.pybuilder.EncodableStringAnnotation"
 
   /**
    * If we are pointing at a getter/accessor, hop to its accessed field symbol 
when possible.
@@ -110,10 +110,20 @@ final class EncodableInspector[C <: blackbox.Context](val 
c: C) {
     val symHasAnn =
       rawSym != null && rawSym != NoSymbol && {
         val accessed = safeAccessed(rawSym)
-        accessed != null && accessed != NoSymbol && 
accessed.annotations.exists(annIsEncodableString)
+        accessed != null && accessed != NoSymbol &&
+          accessed.annotations.exists(annIsEncodableString)
       }
 
-    symHasAnn || (tree.tpe != null && typeHasEncodableString(tree.tpe))
+    val methodReturnHasAnn =
+      rawSym != null && rawSym != NoSymbol && (rawSym match {
+        case m: MethodSymbol =>
+          typeHasEncodableString(m.typeSignature.finalResultType)
+        case _ =>
+          false
+      })
+
+    symHasAnn || methodReturnHasAnn ||
+      (tree.tpe != null && typeHasEncodableString(tree.tpe))
   }
 
   def isPythonTemplateBuilderArg(argExpr: c.Expr[Any]): Boolean = {
diff --git 
a/common/pybuilder/src/main/scala/org/apache/texera/amber/pybuilder/EncodableStringAnnotation.java
 
b/common/pybuilder/src/main/scala/org/apache/texera/amber/pybuilder/EncodableStringAnnotation.java
index ea17e6d013..f94c01f680 100644
--- 
a/common/pybuilder/src/main/scala/org/apache/texera/amber/pybuilder/EncodableStringAnnotation.java
+++ 
b/common/pybuilder/src/main/scala/org/apache/texera/amber/pybuilder/EncodableStringAnnotation.java
@@ -29,6 +29,7 @@ import java.lang.annotation.Target;
     ElementType.FIELD,
     ElementType.PARAMETER,
     ElementType.TYPE_USE,
-    ElementType.LOCAL_VARIABLE
+    ElementType.LOCAL_VARIABLE,
+    ElementType.METHOD
 })
 public @interface EncodableStringAnnotation {}
\ No newline at end of file
diff --git 
a/common/pybuilder/src/test/scala/org/apache/texera/amber/pybuilder/PythonTemplateBuilderSpec.scala
 
b/common/pybuilder/src/test/scala/org/apache/texera/amber/pybuilder/PythonTemplateBuilderSpec.scala
index d2e423f810..7347ba8c2f 100644
--- 
a/common/pybuilder/src/test/scala/org/apache/texera/amber/pybuilder/PythonTemplateBuilderSpec.scala
+++ 
b/common/pybuilder/src/test/scala/org/apache/texera/amber/pybuilder/PythonTemplateBuilderSpec.scala
@@ -275,6 +275,22 @@ class PythonTemplateBuilderSpec extends AnyFunSuite {
     assert(builder.encode == "param-only")
   }
 
+  test("@StringUI method annotation triggers UI encoding") {
+    object Holder {
+      @EncodableStringAnnotation def uiText: String = "method"
+    }
+    val builder = pyb"${Holder.uiText}"
+    assert(builder.encode == decodeExpr("method"))
+  }
+
+  test("@StringUI method annotation on def with parens triggers UI encoding") {
+    object Holder {
+      @EncodableStringAnnotation def uiText(): String = "method-parens"
+    }
+    val builder = pyb"${Holder.uiText()}"
+    assert(builder.encode == decodeExpr("method-parens"))
+  }
+
   test("unannotated String does not become UI (stays raw python)") {
     val rawText: String = "raw"
     val builder = pyb"$rawText"

Reply via email to