8484
8585BIDIRECTIONAL_MAPPINGS : Iterable [Tuple [IbisDtype , Dtype ]] = (
8686 (ibis_dtypes .boolean , pd .BooleanDtype ()),
87+ (ibis_dtypes .date , pd .ArrowDtype (pa .date32 ())),
8788 (ibis_dtypes .float64 , pd .Float64Dtype ()),
8889 (ibis_dtypes .int64 , pd .Int64Dtype ()),
8990 (ibis_dtypes .string , pd .StringDtype (storage = "pyarrow" )),
90- (ibis_dtypes .date , pd .ArrowDtype (pa .date32 ())),
9191 (ibis_dtypes .time , pd .ArrowDtype (pa .time64 ("us" ))),
9292 (ibis_dtypes .Timestamp (timezone = None ), pd .ArrowDtype (pa .timestamp ("us" ))),
9393 (
100100 pandas : ibis for ibis , pandas in BIDIRECTIONAL_MAPPINGS
101101}
102102
103+ IBIS_TO_ARROW : Dict [ibis_dtypes .DataType , pa .DataType ] = {
104+ ibis_dtypes .boolean : pa .bool_ (),
105+ ibis_dtypes .date : pa .date32 (),
106+ ibis_dtypes .float64 : pa .float64 (),
107+ ibis_dtypes .int64 : pa .int64 (),
108+ ibis_dtypes .string : pa .string (),
109+ ibis_dtypes .time : pa .time64 ("us" ),
110+ ibis_dtypes .Timestamp (timezone = None ): pa .timestamp ("us" ),
111+ ibis_dtypes .Timestamp (timezone = "UTC" ): pa .timestamp ("us" , tz = "UTC" ),
112+ }
113+
114+ ARROW_TO_IBIS = {arrow : ibis for ibis , arrow in IBIS_TO_ARROW .items ()}
115+
103116IBIS_TO_BIGFRAMES : Dict [ibis_dtypes .DataType , Union [Dtype , np .dtype [Any ]]] = {
104117 ibis : pandas for ibis , pandas in BIDIRECTIONAL_MAPPINGS
105118}
@@ -148,11 +161,12 @@ def ibis_dtype_to_bigframes_dtype(
148161 # Special cases: Ibis supports variations on these types, but currently
149162 # our IO returns them as objects. Eventually, we should support them as
150163 # ArrowDType (and update the IO accordingly)
151- if isinstance (ibis_dtype , ibis_dtypes .Array ) or isinstance (
152- ibis_dtype , ibis_dtypes .Struct
153- ):
164+ if isinstance (ibis_dtype , ibis_dtypes .Array ):
154165 return np .dtype ("O" )
155166
167+ if isinstance (ibis_dtype , ibis_dtypes .Struct ):
168+ return pd .ArrowDtype (ibis_dtype_to_arrow_dtype (ibis_dtype ))
169+
156170 if ibis_dtype in IBIS_TO_BIGFRAMES :
157171 return IBIS_TO_BIGFRAMES [ibis_dtype ]
158172 elif isinstance (ibis_dtype , ibis_dtypes .Null ):
@@ -164,6 +178,26 @@ def ibis_dtype_to_bigframes_dtype(
164178 )
165179
166180
181+ def ibis_dtype_to_arrow_dtype (ibis_dtype : ibis_dtypes .DataType ) -> pa .DataType :
182+ if isinstance (ibis_dtype , ibis_dtypes .Array ):
183+ return pa .list_ (ibis_dtype_to_arrow_dtype (ibis_dtype .value_type ))
184+
185+ if isinstance (ibis_dtype , ibis_dtypes .Struct ):
186+ return pa .struct (
187+ [
188+ (name , ibis_dtype_to_arrow_dtype (dtype ))
189+ for name , dtype in ibis_dtype .fields .items ()
190+ ]
191+ )
192+
193+ if ibis_dtype in IBIS_TO_ARROW :
194+ return IBIS_TO_ARROW [ibis_dtype ]
195+ else :
196+ raise ValueError (
197+ f"Unexpected Ibis data type { ibis_dtype } . { constants .FEEDBACK_LINK } "
198+ )
199+
200+
167201def ibis_value_to_canonical_type (value : ibis_types .Value ) -> ibis_types .Value :
168202 """Converts an Ibis expression to canonical type.
169203
@@ -187,6 +221,24 @@ def ibis_table_to_canonical_types(table: ibis_types.Table) -> ibis_types.Table:
187221 return table .select (* casted_columns )
188222
189223
224+ def arrow_dtype_to_ibis_dtype (arrow_dtype : pa .DataType ) -> ibis_dtypes .DataType :
225+ if pa .types .is_struct (arrow_dtype ):
226+ struct_dtype = typing .cast (pa .StructType , arrow_dtype )
227+ return ibis_dtypes .Struct .from_tuples (
228+ [
229+ (field .name , arrow_dtype_to_ibis_dtype (field .type ))
230+ for field in struct_dtype
231+ ]
232+ )
233+
234+ if arrow_dtype in ARROW_TO_IBIS :
235+ return ARROW_TO_IBIS [arrow_dtype ]
236+ else :
237+ raise ValueError (
238+ f"Unexpected Arrow data type { arrow_dtype } . { constants .FEEDBACK_LINK } "
239+ )
240+
241+
190242def bigframes_dtype_to_ibis_dtype (
191243 bigframes_dtype : Union [DtypeString , Dtype , np .dtype [Any ]]
192244) -> ibis_dtypes .DataType :
@@ -202,6 +254,9 @@ def bigframes_dtype_to_ibis_dtype(
202254 Raises:
203255 ValueError: If passed a dtype not supported by BigQuery DataFrames.
204256 """
257+ if isinstance (bigframes_dtype , pd .ArrowDtype ):
258+ return arrow_dtype_to_ibis_dtype (bigframes_dtype .pyarrow_dtype )
259+
205260 type_string = str (bigframes_dtype )
206261 if type_string in BIGFRAMES_STRING_TO_BIGFRAMES :
207262 bigframes_dtype = BIGFRAMES_STRING_TO_BIGFRAMES [
0 commit comments