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

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/main/pr-4009-f7dcc3d92ccd87532f6332028e68b11b09446be3
in repository https://gitbox.apache.org/repos/asf/iceberg-python.git

commit 0743814334b1caf86a54a2301e3e5b34d80aff0a
Author: Rodrigo Stachlewski Palma 
<[email protected]>
AuthorDate: Thu Sep 24 19:28:20 2026 +0000

    fix(avro): advance the decoder when skipping an enum (#4009)
    
    EnumReader.skip() was a no-op, so the enum's bytes stayed in the stream and
    the next field was decoded from them. Reading a manifest with the status
    field projected out returns wrong values for every field after it.
    
    Delegate to the wrapped reader, which is what read() already does.
---
 pyiceberg/avro/resolver.py  |  2 +-
 tests/avro/test_resolver.py | 36 ++++++++++++++++++++++++++++++++++--
 2 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/pyiceberg/avro/resolver.py b/pyiceberg/avro/resolver.py
index ec76b331a..3f19ae987 100644
--- a/pyiceberg/avro/resolver.py
+++ b/pyiceberg/avro/resolver.py
@@ -272,7 +272,7 @@ class EnumReader(Reader):
         return self.enum(self.reader.read(decoder))
 
     def skip(self, decoder: BinaryDecoder) -> None:
-        pass
+        self.reader.skip(decoder)
 
 
 class WriteSchemaResolver(PrimitiveWithPartnerVisitor[IcebergType, Writer]):
diff --git a/tests/avro/test_resolver.py b/tests/avro/test_resolver.py
index 2611f9652..106e4ad8f 100644
--- a/tests/avro/test_resolver.py
+++ b/tests/avro/test_resolver.py
@@ -15,11 +15,14 @@
 # specific language governing permissions and limitations
 # under the License.
 
+from collections.abc import Callable
 from tempfile import TemporaryDirectory
 
 import pytest
 from pydantic import Field
 
+from pyiceberg.avro.decoder import BinaryDecoder, StreamingBinaryDecoder
+from pyiceberg.avro.decoder_fast import CythonBinaryDecoder
 from pyiceberg.avro.file import AvroFile
 from pyiceberg.avro.reader import (
     DecimalReader,
@@ -32,7 +35,7 @@ from pyiceberg.avro.reader import (
     StringReader,
     StructReader,
 )
-from pyiceberg.avro.resolver import resolve_reader, resolve_writer
+from pyiceberg.avro.resolver import EnumReader, resolve_reader, resolve_writer
 from pyiceberg.avro.writer import (
     BinaryWriter,
     DefaultWriter,
@@ -46,7 +49,7 @@ from pyiceberg.avro.writer import (
 )
 from pyiceberg.exceptions import ResolveError
 from pyiceberg.io.pyarrow import PyArrowFileIO
-from pyiceberg.manifest import MANIFEST_ENTRY_SCHEMAS
+from pyiceberg.manifest import MANIFEST_ENTRY_SCHEMAS, ManifestEntryStatus
 from pyiceberg.schema import Schema
 from pyiceberg.typedef import Record
 from pyiceberg.types import (
@@ -64,6 +67,8 @@ from pyiceberg.types import (
     StructType,
 )
 
+AVAILABLE_DECODERS = [StreamingBinaryDecoder, CythonBinaryDecoder]
+
 
 def test_resolver() -> None:
     write_schema = Schema(
@@ -418,3 +423,30 @@ def test_writer_missing_optional_in_read_schema() -> None:
     expected = StructWriter(field_writers=((None, 
OptionWriter(option=StringWriter())),))
 
     assert actual == expected
+
+
[email protected]("decoder_class", AVAILABLE_DECODERS)
+def test_enum_reader_skip_advances_the_decoder(decoder_class: 
Callable[[bytes], BinaryDecoder]) -> None:
+    """Skipping an enum field must consume its bytes, or the next field is 
read from them."""
+    # Two ints, zigzag encoded: the enum's ordinal 1, then the next field's 
value 12.
+    decoder = decoder_class(b"\x02\x18")
+    reader = EnumReader(ManifestEntryStatus, IntegerReader())
+
+    reader.skip(decoder)
+
+    assert IntegerReader().read(decoder) == 12
+
+
[email protected]("decoder_class", AVAILABLE_DECODERS)
+def test_enum_reader_skip_matches_read(decoder_class: Callable[[bytes], 
BinaryDecoder]) -> None:
+    """Reading and skipping must leave the decoder at the same position."""
+    encoded = b"\x02\x18"
+    reader = EnumReader(ManifestEntryStatus, IntegerReader())
+
+    read_decoder = decoder_class(encoded)
+    assert reader.read(read_decoder) == ManifestEntryStatus.ADDED
+
+    skip_decoder = decoder_class(encoded)
+    reader.skip(skip_decoder)
+
+    assert IntegerReader().read(read_decoder) == 
IntegerReader().read(skip_decoder)

Reply via email to