Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion xarray/core/indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import numpy as np
import pandas as pd
from pandas.errors import InvalidIndexError

from xarray.core import formatting, nputils, utils
from xarray.core.coordinate_transform import CoordinateTransform
Expand Down Expand Up @@ -1367,7 +1368,14 @@ def sel(self, labels, method=None, tolerance=None) -> IndexSelResult:

elif isinstance(label, tuple):
if _is_nested_tuple(label):
indexer = self.index.get_locs(label)
# When the tuple contains sub-tuples/lists/slices, it could be:
# 1. A single key with tuple-valued levels (e.g., ((1, 1), 2))
# 2. A multi-value selection (e.g., (1, slice(1, 2)))
# Try get_loc first for case 1, fall back to get_locs for case 2
try:
indexer = self.index.get_loc(label)
except (InvalidIndexError, KeyError):
indexer = self.index.get_locs(label)
elif len(label) == self.index.nlevels:
indexer = self.index.get_loc(label)
else:
Expand Down
3 changes: 3 additions & 0 deletions xarray/namedarray/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ def module_available(module: str, minversion: str | None = None) -> bool:
if minversion is not None:
version = importlib.metadata.version(module)

if version is None:
return False

return Version(version) >= Version(minversion)

return True
Expand Down
16 changes: 16 additions & 0 deletions xarray/tests/test_indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,22 @@ def test_copy(self) -> None:
assert actual.dim == expected.dim
assert actual.level_coords_dtype == expected.level_coords_dtype

def test_sel_nested_tuple_key_collapses_dimension(self) -> None:
# Regression test for GH#11341
# When indexing with a single nested tuple key (where one level has
# tuple-valued entries), the dimension should collapse like scalar selection
nested_level_0 = pd.Index(
[(1, 1), (1, 1), (2, 2), (3, 3)], name="a", tupleize_cols=False
)
nested_level_1 = pd.Index([1, 2, 10, 20], name="b")
nested_mi = pd.MultiIndex.from_arrays([nested_level_0, nested_level_1])
index = PandasMultiIndex(nested_mi, "index")

# A single nested tuple key should produce a scalar indexer (int),
# not an array, collapsing the dimension
actual = index.sel({"index": ((1, 1), 2)})
assert isinstance(actual.dim_indexers["index"], (int, np.integer))


class TestIndexes:
@pytest.fixture
Expand Down
13 changes: 13 additions & 0 deletions xarray/tests/test_namedarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -666,3 +666,16 @@ def test_fake_target_chunksize_cftime() -> None:

assert faked_chunksize == 73
assert dtype == np.float64


def test_module_available_with_none_version(monkeypatch):
"""Regression test for https://github.com/pydata/xarray/issues/11344."""
import importlib.metadata

from xarray.namedarray.utils import module_available

module_available.cache_clear()
monkeypatch.setattr(importlib.metadata, "version", lambda name: None)

assert module_available("numpy", minversion="1.0.0") is False
assert module_available("numpy") is True
Loading