[python] Fix MAP key resolution and ROW projection nullability - #10054
Conversation
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
No unresolved review issues remain, and regression coverage is included.
Review effort: Lite
Findings: None
What changed in this PR
Fixes nested projection handling for literal MAP keys and nullability through nullable ROW ancestors.
Changes:
- Resolves MAP selectors using valid longest-prefix matching and literal struct-field indexes.
- Propagates projected nullability without mutating source schemas.
- Adds regression coverage for MAP keys, prefix handling, and nullable ROW exports.
| File | Description |
|---|---|
paimon-python/pypaimon/utils/projection.py |
Propagates projection nullability. |
paimon-python/pypaimon/tests/test_projection_utility.py |
Tests ancestor nullability. |
paimon-python/pypaimon/tests/test_nested_projection_e2e.py |
Tests nullable ROW Parquet round trips. |
paimon-python/pypaimon/tests/map_selected_key_projection_test.py |
Tests literal MAP keys and prefix resolution. |
paimon-python/pypaimon/read/reader/nested_leaf_batch_reader.py |
Uses literal struct-field indexes. |
paimon-python/pypaimon/read/read_builder.py |
Resolves ROW and MAP projection paths. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Requirement fit: SUPPORTED. Literal MAP keys beginning with a dot and nullable ROW ancestors affect returned values and projected schema nullability. The patch resolves struct fields by literal index and propagates ancestor nullability without mutating the source type; regressions cover Parquet and row-file reads. Implementation: CLEAN in this diff. I did not rerun the Python suite locally. |
Purpose
Fixes #10053.
PyPaimon can return the wrong MAP value when projecting a key that starts with a dot. For a MAP containing
foo=100and.foo=107, selecting both keys returns100, 100. This change resolves struct children by their literal names before passing field indexes to Arrow, so the read returns100, 107and preserves parent NULLs.The change also fixes two projection cases:
Exact top-level field matches and the existing ROW prefix precedence remain unchanged. The ROW path walker is extracted into a helper, and projection path annotations now include
MapKeysteps.Tests
Added four regression tests, all of which fail before the fix:
The following local test scope passed: 102 passed (Python 3.12.6, PyArrow 19.0.1):
cd paimon-python python -m pytest -q \ pypaimon/tests/test_read_builder_nested_projection.py \ pypaimon/tests/test_nested_projection_e2e.py \ pypaimon/tests/map_selected_key_projection_test.py \ pypaimon/tests/test_projection_utility.py \ pypaimon/tests/test_outer_projection_record_reader.py \ pypaimon/tests/projection_predicate_index_test.pyRuff formatting checks passed for the changed ranges, Ruff lint passed for the six changed Python files, and
git diff --checkpassed.Flake8 4.0.1 passed for all 826 Python source files using
dev/cfg.ini(Python 3.11.12). The two affected ROW/MAP selector tests also passed after the slice-formatting adjustment.