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"