@@ -73,10 +73,25 @@ impl PartitionStream for PyArrowStreamPartition {
7373 Python :: with_gil ( |py| {
7474 let bound = obj. bind ( py) ;
7575
76- // Create a stream reader and collect all batches
7776 match ArrowArrayStreamReader :: from_pyarrow_bound ( bound) {
78- Ok ( reader) => reader. filter_map ( |result| result. ok ( ) ) . collect ( ) ,
79- Err ( _) => vec ! [ ] ,
77+ Ok ( reader) => {
78+ // Collect batches, propagating errors as warnings
79+ // In streaming context, we can't easily return errors,
80+ // so we log and skip failed batches
81+ reader
82+ . filter_map ( |result| match result {
83+ Ok ( batch) => Some ( batch) ,
84+ Err ( e) => {
85+ eprintln ! ( "Warning: Failed to read batch: {e}" ) ;
86+ None
87+ }
88+ } )
89+ . collect ( )
90+ }
91+ Err ( e) => {
92+ eprintln ! ( "Warning: Failed to create stream reader: {e}" ) ;
93+ vec ! [ ]
94+ }
8095 }
8196 } )
8297 }
@@ -86,7 +101,6 @@ impl PartitionStream for PyArrowStreamPartition {
86101 }
87102 } ;
88103
89- // Wrap the batches in a MemoryStream
90104 Box :: pin (
91105 MemoryStream :: try_new ( batches, Arc :: clone ( & self . schema ) , None )
92106 . expect ( "MemoryStream creation should not fail with valid schema" ) ,
@@ -190,28 +204,10 @@ impl LazyArrowStreamTable {
190204 )
191205 }
192206
193- /// Get the schema of the table.
207+ /// Get the schema of the table as a PyArrow Schema .
194208 fn schema ( & self , py : Python < ' _ > ) -> PyResult < PyObject > {
195- let schema = self . table . schema ( ) ;
196- // Convert to PyArrow schema
197- let pyarrow = py. import ( "pyarrow" ) ?;
198- let schema_cls = pyarrow. getattr ( "schema" ) ?;
199-
200- // Build field list
201- let fields: Vec < _ > = schema
202- . fields ( )
203- . iter ( )
204- . map ( |f : & arrow:: datatypes:: FieldRef | {
205- let field_fn = pyarrow. getattr ( "field" ) . unwrap ( ) ;
206- let dtype = arrow_type_to_pyarrow ( py, f. data_type ( ) ) . unwrap ( ) ;
207- field_fn
208- . call1 ( ( f. name ( ) , dtype, f. is_nullable ( ) ) )
209- . unwrap ( )
210- } )
211- . collect ( ) ;
212-
213- let result = schema_cls. call1 ( ( fields, ) ) ?;
214- Ok ( result. into ( ) )
209+ use arrow:: pyarrow:: ToPyArrow ;
210+ self . table . schema ( ) . to_pyarrow ( py)
215211 }
216212
217213 fn __repr__ ( & self ) -> String {
@@ -222,84 +218,30 @@ impl LazyArrowStreamTable {
222218 }
223219}
224220
225- /// Get schema from a Python object that has a schema attribute or method .
221+ /// Get schema from a Python object that has a schema attribute.
226222///
227- /// This function extracts the schema WITHOUT consuming the stream, which is
223+ /// This extracts the schema WITHOUT consuming the stream, which is
228224/// important for lazy evaluation.
229225fn get_schema_from_stream ( stream : & Bound < ' _ , PyAny > ) -> PyResult < SchemaRef > {
230226 use arrow:: datatypes:: Schema ;
231227 use arrow:: pyarrow:: FromPyArrow ;
232228
233- // Try to get the schema attribute (PyArrow RecordBatchReader has .schema property)
234229 let py_schema = stream. getattr ( "schema" ) . map_err ( |e| {
235230 pyo3:: exceptions:: PyTypeError :: new_err ( format ! (
236- "Object does not have a 'schema' attribute: {e}. \
237- Expected a RecordBatchReader or similar object with a schema property."
231+ "Object must have a 'schema' attribute (e.g., RecordBatchReader): {e}"
238232 ) )
239233 } ) ?;
240234
241- // Convert the PyArrow Schema to Rust Schema
242235 let schema = Schema :: from_pyarrow_bound ( & py_schema) . map_err ( |e| {
243- pyo3:: exceptions:: PyTypeError :: new_err ( format ! (
244- "Failed to convert schema: {e}"
245- ) )
236+ pyo3:: exceptions:: PyTypeError :: new_err ( format ! ( "Failed to convert schema: {e}" ) )
246237 } ) ?;
247238
248239 Ok ( Arc :: new ( schema) )
249240}
250241
251- /// Convert Arrow DataType to PyArrow type
252- fn arrow_type_to_pyarrow ( py : Python < ' _ > , dtype : & arrow:: datatypes:: DataType ) -> PyResult < PyObject > {
253- let pyarrow = py. import ( "pyarrow" ) ?;
254-
255- use arrow:: datatypes:: DataType ;
256- let result = match dtype {
257- DataType :: Null => pyarrow. call_method0 ( "null" ) ?,
258- DataType :: Boolean => pyarrow. call_method0 ( "bool_" ) ?,
259- DataType :: Int8 => pyarrow. call_method0 ( "int8" ) ?,
260- DataType :: Int16 => pyarrow. call_method0 ( "int16" ) ?,
261- DataType :: Int32 => pyarrow. call_method0 ( "int32" ) ?,
262- DataType :: Int64 => pyarrow. call_method0 ( "int64" ) ?,
263- DataType :: UInt8 => pyarrow. call_method0 ( "uint8" ) ?,
264- DataType :: UInt16 => pyarrow. call_method0 ( "uint16" ) ?,
265- DataType :: UInt32 => pyarrow. call_method0 ( "uint32" ) ?,
266- DataType :: UInt64 => pyarrow. call_method0 ( "uint64" ) ?,
267- DataType :: Float16 => pyarrow. call_method0 ( "float16" ) ?,
268- DataType :: Float32 => pyarrow. call_method0 ( "float32" ) ?,
269- DataType :: Float64 => pyarrow. call_method0 ( "float64" ) ?,
270- DataType :: Utf8 => pyarrow. call_method0 ( "utf8" ) ?,
271- DataType :: LargeUtf8 => pyarrow. call_method0 ( "large_utf8" ) ?,
272- DataType :: Binary => pyarrow. call_method0 ( "binary" ) ?,
273- DataType :: LargeBinary => pyarrow. call_method0 ( "large_binary" ) ?,
274- DataType :: Date32 => pyarrow. call_method0 ( "date32" ) ?,
275- DataType :: Date64 => pyarrow. call_method0 ( "date64" ) ?,
276- DataType :: Timestamp ( unit, tz) => {
277- let unit_str = match unit {
278- arrow:: datatypes:: TimeUnit :: Second => "s" ,
279- arrow:: datatypes:: TimeUnit :: Millisecond => "ms" ,
280- arrow:: datatypes:: TimeUnit :: Microsecond => "us" ,
281- arrow:: datatypes:: TimeUnit :: Nanosecond => "ns" ,
282- } ;
283- match tz {
284- Some ( tz) => pyarrow. call_method1 ( "timestamp" , ( unit_str, tz. to_string ( ) ) ) ?,
285- None => pyarrow. call_method1 ( "timestamp" , ( unit_str, ) ) ?,
286- }
287- }
288- _ => {
289- // Fallback: convert to string and let PyArrow parse it
290- let type_str = format ! ( "{dtype}" ) ;
291- pyarrow
292- . getattr ( "type_for_alias" ) ?
293- . call1 ( ( type_str. as_str ( ) , ) ) ?
294- }
295- } ;
296-
297- Ok ( result. into ( ) )
298- }
299-
300242/// Python module initialization
301243#[ pymodule]
302244fn _native ( m : & Bound < ' _ , PyModule > ) -> PyResult < ( ) > {
303245 m. add_class :: < LazyArrowStreamTable > ( ) ?;
304246 Ok ( ( ) )
305- }
247+ }
0 commit comments