This is an automated email from the ASF dual-hosted git repository.

AlenkaF pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new b8079cd294 GH-54637: [Python] add `MemoryPool` support to 
`pq.read_table` (#54919)
b8079cd294 is described below

commit b8079cd294ad60bdb81da8a0989e8fd27918c517
Author: Omkar Kabde <[email protected]>
AuthorDate: Wed Oct 28 20:27:19 2026 +0530

    GH-54637: [Python] add `MemoryPool` support to `pq.read_table` (#54919)
    
    ### Rationale for this change
    `pq.read_table` has no way to pass a memory pool. `ParquetReader` and 
`Dataset.to_table` already accept one, it just wasn't added.
    
    ### What changes are included in this PR?
    I added a `memory_pool` argument to `read_table`, `ParquetFile` and 
`ParquetDataset`. It is passed to `ParquetReader` and to `Dataset.to_table`, 
with docstrings updated.
    
    ### Are these changes tested?
    Yes. I added new tests in `test_basic.py` - It reads a Parquet file with a 
tracked memory pool and check that the pool was actually used. They cover 
`read_table`, `ParquetFile` and `ParquetDataset`.
    
    ### Are there any user-facing changes?
    New optional `memory_pool` keyword. No breaking changes.
    
    ### Was AI used for this PR?
    
    **PR code and description written by:**
    - [x] Human
    - [x] AI
    
    **Reviewed before submission by:**
    - [x] Human
    - [ ] AI
    
    Github Issue - https://github.com/apache/arrow/issues/54637
    * GitHub Issue: #54637
    
    Authored-by: Omkar Kabde <[email protected]>
    Signed-off-by: AlenkaF <[email protected]>
---
 python/pyarrow/parquet/core.py             | 28 ++++++++++++----
 python/pyarrow/tests/parquet/test_basic.py | 51 ++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+), 6 deletions(-)

diff --git a/python/pyarrow/parquet/core.py b/python/pyarrow/parquet/core.py
index 253a8a3312..fa3b897ad2 100644
--- a/python/pyarrow/parquet/core.py
+++ b/python/pyarrow/parquet/core.py
@@ -272,6 +272,9 @@ class ParquetFile:
         If True, read Parquet logical types as Arrow extension types where
         possible (e.g., read JSON as the canonical `arrow.json` extension type
         or UUID as the canonical `arrow.uuid` extension type).
+    memory_pool : pyarrow.MemoryPool, optional
+        Pool to allocate memory from. If not passed, the default memory pool
+        is used.
 
     Examples
     --------
@@ -322,7 +325,8 @@ class ParquetFile:
                  decryption_properties=None, thrift_string_size_limit=None,
                  thrift_container_size_limit=None, schema_depth_limit=None,
                  filesystem=None,
-                 page_checksum_verification=False, 
arrow_extensions_enabled=True):
+                 page_checksum_verification=False, 
arrow_extensions_enabled=True,
+                 memory_pool=None):
 
         self._close_source = getattr(source, 'closed', True)
 
@@ -332,7 +336,7 @@ class ParquetFile:
             source = filesystem.open_input_file(source)
             self._close_source = True  # We opened it here, ensure we close it.
 
-        self.reader = ParquetReader()
+        self.reader = ParquetReader(memory_pool=memory_pool)
         self.reader.open(
             source, use_memory_map=memory_map,
             buffer_size=buffer_size, pre_buffer=pre_buffer,
@@ -1537,7 +1541,8 @@ Examples
         """
         return self._dataset.schema
 
-    def read(self, columns=None, use_threads=True, use_pandas_metadata=False):
+    def read(self, columns=None, use_threads=True, use_pandas_metadata=False,
+             memory_pool=None):
         """
         Read (multiple) Parquet files as a single pyarrow.Table.
 
@@ -1551,6 +1556,9 @@ Examples
         use_pandas_metadata : bool, default False
             If True and file has custom pandas schema metadata, ensure that
             index columns are also loaded.
+        memory_pool : pyarrow.MemoryPool, optional
+            Pool to allocate memory from. If not passed, the default memory
+            pool is used.
 
         Returns
         -------
@@ -1605,7 +1613,7 @@ Examples
 
         table = self._dataset.to_table(
             columns=columns, filter=self._filter_expression,
-            use_threads=use_threads
+            use_threads=use_threads, memory_pool=memory_pool
         )
 
         # if the "pandas" metadata entry was retrieved from common_metadata,
@@ -1813,6 +1821,9 @@ arrow_extensions_enabled : bool, default True
     If True, read Parquet logical types as Arrow extension types where 
possible,
     (e.g., read JSON as the canonical `arrow.json` extension type or UUID as
     the canonical `arrow.uuid` extension type).
+memory_pool : pyarrow.MemoryPool, optional
+    Pool to allocate memory from. If not passed, the default memory pool
+    is used.
 
 Returns
 -------
@@ -1909,8 +1920,9 @@ def read_table(source, *, columns=None, use_threads=True,
                decryption_properties=None, thrift_string_size_limit=None,
                thrift_container_size_limit=None, schema_depth_limit=None,
                page_checksum_verification=False,
-               arrow_extensions_enabled=True):
+               arrow_extensions_enabled=True, memory_pool=None):
 
+    read_kwargs = {"memory_pool": memory_pool}
     try:
         dataset = ParquetDataset(
             source,
@@ -1980,10 +1992,14 @@ def read_table(source, *, columns=None, 
use_threads=True,
             thrift_container_size_limit=thrift_container_size_limit,
             schema_depth_limit=schema_depth_limit,
             page_checksum_verification=page_checksum_verification,
+            memory_pool=memory_pool,
         )
+        # ParquetFile takes the pool when it is opened, not when it is read
+        read_kwargs = {}
 
     return dataset.read(columns=columns, use_threads=use_threads,
-                        use_pandas_metadata=use_pandas_metadata)
+                        use_pandas_metadata=use_pandas_metadata,
+                        **read_kwargs)
 
 
 read_table.__doc__ = _read_table_docstring.format(
diff --git a/python/pyarrow/tests/parquet/test_basic.py 
b/python/pyarrow/tests/parquet/test_basic.py
index ce8c75f3c1..ba88118b82 100644
--- a/python/pyarrow/tests/parquet/test_basic.py
+++ b/python/pyarrow/tests/parquet/test_basic.py
@@ -1089,3 +1089,54 @@ def test_filters_to_expression_deprecated_alias():
         result = pq._filters_to_expression(filters)
     assert isinstance(result, ds.Expression)
     assert result.equals(expected)
+
+
[email protected]
+def proxy_pool():
+    # Owned by the fixture so that it outlives every object created from it
+    # inside the test function (readers and tables keep a raw pool pointer).
+    return pa.proxy_memory_pool(pa.default_memory_pool())
+
+
[email protected]("use_dataset_path", [True, False])
+def test_read_table_memory_pool(tempdir, proxy_pool, use_dataset_path,
+                                monkeypatch):
+    table = pa.table({'a': list(range(1000)),
+                      'b': [str(i) for i in range(1000)]})
+    path = str(tempdir / 'data.parquet')
+    pq.write_table(table, path)
+
+    if not use_dataset_path:
+        # Exercise the ParquetFile fallback used without pyarrow.dataset
+        monkeypatch.setitem(sys.modules, "pyarrow.dataset", None)
+
+    result = pq.read_table(path, memory_pool=proxy_pool)
+    assert result.equals(table)
+    assert proxy_pool.bytes_allocated() >= table.nbytes
+    result = None
+    assert proxy_pool.bytes_allocated() == 0
+
+
+def test_parquet_file_memory_pool(tempdir, proxy_pool):
+    table = pa.table({'a': list(range(1000))})
+    path = str(tempdir / 'data.parquet')
+    pq.write_table(table, path)
+
+    result = pq.ParquetFile(path, memory_pool=proxy_pool).read()
+    assert result.equals(table)
+    assert proxy_pool.bytes_allocated() >= table.nbytes
+    result = None
+    assert proxy_pool.bytes_allocated() == 0
+
+
+def test_parquet_dataset_memory_pool(tempdir, proxy_pool):
+    table = pa.table({'a': list(range(1000)), 'part': ['x', 'y'] * 500})
+    root = str(tempdir / 'dataset')
+    pq.write_to_dataset(table, root, partition_cols=['part'])
+
+    result = pq.ParquetDataset(root).read(
+        use_threads=False, memory_pool=proxy_pool)
+    assert result.num_rows == table.num_rows
+    assert proxy_pool.bytes_allocated() > 0
+    result = None
+    assert proxy_pool.bytes_allocated() == 0

Reply via email to