)]}'
{
  "commit": "aa39484a5f1614e2bf910d00234b2ad5aa1bb2b8",
  "tree": "a19035e62553b8b6a7afadf7ed59d7cc66c4dbb8",
  "parents": [
    "6da06adfa82eda8d647060632115e75a35634b87"
  ],
  "author": {
    "name": "Sreesh Maheshwar",
    "email": "maheshwarsreesh@gmail.com",
    "time": "Sat Jun 20 19:34:39 2026 +0100"
  },
  "committer": {
    "name": "GitHub",
    "email": "noreply@github.com",
    "time": "Sat Jun 20 11:34:39 2026 -0700"
  },
  "message": "Refactor: extract `BaseScan` and `ManifestGroupPlanner` (#3511)\n\n# Rationale for this change\n\nSplit out of #3364 at the reviewers\u0027 request (to @rambleraptor\u0027s and\n@kevinjqliu\u0027s point that the architecture refactor and the new feature\nare easier to review separately).\n\nThis PR will be followed by\nhttps://github.com/apache/iceberg-python/pull/3512 that makes use of\nthis refactor to implement append scans more cleanly.\n\n**This PR is a pure refactor with no behavioural change.** The diff\nlooks large, but it is almost entirely code being moved, not changed.\n\n# Changes\n\n- Introduce `BaseScan(ABC)` as a superclass of `TableScan`, holding the\nsnapshot-independent surface: `table_metadata`, `io`, `row_filter`,\n`selected_fields`, `case_sensitive`, `options`, `limit`, the chaining\nhelpers (`select` / `filter` / `with_case_sensitive` / `update`), and\nthe format-converter sinks (`to_pandas` / `to_polars` / `to_duckdb` /\n`to_ray`) built on an abstract `to_arrow()`.\n- `TableScan` keeps everything snapshot-specific — `snapshot_id`,\n`catalog`, `table_identifier`, `snapshot()`, the snapshot-aware\n`projection()`, `use_ref()`, and abstract `count()` — so its existing\npublic surface is unchanged.\n- Extract `ManifestGroupPlanner` from `DataScan` (the `_build_*`\nevaluators, `_check_sequence_number`, and the manifest-entry /\nfile-scan-task planning) and route all of `DataScan`\u0027s local planning —\n`scan_plan_helper()` and `_plan_files_local()` — through it, so the\npartition / metrics / residual pipeline lives in exactly one place.\n\n# Back-compatibility\n\n- `to_arrow_batch_reader` stays concrete on `DataScan` and is **not**\nmade abstract on `BaseScan`, so external `TableScan` subclasses that\nwere valid before still instantiate.\n- `to_pandas` / `to_polars` become concrete defaults on `BaseScan`, and\n`to_duckdb` / `to_ray` move up to `BaseScan` too. This **loosens**\n`TableScan`\u0027s abstract contract (they were abstract on `TableScan`\nbefore) without breaking existing subclasses.\n- All docstrings and explanatory comments are preserved.\n\n# Are these changes tested?\n\nThe existing `DataScan` unit and integration tests exercise the\nrefactored planning path unchanged. A regression test is added for the\nno-current-snapshot planning path, which now flows through\n`ManifestGroupPlanner`.\n\n# Are there any user-facing changes?\n\nNo. Some previously-`DataScan`-only converters (`to_duckdb` / `to_ray`)\nare now inherited by `TableScan` as well, which is purely additive.\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) \u003cnoreply@anthropic.com\u003e\nCo-authored-by: Kevin Liu \u003ckevinjqliu@users.noreply.github.com\u003e",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "463ea60d528c0e0e58d799e6640e3560fe141453",
      "old_mode": 33188,
      "old_path": "pyiceberg/table/__init__.py",
      "new_id": "597f62632f18120179a68b31fa3ec9d4b1578dd0",
      "new_mode": 33188,
      "new_path": "pyiceberg/table/__init__.py"
    },
    {
      "type": "modify",
      "old_id": "d03556a5e96a0b241639dfccb72a43158672d5eb",
      "old_mode": 33188,
      "old_path": "tests/table/test_init.py",
      "new_id": "7e64e6e7c04443e9dfa30b445820912105938bae",
      "new_mode": 33188,
      "new_path": "tests/table/test_init.py"
    }
  ]
}
