Repository: pandas-dev/pandas

Issue:
core.internals checking `hasattr(item, 'reindex_axis')`
`Block` and `SparseBlock` each have a `reindex_axis` method that is not used anywhere, _but_ a bunch of things in core.internals do a check of the form

```
if hasattr(new, 'reindex_axis'):
    new = new.values

if hasattr(mask, 'reindex_axis'):
     mask = mask.values
```

It would be nice to get rid of the unused methods.  Any idea what this ducktype checks are actually intending to catch?



Discussion:

Resolving patch:
diff --git a/pandas/core/internals.py b/pandas/core/internals.py
--- a/pandas/core/internals.py
+++ b/pandas/core/internals.py
@@ -303,10 +303,6 @@ def getitem_block(self, slicer, new_mgr_locs=None):
     def shape(self):
         return self.values.shape
 
-    @property
-    def itemsize(self):
-        return self.values.itemsize
-
     @property
     def dtype(self):
         return self.values.dtype
@@ -327,21 +323,6 @@ def concat_same_type(self, to_concat, placement=None):
         return self.make_block_same_class(
             values, placement=placement or slice(0, len(values), 1))
 
-    def reindex_axis(self, indexer, method=None, axis=1, fill_value=None,
-                     limit=None, mask_info=None):
-        """
-        Reindex using pre-computed indexer information
-        """
-        if axis < 1:
-            raise AssertionError(
-                'axis must be at least 1, got {axis}'.format(axis=axis))
-        if fill_value is None:
-            fill_value = self.fill_value
-
-        new_values = algos.take_nd(self.values, indexer, axis,
-                                   fill_value=fill_value, mask_info=mask_info)
-        return self.make_block(new_values)
-
     def iget(self, i):
         return self.values[i]
 
@@ -936,11 +917,8 @@ def putmask(self, mask, new, align=True, inplace=False, axis=0,
 
         new_values = self.values if inplace else self.values.copy()
 
-        if hasattr(new, 'reindex_axis'):
-            new = new.values
-
-        if hasattr(mask, 'reindex_axis'):
-            mask = mask.values
+        new = getattr(new, 'values', new)
+        mask = getattr(mask, 'values', mask)
 
         # if we are passed a scalar None, convert it here
         if not is_list_like(new) and isna(new) and not self.is_object:
@@ -1297,8 +1275,7 @@ def eval(self, func, other, errors='raise', try_cast=False, mgr=None):
         orig_other = other
         values = self.values
 
-        if hasattr(other, 'reindex_axis'):
-            other = other.values
+        other = getattr(other, 'values', other)
 
         # make sure that we can broadcast
         is_transposed = False
@@ -1446,11 +1423,8 @@ def where(self, other, cond, align=True, errors='raise',
         if transpose:
             values = values.T
 
-        if hasattr(other, 'reindex_axis'):
-            other = other.values
-
-        if hasattr(cond, 'reindex_axis'):
-            cond = cond.values
+        other = getattr(other, 'values', other)
+        cond = getattr(cond, 'values', cond)
 
         # If the default broadcasting would go in the wrong direction, then
         # explicitly reshape other instead
@@ -2630,9 +2604,8 @@ def external_values(self):
     def get_values(self, dtype=None):
         # return object dtype as Timestamps with the zones
         if is_object_dtype(dtype):
-            f = lambda x: lib.Timestamp(x, tz=self.values.tz)
             return lib.map_infer(
-                self.values.ravel(), f).reshape(self.values.shape)
+                self.values.ravel(), self._box_func).reshape(self.values.shape)
         return self.values
 
     def _slice(self, slicer):
@@ -2760,10 +2733,6 @@ class SparseBlock(NonConsolidatableMixIn, Block):
     def shape(self):
         return (len(self.mgr_locs), self.sp_index.length)
 
-    @property
-    def itemsize(self):
-        return self.dtype.itemsize
-
     @property
     def fill_value(self):
         # return np.nan
@@ -2887,22 +2856,6 @@ def shift(self, periods, axis=0, mgr=None):
         return [self.make_block_same_class(new_values,
                                            placement=self.mgr_locs)]
 
-    def reindex_axis(self, indexer, method=None, axis=1, fill_value=None,
-                     limit=None, mask_info=None):
-        """
-        Reindex using pre-computed indexer information
-        """
-        if axis < 1:
-            raise AssertionError(
-                'axis must be at least 1, got {axis}'.format(axis=axis))
-
-        # taking on the 0th axis always here
-        if fill_value is None:
-            fill_value = self.fill_value
-        return self.make_block_same_class(self.values.take(indexer),
-                                          fill_value=fill_value,
-                                          placement=self.mgr_locs)
-
     def sparse_reindex(self, new_index):
         """ sparse reindex and return a new block
             current reindex only works for float64 dtype! """
@@ -3324,7 +3277,7 @@ def apply(self, f, axes=None, filter=None, do_integrity_check=False,
 
         aligned_args = dict((k, kwargs[k])
                             for k in align_keys
-                            if hasattr(kwargs[k], 'reindex_axis'))
+                            if hasattr(kwargs[k], 'values'))
 
         for b in self.blocks:
             if filter is not None:
@@ -4552,10 +4505,6 @@ def asobject(self):
         """
         return self._block.get_values(dtype=object)
 
-    @property
-    def itemsize(self):
-        return self._block.values.itemsize
-
     @property
     def _can_hold_na(self):
         return self._block._can_hold_na


Test patch: