A column object, with only the methods and properties required by the interchange protocol defined. A column can contain one or more chunks. Each chunk can contain up to three buffers - a data buffer, a mask buffer (depending on null representation), and an offsets buffer (if v
| 156 | |
| 157 | |
| 158 | class _PyArrowColumn: |
| 159 | """ |
| 160 | A column object, with only the methods and properties required by the |
| 161 | interchange protocol defined. |
| 162 | |
| 163 | A column can contain one or more chunks. Each chunk can contain up to three |
| 164 | buffers - a data buffer, a mask buffer (depending on null representation), |
| 165 | and an offsets buffer (if variable-size binary; e.g., variable-length |
| 166 | strings). |
| 167 | |
| 168 | TBD: Arrow has a separate "null" dtype, and has no separate mask concept. |
| 169 | Instead, it seems to use "children" for both columns with a bit mask, |
| 170 | and for nested dtypes. Unclear whether this is elegant or confusing. |
| 171 | This design requires checking the null representation explicitly. |
| 172 | |
| 173 | The Arrow design requires checking: |
| 174 | 1. the ARROW_FLAG_NULLABLE (for sentinel values) |
| 175 | 2. if a column has two children, combined with one of those children |
| 176 | having a null dtype. |
| 177 | |
| 178 | Making the mask concept explicit seems useful. One null dtype would |
| 179 | not be enough to cover both bit and byte masks, so that would mean |
| 180 | even more checking if we did it the Arrow way. |
| 181 | |
| 182 | TBD: there's also the "chunk" concept here, which is implicit in Arrow as |
| 183 | multiple buffers per array (= column here). Semantically it may make |
| 184 | sense to have both: chunks were meant for example for lazy evaluation |
| 185 | of data which doesn't fit in memory, while multiple buffers per column |
| 186 | could also come from doing a selection operation on a single |
| 187 | contiguous buffer. |
| 188 | |
| 189 | Given these concepts, one would expect chunks to be all of the same |
| 190 | size (say a 10,000 row dataframe could have 10 chunks of 1,000 rows), |
| 191 | while multiple buffers could have data-dependent lengths. Not an issue |
| 192 | in pandas if one column is backed by a single NumPy array, but in |
| 193 | Arrow it seems possible. |
| 194 | Are multiple chunks *and* multiple buffers per column necessary for |
| 195 | the purposes of this interchange protocol, or must producers either |
| 196 | reuse the chunk concept for this or copy the data? |
| 197 | |
| 198 | Note: this Column object can only be produced by ``__dataframe__``, so |
| 199 | doesn't need its own version or ``__column__`` protocol. |
| 200 | """ |
| 201 | |
| 202 | def __init__( |
| 203 | self, column: pa.Array | pa.ChunkedArray, allow_copy: bool = True |
| 204 | ) -> None: |
| 205 | """ |
| 206 | Handles PyArrow Arrays and ChunkedArrays. |
| 207 | """ |
| 208 | # Store the column as a private attribute |
| 209 | if isinstance(column, pa.ChunkedArray): |
| 210 | if column.num_chunks == 1: |
| 211 | column = column.chunk(0) |
| 212 | else: |
| 213 | if not allow_copy: |
| 214 | raise RuntimeError( |
| 215 | "Chunks will be combined and a copy is required which " |
no outgoing calls