From 8c9e55d83e974d9e5d7887211925be07c11b99e9 Mon Sep 17 00:00:00 2001 From: Brock Date: Fri, 20 Nov 2020 18:21:08 -0800 Subject: [PATCH] CLN: make MultiIndex._shallow_copy signature match other subclasses --- pandas/core/indexes/base.py | 8 +++- pandas/core/indexes/datetimelike.py | 60 +++++++++++++------------- pandas/core/indexes/datetimes.py | 4 +- pandas/core/indexes/multi.py | 65 +++++++++++++---------------- pandas/core/indexes/period.py | 2 +- pandas/core/indexes/timedeltas.py | 4 +- 6 files changed, 69 insertions(+), 74 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 5eb890c9817c0..7658230d9e1dd 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -3986,7 +3986,11 @@ def _join_monotonic(self, other, how="left", return_indexers=False): else: return join_index - def _wrap_joined_index(self, joined, other): + def _wrap_joined_index( + self: _IndexT, joined: np.ndarray, other: _IndexT + ) -> _IndexT: + assert other.dtype == self.dtype + if isinstance(self, ABCMultiIndex): name = self.names if self.names == other.names else None else: @@ -4188,7 +4192,7 @@ def _is_memory_usage_qualified(self) -> bool: """ return self.is_object() - def is_type_compatible(self, kind) -> bool: + def is_type_compatible(self, kind: str_t) -> bool: """ Whether the index type is compatible with the provided type. """ diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index f80254b91231a..157ef1db8e6d3 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -414,6 +414,36 @@ def _format_attrs(self): attrs.append(("freq", freq)) return attrs + def _summary(self, name=None) -> str: + """ + Return a summarized representation. + + Parameters + ---------- + name : str + Name to use in the summary representation. + + Returns + ------- + str + Summarized representation of the index. + """ + formatter = self._formatter_func + if len(self) > 0: + index_summary = f", {formatter(self[0])} to {formatter(self[-1])}" + else: + index_summary = "" + + if name is None: + name = type(self).__name__ + result = f"{name}: {len(self)} entries{index_summary}" + if self.freq: + result += f"\nFreq: {self.freqstr}" + + # display as values, not quoted + result = result.replace("'", "") + return result + # -------------------------------------------------------------------- # Indexing Methods @@ -518,36 +548,6 @@ def where(self, cond, other=None): arr = self._data._from_backing_data(result) return type(self)._simple_new(arr, name=self.name) - def _summary(self, name=None) -> str: - """ - Return a summarized representation. - - Parameters - ---------- - name : str - Name to use in the summary representation. - - Returns - ------- - str - Summarized representation of the index. - """ - formatter = self._formatter_func - if len(self) > 0: - index_summary = f", {formatter(self[0])} to {formatter(self[-1])}" - else: - index_summary = "" - - if name is None: - name = type(self).__name__ - result = f"{name}: {len(self)} entries{index_summary}" - if self.freq: - result += f"\nFreq: {self.freqstr}" - - # display as values, not quoted - result = result.replace("'", "") - return result - def shift(self, periods=1, freq=None): """ Shift index by desired number of time frequency increments. diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index e262d33e1aaf0..634705032bc6f 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -819,8 +819,8 @@ def slice_indexer(self, start=None, end=None, step=None, kind=None): # -------------------------------------------------------------------- - def is_type_compatible(self, typ) -> bool: - return typ == self.inferred_type or typ == "datetime" + def is_type_compatible(self, kind: str) -> bool: + return kind == self.inferred_type or kind == "datetime" @property def inferred_type(self) -> str: diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 6e18b29673ca0..66e3aebc26b04 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -1065,34 +1065,19 @@ def _engine(self): @property def _constructor(self): - return MultiIndex.from_tuples + return type(self).from_tuples @doc(Index._shallow_copy) - def _shallow_copy( - self, - values=None, - name=lib.no_default, - levels=None, - codes=None, - sortorder=None, - names=lib.no_default, - ): - if names is not lib.no_default and name is not lib.no_default: - raise TypeError("Can only provide one of `names` and `name`") - elif names is lib.no_default: - names = name if name is not lib.no_default else self.names + def _shallow_copy(self, values=None, name=lib.no_default): + names = name if name is not lib.no_default else self.names if values is not None: - assert levels is None and codes is None - return MultiIndex.from_tuples(values, sortorder=sortorder, names=names) + return type(self).from_tuples(values, sortorder=None, names=names) - levels = levels if levels is not None else self.levels - codes = codes if codes is not None else self.codes - - result = MultiIndex( - levels=levels, - codes=codes, - sortorder=sortorder, + result = type(self)( + levels=self.levels, + codes=self.codes, + sortorder=None, names=names, verify_integrity=False, ) @@ -1100,18 +1085,6 @@ def _shallow_copy( result._cache.pop("levels", None) # GH32669 return result - def symmetric_difference(self, other, result_name=None, sort=None): - # On equal symmetric_difference MultiIndexes the difference is empty. - # Therefore, an empty MultiIndex is returned GH13490 - tups = Index.symmetric_difference(self, other, result_name, sort) - if len(tups) == 0: - return MultiIndex( - levels=[[] for _ in range(self.nlevels)], - codes=[[] for _ in range(self.nlevels)], - names=tups.name, - ) - return type(self).from_tuples(tups, names=tups.name) - # -------------------------------------------------------------------- def copy( @@ -1177,12 +1150,18 @@ def copy( if codes is None: codes = deepcopy(self.codes) - new_index = self._shallow_copy( + levels = levels if levels is not None else self.levels + codes = codes if codes is not None else self.codes + + new_index = type(self)( levels=levels, codes=codes, - names=names, sortorder=self.sortorder, + names=names, + verify_integrity=False, ) + new_index._cache = self._cache.copy() + new_index._cache.pop("levels", None) # GH32669 if dtype: warnings.warn( @@ -3612,6 +3591,18 @@ def _convert_can_do_setop(self, other): return other, result_names + def symmetric_difference(self, other, result_name=None, sort=None): + # On equal symmetric_difference MultiIndexes the difference is empty. + # Therefore, an empty MultiIndex is returned GH13490 + tups = Index.symmetric_difference(self, other, result_name, sort) + if len(tups) == 0: + return type(self)( + levels=[[] for _ in range(self.nlevels)], + codes=[[] for _ in range(self.nlevels)], + names=tups.name, + ) + return type(self).from_tuples(tups, names=tups.name) + # -------------------------------------------------------------------- @doc(Index.astype) diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index 0b0f985697da9..c252fed72e4bc 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -249,7 +249,7 @@ def __new__( @property def values(self) -> np.ndarray: - return np.asarray(self) + return np.asarray(self, dtype=object) @property def _has_complex_internals(self) -> bool: diff --git a/pandas/core/indexes/timedeltas.py b/pandas/core/indexes/timedeltas.py index 8ce04b107d23b..a9176b7eb5418 100644 --- a/pandas/core/indexes/timedeltas.py +++ b/pandas/core/indexes/timedeltas.py @@ -236,8 +236,8 @@ def _maybe_cast_slice_bound(self, label, side: str, kind): # ------------------------------------------------------------------- - def is_type_compatible(self, typ) -> bool: - return typ == self.inferred_type or typ == "timedelta" + def is_type_compatible(self, kind: str) -> bool: + return kind == self.inferred_type or kind == "timedelta" @property def inferred_type(self) -> str: