|  | 
| 31 | 31 |     lib, | 
| 32 | 32 | ) | 
| 33 | 33 | from pandas._libs.hashtable import duplicated | 
| 34 |  | -from pandas._libs.tslibs.timestamps import Timestamp | 
| 35 | 34 | from pandas._typing import ( | 
| 36 | 35 |     AnyAll, | 
| 37 | 36 |     AnyArrayLike, | 
| @@ -3612,34 +3611,43 @@ def maybe_mi_droplevels(indexer, levels): | 
| 3612 | 3611 | 
 | 
| 3613 | 3612 |     def _is_key_type_compatible(self, key, level): | 
| 3614 | 3613 |         """ | 
| 3615 |  | -        Return True if the key is compatible with the type of the level's values. | 
|  | 3614 | +        Return True if the key type is compatible with the type of the level's values. | 
|  | 3615 | +
 | 
|  | 3616 | +        Compatible types: | 
|  | 3617 | +        - int ↔ np.integer | 
|  | 3618 | +        - float ↔ np.floating | 
|  | 3619 | +        - str ↔ np.str_ | 
|  | 3620 | +        - datetime.date ↔ datetime.datetime | 
|  | 3621 | +        - slices (for partial indexing) | 
| 3616 | 3622 |         """ | 
| 3617 | 3623 |         if len(self.levels[level]) == 0: | 
| 3618 | 3624 |             return True  # nothing to compare | 
| 3619 | 3625 | 
 | 
| 3620 |  | -        level_type = self.levels[level][0] | 
|  | 3626 | +        level_val = self.levels[level][0] | 
|  | 3627 | +        level_type = type(level_val) | 
| 3621 | 3628 | 
 | 
| 3622 |  | -        # Allow slices (used in partial indexing) | 
| 3623 |  | -        if isinstance(key, slice): | 
|  | 3629 | +        # Same type | 
|  | 3630 | +        if isinstance(key, level_type): | 
| 3624 | 3631 |             return True | 
| 3625 | 3632 | 
 | 
| 3626 |  | -        # datetime/date/Timestamp compatibility | 
| 3627 |  | -        datetime_types = (datetime.date, np.datetime64, Timestamp) | 
| 3628 |  | -        if isinstance(level_type, datetime_types) and isinstance( | 
| 3629 |  | -            key, datetime_types + (str,) | 
| 3630 |  | -        ): | 
|  | 3633 | +        # NumPy integer / float / string compatibility | 
|  | 3634 | +        if isinstance(level_val, np.integer) and isinstance(key, int): | 
|  | 3635 | +            return True | 
|  | 3636 | +        if isinstance(level_val, np.floating) and isinstance(key, float): | 
|  | 3637 | +            return True | 
|  | 3638 | +        if isinstance(level_val, np.str_) and isinstance(key, str): | 
| 3631 | 3639 |             return True | 
| 3632 | 3640 | 
 | 
| 3633 |  | -        # numeric compatibility | 
| 3634 |  | -        if np.issubdtype(type(level_type), np.integer) and isinstance(key, int): | 
|  | 3641 | +        # Allow subclasses of datetime.date for datetime levels | 
|  | 3642 | +        if isinstance(level_val, datetime.date) and isinstance(key, datetime.date): | 
| 3635 | 3643 |             return True | 
| 3636 |  | -        if np.issubdtype(type(level_type), np.floating) and isinstance( | 
| 3637 |  | -            key, (int, float) | 
| 3638 |  | -        ): | 
|  | 3644 | + | 
|  | 3645 | +        # Allow slices (used internally for partial selection) | 
|  | 3646 | +        if isinstance(key, slice): | 
| 3639 | 3647 |             return True | 
| 3640 | 3648 | 
 | 
| 3641 |  | -        # string compatibility | 
| 3642 |  | -        if isinstance(level_type, str) and isinstance(key, str): | 
|  | 3649 | +        # Allow any NumPy generic types for flexibility | 
|  | 3650 | +        if isinstance(key, np.generic): | 
| 3643 | 3651 |             return True | 
| 3644 | 3652 | 
 | 
| 3645 | 3653 |         return False | 
|  | 
0 commit comments