anxkhn opened a new pull request, #3660:
URL: https://github.com/apache/iceberg-python/pull/3660

   
   # Rationale for this change
   
   `ManifestWriter.to_manifest_file()` computed the manifest's minimum data
   sequence number with a truthiness fallback:
   
   ```python
   min_sequence_number = self._min_sequence_number or UNASSIGNED_SEQ
   ```
   
   A data sequence number of `0` is a legitimate minimum for a live file (files
   from a v1 table, or the initial commit of a v2 table). Because `0` is falsy,
   `or` collapses it to `UNASSIGNED_SEQ` (`-1`), i.e. it treats a real `0` the 
same
   as "unset".
   
   This diverges from the Java reference implementation, which falls back to
   `UNASSIGNED_SEQ` only when the value is actually unset:
   
   ```java
   // ManifestWriter#toManifestFile (apache/iceberg)
   long minSeqNumber = minDataSequenceNumber != null ? minDataSequenceNumber : 
UNASSIGNED_SEQ;
   ```
   
   The `-1` is not harmless. When the manifest is produced by a merge/compaction
   (so its `added_snapshot_id` equals the current commit snapshot id),
   `ManifestListWriter.prepare_manifest()` treats `min_sequence_number ==
   UNASSIGNED_SEQ` as "no file had an assigned sequence number" and overwrites 
it
   with the current, higher commit sequence number
   (`pyiceberg/manifest.py`, the `if wrapped_manifest_file.min_sequence_number 
==
   UNASSIGNED_SEQ:` branch). The manifest's minimum data sequence number is 
thereby
   silently raised, which affects sequence-number-based delete-file application 
and
   scans.
   
   The fix uses an explicit `None` check instead of a truthiness fallback,
   mirroring the Java writer:
   
   ```python
   min_sequence_number = self._min_sequence_number if self._min_sequence_number 
is not None else UNASSIGNED_SEQ
   ```
   
   ## Are these changes tested?
   
   Yes. A new parametrized regression test,
   `tests/utils/test_manifest.py::test_write_manifest_min_sequence_number_zero`
   (format versions 1 and 2), drives a live `EXISTING` entry with
   `sequence_number=0` through `ManifestWriter.existing()` and asserts that
   `to_manifest_file().min_sequence_number == 0`.
   
   The test fails before the fix (`assert -1 == 0`) and passes after it. This 
path
   had no prior coverage: no existing test drove a live sequence-0 entry through
   `to_manifest_file()`, which is why the defect was not caught.
   
   Local runs (unit tests):
   - `pytest tests/utils/test_manifest.py -q` -> passes.
   - `pytest tests/table/test_snapshots.py tests/table/test_manage_snapshots.py 
-q`
     -> passes.
   - `make lint` (ruff, ruff-format, mypy, pydocstyle, codespell) -> clean on 
the
     changed files.
   
   The merge/compaction integration path exercised by `prepare_manifest()` is
   covered by the integration suite, which requires Docker and Spark; those were
   not run locally. The new unit test exercises the same `to_manifest_file()` 
write
   path that feeds it.
   
   ## Are there any user-facing changes?
   
   No API changes. It is a correctness fix: manifests written for live files 
whose
   minimum data sequence number is `0` now record `0` instead of `-1`, so a
   subsequent merge/compaction no longer silently raises the manifest's minimum
   data sequence number.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to