Skip to content

[Python] pa.record_batch raises TypeError for tuple data #55418

Open

Description

@AlenkaF

Describe the bug, including details regarding any error messages, version, and platform.

pa.record_batch() checks isinstance(data, (list, tuple)) before passing data to RecordBatch.from_arrays

arrow/python/pyarrow/table.pxi

Lines 6046 to 6048 in 802102a

if isinstance(data, (list, tuple)):
return RecordBatch.from_arrays(data, names=names, schema=schema,
metadata=metadata)

but a tuple of arrays raises a TypeError as arrays is typed as list in Cython:

def from_arrays(list arrays, names=None, schema=None, metadata=None):

Example:

>>> import pyarrow as pa
>>> pa.record_batch((pa.array([1]),), names=["a"])
Traceback (most recent call last):
  File "<python-input-2>", line 1, in <module>
    pa.record_batch((pa.array([1]),), names=["a"])
  File "pyarrow/table.pxi", line 6080, in pyarrow.lib.record_batch
    return RecordBatch.from_arrays(data, names=names, schema=schema,
TypeError: Argument 'arrays' has incorrect type (expected list, got tuple)

The same data passed as a list works.
Note: pa.table() works correctly:

>>> pa.table(([1],), names=["a"])
pyarrow.Table
a: int64
----
a: [[1]]

I have found the issue when reviewing __lib/table.pyi in #55264

Component(s)

Python

Activity

  1. Moemenmohamed24 commented on Nov 5, 2026

    @Moemenmohamed24
    Contributor

    Hello @AlenkaF
    I would like to work on this issue and submit a solution along with the necessary tests.
    Would it be possible for me to take responsibility for this issue ?
    Thank you

  2. kartik00052 commented on Nov 6, 2026

    @kartik00052

    can I work on this now...??

  3. AlenkaF commented on Nov 6, 2026

    @AlenkaF
    MemberAuthor

    This issue needs some discussion on the approach to take first, before any PR is made.

  4. raulcd commented on Nov 6, 2026

    @raulcd
    Member

    @kartik00052 please stop indiscriminately posting on all newly created issues or we will have to ban you. There is a reason the previous PR was closed. Please investigate a little bit before indiscriminately pinging if you can work on an issue.
    Check whether there's someone else working on it (does it have PRs? is it assigned?) also check if there are related closed PRs what is the reason, if there is a conversation take that into account.

  5. Awesome06 commented on Nov 8, 2026

    @Awesome06
    Contributor

    There appear to be two ways to resolve this:

    1. Remove the Cython list type restriction on RecordBatch.from_arrays(arrays, ...) to accept any sequence, matching Table.from_arrays and the Sequence[...] typing stubs in GH-55263: [Python][Annotations] Add internal types and core data structures #55264.
    2. Keep RecordBatch.from_arrays restricted to lists and convert tuples via list(data) inside pa.record_batch().

    Option 1 provides consistency across both tabular constructors. Does removing the list restriction on RecordBatch.from_arrays match the intended design?

    Happy to put together a PR with tests for (1) if that is the preferred direction.

  6. AlenkaF commented on Nov 9, 2026

    @AlenkaF
    MemberAuthor

    My first question, which I haven't investigated yet, is: why is arrays parameter typed to list in Cython, is there a special reason behind that decision? If yes, we can not blindly remove the type restriction there.

    No PRs yet, please.

  7. Awesome06 commented on Nov 9, 2026

    @Awesome06
    Contributor

    I checked the history and implementation of RecordBatch.from_arrays to see why arrays was typed to list in Cython:

    There does not appear to be an architectural or safety reason for it, looks to be a historical artifact from 2017.

    A few details:

    1. Under the hood: RecordBatch.from_arrays only checks len(arrays) and arrays[0] before passing it to _sanitize_arrays(arrays, ...). _sanitize_arrays produces an internal Python list (converted_arrays), which is then used to populate the C++ vector[shared_ptr[CArray]]. The input sequence is never passed directly to C++.
    2. Parity with Table: Table.from_arrays has always kept arrays untyped and accepts tuples without issue.
    3. Original intent: When pa.record_batch() was added in ARROW-6263, it was explicitly written as if isinstance(data, (list, tuple)): return RecordBatch.from_arrays(data, ...). Tuples were clearly intended to be supported, but were blocked by the legacy Cython typing.

    Given that, dropping the list restriction on RecordBatch.from_arrays (def from_arrays(arrays, ...)) should be completely safe and aligns it with Table.from_arrays and the typing stubs in #55264.

    Commit history details
    • Oct 2016 (a9747ceac, ARROW-312): Both RecordBatch.from_arrays and Table.from_arrays were originally untyped (def from_arrays(names, arrays)).
    • Apr 2017 (7d433dc27, ARROW-483 / PR ARROW-483: [C++/Python] Provide access to "custom_metadata" Field attribute in IPC setting #588): RecordBatch.from_arrays had Cython types added (def from_arrays(list arrays, list names, dict metadata=None)), while Table.from_arrays kept arrays untyped.
    • Jul 2018 (ec9b72a23, ARROW-1715): list names was relaxed to names in RecordBatch.from_arrays to support schemas during unpickling, leaving list arrays.
    • Dec 2018 (9da458437, ARROW-2624): dict metadata was relaxed to metadata to allow arbitrary mappings, leaving list arrays.
    • Aug 2019 (05bc63c3b, ARROW-6263): pa.record_batch and pa.table factory functions were added with isinstance(data, (list, tuple)). pa.table worked because Table.from_arrays was untyped, while pa.record_batch failed on tuples due to the remaining Cython check.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions