@@ -2581,35 +2581,6 @@ def _get_indexer_level_0(self, target) -> np.ndarray:
2581
2581
ci = Index (cat )
2582
2582
return ci .get_indexer_for (target )
2583
2583
2584
- def _get_partial_string_timestamp_match_key (self , key ):
2585
- """
2586
- Translate any partial string timestamp matches in key, returning the
2587
- new key.
2588
-
2589
- Only relevant for MultiIndex.
2590
- """
2591
- # GH#10331
2592
- if isinstance (key , str ) and self .levels [0 ]._supports_partial_string_indexing :
2593
- # Convert key '2016-01-01' to
2594
- # ('2016-01-01'[, slice(None, None, None)]+)
2595
- key = (key ,) + (slice (None ),) * (len (self .levels ) - 1 )
2596
-
2597
- if isinstance (key , tuple ):
2598
- # Convert (..., '2016-01-01', ...) in tuple to
2599
- # (..., slice('2016-01-01', '2016-01-01', None), ...)
2600
- new_key = []
2601
- for i , component in enumerate (key ):
2602
- if (
2603
- isinstance (component , str )
2604
- and self .levels [i ]._supports_partial_string_indexing
2605
- ):
2606
- new_key .append (slice (component , component , None ))
2607
- else :
2608
- new_key .append (component )
2609
- key = tuple (new_key )
2610
-
2611
- return key
2612
-
2613
2584
def get_slice_bound (
2614
2585
self , label : Hashable | Sequence [Hashable ], side : str , kind : str | None = None
2615
2586
) -> int :
@@ -2858,7 +2829,12 @@ def _maybe_to_slice(loc):
2858
2829
)
2859
2830
2860
2831
if keylen == self .nlevels and self .is_unique :
2861
- return self ._engine .get_loc (key )
2832
+ try :
2833
+ return self ._engine .get_loc (key )
2834
+ except TypeError :
2835
+ # e.g. partial string slicing
2836
+ loc , _ = self .get_loc_level (key , list (range (self .nlevels )))
2837
+ return loc
2862
2838
2863
2839
# -- partial selection or non-unique index
2864
2840
# break the key into 2 parts based on the lexsort_depth of the index;
@@ -3008,6 +2984,10 @@ def maybe_mi_droplevels(indexer, levels):
3008
2984
return (self ._engine .get_loc (key ), None )
3009
2985
except KeyError as err :
3010
2986
raise KeyError (key ) from err
2987
+ except TypeError :
2988
+ # e.g. partial string indexing
2989
+ # test_partial_string_timestamp_multiindex
2990
+ pass
3011
2991
3012
2992
# partial selection
3013
2993
indexer = self .get_loc (key )
@@ -3019,7 +2999,19 @@ def maybe_mi_droplevels(indexer, levels):
3019
2999
3020
3000
# TODO: in some cases we still need to drop some levels,
3021
3001
# e.g. test_multiindex_perf_warn
3022
- ilevels = []
3002
+ # test_partial_string_timestamp_multiindex
3003
+ ilevels = [
3004
+ i
3005
+ for i in range (len (key ))
3006
+ if (
3007
+ not isinstance (key [i ], str )
3008
+ or not self .levels [i ]._supports_partial_string_indexing
3009
+ )
3010
+ and key [i ] != slice (None , None )
3011
+ ]
3012
+ if len (ilevels ) == self .nlevels :
3013
+ # TODO: why?
3014
+ ilevels = []
3023
3015
return indexer , maybe_mi_droplevels (indexer , ilevels )
3024
3016
3025
3017
else :
@@ -3060,6 +3052,16 @@ def maybe_mi_droplevels(indexer, levels):
3060
3052
return indexer , maybe_mi_droplevels (indexer , ilevels )
3061
3053
else :
3062
3054
indexer = self ._get_level_indexer (key , level = level )
3055
+ if (
3056
+ isinstance (key , str )
3057
+ and self .levels [level ]._supports_partial_string_indexing
3058
+ ):
3059
+ # check to see if we did an exact lookup vs sliced
3060
+ check = self .levels [level ].get_loc (key )
3061
+ if not is_integer (check ):
3062
+ # e.g. test_partial_string_timestamp_multiindex
3063
+ return indexer , self [indexer ]
3064
+
3063
3065
return indexer , maybe_mi_droplevels (indexer , [level ])
3064
3066
3065
3067
def _get_level_indexer (
@@ -3157,15 +3159,21 @@ def convert_indexer(start, stop, step, indexer=indexer, codes=level_codes):
3157
3159
3158
3160
if level > 0 or self ._lexsort_depth == 0 :
3159
3161
# Desired level is not sorted
3162
+ if isinstance (idx , slice ):
3163
+ locs = (level_codes >= idx .start ) & (level_codes < idx .stop )
3164
+ return locs
3165
+
3160
3166
locs = np .array (level_codes == idx , dtype = bool , copy = False )
3161
3167
if not locs .any ():
3162
3168
# The label is present in self.levels[level] but unused:
3163
3169
raise KeyError (key )
3164
3170
return locs
3165
3171
3166
3172
if isinstance (idx , slice ):
3167
- start = idx .start
3168
- end = idx .stop
3173
+ # e.g. test_partial_string_timestamp_multiindex
3174
+ start = level_codes .searchsorted (idx .start , side = "left" )
3175
+ # NB: "left" here bc of slice semantics
3176
+ end = level_codes .searchsorted (idx .stop , side = "left" )
3169
3177
else :
3170
3178
start = level_codes .searchsorted (idx , side = "left" )
3171
3179
end = level_codes .searchsorted (idx , side = "right" )
0 commit comments