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

Abacn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git


The following commit(s) were added to refs/heads/master by this push:
     new 4d3e1f017e5 Support array-valued schema options in Python (#39583)
4d3e1f017e5 is described below

commit 4d3e1f017e54cfe40a11dcfdfcebd67af083c208
Author: Bruno Volpato <[email protected]>
AuthorDate: Mon Aug 3 12:37:51 2026 -0400

    Support array-valued schema options in Python (#39583)
---
 .../org/apache/beam/io/debezium/DebeziumIO.java    | 16 +++++--
 sdks/python/apache_beam/typehints/schemas.py       | 52 ++++++++++++++--------
 sdks/python/apache_beam/typehints/schemas_test.py  | 16 +++++++
 3 files changed, 63 insertions(+), 21 deletions(-)

diff --git 
a/sdks/java/io/debezium/src/main/java/org/apache/beam/io/debezium/DebeziumIO.java
 
b/sdks/java/io/debezium/src/main/java/org/apache/beam/io/debezium/DebeziumIO.java
index a6cebe1851d..6c31d5a0234 100644
--- 
a/sdks/java/io/debezium/src/main/java/org/apache/beam/io/debezium/DebeziumIO.java
+++ 
b/sdks/java/io/debezium/src/main/java/org/apache/beam/io/debezium/DebeziumIO.java
@@ -23,6 +23,7 @@ import com.google.auto.value.AutoValue;
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.stream.Collectors;
 import org.apache.beam.sdk.coders.Coder;
 import org.apache.beam.sdk.coders.MapCoder;
 import org.apache.beam.sdk.coders.StringUtf8Coder;
@@ -318,14 +319,23 @@ public class DebeziumIO {
       SourceRecord sampledRecord =
           fn.getOneRecord(getConnectorConfiguration().getConfigurationMap());
       fn.reset();
+      Schema keySchema =
+          sampledRecord.keySchema() != null
+              ? 
KafkaConnectUtils.beamSchemaFromKafkaConnectSchema(sampledRecord.keySchema())
+              : Schema.builder().build();
       Schema valueSchema =
           
KafkaConnectUtils.beamSchemaFromKafkaConnectSchema(sampledRecord.valueSchema());
 
       return Schema.builder()
           .addFields(valueSchema.getFields())
-          // TODO(https://github.com/apache/beam/issues/39557):
-          // Restore 'primaryKeyColumns' once Python can decode ARRAY<STRING>
-          // schema options across the Java/Python cross-language boundary.
+          .setOptions(
+              Schema.Options.builder()
+                  .setOption(
+                      "primaryKeyColumns",
+                      Schema.FieldType.array(Schema.FieldType.STRING),
+                      keySchema.getFields().stream()
+                          .map(Schema.Field::getName)
+                          .collect(Collectors.toList())))
           .build();
     }
 
diff --git a/sdks/python/apache_beam/typehints/schemas.py 
b/sdks/python/apache_beam/typehints/schemas.py
index 084ecc93581..2fd3c22e1e5 100644
--- a/sdks/python/apache_beam/typehints/schemas.py
+++ b/sdks/python/apache_beam/typehints/schemas.py
@@ -486,27 +486,40 @@ class SchemaTranslation(object):
       self,
       type_proto: schema_pb2.FieldType,
       value_proto: schema_pb2.FieldValue):
-    if type_proto.WhichOneof("type_info") != "atomic_type":
-      # TODO: Allow other value types
+    type_info = type_proto.WhichOneof("type_info")
+    if type_info == "atomic_type":
+      return self.atomic_value_from_runner_api(
+          type_proto.atomic_type, value_proto.atomic_value)
+    elif type_info == "array_type":
+      element_type = type_proto.array_type.element_type
+      return [
+          self.value_from_runner_api(element_type, element)
+          for element in value_proto.array_value.element
+      ]
+    else:
       raise ValueError(
-          "Encounterd option with unsupported type. Only "
-          f"atomic_type options are supported: {type_proto}")
-
-    value = self.atomic_value_from_runner_api(
-        type_proto.atomic_type, value_proto.atomic_value)
-    return value
+          "Encountered option with unsupported type. Only atomic_type and "
+          f"array_type options are supported: {type_proto}")
 
   def value_to_runner_api(self, typing_proto: schema_pb2.FieldType, value):
-    if typing_proto.WhichOneof("type_info") != "atomic_type":
-      # TODO: Allow other value types
+    type_info = typing_proto.WhichOneof("type_info")
+    if type_info == "atomic_type":
+      return schema_pb2.FieldValue(
+          atomic_value=self.atomic_value_to_runner_api(
+              typing_proto.atomic_type, value))
+    elif type_info == "array_type":
+      element_type = typing_proto.array_type.element_type
+      return schema_pb2.FieldValue(
+          array_value=schema_pb2.ArrayTypeValue(
+              element=[
+                  self.value_to_runner_api(element_type, element)
+                  for element in value
+              ]))
+    else:
       raise ValueError(
-          "Only atomic_type option values are currently supported in Python. "
-          f"Got {value!r}, which maps to fieldtype {typing_proto!r}.")
-
-    atomic_value = self.atomic_value_to_runner_api(
-        typing_proto.atomic_type, value)
-    value_proto = schema_pb2.FieldValue(atomic_value=atomic_value)
-    return value_proto
+          "Only atomic_type and array_type option values are currently "
+          f"supported in Python. Got {value!r}, which maps to fieldtype "
+          f"{typing_proto!r}.")
 
   def option_from_runner_api(
       self, option_proto: schema_pb2.Option) -> Tuple[str, Any]:
@@ -524,7 +537,10 @@ class SchemaTranslation(object):
       # Don't set type, value
       return schema_pb2.Option(name=name)
 
-    type_proto = self.typing_to_runner_api(type(value))
+    from apache_beam.typehints import trivial_inference
+
+    type_proto = self.typing_to_runner_api(
+        trivial_inference.instance_to_type(value))
     value_proto = self.value_to_runner_api(type_proto, value)
     return schema_pb2.Option(name=name, type=type_proto, value=value_proto)
 
diff --git a/sdks/python/apache_beam/typehints/schemas_test.py 
b/sdks/python/apache_beam/typehints/schemas_test.py
index c2c21a7ce39..327fe7947ca 100644
--- a/sdks/python/apache_beam/typehints/schemas_test.py
+++ b/sdks/python/apache_beam/typehints/schemas_test.py
@@ -257,6 +257,22 @@ def get_test_beam_fieldtype_protos():
                           value=schema_pb2.FieldValue(
                               atomic_value=schema_pb2.AtomicTypeValue(
                                   bytes=b'bytes!'))),
+                      schema_pb2.Option(
+                          name='a_string_array',
+                          type=schema_pb2.FieldType(
+                              array_type=schema_pb2.ArrayType(
+                                  element_type=schema_pb2.FieldType(
+                                      atomic_type=schema_pb2.STRING))),
+                          value=schema_pb2.FieldValue(
+                              array_value=schema_pb2.ArrayTypeValue(
+                                  element=[
+                                      schema_pb2.FieldValue(
+                                          atomic_value=schema_pb2.
+                                          AtomicTypeValue(string='a')),
+                                      schema_pb2.FieldValue(
+                                          atomic_value=schema_pb2.
+                                          AtomicTypeValue(string='b')),
+                                  ]))),
                   ]))),
       schema_pb2.FieldType(
           row_type=schema_pb2.RowType(

Reply via email to