qzyu999 opened a new issue, #3857:
URL: https://github.com/apache/iceberg-python/issues/3857

   ## Description
   
   `_DeleteFiles.delete_data_file()` silently drops explicit file references 
because `_compute_deletes` resets `self._deleted_data_files = set()` before 
scanning manifests by predicate.
   
   The `delete_data_file()` method is inherited from `_SnapshotProducer` and 
adds to `self._deleted_data_files`. However, when 
`_DeleteFiles._compute_deletes` runs (triggered by `_deleted_entries()`), it 
resets this field to an empty set and repopulates it only from files matched by 
the predicate evaluator. Any explicitly added files are silently lost.
   
   While the high-level `table.delete()` API only uses predicates (so this 
isn't hit in normal usage), the low-level `update_snapshot().delete()` API 
exposes `delete_data_file()` as a public method. Calling it produces no error 
and no effect.
   
   ## Reproduction
   
   ```python
   import pyarrow as pa
   from pyiceberg.catalog import load_catalog
   from pyiceberg.schema import Schema
   from pyiceberg.types import LongType, NestedField
   
   catalog = load_catalog("default")
   catalog.create_namespace("default")
   table = catalog.create_table(
       "default.delete_explicit",
       Schema(NestedField(1, "x", LongType(), required=False)),
   )
   table.append(pa.table({"x": [1, 2, 3]}))
   
   data_file = next(iter(table.scan().plan_files())).file
   
   # This should delete the file but silently does nothing
   with table.transaction() as tx:
       delete_snapshot = tx.update_snapshot().delete()
       delete_snapshot.delete_data_file(data_file)
   
   # Bug: table still has [1, 2, 3]
   print(table.scan().to_arrow()["x"].to_pylist())
   ```
   
   Expected: table is empty after commit.
   Actual: table still has `[1, 2, 3]`.
   
   ## Root cause
   
   In `pyiceberg/table/update/snapshot.py`, `_DeleteFiles._compute_deletes` 
(line ~598):
   
   ```python
   self._deleted_data_files = set()  # <-- overwrites any explicit files added 
via delete_data_file()
   ```
   
   Then it repopulates from predicate matches only. Since no predicate was set 
(`AlwaysFalse` by default), nothing matches, nothing is deleted.
   
   ## Suggested fix
   
   Before resetting, preserve explicit files and include them in the deletion 
scan:
   
   ```python
   # Preserve files explicitly requested for deletion
   explicit_deletes = set(self._deleted_data_files)
   self._deleted_data_files = set()
   
   # ... existing predicate-based scan ...
   # After the scan, also mark explicitly requested files as deleted:
   for entry in manifest_entries:
       if entry.data_file in explicit_deletes:
           # mark as deleted
   ```
   
   Alternatively, prevent calling `delete_data_file()` on `_DeleteFiles` 
entirely by raising `NotImplementedError`.
   
   ## Related
   
   Follow-up observation from #3818 review. The `_OverwriteFiles` path handles 
`delete_data_file()` correctly because it does not reset the field.
   


-- 
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