Handles explicit indexing for a pandas.MultiIndex. This allows creating one instance for each multi-index level while preserving indexing efficiency (memoized + might reuse another instance with the same multi-index).
| 2073 | |
| 2074 | |
| 2075 | class PandasMultiIndexingAdapter(PandasIndexingAdapter): |
| 2076 | """Handles explicit indexing for a pandas.MultiIndex. |
| 2077 | |
| 2078 | This allows creating one instance for each multi-index level while |
| 2079 | preserving indexing efficiency (memoized + might reuse another instance with |
| 2080 | the same multi-index). |
| 2081 | """ |
| 2082 | |
| 2083 | __slots__ = ("_dtype", "adapter", "array", "level") |
| 2084 | |
| 2085 | array: pd.MultiIndex |
| 2086 | _dtype: np.dtype | pd.api.extensions.ExtensionDtype |
| 2087 | level: str | None |
| 2088 | |
| 2089 | def __init__( |
| 2090 | self, |
| 2091 | array: pd.MultiIndex, |
| 2092 | dtype: DTypeLike | pd.api.extensions.ExtensionDtype | None = None, |
| 2093 | level: str | None = None, |
| 2094 | ): |
| 2095 | super().__init__(array, dtype) |
| 2096 | self.level = level |
| 2097 | |
| 2098 | def __array__( |
| 2099 | self, |
| 2100 | dtype: DTypeLike | None = None, |
| 2101 | /, |
| 2102 | *, |
| 2103 | copy: bool | None = None, |
| 2104 | ) -> np.ndarray: |
| 2105 | dtype = self._get_numpy_dtype(dtype) |
| 2106 | |
| 2107 | if self.level is not None: |
| 2108 | return np.asarray( |
| 2109 | self.array.get_level_values(self.level).values, dtype=dtype |
| 2110 | ) |
| 2111 | else: |
| 2112 | return super().__array__(dtype, copy=copy) |
| 2113 | |
| 2114 | @property |
| 2115 | def _in_memory(self) -> bool: |
| 2116 | # The pd.MultiIndex's data is fully in memory, but it has a different |
| 2117 | # layout than the level and dimension coordinate arrays. Marking this |
| 2118 | # adapter class as a "lazy" array will prevent costly conversion when, |
| 2119 | # e.g., formatting the Xarray reprs. |
| 2120 | return False |
| 2121 | |
| 2122 | def _convert_scalar(self, item: Any): |
| 2123 | if isinstance(item, tuple) and self.level is not None: |
| 2124 | idx = tuple(self.array.names).index(self.level) |
| 2125 | item = item[idx] |
| 2126 | return super()._convert_scalar(item) |
| 2127 | |
| 2128 | def _index_get( |
| 2129 | self, indexer: ExplicitIndexer, func_name: str |
| 2130 | ) -> PandasIndexingAdapter | np.ndarray: |
| 2131 | result = super()._index_get(indexer, func_name) |
| 2132 | if isinstance(result, type(self)): |
no outgoing calls
no test coverage detected
searching dependent graphs…