kszucs commented on code in PR #3889:
URL: https://github.com/apache/iceberg-python/pull/3889#discussion_r3907898761


##########
tests/io/test_pyarrow.py:
##########
@@ -5462,3 +5463,89 @@ def 
test_dictionary_columns_produces_dict_encoded_output(tmpdir: str) -> None:
 
     # Values must be identical
     assert result_plain.column("label").to_pylist() == 
result_dict.column("label").to_pylist()
+
+
[email protected](
+    "table_properties,expected",
+    [
+        ({}, None),
+        (
+            {TableProperties.PARQUET_CDC_ENABLED: "true"},
+            {
+                "min_chunk_size": 
TableProperties.PARQUET_CDC_MIN_CHUNK_SIZE_DEFAULT,
+                "max_chunk_size": 
TableProperties.PARQUET_CDC_MAX_CHUNK_SIZE_DEFAULT,
+                "norm_level": TableProperties.PARQUET_CDC_NORM_LEVEL_DEFAULT,
+            },
+        ),
+        (
+            {
+                TableProperties.PARQUET_CDC_ENABLED: "true",
+                TableProperties.PARQUET_CDC_MIN_CHUNK_SIZE: "4096",
+                TableProperties.PARQUET_CDC_MAX_CHUNK_SIZE: "8192",
+                TableProperties.PARQUET_CDC_NORM_LEVEL: "2",
+            },
+            {"min_chunk_size": 4096, "max_chunk_size": 8192, "norm_level": 2},
+        ),
+    ],
+)
+def test_get_parquet_writer_kwargs_cdc(table_properties: dict[str, str], 
expected: dict[str, int] | None) -> None:
+    kwargs = _get_parquet_writer_kwargs(table_properties)
+    assert kwargs.get("use_content_defined_chunking") == expected
+
+
+def 
test_get_parquet_writer_kwargs_cdc_enabled_unsupported_pyarrow_version(monkeypatch:
 pytest.MonkeyPatch) -> None:
+    monkeypatch.setattr(pyarrow, "__version__", "17.0.0")
+    with pytest.raises(ImportError, match="pyarrow version >= 21.0.0"):
+        _get_parquet_writer_kwargs({TableProperties.PARQUET_CDC_ENABLED: 
"true"})
+
+
+def 
test_get_parquet_writer_kwargs_cdc_invalid_chunk_sizes_raises_from_pyarrow() -> 
None:
+    """PyArrow validates min/max chunk sizes itself; pyiceberg doesn't 
duplicate that check."""
+    kwargs = _get_parquet_writer_kwargs(
+        {
+            TableProperties.PARQUET_CDC_ENABLED: "true",
+            TableProperties.PARQUET_CDC_MIN_CHUNK_SIZE: "8192",
+            TableProperties.PARQUET_CDC_MAX_CHUNK_SIZE: "4096",
+        }
+    )
+    table = pa.table({"id": pa.array([1, 2, 3], type=pa.int32())})
+    with pytest.raises(OSError, match="max_chunk_size must be greater than 
min_chunk_size"):
+        with pq.ParquetWriter(pa.BufferOutputStream(), table.schema, **kwargs) 
as writer:
+            writer.write_table(table)
+
+
+def test_write_file_with_content_defined_chunking_enabled(tmp_path: Path) -> 
None:
+    """Writing a table with CDC enabled should forward 
use_content_defined_chunking to pq.ParquetWriter."""
+    from pyiceberg.table import WriteTask
+
+    table_schema = Schema(NestedField(1, "id", IntegerType(), required=False))
+    arrow_data = pa.table({"id": pa.array(range(1000), type=pa.int32())})
+
+    table_metadata = TableMetadataV2(
+        location=f"file://{tmp_path}",

Review Comment:
   Keeping this as is: `f"file://{tmp_path}"` plus the `.replace("file://", 
"")` read-back is the established pattern in this file (e.g. lines 3048 and 
3116, and ~13 other sites), and the `windows-unit-test` job runs exactly this 
test selection and passes on this PR. Switching a single test to 
`tmp_path.as_uri()` would produce a differently-shaped URI from the rest of the 
file for no behavioural gain; if the convention is worth changing, it should be 
changed file-wide in a separate PR.



##########
tests/io/test_pyarrow.py:
##########
@@ -5462,3 +5463,89 @@ def 
test_dictionary_columns_produces_dict_encoded_output(tmpdir: str) -> None:
 
     # Values must be identical
     assert result_plain.column("label").to_pylist() == 
result_dict.column("label").to_pylist()
+
+
[email protected](
+    "table_properties,expected",
+    [
+        ({}, None),
+        (
+            {TableProperties.PARQUET_CDC_ENABLED: "true"},
+            {
+                "min_chunk_size": 
TableProperties.PARQUET_CDC_MIN_CHUNK_SIZE_DEFAULT,
+                "max_chunk_size": 
TableProperties.PARQUET_CDC_MAX_CHUNK_SIZE_DEFAULT,
+                "norm_level": TableProperties.PARQUET_CDC_NORM_LEVEL_DEFAULT,
+            },
+        ),
+        (
+            {
+                TableProperties.PARQUET_CDC_ENABLED: "true",
+                TableProperties.PARQUET_CDC_MIN_CHUNK_SIZE: "4096",
+                TableProperties.PARQUET_CDC_MAX_CHUNK_SIZE: "8192",
+                TableProperties.PARQUET_CDC_NORM_LEVEL: "2",
+            },
+            {"min_chunk_size": 4096, "max_chunk_size": 8192, "norm_level": 2},
+        ),
+    ],
+)
+def test_get_parquet_writer_kwargs_cdc(table_properties: dict[str, str], 
expected: dict[str, int] | None) -> None:
+    kwargs = _get_parquet_writer_kwargs(table_properties)
+    assert kwargs.get("use_content_defined_chunking") == expected
+
+
+def 
test_get_parquet_writer_kwargs_cdc_enabled_unsupported_pyarrow_version(monkeypatch:
 pytest.MonkeyPatch) -> None:
+    monkeypatch.setattr(pyarrow, "__version__", "17.0.0")
+    with pytest.raises(ImportError, match="pyarrow version >= 21.0.0"):
+        _get_parquet_writer_kwargs({TableProperties.PARQUET_CDC_ENABLED: 
"true"})
+
+
+def 
test_get_parquet_writer_kwargs_cdc_invalid_chunk_sizes_raises_from_pyarrow() -> 
None:
+    """PyArrow validates min/max chunk sizes itself; pyiceberg doesn't 
duplicate that check."""
+    kwargs = _get_parquet_writer_kwargs(
+        {
+            TableProperties.PARQUET_CDC_ENABLED: "true",
+            TableProperties.PARQUET_CDC_MIN_CHUNK_SIZE: "8192",
+            TableProperties.PARQUET_CDC_MAX_CHUNK_SIZE: "4096",
+        }
+    )
+    table = pa.table({"id": pa.array([1, 2, 3], type=pa.int32())})
+    with pytest.raises(OSError, match="max_chunk_size must be greater than 
min_chunk_size"):
+        with pq.ParquetWriter(pa.BufferOutputStream(), table.schema, **kwargs) 
as writer:
+            writer.write_table(table)
+
+
+def test_write_file_with_content_defined_chunking_enabled(tmp_path: Path) -> 
None:
+    """Writing a table with CDC enabled should forward 
use_content_defined_chunking to pq.ParquetWriter."""
+    from pyiceberg.table import WriteTask
+
+    table_schema = Schema(NestedField(1, "id", IntegerType(), required=False))
+    arrow_data = pa.table({"id": pa.array(range(1000), type=pa.int32())})
+
+    table_metadata = TableMetadataV2(
+        location=f"file://{tmp_path}",
+        last_column_id=1,
+        format_version=2,
+        schemas=[table_schema],
+        partition_specs=[PartitionSpec()],
+        properties={TableProperties.PARQUET_CDC_ENABLED: "true"},
+    )
+
+    task = WriteTask(
+        write_uuid=uuid.uuid4(),
+        task_id=0,
+        record_batches=arrow_data.to_batches(),
+        schema=table_schema,
+    )
+
+    with patch("pyiceberg.io.pyarrow.pq.ParquetWriter", 
wraps=pq.ParquetWriter) as mock_writer:
+        data_files = list(write_file(io=PyArrowFileIO(), 
table_metadata=table_metadata, tasks=iter([task])))
+
+    assert mock_writer.call_args.kwargs["use_content_defined_chunking"] == {
+        "min_chunk_size": TableProperties.PARQUET_CDC_MIN_CHUNK_SIZE_DEFAULT,
+        "max_chunk_size": TableProperties.PARQUET_CDC_MAX_CHUNK_SIZE_DEFAULT,
+        "norm_level": TableProperties.PARQUET_CDC_NORM_LEVEL_DEFAULT,
+    }
+
+    assert len(data_files) == 1
+    written_table = pq.read_table(data_files[0].file_path.replace("file://", 
""))

Review Comment:
   Keeping this as is: `f"file://{tmp_path}"` plus the `.replace("file://", 
"")` read-back is the established pattern in this file (e.g. lines 3048 and 
3116, and ~13 other sites), and the `windows-unit-test` job runs exactly this 
test selection and passes on this PR. Switching a single test to 
`tmp_path.as_uri()` would produce a differently-shaped URI from the rest of the 
file for no behavioural gain; if the convention is worth changing, it should be 
changed file-wide in a separate PR.



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