@@ -64,6 +64,7 @@ use pyo3::exceptions::{PyTypeError, PyValueError};
64
64
use pyo3:: ffi:: Py_uintptr_t ;
65
65
use pyo3:: import_exception;
66
66
use pyo3:: prelude:: * ;
67
+ use pyo3:: pybacked:: PyBackedStr ;
67
68
use pyo3:: types:: { PyCapsule , PyList , PyTuple } ;
68
69
69
70
use crate :: array:: { make_array, ArrayData } ;
@@ -82,7 +83,12 @@ fn to_py_err(err: ArrowError) -> PyErr {
82
83
}
83
84
84
85
pub trait FromPyArrow : Sized {
85
- fn from_pyarrow ( value : & PyAny ) -> PyResult < Self > ;
86
+ #[ deprecated( since = "52.0.0" , note = "Use from_pyarrow_bound" ) ]
87
+ fn from_pyarrow ( value : & PyAny ) -> PyResult < Self > {
88
+ Self :: from_pyarrow_bound ( & value. as_borrowed ( ) )
89
+ }
90
+
91
+ fn from_pyarrow_bound ( value : & Bound < PyAny > ) -> PyResult < Self > ;
86
92
}
87
93
88
94
/// Create a new PyArrow object from a arrow-rs type.
@@ -101,15 +107,17 @@ impl<T: ToPyArrow> IntoPyArrow for T {
101
107
}
102
108
}
103
109
104
- fn validate_class ( expected : & str , value : & PyAny ) -> PyResult < ( ) > {
105
- let pyarrow = PyModule :: import ( value. py ( ) , "pyarrow" ) ?;
110
+ fn validate_class ( expected : & str , value : & Bound < PyAny > ) -> PyResult < ( ) > {
111
+ let pyarrow = PyModule :: import_bound ( value. py ( ) , "pyarrow" ) ?;
106
112
let class = pyarrow. getattr ( expected) ?;
107
- if !value. is_instance ( class) ? {
108
- let expected_module = class. getattr ( "__module__" ) ?. extract :: < & str > ( ) ?;
109
- let expected_name = class. getattr ( "__name__" ) ?. extract :: < & str > ( ) ?;
113
+ if !value. is_instance ( & class) ? {
114
+ let expected_module = class. getattr ( "__module__" ) ?. extract :: < PyBackedStr > ( ) ?;
115
+ let expected_name = class. getattr ( "__name__" ) ?. extract :: < PyBackedStr > ( ) ?;
110
116
let found_class = value. get_type ( ) ;
111
- let found_module = found_class. getattr ( "__module__" ) ?. extract :: < & str > ( ) ?;
112
- let found_name = found_class. getattr ( "__name__" ) ?. extract :: < & str > ( ) ?;
117
+ let found_module = found_class
118
+ . getattr ( "__module__" ) ?
119
+ . extract :: < PyBackedStr > ( ) ?;
120
+ let found_name = found_class. getattr ( "__name__" ) ?. extract :: < PyBackedStr > ( ) ?;
113
121
return Err ( PyTypeError :: new_err ( format ! (
114
122
"Expected instance of {}.{}, got {}.{}" ,
115
123
expected_module, expected_name, found_module, found_name
@@ -118,7 +126,7 @@ fn validate_class(expected: &str, value: &PyAny) -> PyResult<()> {
118
126
Ok ( ( ) )
119
127
}
120
128
121
- fn validate_pycapsule ( capsule : & PyCapsule , name : & str ) -> PyResult < ( ) > {
129
+ fn validate_pycapsule ( capsule : & Bound < PyCapsule > , name : & str ) -> PyResult < ( ) > {
122
130
let capsule_name = capsule. name ( ) ?;
123
131
if capsule_name. is_none ( ) {
124
132
return Err ( PyValueError :: new_err (
@@ -138,13 +146,13 @@ fn validate_pycapsule(capsule: &PyCapsule, name: &str) -> PyResult<()> {
138
146
}
139
147
140
148
impl FromPyArrow for DataType {
141
- fn from_pyarrow ( value : & PyAny ) -> PyResult < Self > {
149
+ fn from_pyarrow_bound ( value : & Bound < PyAny > ) -> PyResult < Self > {
142
150
// Newer versions of PyArrow as well as other libraries with Arrow data implement this
143
151
// method, so prefer it over _export_to_c.
144
152
// See https://arrow.apache.org/docs/format/CDataInterface/PyCapsuleInterface.html
145
153
if value. hasattr ( "__arrow_c_schema__" ) ? {
146
- let capsule: & PyCapsule =
147
- PyTryInto :: try_into ( value . getattr ( "__arrow_c_schema__" ) ? . call0 ( ) ? ) ?;
154
+ let capsule = value . getattr ( "__arrow_c_schema__" ) ? . call0 ( ) ? ;
155
+ let capsule = capsule . downcast :: < PyCapsule > ( ) ?;
148
156
validate_pycapsule ( capsule, "arrow_schema" ) ?;
149
157
150
158
let schema_ptr = unsafe { capsule. reference :: < FFI_ArrowSchema > ( ) } ;
@@ -166,21 +174,21 @@ impl ToPyArrow for DataType {
166
174
fn to_pyarrow ( & self , py : Python ) -> PyResult < PyObject > {
167
175
let c_schema = FFI_ArrowSchema :: try_from ( self ) . map_err ( to_py_err) ?;
168
176
let c_schema_ptr = & c_schema as * const FFI_ArrowSchema ;
169
- let module = py. import ( "pyarrow" ) ?;
177
+ let module = py. import_bound ( "pyarrow" ) ?;
170
178
let class = module. getattr ( "DataType" ) ?;
171
179
let dtype = class. call_method1 ( "_import_from_c" , ( c_schema_ptr as Py_uintptr_t , ) ) ?;
172
180
Ok ( dtype. into ( ) )
173
181
}
174
182
}
175
183
176
184
impl FromPyArrow for Field {
177
- fn from_pyarrow ( value : & PyAny ) -> PyResult < Self > {
185
+ fn from_pyarrow_bound ( value : & Bound < PyAny > ) -> PyResult < Self > {
178
186
// Newer versions of PyArrow as well as other libraries with Arrow data implement this
179
187
// method, so prefer it over _export_to_c.
180
188
// See https://arrow.apache.org/docs/format/CDataInterface/PyCapsuleInterface.html
181
189
if value. hasattr ( "__arrow_c_schema__" ) ? {
182
- let capsule: & PyCapsule =
183
- PyTryInto :: try_into ( value . getattr ( "__arrow_c_schema__" ) ? . call0 ( ) ? ) ?;
190
+ let capsule = value . getattr ( "__arrow_c_schema__" ) ? . call0 ( ) ? ;
191
+ let capsule = capsule . downcast :: < PyCapsule > ( ) ?;
184
192
validate_pycapsule ( capsule, "arrow_schema" ) ?;
185
193
186
194
let schema_ptr = unsafe { capsule. reference :: < FFI_ArrowSchema > ( ) } ;
@@ -202,21 +210,21 @@ impl ToPyArrow for Field {
202
210
fn to_pyarrow ( & self , py : Python ) -> PyResult < PyObject > {
203
211
let c_schema = FFI_ArrowSchema :: try_from ( self ) . map_err ( to_py_err) ?;
204
212
let c_schema_ptr = & c_schema as * const FFI_ArrowSchema ;
205
- let module = py. import ( "pyarrow" ) ?;
213
+ let module = py. import_bound ( "pyarrow" ) ?;
206
214
let class = module. getattr ( "Field" ) ?;
207
215
let dtype = class. call_method1 ( "_import_from_c" , ( c_schema_ptr as Py_uintptr_t , ) ) ?;
208
216
Ok ( dtype. into ( ) )
209
217
}
210
218
}
211
219
212
220
impl FromPyArrow for Schema {
213
- fn from_pyarrow ( value : & PyAny ) -> PyResult < Self > {
221
+ fn from_pyarrow_bound ( value : & Bound < PyAny > ) -> PyResult < Self > {
214
222
// Newer versions of PyArrow as well as other libraries with Arrow data implement this
215
223
// method, so prefer it over _export_to_c.
216
224
// See https://arrow.apache.org/docs/format/CDataInterface/PyCapsuleInterface.html
217
225
if value. hasattr ( "__arrow_c_schema__" ) ? {
218
- let capsule: & PyCapsule =
219
- PyTryInto :: try_into ( value . getattr ( "__arrow_c_schema__" ) ? . call0 ( ) ? ) ?;
226
+ let capsule = value . getattr ( "__arrow_c_schema__" ) ? . call0 ( ) ? ;
227
+ let capsule = capsule . downcast :: < PyCapsule > ( ) ?;
220
228
validate_pycapsule ( capsule, "arrow_schema" ) ?;
221
229
222
230
let schema_ptr = unsafe { capsule. reference :: < FFI_ArrowSchema > ( ) } ;
@@ -238,15 +246,15 @@ impl ToPyArrow for Schema {
238
246
fn to_pyarrow ( & self , py : Python ) -> PyResult < PyObject > {
239
247
let c_schema = FFI_ArrowSchema :: try_from ( self ) . map_err ( to_py_err) ?;
240
248
let c_schema_ptr = & c_schema as * const FFI_ArrowSchema ;
241
- let module = py. import ( "pyarrow" ) ?;
249
+ let module = py. import_bound ( "pyarrow" ) ?;
242
250
let class = module. getattr ( "Schema" ) ?;
243
251
let schema = class. call_method1 ( "_import_from_c" , ( c_schema_ptr as Py_uintptr_t , ) ) ?;
244
252
Ok ( schema. into ( ) )
245
253
}
246
254
}
247
255
248
256
impl FromPyArrow for ArrayData {
249
- fn from_pyarrow ( value : & PyAny ) -> PyResult < Self > {
257
+ fn from_pyarrow_bound ( value : & Bound < PyAny > ) -> PyResult < Self > {
250
258
// Newer versions of PyArrow as well as other libraries with Arrow data implement this
251
259
// method, so prefer it over _export_to_c.
252
260
// See https://arrow.apache.org/docs/format/CDataInterface/PyCapsuleInterface.html
@@ -259,8 +267,10 @@ impl FromPyArrow for ArrayData {
259
267
) ) ;
260
268
}
261
269
262
- let schema_capsule: & PyCapsule = PyTryInto :: try_into ( tuple. get_item ( 0 ) ?) ?;
263
- let array_capsule: & PyCapsule = PyTryInto :: try_into ( tuple. get_item ( 1 ) ?) ?;
270
+ let schema_capsule = tuple. get_item ( 0 ) ?;
271
+ let schema_capsule = schema_capsule. downcast :: < PyCapsule > ( ) ?;
272
+ let array_capsule = tuple. get_item ( 1 ) ?;
273
+ let array_capsule = array_capsule. downcast :: < PyCapsule > ( ) ?;
264
274
265
275
validate_pycapsule ( schema_capsule, "arrow_schema" ) ?;
266
276
validate_pycapsule ( array_capsule, "arrow_array" ) ?;
@@ -296,7 +306,7 @@ impl ToPyArrow for ArrayData {
296
306
let array = FFI_ArrowArray :: new ( self ) ;
297
307
let schema = FFI_ArrowSchema :: try_from ( self . data_type ( ) ) . map_err ( to_py_err) ?;
298
308
299
- let module = py. import ( "pyarrow" ) ?;
309
+ let module = py. import_bound ( "pyarrow" ) ?;
300
310
let class = module. getattr ( "Array" ) ?;
301
311
let array = class. call_method1 (
302
312
"_import_from_c" ,
@@ -310,9 +320,9 @@ impl ToPyArrow for ArrayData {
310
320
}
311
321
312
322
impl < T : FromPyArrow > FromPyArrow for Vec < T > {
313
- fn from_pyarrow ( value : & PyAny ) -> PyResult < Self > {
323
+ fn from_pyarrow_bound ( value : & Bound < PyAny > ) -> PyResult < Self > {
314
324
let list = value. downcast :: < PyList > ( ) ?;
315
- list. iter ( ) . map ( |x| T :: from_pyarrow ( x) ) . collect ( )
325
+ list. iter ( ) . map ( |x| T :: from_pyarrow_bound ( & x) ) . collect ( )
316
326
}
317
327
}
318
328
@@ -327,7 +337,7 @@ impl<T: ToPyArrow> ToPyArrow for Vec<T> {
327
337
}
328
338
329
339
impl FromPyArrow for RecordBatch {
330
- fn from_pyarrow ( value : & PyAny ) -> PyResult < Self > {
340
+ fn from_pyarrow_bound ( value : & Bound < PyAny > ) -> PyResult < Self > {
331
341
// Newer versions of PyArrow as well as other libraries with Arrow data implement this
332
342
// method, so prefer it over _export_to_c.
333
343
// See https://arrow.apache.org/docs/format/CDataInterface/PyCapsuleInterface.html
@@ -340,8 +350,10 @@ impl FromPyArrow for RecordBatch {
340
350
) ) ;
341
351
}
342
352
343
- let schema_capsule: & PyCapsule = PyTryInto :: try_into ( tuple. get_item ( 0 ) ?) ?;
344
- let array_capsule: & PyCapsule = PyTryInto :: try_into ( tuple. get_item ( 1 ) ?) ?;
353
+ let schema_capsule = tuple. get_item ( 0 ) ?;
354
+ let schema_capsule = schema_capsule. downcast :: < PyCapsule > ( ) ?;
355
+ let array_capsule = tuple. get_item ( 1 ) ?;
356
+ let array_capsule = array_capsule. downcast :: < PyCapsule > ( ) ?;
345
357
346
358
validate_pycapsule ( schema_capsule, "arrow_schema" ) ?;
347
359
validate_pycapsule ( array_capsule, "arrow_array" ) ?;
@@ -370,12 +382,13 @@ impl FromPyArrow for RecordBatch {
370
382
validate_class ( "RecordBatch" , value) ?;
371
383
// TODO(kszucs): implement the FFI conversions in arrow-rs for RecordBatches
372
384
let schema = value. getattr ( "schema" ) ?;
373
- let schema = Arc :: new ( Schema :: from_pyarrow ( schema) ?) ;
385
+ let schema = Arc :: new ( Schema :: from_pyarrow_bound ( & schema) ?) ;
374
386
375
- let arrays = value. getattr ( "columns" ) ?. downcast :: < PyList > ( ) ? ;
387
+ let arrays = value. getattr ( "columns" ) ?;
376
388
let arrays = arrays
389
+ . downcast :: < PyList > ( ) ?
377
390
. iter ( )
378
- . map ( |a| Ok ( make_array ( ArrayData :: from_pyarrow ( a) ?) ) )
391
+ . map ( |a| Ok ( make_array ( ArrayData :: from_pyarrow_bound ( & a) ?) ) )
379
392
. collect :: < PyResult < _ > > ( ) ?;
380
393
381
394
let batch = RecordBatch :: try_new ( schema, arrays) . map_err ( to_py_err) ?;
@@ -395,13 +408,13 @@ impl ToPyArrow for RecordBatch {
395
408
396
409
/// Supports conversion from `pyarrow.RecordBatchReader` to [ArrowArrayStreamReader].
397
410
impl FromPyArrow for ArrowArrayStreamReader {
398
- fn from_pyarrow ( value : & PyAny ) -> PyResult < Self > {
411
+ fn from_pyarrow_bound ( value : & Bound < PyAny > ) -> PyResult < Self > {
399
412
// Newer versions of PyArrow as well as other libraries with Arrow data implement this
400
413
// method, so prefer it over _export_to_c.
401
414
// See https://arrow.apache.org/docs/format/CDataInterface/PyCapsuleInterface.html
402
415
if value. hasattr ( "__arrow_c_stream__" ) ? {
403
- let capsule: & PyCapsule =
404
- PyTryInto :: try_into ( value . getattr ( "__arrow_c_stream__" ) ? . call0 ( ) ? ) ?;
416
+ let capsule = value . getattr ( "__arrow_c_stream__" ) ? . call0 ( ) ? ;
417
+ let capsule = capsule . downcast :: < PyCapsule > ( ) ?;
405
418
validate_pycapsule ( capsule, "arrow_array_stream" ) ?;
406
419
407
420
let stream = unsafe { FFI_ArrowArrayStream :: from_raw ( capsule. pointer ( ) as _ ) } ;
@@ -421,7 +434,7 @@ impl FromPyArrow for ArrowArrayStreamReader {
421
434
// make the conversion through PyArrow's private API
422
435
// this changes the pointer's memory and is thus unsafe.
423
436
// In particular, `_export_to_c` can go out of bounds
424
- let args = PyTuple :: new ( value. py ( ) , [ stream_ptr as Py_uintptr_t ] ) ;
437
+ let args = PyTuple :: new_bound ( value. py ( ) , [ stream_ptr as Py_uintptr_t ] ) ;
425
438
value. call_method1 ( "_export_to_c" , args) ?;
426
439
427
440
let stream_reader = ArrowArrayStreamReader :: try_new ( stream)
@@ -439,9 +452,9 @@ impl IntoPyArrow for Box<dyn RecordBatchReader + Send> {
439
452
let mut stream = FFI_ArrowArrayStream :: new ( self ) ;
440
453
441
454
let stream_ptr = ( & mut stream) as * mut FFI_ArrowArrayStream ;
442
- let module = py. import ( "pyarrow" ) ?;
455
+ let module = py. import_bound ( "pyarrow" ) ?;
443
456
let class = module. getattr ( "RecordBatchReader" ) ?;
444
- let args = PyTuple :: new ( py, [ stream_ptr as Py_uintptr_t ] ) ;
457
+ let args = PyTuple :: new_bound ( py, [ stream_ptr as Py_uintptr_t ] ) ;
445
458
let reader = class. call_method1 ( "_import_from_c" , args) ?;
446
459
447
460
Ok ( PyObject :: from ( reader) )
@@ -463,8 +476,8 @@ impl IntoPyArrow for ArrowArrayStreamReader {
463
476
pub struct PyArrowType < T > ( pub T ) ;
464
477
465
478
impl < ' source , T : FromPyArrow > FromPyObject < ' source > for PyArrowType < T > {
466
- fn extract ( value : & ' source PyAny ) -> PyResult < Self > {
467
- Ok ( Self ( T :: from_pyarrow ( value) ?) )
479
+ fn extract_bound ( value : & Bound < ' source , PyAny > ) -> PyResult < Self > {
480
+ Ok ( Self ( T :: from_pyarrow_bound ( value) ?) )
468
481
}
469
482
}
470
483
0 commit comments