This is an automated email from the ASF dual-hosted git repository.
RyanSkraba pushed a commit to branch branch-1.12
in repository https://gitbox.apache.org/repos/asf/avro.git
The following commit(s) were added to refs/heads/branch-1.12 by this push:
new 3ecb553ad5 AVRO-3760: [python] Fix resolution of future enum with
default symbol (#2250)
3ecb553ad5 is described below
commit 3ecb553ad519cf2c0e5c5391d03b8f368698be03
Author: Anton Agestam <[email protected]>
AuthorDate: Wed Aug 5 18:02:42 2026 +0200
AVRO-3760: [python] Fix resolution of future enum with default symbol
(#2250)
* AVRO-3760: [python] Fix resolution of future enum with default symbol
* Change error from review
---------
Co-authored-by: Ryan Skraba <[email protected]>
---
lang/py/avro/io.py | 3 ++
lang/py/avro/schema.py | 9 ++++
lang/py/avro/test/test_io.py | 110 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 122 insertions(+)
diff --git a/lang/py/avro/io.py b/lang/py/avro/io.py
index 4be3d8e057..d0d9a738eb 100644
--- a/lang/py/avro/io.py
+++ b/lang/py/avro/io.py
@@ -766,6 +766,9 @@ class DatumReader:
# read data
index_of_symbol = decoder.read_int()
if index_of_symbol >= len(writers_schema.symbols):
+ default = writers_schema.default
+ if default is not None:
+ return default
raise avro.errors.SchemaResolutionException(
f"Can't access enum index {index_of_symbol} for enum with
{len(writers_schema.symbols)} symbols", writers_schema, readers_schema
)
diff --git a/lang/py/avro/schema.py b/lang/py/avro/schema.py
index 018f74debe..360e88eb59 100644
--- a/lang/py/avro/schema.py
+++ b/lang/py/avro/schema.py
@@ -715,6 +715,15 @@ class EnumSchema(EqualByPropsMixin, NamedSchema):
return symbols
raise Exception
+ @property
+ def default(self) -> Union[str, None]:
+ symbol = self.get_prop("default")
+ if isinstance(symbol, str):
+ return symbol
+ if symbol is None:
+ return None
+ raise avro.errors.InvalidDefault(f"Enum default '{symbol}' is not a
valid member of symbols '{self.symbols}'")
+
@property
def doc(self):
return self.get_prop("doc")
diff --git a/lang/py/avro/test/test_io.py b/lang/py/avro/test/test_io.py
index 36a85b3e5f..82ad22e6e3 100644
--- a/lang/py/avro/test/test_io.py
+++ b/lang/py/avro/test/test_io.py
@@ -662,6 +662,116 @@ class TestMisc(unittest.TestCase):
with self.assertRaisesRegex(avro.errors.AvroTypeException, r"The datum
\".*\" provided for \".*\" is not an example of the schema [\s\S]*"):
write_datum(datum_to_write, writers_schema)
+ def test_can_read_future_enum_symbol_with_default(self) -> None:
+ default_symbol = "unknown"
+ future_symbol = "crc32_be"
+
+ readers_schema = avro.schema.parse(
+ json.dumps(
+ {
+ "fields": [
+ {
+ "name": "checksum_algorithm",
+ "type": {
+ "name": "ChecksumAlgorithm",
+ "symbols": [default_symbol, "xxhash3_64_be"],
+ "type": "enum",
+ "default": default_symbol,
+ },
+ },
+ ],
+ "name": "Test",
+ "type": "record",
+ }
+ )
+ )
+ # Writer adds the "crc32_be" symbol.
+ writers_schema = avro.schema.parse(
+ json.dumps(
+ {
+ "fields": [
+ {
+ "name": "checksum_algorithm",
+ "type": {
+ "name": "ChecksumAlgorithm",
+ "symbols": [
+ "unknown",
+ "xxhash3_64_be",
+ future_symbol,
+ ],
+ "type": "enum",
+ "default": default_symbol,
+ },
+ }
+ ],
+ "name": "Test",
+ "type": "record",
+ }
+ )
+ )
+
+ datum_to_write = {"checksum_algorithm": future_symbol}
+
+ buffer, encoder, datum_writer = write_datum(datum_to_write,
writers_schema)
+ buffer.seek(0)
+ decoder = avro.io.BinaryDecoder(buffer)
+ reader = avro.io.DatumReader(readers_schema)
+ datum_read = reader.read(decoder)
+ self.assertEqual(datum_read, {"checksum_algorithm": default_symbol})
+
+ def test_raises_error_for_future_enum_symbol_without_default(self) -> None:
+ future_symbol = "crc32_be"
+
+ readers_schema = avro.schema.parse(
+ json.dumps(
+ {
+ "fields": [
+ {
+ "name": "checksum_algorithm",
+ "type": {
+ "name": "ChecksumAlgorithm",
+ "symbols": ["xxhash3_64_be"],
+ "type": "enum",
+ },
+ },
+ ],
+ "name": "Test",
+ "type": "record",
+ }
+ )
+ )
+ # Writer adds the "crc32_be" symbol.
+ writers_schema = avro.schema.parse(
+ json.dumps(
+ {
+ "fields": [
+ {
+ "name": "checksum_algorithm",
+ "type": {
+ "name": "ChecksumAlgorithm",
+ "symbols": [
+ "xxhash3_64_be",
+ future_symbol,
+ ],
+ "type": "enum",
+ },
+ }
+ ],
+ "name": "Test",
+ "type": "record",
+ }
+ )
+ )
+
+ datum_to_write = {"checksum_algorithm": future_symbol}
+
+ buffer, encoder, datum_writer = write_datum(datum_to_write,
writers_schema)
+ buffer.seek(0)
+ decoder = avro.io.BinaryDecoder(buffer)
+ reader = avro.io.DatumReader(readers_schema)
+ with self.assertRaises(avro.errors.SchemaResolutionException):
+ reader.read(decoder)
+
def load_tests(loader: unittest.TestLoader, default_tests: None, pattern:
None) -> unittest.TestSuite:
"""Generate test cases across many test schema."""