1
1
from __future__ import annotations
2
2
3
+ import contextlib
3
4
import json
4
5
import warnings
5
6
10
11
11
12
import ibis .expr .datatypes as dt
12
13
import ibis .expr .schema as sch
14
+ from ibis .common .temporal import normalize_timezone
13
15
from ibis .formats import DataMapper , SchemaMapper , TableProxy
14
16
from ibis .formats .numpy import NumpyType
15
17
from ibis .formats .pyarrow import PyArrowData , PyArrowSchema , PyArrowType
@@ -132,8 +134,8 @@ def convert_column(cls, obj, dtype):
132
134
assert not isinstance (result , np .ndarray ), f"{ convert_method } -> { type (result )} "
133
135
return result
134
136
135
- @staticmethod
136
- def convert_GeoSpatial (s , dtype , pandas_type ):
137
+ @classmethod
138
+ def convert_GeoSpatial (cls , s , dtype , pandas_type ):
137
139
return s
138
140
139
141
convert_Point = (
@@ -144,15 +146,15 @@ def convert_GeoSpatial(s, dtype, pandas_type):
144
146
convert_MultiLineString
145
147
) = convert_MultiPoint = convert_MultiPolygon = convert_GeoSpatial
146
148
147
- @staticmethod
148
- def convert_default (s , dtype , pandas_type ):
149
+ @classmethod
150
+ def convert_default (cls , s , dtype , pandas_type ):
149
151
try :
150
152
return s .astype (pandas_type )
151
153
except Exception : # noqa: BLE001
152
154
return s
153
155
154
- @staticmethod
155
- def convert_Boolean (s , dtype , pandas_type ):
156
+ @classmethod
157
+ def convert_Boolean (cls , s , dtype , pandas_type ):
156
158
if s .empty :
157
159
return s .astype (pandas_type )
158
160
elif pdt .is_object_dtype (s .dtype ):
@@ -162,8 +164,8 @@ def convert_Boolean(s, dtype, pandas_type):
162
164
else :
163
165
return s
164
166
165
- @staticmethod
166
- def convert_Timestamp (s , dtype , pandas_type ):
167
+ @classmethod
168
+ def convert_Timestamp (cls , s , dtype , pandas_type ):
167
169
if isinstance (dtype , pd .DatetimeTZDtype ):
168
170
return s .dt .tz_convert (dtype .timezone )
169
171
elif pdt .is_datetime64_dtype (s .dtype ):
@@ -184,14 +186,14 @@ def convert_Timestamp(s, dtype, pandas_type):
184
186
except TypeError :
185
187
return pd .to_datetime (s ).dt .tz_localize (dtype .timezone )
186
188
187
- @staticmethod
188
- def convert_Date (s , dtype , pandas_type ):
189
+ @classmethod
190
+ def convert_Date (cls , s , dtype , pandas_type ):
189
191
if isinstance (s .dtype , pd .DatetimeTZDtype ):
190
192
s = s .dt .tz_convert ("UTC" ).dt .tz_localize (None )
191
193
return s .astype (pandas_type , errors = "ignore" ).dt .normalize ()
192
194
193
- @staticmethod
194
- def convert_Interval (s , dtype , pandas_type ):
195
+ @classmethod
196
+ def convert_Interval (cls , s , dtype , pandas_type ):
195
197
values = s .values
196
198
try :
197
199
result = values .astype (pandas_type )
@@ -201,42 +203,41 @@ def convert_Interval(s, dtype, pandas_type):
201
203
result = s .__class__ (result , index = s .index , name = s .name )
202
204
return result
203
205
204
- @staticmethod
205
- def convert_String (s , dtype , pandas_type ):
206
+ @classmethod
207
+ def convert_String (cls , s , dtype , pandas_type ):
206
208
return s .astype (pandas_type , errors = "ignore" )
207
209
208
- @staticmethod
209
- def convert_UUID (s , dtype , pandas_type ):
210
- return s .map (PandasData .get_element_converter (dtype ), na_action = "ignore" )
211
-
212
- @staticmethod
213
- def convert_Struct (s , dtype , pandas_type ):
214
- return s .map (PandasData .get_element_converter (dtype ), na_action = "ignore" )
210
+ @classmethod
211
+ def convert_UUID (cls , s , dtype , pandas_type ):
212
+ return s .map (cls .get_element_converter (dtype ), na_action = "ignore" )
215
213
216
- @staticmethod
217
- def convert_Array ( s , dtype , pandas_type ):
218
- return s .map (PandasData .get_element_converter (dtype ), na_action = "ignore" )
214
+ @classmethod
215
+ def convert_Struct ( cls , s , dtype , pandas_type ):
216
+ return s .map (cls .get_element_converter (dtype ), na_action = "ignore" )
219
217
220
- @staticmethod
221
- def convert_Map ( s , dtype , pandas_type ):
222
- return s .map (PandasData .get_element_converter (dtype ), na_action = "ignore" )
218
+ @classmethod
219
+ def convert_Array ( cls , s , dtype , pandas_type ):
220
+ return s .map (cls .get_element_converter (dtype ), na_action = "ignore" )
223
221
224
- @staticmethod
225
- def convert_JSON (s , dtype , pandas_type ):
226
- return s .map (
227
- PandasData .get_element_converter (dtype ), na_action = "ignore"
228
- ).astype ("object" )
222
+ @classmethod
223
+ def convert_Map (cls , s , dtype , pandas_type ):
224
+ return s .map (cls .get_element_converter (dtype ), na_action = "ignore" )
229
225
230
- @staticmethod
231
- def get_element_converter ( dtype ):
232
- funcgen = getattr (
233
- PandasData , f"convert_ { type ( dtype ). __name__ } _element" , lambda _ : lambda x : x
226
+ @classmethod
227
+ def convert_JSON ( cls , s , dtype , pandas_type ):
228
+ return s . map ( cls . get_element_converter ( dtype ), na_action = "ignore" ). astype (
229
+ "object"
234
230
)
231
+
232
+ @classmethod
233
+ def get_element_converter (cls , dtype ):
234
+ name = f"convert_{ type (dtype ).__name__ } _element"
235
+ funcgen = getattr (cls , name , lambda _ : lambda x : x )
235
236
return funcgen (dtype )
236
237
237
- @staticmethod
238
- def convert_Struct_element (dtype ):
239
- converters = tuple (map (PandasData .get_element_converter , dtype .types ))
238
+ @classmethod
239
+ def convert_Struct_element (cls , dtype ):
240
+ converters = tuple (map (cls .get_element_converter , dtype .types ))
240
241
241
242
def convert (values , names = dtype .names , converters = converters ):
242
243
items = values .items () if isinstance (values , dict ) else zip (names , values )
@@ -247,8 +248,8 @@ def convert(values, names=dtype.names, converters=converters):
247
248
248
249
return convert
249
250
250
- @staticmethod
251
- def convert_JSON_element (_ ):
251
+ @classmethod
252
+ def convert_JSON_element (cls , _ ):
252
253
def try_json (x ):
253
254
if x is None :
254
255
return x
@@ -259,23 +260,36 @@ def try_json(x):
259
260
260
261
return try_json
261
262
262
- @staticmethod
263
- def convert_Array_element (dtype ):
264
- convert_value = PandasData .get_element_converter (dtype .value_type )
263
+ @classmethod
264
+ def convert_Timestamp_element (cls , dtype ):
265
+ def converter (value , dtype = dtype ):
266
+ with contextlib .suppress (AttributeError ):
267
+ value = value .item ()
268
+
269
+ if (tz := dtype .timezone ) is not None :
270
+ return value .astimezone (normalize_timezone (tz ))
271
+
272
+ return value .replace (tzinfo = None )
273
+
274
+ return converter
275
+
276
+ @classmethod
277
+ def convert_Array_element (cls , dtype ):
278
+ convert_value = cls .get_element_converter (dtype .value_type )
265
279
return lambda values : [
266
280
convert_value (value ) if value is not None else value for value in values
267
281
]
268
282
269
- @staticmethod
270
- def convert_Map_element (dtype ):
271
- convert_value = PandasData .get_element_converter (dtype .value_type )
283
+ @classmethod
284
+ def convert_Map_element (cls , dtype ):
285
+ convert_value = cls .get_element_converter (dtype .value_type )
272
286
return lambda row : {
273
287
key : convert_value (value ) if value is not None else value
274
288
for key , value in dict (row ).items ()
275
289
}
276
290
277
- @staticmethod
278
- def convert_UUID_element (_ ):
291
+ @classmethod
292
+ def convert_UUID_element (cls , _ ):
279
293
from uuid import UUID
280
294
281
295
return lambda v : v if isinstance (v , UUID ) else UUID (v )
0 commit comments