@@ -217,7 +217,7 @@ def _isnull_new(obj):
217
217
return _isnull_ndarraylike (obj )
218
218
elif isinstance (obj , ABCGeneric ):
219
219
return obj ._constructor (obj ._data .isnull (func = isnull ))
220
- elif isinstance (obj , list ) or hasattr (obj , '__array__' ):
220
+ elif isinstance (obj , list ) or is_array_like (obj ):
221
221
return _isnull_ndarraylike (np .asarray (obj ))
222
222
else :
223
223
return obj is None
@@ -243,7 +243,7 @@ def _isnull_old(obj):
243
243
return _isnull_ndarraylike_old (obj )
244
244
elif isinstance (obj , ABCGeneric ):
245
245
return obj ._constructor (obj ._data .isnull (func = _isnull_old ))
246
- elif isinstance (obj , list ) or hasattr (obj , '__array__' ):
246
+ elif isinstance (obj , list ) or is_array_like (obj ):
247
247
return _isnull_ndarraylike_old (np .asarray (obj ))
248
248
else :
249
249
return obj is None
@@ -2266,7 +2266,7 @@ def _asarray_tuplesafe(values, dtype=None):
2266
2266
from pandas .core .index import Index
2267
2267
2268
2268
if not (isinstance (values , (list , tuple ))
2269
- or hasattr (values , '__array__' )):
2269
+ or is_array_like (values )):
2270
2270
values = list (values )
2271
2271
elif isinstance (values , Index ):
2272
2272
return values .values
@@ -2489,6 +2489,38 @@ def is_list_like(arg):
2489
2489
return (hasattr (arg , '__iter__' ) and
2490
2490
not isinstance (arg , compat .string_and_binary_types ))
2491
2491
2492
+ def is_array_like (obj ):
2493
+ """
2494
+ Check if object provides access to a data buffer via one of the numpy
2495
+ array apis.
2496
+
2497
+ http://docs.scipy.org/doc/numpy/reference/arrays.classes.html
2498
+ http://docs.scipy.org/doc/numpy/reference/arrays.interface.html
2499
+
2500
+ Parameters
2501
+ ----------
2502
+ obj : Object
2503
+
2504
+ Note
2505
+ ----
2506
+ Remember that ndarrays and NDFrames are array-like.
2507
+ """
2508
+ # numpy ndarray subclass api
2509
+ tmp = getattr (obj , '__array__' , None )
2510
+ if callable (tmp ):
2511
+ return True
2512
+
2513
+ # Python side
2514
+ # __array_interface__ is a dict
2515
+ tmp = getattr (obj , '__array_interface__' , None )
2516
+ if isinstance (tmp , dict ):
2517
+ return True
2518
+
2519
+ # C-struct access
2520
+ if hasattr (obj , '__array_struct__' ):
2521
+ return True
2522
+
2523
+ return False
2492
2524
2493
2525
def _is_sequence (x ):
2494
2526
try :
@@ -3105,3 +3137,39 @@ def _maybe_match_name(a, b):
3105
3137
if a_name == b_name :
3106
3138
return a_name
3107
3139
return None
3140
+
3141
+ def _unhandled_array_interface (obj ):
3142
+ """
3143
+ Checks whether an object:
3144
+ 1) Implements the array interface
3145
+ 2) Is not an object type that pandas handles natively
3146
+
3147
+ #2 is a moving target. Essentially any 3rd party module can implement the
3148
+ NumPy Array Interface and should be treated as array-like. For example,
3149
+ the rpy2 SexpVector implements `__array_struct__` which we do not
3150
+ explicitly handle.
3151
+
3152
+ In the future, if we add explicit handling for the SexpVector, this
3153
+ function would have to account for that.
3154
+
3155
+ Parameters
3156
+ ----------
3157
+ obj : Object
3158
+
3159
+ Usage
3160
+ -----
3161
+
3162
+ ```
3163
+ if com._unhandled_array_interface(data):
3164
+ data = np.asarray(data)
3165
+ ```
3166
+
3167
+ """
3168
+ if isinstance (obj , (np .ndarray )):
3169
+ return False
3170
+
3171
+ import pandas .core .base as base
3172
+ if isinstance (obj , (base .PandasObject )):
3173
+ return False
3174
+
3175
+ return is_array_like (obj )
0 commit comments