Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
4 changes: 4 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ New Features
Breaking changes
~~~~~~~~~~~~~~~~

- Explicitly forbid creating xarray objects with repeated dimension names.
This is technically a breaking change, but whilst allowed by the constructor,
this behaviour was never actually supported! (:issue:`3731`, :pull:`8491`)
By `Tom Nicholas <https://github.com/TomNicholas>`_.

Deprecations
~~~~~~~~~~~~
Expand Down
2 changes: 2 additions & 0 deletions xarray/core/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
emit_user_level_warning,
is_scalar,
)
from xarray.namedarray.core import _raise_if_any_duplicate_dimensions

try:
import cftime
Expand Down Expand Up @@ -217,6 +218,7 @@ def get_axis_num(self, dim: Hashable | Iterable[Hashable]) -> int | tuple[int, .
return self._get_axis_num(dim)

def _get_axis_num(self: Any, dim: Hashable) -> int:
_raise_if_any_duplicate_dimensions(self.dims, dim)
try:
return self.dims.index(dim)
except ValueError:
Expand Down
9 changes: 3 additions & 6 deletions xarray/core/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
is_duck_array,
maybe_coerce_to_str,
)
from xarray.namedarray.core import NamedArray
from xarray.namedarray.core import NamedArray, _raise_if_any_duplicate_dimensions

NON_NUMPY_SUPPORTED_ARRAY_TYPES = (
indexing.ExplicitlyIndexed,
Expand Down Expand Up @@ -2876,11 +2876,8 @@ def _unified_dims(variables):
all_dims = {}
for var in variables:
var_dims = var.dims
if len(set(var_dims)) < len(var_dims):
raise ValueError(
"broadcasting cannot handle duplicate "
f"dimensions: {list(var_dims)!r}"
)
_raise_if_any_duplicate_dimensions(var_dims, err_context="Broadcasting")

for d, s in zip(var_dims, var.shape):
if d not in all_dims:
all_dims[d] = s
Expand Down
8 changes: 8 additions & 0 deletions xarray/namedarray/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,14 @@ def _parse_dimensions(self, dims: _DimsLike) -> _Dims:
f"dimensions {dims} must have the same length as the "
f"number of data dimensions, ndim={self.ndim}"
)
if len(set(dims)) < len(dims):
repeated_dims = set([d for d in dims if dims.count(d) > 1])
warnings.warn(
f"Duplicate dimension names present: dimensions {repeated_dims} appear more than once in dims={dims}. "
"We do not yet support duplicate dimension names, but we do allow initial construction of the object. "
"We recommend you rename the dims immediately to become distinct, as most xarray functionality is likely to fail silently if you do not.",
UserWarning,
)
return dims

@property
Expand Down
4 changes: 4 additions & 0 deletions xarray/tests/test_namedarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,3 +475,7 @@ def _new(
var_float2: Variable[Any, np.dtype[np.float32]]
var_float2 = var_float._replace(("x",), np_val2)
assert var_float2.dtype == dtype_float

def test_warn_on_repeated_dimension_names(self) -> None:
with pytest.warns(UserWarning, match="Duplicate dimension names"):
NamedArray(("x", "x"), np.arange(4).reshape(2, 2))