Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/py-polars/tests/unit/interchange/test_from_dataframe.py
6939 views
1
from __future__ import annotations
2
3
from datetime import date, datetime, time, timedelta
4
from typing import Any
5
6
import pandas as pd
7
import pyarrow as pa
8
import pytest
9
10
import polars as pl
11
from polars.interchange.buffer import PolarsBuffer
12
from polars.interchange.column import PolarsColumn
13
from polars.interchange.from_dataframe import (
14
_categorical_column_to_series,
15
_column_to_series,
16
_construct_data_buffer,
17
_construct_offsets_buffer,
18
_construct_validity_buffer,
19
_construct_validity_buffer_from_bitmask,
20
_construct_validity_buffer_from_bytemask,
21
_string_column_to_series,
22
)
23
from polars.interchange.protocol import (
24
ColumnNullType,
25
CopyNotAllowedError,
26
DtypeKind,
27
Endianness,
28
)
29
from polars.testing import assert_frame_equal, assert_series_equal
30
31
NE = Endianness.NATIVE
32
33
34
def test_from_dataframe_polars() -> None:
35
df = pl.DataFrame({"a": [1, 2], "b": [3.0, 4.0], "c": ["foo", "bar"]})
36
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
37
result = pl.from_dataframe(df, allow_copy=False)
38
assert_frame_equal(result, df)
39
40
41
def test_from_dataframe_polars_interchange_fast_path() -> None:
42
df = pl.DataFrame(
43
{"a": [1, 2], "b": [3.0, 4.0], "c": ["foo", "bar"]},
44
schema_overrides={"c": pl.Categorical},
45
)
46
dfi = df.__dataframe__()
47
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
48
result = pl.from_dataframe(dfi, allow_copy=False)
49
assert_frame_equal(result, df)
50
51
52
def test_from_dataframe_categorical() -> None:
53
df = pl.DataFrame({"a": ["foo", "bar"]}, schema={"a": pl.Categorical})
54
df_pa = df.to_arrow()
55
56
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
57
result = pl.from_dataframe(df_pa, allow_copy=True)
58
expected = pl.DataFrame({"a": ["foo", "bar"]}, schema={"a": pl.Categorical})
59
assert_frame_equal(result, expected)
60
61
62
def test_from_dataframe_empty_string_zero_copy() -> None:
63
df = pl.DataFrame({"a": []}, schema={"a": pl.String})
64
df_pa = df.to_arrow()
65
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
66
result = pl.from_dataframe(df_pa, allow_copy=False)
67
assert_frame_equal(result, df)
68
69
70
def test_from_dataframe_empty_bool_zero_copy() -> None:
71
df = pl.DataFrame(schema={"a": pl.Boolean})
72
df_pd = df.to_pandas()
73
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
74
result = pl.from_dataframe(df_pd, allow_copy=False)
75
assert_frame_equal(result, df)
76
77
78
def test_from_dataframe_empty_categories_zero_copy() -> None:
79
df = pl.DataFrame(schema={"a": pl.Enum([])})
80
df_pa = df.to_arrow()
81
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
82
result = pl.from_dataframe(df_pa, allow_copy=False)
83
assert_frame_equal(result, df)
84
85
86
def test_from_dataframe_pandas_zero_copy() -> None:
87
data = {"a": [1, 2], "b": [3.0, 4.0]}
88
89
df = pd.DataFrame(data)
90
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
91
result = pl.from_dataframe(df, allow_copy=False)
92
expected = pl.DataFrame(data)
93
assert_frame_equal(result, expected)
94
95
96
def test_from_dataframe_pyarrow_table_zero_copy() -> None:
97
df = pl.DataFrame(
98
{
99
"a": [1, 2],
100
"b": [3.0, 4.0],
101
}
102
)
103
df_pa = df.to_arrow()
104
105
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
106
result = pl.from_dataframe(df_pa, allow_copy=False)
107
assert_frame_equal(result, df)
108
109
110
def test_from_dataframe_pyarrow_empty_table() -> None:
111
df = pl.Series("a", dtype=pl.Int8).to_frame()
112
df_pa = df.to_arrow()
113
114
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
115
result = pl.from_dataframe(df_pa, allow_copy=False)
116
assert_frame_equal(result, df)
117
118
119
def test_from_dataframe_pyarrow_recordbatch_zero_copy() -> None:
120
a = pa.array([1, 2])
121
b = pa.array([3.0, 4.0])
122
123
batch = pa.record_batch([a, b], names=["a", "b"])
124
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
125
result = pl.from_dataframe(batch, allow_copy=False)
126
127
expected = pl.DataFrame({"a": [1, 2], "b": [3.0, 4.0]})
128
assert_frame_equal(result, expected)
129
130
131
def test_from_dataframe_invalid_type() -> None:
132
df = [[1, 2], [3, 4]]
133
with pytest.raises(TypeError):
134
pl.from_dataframe(df) # type: ignore[arg-type]
135
136
137
def test_from_dataframe_pyarrow_boolean() -> None:
138
df = pl.Series("a", [True, False]).to_frame()
139
df_pa = df.to_arrow()
140
141
result = pl.from_dataframe(df_pa)
142
assert_frame_equal(result, df)
143
144
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
145
result = pl.from_dataframe(df_pa, allow_copy=False)
146
assert_frame_equal(result, df)
147
148
149
def test_from_dataframe_chunked() -> None:
150
df = pl.Series("a", [0, 1], dtype=pl.Int8).to_frame()
151
df_chunked = pl.concat([df[:1], df[1:]], rechunk=False)
152
153
df_pa = df_chunked.to_arrow()
154
result = pl.from_dataframe(df_pa, rechunk=False)
155
156
assert_frame_equal(result, df_chunked)
157
assert result.n_chunks() == 2
158
159
160
@pytest.mark.may_fail_auto_streaming
161
@pytest.mark.may_fail_cloud # reason: chunking
162
def test_from_dataframe_chunked_string() -> None:
163
df = pl.Series("a", ["a", None, "bc", "d", None, "efg"]).to_frame()
164
df_chunked = pl.concat([df[:1], df[1:3], df[3:]], rechunk=False)
165
166
df_pa = df_chunked.to_arrow()
167
result = pl.from_dataframe(df_pa, rechunk=False)
168
169
assert_frame_equal(result, df_chunked)
170
assert result.n_chunks() == 3
171
172
173
def test_from_dataframe_pandas_nan_as_null() -> None:
174
df = pd.Series([1.0, float("nan"), float("inf")], name="a").to_frame()
175
result = pl.from_dataframe(df)
176
expected = pl.Series("a", [1.0, None, float("inf")]).to_frame()
177
assert_frame_equal(result, expected)
178
assert result.n_chunks() == 1
179
180
181
def test_from_dataframe_pandas_boolean_bytes() -> None:
182
df = pd.Series([True, False], name="a").to_frame()
183
result = pl.from_dataframe(df)
184
185
expected = pl.Series("a", [True, False]).to_frame()
186
assert_frame_equal(result, expected)
187
188
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
189
result = pl.from_dataframe(df, allow_copy=False)
190
expected = pl.Series("a", [True, False]).to_frame()
191
assert_frame_equal(result, expected)
192
193
194
def test_from_dataframe_categorical_pandas() -> None:
195
values = ["a", "b", None, "a"]
196
197
df_pd = pd.Series(values, dtype="category", name="a").to_frame()
198
199
result = pl.from_dataframe(df_pd)
200
expected = pl.Series("a", values, dtype=pl.Categorical).to_frame()
201
assert_frame_equal(result, expected)
202
203
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
204
result = pl.from_dataframe(df_pd, allow_copy=False)
205
expected = pl.Series("a", values, dtype=pl.Categorical).to_frame()
206
assert_frame_equal(result, expected)
207
208
209
def test_from_dataframe_categorical_pyarrow() -> None:
210
values = ["a", "b", None, "a"]
211
212
dtype = pa.dictionary(pa.int32(), pa.utf8())
213
arr = pa.array(values, dtype)
214
df_pa = pa.Table.from_arrays([arr], names=["a"])
215
216
result = pl.from_dataframe(df_pa)
217
expected = pl.Series("a", values, dtype=pl.Categorical).to_frame()
218
assert_frame_equal(result, expected)
219
220
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
221
result = pl.from_dataframe(df_pa, allow_copy=False)
222
assert_frame_equal(result, expected)
223
224
225
def test_from_dataframe_categorical_non_string_keys() -> None:
226
values = [1, 2, None, 1]
227
228
dtype = pa.dictionary(pa.uint32(), pa.int32())
229
arr = pa.array(values, dtype)
230
df_pa = pa.Table.from_arrays([arr], names=["a"])
231
result = pl.from_dataframe(df_pa)
232
expected = pl.DataFrame({"a": [1, 2, None, 1]}, schema={"a": pl.Int32})
233
assert_frame_equal(result, expected)
234
235
236
def test_from_dataframe_categorical_non_u32_values() -> None:
237
values = [None, None]
238
239
dtype = pa.dictionary(pa.int8(), pa.utf8())
240
arr = pa.array(values, dtype)
241
df_pa = pa.Table.from_arrays([arr], names=["a"])
242
243
result = pl.from_dataframe(df_pa)
244
expected = pl.Series("a", values, dtype=pl.Categorical).to_frame()
245
assert_frame_equal(result, expected)
246
247
with pytest.deprecated_call(match="`allow_copy` is deprecated"):
248
result = pl.from_dataframe(df_pa, allow_copy=False)
249
assert_frame_equal(result, expected)
250
251
252
class PatchableColumn(PolarsColumn):
253
"""Helper class that allows patching certain PolarsColumn properties."""
254
255
describe_null: tuple[ColumnNullType, Any] = (ColumnNullType.USE_BITMASK, 0)
256
describe_categorical: dict[str, Any] = {} # type: ignore[assignment] # noqa: RUF012
257
null_count = 0
258
259
260
def test_column_to_series_use_sentinel_i64_min() -> None:
261
I64_MIN = -9223372036854775808
262
dtype = pl.Datetime("us")
263
physical = pl.Series([0, I64_MIN])
264
logical = physical.cast(dtype)
265
266
col = PatchableColumn(logical)
267
col.describe_null = (ColumnNullType.USE_SENTINEL, I64_MIN)
268
col.null_count = 1
269
270
result = _column_to_series(col, dtype, allow_copy=True)
271
expected = pl.Series([datetime(1970, 1, 1), None])
272
assert_series_equal(result, expected)
273
274
275
def test_column_to_series_duration() -> None:
276
s = pl.Series([timedelta(seconds=10), timedelta(days=5), None])
277
col = PolarsColumn(s)
278
result = _column_to_series(col, s.dtype, allow_copy=True)
279
assert_series_equal(result, s)
280
281
282
def test_column_to_series_time() -> None:
283
s = pl.Series([time(10, 0), time(23, 59, 59), None])
284
col = PolarsColumn(s)
285
result = _column_to_series(col, s.dtype, allow_copy=True)
286
assert_series_equal(result, s)
287
288
289
def test_column_to_series_use_sentinel_date() -> None:
290
mask_value = date(1900, 1, 1)
291
292
s = pl.Series([date(1970, 1, 1), mask_value, date(2000, 1, 1)])
293
294
col = PatchableColumn(s)
295
col.describe_null = (ColumnNullType.USE_SENTINEL, mask_value)
296
col.null_count = 1
297
298
result = _column_to_series(col, pl.Date, allow_copy=True)
299
expected = pl.Series([date(1970, 1, 1), None, date(2000, 1, 1)])
300
assert_series_equal(result, expected)
301
302
303
def test_column_to_series_use_sentinel_datetime() -> None:
304
dtype = pl.Datetime("ns")
305
mask_value = datetime(1900, 1, 1)
306
307
s = pl.Series([datetime(1970, 1, 1), mask_value, datetime(2000, 1, 1)], dtype=dtype)
308
309
col = PatchableColumn(s)
310
col.describe_null = (ColumnNullType.USE_SENTINEL, mask_value)
311
col.null_count = 1
312
313
result = _column_to_series(col, dtype, allow_copy=True)
314
expected = pl.Series(
315
[datetime(1970, 1, 1), None, datetime(2000, 1, 1)], dtype=dtype
316
)
317
assert_series_equal(result, expected)
318
319
320
def test_column_to_series_use_sentinel_invalid_value() -> None:
321
dtype = pl.Datetime("ns")
322
mask_value = "invalid"
323
324
s = pl.Series([datetime(1970, 1, 1), None, datetime(2000, 1, 1)], dtype=dtype)
325
326
col = PatchableColumn(s)
327
col.describe_null = (ColumnNullType.USE_SENTINEL, mask_value)
328
col.null_count = 1
329
330
with pytest.raises(
331
TypeError,
332
match="invalid sentinel value for column of type Datetime\\(time_unit='ns', time_zone=None\\): 'invalid'",
333
):
334
_column_to_series(col, dtype, allow_copy=True)
335
336
337
def test_string_column_to_series_no_offsets() -> None:
338
s = pl.Series([97, 98, 99])
339
col = PolarsColumn(s)
340
with pytest.raises(
341
RuntimeError,
342
match="cannot create String column without an offsets buffer",
343
):
344
_string_column_to_series(col, allow_copy=True)
345
346
347
def test_categorical_column_to_series_non_dictionary() -> None:
348
s = pl.Series(["a", "b", None, "a"], dtype=pl.Categorical)
349
350
col = PatchableColumn(s)
351
col.describe_categorical = {"is_dictionary": False}
352
353
with pytest.raises(
354
NotImplementedError, match="non-dictionary categoricals are not yet supported"
355
):
356
_categorical_column_to_series(col, allow_copy=True)
357
358
359
def test_construct_data_buffer() -> None:
360
data = pl.Series([0, 1, 3, 3, 9], dtype=pl.Int64)
361
buffer = PolarsBuffer(data)
362
dtype = (DtypeKind.INT, 64, "l", NE)
363
364
result = _construct_data_buffer(buffer, dtype, length=5, allow_copy=True)
365
assert_series_equal(result, data)
366
367
368
def test_construct_data_buffer_boolean_sliced() -> None:
369
data = pl.Series([False, True, True, False])
370
data_sliced = data[2:]
371
buffer = PolarsBuffer(data_sliced)
372
dtype = (DtypeKind.BOOL, 1, "b", NE)
373
374
result = _construct_data_buffer(buffer, dtype, length=2, offset=2, allow_copy=True)
375
assert_series_equal(result, data_sliced)
376
377
378
def test_construct_data_buffer_logical_dtype() -> None:
379
data = pl.Series([100, 200, 300], dtype=pl.Int32)
380
buffer = PolarsBuffer(data)
381
dtype = (DtypeKind.DATETIME, 32, "tdD", NE)
382
383
result = _construct_data_buffer(buffer, dtype, length=3, allow_copy=True)
384
assert_series_equal(result, data)
385
386
387
def test_construct_offsets_buffer() -> None:
388
data = pl.Series([0, 1, 3, 3, 9], dtype=pl.Int64)
389
buffer = PolarsBuffer(data)
390
dtype = (DtypeKind.INT, 64, "l", NE)
391
392
result = _construct_offsets_buffer(buffer, dtype, offset=0, allow_copy=True)
393
assert_series_equal(result, data)
394
395
396
def test_construct_offsets_buffer_offset() -> None:
397
data = pl.Series([0, 1, 3, 3, 9], dtype=pl.Int64)
398
buffer = PolarsBuffer(data)
399
dtype = (DtypeKind.INT, 64, "l", NE)
400
offset = 2
401
402
result = _construct_offsets_buffer(buffer, dtype, offset=offset, allow_copy=True)
403
assert_series_equal(result, data[offset:])
404
405
406
def test_construct_offsets_buffer_copy() -> None:
407
data = pl.Series([0, 1, 3, 3, 9], dtype=pl.UInt32)
408
buffer = PolarsBuffer(data)
409
dtype = (DtypeKind.UINT, 32, "I", NE)
410
411
with pytest.raises(CopyNotAllowedError):
412
_construct_offsets_buffer(buffer, dtype, offset=0, allow_copy=False)
413
414
result = _construct_offsets_buffer(buffer, dtype, offset=0, allow_copy=True)
415
expected = pl.Series([0, 1, 3, 3, 9], dtype=pl.Int64)
416
assert_series_equal(result, expected)
417
418
419
@pytest.fixture
420
def bitmask() -> PolarsBuffer:
421
data = pl.Series([False, True, True, False])
422
return PolarsBuffer(data)
423
424
425
@pytest.fixture
426
def bytemask() -> PolarsBuffer:
427
data = pl.Series([0, 1, 1, 0], dtype=pl.UInt8)
428
return PolarsBuffer(data)
429
430
431
def test_construct_validity_buffer_non_nullable() -> None:
432
s = pl.Series([1, 2, 3])
433
434
col = PatchableColumn(s)
435
col.describe_null = (ColumnNullType.NON_NULLABLE, None)
436
col.null_count = 1
437
438
result = _construct_validity_buffer(None, col, s.dtype, s, allow_copy=True)
439
assert result is None
440
441
442
def test_construct_validity_buffer_null_count() -> None:
443
s = pl.Series([1, 2, 3])
444
445
col = PatchableColumn(s)
446
col.describe_null = (ColumnNullType.USE_SENTINEL, -1)
447
col.null_count = 0
448
449
result = _construct_validity_buffer(None, col, s.dtype, s, allow_copy=True)
450
assert result is None
451
452
453
def test_construct_validity_buffer_use_bitmask(bitmask: PolarsBuffer) -> None:
454
s = pl.Series([1, 2, 3, 4])
455
456
col = PatchableColumn(s)
457
col.describe_null = (ColumnNullType.USE_BITMASK, 0)
458
col.null_count = 2
459
460
dtype = (DtypeKind.BOOL, 1, "b", NE)
461
validity_buffer_info = (bitmask, dtype)
462
463
result = _construct_validity_buffer(
464
validity_buffer_info, col, s.dtype, s, allow_copy=True
465
)
466
expected = pl.Series([False, True, True, False])
467
assert_series_equal(result, expected) # type: ignore[arg-type]
468
469
result = _construct_validity_buffer(None, col, s.dtype, s, allow_copy=True)
470
assert result is None
471
472
473
def test_construct_validity_buffer_use_bytemask(bytemask: PolarsBuffer) -> None:
474
s = pl.Series([1, 2, 3, 4])
475
476
col = PatchableColumn(s)
477
col.describe_null = (ColumnNullType.USE_BYTEMASK, 0)
478
col.null_count = 2
479
480
dtype = (DtypeKind.UINT, 8, "C", NE)
481
validity_buffer_info = (bytemask, dtype)
482
483
result = _construct_validity_buffer(
484
validity_buffer_info, col, s.dtype, s, allow_copy=True
485
)
486
expected = pl.Series([False, True, True, False])
487
assert_series_equal(result, expected) # type: ignore[arg-type]
488
489
result = _construct_validity_buffer(None, col, s.dtype, s, allow_copy=True)
490
assert result is None
491
492
493
def test_construct_validity_buffer_use_nan() -> None:
494
s = pl.Series([1.0, 2.0, float("nan")])
495
496
col = PatchableColumn(s)
497
col.describe_null = (ColumnNullType.USE_NAN, None)
498
col.null_count = 1
499
500
result = _construct_validity_buffer(None, col, s.dtype, s, allow_copy=True)
501
expected = pl.Series([True, True, False])
502
assert_series_equal(result, expected) # type: ignore[arg-type]
503
504
with pytest.raises(CopyNotAllowedError, match="bitmask must be constructed"):
505
_construct_validity_buffer(None, col, s.dtype, s, allow_copy=False)
506
507
508
def test_construct_validity_buffer_use_sentinel() -> None:
509
s = pl.Series(["a", "bc", "NULL"])
510
511
col = PatchableColumn(s)
512
col.describe_null = (ColumnNullType.USE_SENTINEL, "NULL")
513
col.null_count = 1
514
515
result = _construct_validity_buffer(None, col, s.dtype, s, allow_copy=True)
516
expected = pl.Series([True, True, False])
517
assert_series_equal(result, expected) # type: ignore[arg-type]
518
519
with pytest.raises(CopyNotAllowedError, match="bitmask must be constructed"):
520
_construct_validity_buffer(None, col, s.dtype, s, allow_copy=False)
521
522
523
def test_construct_validity_buffer_unsupported() -> None:
524
s = pl.Series([1, 2, 3])
525
526
col = PatchableColumn(s)
527
col.describe_null = (100, None) # type: ignore[assignment]
528
col.null_count = 1
529
530
with pytest.raises(NotImplementedError, match="unsupported null type: 100"):
531
_construct_validity_buffer(None, col, s.dtype, s, allow_copy=True)
532
533
534
@pytest.mark.parametrize("allow_copy", [True, False])
535
def test_construct_validity_buffer_from_bitmask(
536
allow_copy: bool, bitmask: PolarsBuffer
537
) -> None:
538
result = _construct_validity_buffer_from_bitmask(
539
bitmask, null_value=0, offset=0, length=4, allow_copy=allow_copy
540
)
541
expected = pl.Series([False, True, True, False])
542
assert_series_equal(result, expected)
543
544
545
def test_construct_validity_buffer_from_bitmask_inverted(bitmask: PolarsBuffer) -> None:
546
result = _construct_validity_buffer_from_bitmask(
547
bitmask, null_value=1, offset=0, length=4, allow_copy=True
548
)
549
expected = pl.Series([True, False, False, True])
550
assert_series_equal(result, expected)
551
552
553
def test_construct_validity_buffer_from_bitmask_zero_copy_fails(
554
bitmask: PolarsBuffer,
555
) -> None:
556
with pytest.raises(CopyNotAllowedError):
557
_construct_validity_buffer_from_bitmask(
558
bitmask, null_value=1, offset=0, length=4, allow_copy=False
559
)
560
561
562
def test_construct_validity_buffer_from_bitmask_sliced() -> None:
563
data = pl.Series([False, True, True, False])
564
data_sliced = data[2:]
565
bitmask = PolarsBuffer(data_sliced)
566
567
result = _construct_validity_buffer_from_bitmask(
568
bitmask, null_value=0, offset=2, length=2, allow_copy=True
569
)
570
assert_series_equal(result, data_sliced)
571
572
573
def test_construct_validity_buffer_from_bytemask(bytemask: PolarsBuffer) -> None:
574
result = _construct_validity_buffer_from_bytemask(
575
bytemask, null_value=0, allow_copy=True
576
)
577
expected = pl.Series([False, True, True, False])
578
assert_series_equal(result, expected)
579
580
581
def test_construct_validity_buffer_from_bytemask_inverted(
582
bytemask: PolarsBuffer,
583
) -> None:
584
result = _construct_validity_buffer_from_bytemask(
585
bytemask, null_value=1, allow_copy=True
586
)
587
expected = pl.Series([True, False, False, True])
588
assert_series_equal(result, expected)
589
590
591
def test_construct_validity_buffer_from_bytemask_zero_copy_fails(
592
bytemask: PolarsBuffer,
593
) -> None:
594
with pytest.raises(CopyNotAllowedError):
595
_construct_validity_buffer_from_bytemask(
596
bytemask, null_value=0, allow_copy=False
597
)
598
599
600
def test_interchange_protocol_fallback(monkeypatch: pytest.MonkeyPatch) -> None:
601
df_pd = pd.DataFrame({"a": [1, 2, 3]})
602
monkeypatch.setattr(df_pd, "__arrow_c_stream__", lambda *args, **kwargs: 1 / 0)
603
with pytest.warns(
604
UserWarning, match="Falling back to Dataframe Interchange Protocol"
605
):
606
result = pl.from_dataframe(df_pd)
607
expected = pl.DataFrame({"a": [1, 2, 3]})
608
assert_frame_equal(result, expected)
609
610
611
def test_to_pandas_int8_20316() -> None:
612
df = pl.Series("a", [None], pl.Int8).to_frame()
613
df_pd = df.to_pandas(use_pyarrow_extension_array=True)
614
result = pl.from_dataframe(df_pd)
615
assert_frame_equal(result, df)
616
617