Repository: pandas-dev/pandas
Pull request: CLN: Remove unused core.internals methods
De-duplicate some bits of DatetimeBlock and DatetimeTZBlock.

- [x] closes #19243
- [ ] tests added / passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [ ] whatsnew entry


Problem statement:
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?

Hints from issue discussion:

Commit message: remove unused reindex_axis methods

Patch to review:
diff --git a/pandas/core/internals.py b/pandas/core/internals.py
index 3c923133477df..8dcfec63561e2 100644
--- 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, fastpath=True)
-
     def iget(self, i):
         return self.values[i]
 
@@ -937,10 +918,10 @@ 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'):
+        if hasattr(new, 'values'):
             new = new.values
 
-        if hasattr(mask, 'reindex_axis'):
+        if hasattr(mask, 'values'):
             mask = mask.values
 
         # if we are passed a scalar None, convert it here
@@ -1299,7 +1280,7 @@ def eval(self, func, other, errors='raise', try_cast=False, mgr=None):
         orig_other = other
         values = self.values
 
-        if hasattr(other, 'reindex_axis'):
+        if hasattr(other, 'values'):
             other = other.values
 
         # make sure that we can broadcast
@@ -1448,10 +1429,10 @@ def where(self, other, cond, align=True, errors='raise',
         if transpose:
             values = values.T
 
-        if hasattr(other, 'reindex_axis'):
+        if hasattr(other, 'values'):
             other = other.values
 
-        if hasattr(cond, 'reindex_axis'):
+        if hasattr(cond, 'values'):
             cond = cond.values
 
         # If the default broadcasting would go in the wrong direction, then
@@ -1929,6 +1910,7 @@ def should_store(self, value):
 
 
 class DatetimeLikeBlockMixin(object):
+    freq = None  # compat with Datetimelike Index subclasses
 
     @property
     def _na_value(self):
@@ -2466,6 +2448,7 @@ class DatetimeBlock(DatetimeLikeBlockMixin, Block):
     __slots__ = ()
     is_datetime = True
     _can_hold_na = True
+    tz = None
 
     def __init__(self, values, placement, fastpath=False, **kwargs):
         if values.dtype != _NS_DTYPE:
@@ -2559,7 +2542,7 @@ def _try_coerce_result(self, result):
 
     @property
     def _box_func(self):
-        return tslib.Timestamp
+        return lambda x: tslib.Timestamp(x, freq=self.freq, tz=self.tz)
 
     def to_native_types(self, slicer=None, na_rep=None, date_format=None,
                         quoting=None, **kwargs):
@@ -2603,6 +2586,12 @@ class DatetimeTZBlock(NonConsolidatableMixIn, DatetimeBlock):
     _concatenator = staticmethod(_concat._concat_datetime)
     is_datetimetz = True
 
+    get_values = DatetimeBlock.get_values  # override NonConsolidatableMixin
+
+    @property
+    def tz(self):
+        return self.dtype.tz
+
     def __init__(self, values, placement, ndim=2, **kwargs):
 
         if not isinstance(values, self._holder):
@@ -2634,14 +2623,6 @@ def external_values(self):
         """
         return self.values.astype('datetime64[ns]').values
 
-    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)
-        return self.values
-
     def _slice(self, slicer):
         """ return a slice of my values """
         if isinstance(slicer, tuple):
@@ -2713,10 +2694,6 @@ def _try_coerce_result(self, result):
 
         return result
 
-    @property
-    def _box_func(self):
-        return lambda x: tslib.Timestamp(x, tz=self.dtype.tz)
-
     def shift(self, periods, axis=0, mgr=None):
         """ shift the block by periods """
 
@@ -2767,10 +2744,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
@@ -2895,22 +2868,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! """
@@ -3311,7 +3268,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:
@@ -4542,10 +4499,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


Code review comments:
diff_hunk: @@ -2603,6 +2586,12 @@ class DatetimeTZBlock(NonConsolidatableMixIn, DatetimeBlock):
     _concatenator = staticmethod(_concat._concat_datetime)
     is_datetimetz = True
 
+    get_values = DatetimeBlock.get_values  # override NonConsolidatableMixin
path: pandas/core/internals.py
text: @user1:
I'd rather you write an actual function here (that can call DatetimeBlock.get_values), but that has a doc-string and such