Skip to content

Commit

Permalink
Merge branch 'main' into named-array
Browse files Browse the repository at this point in the history
  • Loading branch information
andersy005 authored Sep 21, 2023
2 parents 76bb881 + 3ace2fb commit 2d59cf5
Show file tree
Hide file tree
Showing 15 changed files with 503 additions and 472 deletions.
13 changes: 11 additions & 2 deletions asv_bench/benchmarks/rolling.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

from . import parameterized, randn, requires_dask

nx = 300
nx = 3000
long_nx = 30000
ny = 200
nt = 100
nt = 1000
window = 20

randn_xy = randn((nx, ny), frac_nan=0.1)
Expand Down Expand Up @@ -115,6 +115,11 @@ def peakmem_1drolling_reduce(self, func, use_bottleneck):
roll = self.ds.var3.rolling(t=100)
getattr(roll, func)()

@parameterized(["stride"], ([None, 5, 50]))
def peakmem_1drolling_construct(self, stride):
self.ds.var2.rolling(t=100).construct("w", stride=stride)
self.ds.var3.rolling(t=100).construct("w", stride=stride)


class DatasetRollingMemory(RollingMemory):
@parameterized(["func", "use_bottleneck"], (["sum", "max", "mean"], [True, False]))
Expand All @@ -128,3 +133,7 @@ def peakmem_1drolling_reduce(self, func, use_bottleneck):
with xr.set_options(use_bottleneck=use_bottleneck):
roll = self.ds.rolling(t=100)
getattr(roll, func)()

@parameterized(["stride"], ([None, 5, 50]))
def peakmem_1drolling_construct(self, stride):
self.ds.rolling(t=100).construct("w", stride=stride)
5 changes: 4 additions & 1 deletion doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,12 @@ Bug fixes
of :py:meth:`DataArray.__setitem__` lose dimension names.
(:issue:`7030`, :pull:`8067`) By `Darsh Ranjan <https://github.com/dranjan>`_.
- Return ``float64`` in presence of ``NaT`` in :py:class:`~core.accessor_dt.DatetimeAccessor` and
special case ``NaT`` handling in :py:meth:`~core.accessor_dt.DatetimeAccessor.isocalendar()`
special case ``NaT`` handling in :py:meth:`~core.accessor_dt.DatetimeAccessor.isocalendar`
(:issue:`7928`, :pull:`8084`).
By `Kai Mühlbauer <https://github.com/kmuehlbauer>`_.
- Fix :py:meth:`~core.rolling.DatasetRolling.construct` with stride on Datasets without indexes.
(:issue:`7021`, :pull:`7578`).
By `Amrest Chinkamol <https://github.com/p4perf4ce>`_ and `Michael Niklas <https://github.com/headtr1ck>`_.
- Calling plot with kwargs ``col``, ``row`` or ``hue`` no longer squeezes dimensions passed via these arguments
(:issue:`7552`, :pull:`8174`).
By `Wiktor Kraśnicki <https://github.com/wkrasnicki>`_.
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ source = ["xarray"]
exclude_lines = ["pragma: no cover", "if TYPE_CHECKING"]

[tool.mypy]
enable_error_code = "redundant-self"
exclude = 'xarray/util/generate_.*\.py'
files = "xarray"
show_error_codes = true
Expand Down
2 changes: 1 addition & 1 deletion xarray/core/accessor_str.py
Original file line number Diff line number Diff line change
Expand Up @@ -2386,7 +2386,7 @@ def _partitioner(

# _apply breaks on an empty array in this case
if not self._obj.size:
return self._obj.copy().expand_dims({dim: 0}, axis=-1) # type: ignore[return-value]
return self._obj.copy().expand_dims({dim: 0}, axis=-1)

arrfunc = lambda x, isep: np.array(func(x, isep), dtype=self._obj.dtype)

Expand Down
40 changes: 18 additions & 22 deletions xarray/core/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
DatetimeLike,
DTypeLikeSave,
ScalarOrArray,
Self,
SideOptions,
T_Chunks,
T_DataWithCoords,
Expand Down Expand Up @@ -381,11 +382,11 @@ class DataWithCoords(AttrAccessMixin):
__slots__ = ("_close",)

def squeeze(
self: T_DataWithCoords,
self,
dim: Hashable | Iterable[Hashable] | None = None,
drop: bool = False,
axis: int | Iterable[int] | None = None,
) -> T_DataWithCoords:
) -> Self:
"""Return a new object with squeezed data.
Parameters
Expand Down Expand Up @@ -414,12 +415,12 @@ def squeeze(
return self.isel(drop=drop, **{d: 0 for d in dims})

def clip(
self: T_DataWithCoords,
self,
min: ScalarOrArray | None = None,
max: ScalarOrArray | None = None,
*,
keep_attrs: bool | None = None,
) -> T_DataWithCoords:
) -> Self:
"""
Return an array whose values are limited to ``[min, max]``.
At least one of max or min must be given.
Expand Down Expand Up @@ -472,10 +473,10 @@ def _calc_assign_results(
return {k: v(self) if callable(v) else v for k, v in kwargs.items()}

def assign_coords(
self: T_DataWithCoords,
self,
coords: Mapping[Any, Any] | None = None,
**coords_kwargs: Any,
) -> T_DataWithCoords:
) -> Self:
"""Assign new coordinates to this object.
Returns a new object with all the original data in addition to the new
Expand Down Expand Up @@ -620,9 +621,7 @@ def assign_coords(
data.coords.update(results)
return data

def assign_attrs(
self: T_DataWithCoords, *args: Any, **kwargs: Any
) -> T_DataWithCoords:
def assign_attrs(self, *args: Any, **kwargs: Any) -> Self:
"""Assign new attrs to this object.
Returns a new object equivalent to ``self.attrs.update(*args, **kwargs)``.
Expand Down Expand Up @@ -1061,11 +1060,12 @@ def _resample(
restore_coord_dims=restore_coord_dims,
)

def where(
self: T_DataWithCoords, cond: Any, other: Any = dtypes.NA, drop: bool = False
) -> T_DataWithCoords:
def where(self, cond: Any, other: Any = dtypes.NA, drop: bool = False) -> Self:
"""Filter elements from this object according to a condition.
Returns elements from 'DataArray', where 'cond' is True,
otherwise fill in 'other'.
This operation follows the normal broadcasting and alignment rules that
xarray uses for binary arithmetic.
Expand Down Expand Up @@ -1205,9 +1205,7 @@ def close(self) -> None:
self._close()
self._close = None

def isnull(
self: T_DataWithCoords, keep_attrs: bool | None = None
) -> T_DataWithCoords:
def isnull(self, keep_attrs: bool | None = None) -> Self:
"""Test each value in the array for whether it is a missing value.
Parameters
Expand Down Expand Up @@ -1250,9 +1248,7 @@ def isnull(
keep_attrs=keep_attrs,
)

def notnull(
self: T_DataWithCoords, keep_attrs: bool | None = None
) -> T_DataWithCoords:
def notnull(self, keep_attrs: bool | None = None) -> Self:
"""Test each value in the array for whether it is not a missing value.
Parameters
Expand Down Expand Up @@ -1295,7 +1291,7 @@ def notnull(
keep_attrs=keep_attrs,
)

def isin(self: T_DataWithCoords, test_elements: Any) -> T_DataWithCoords:
def isin(self, test_elements: Any) -> Self:
"""Tests each value in the array for whether it is in test elements.
Parameters
Expand Down Expand Up @@ -1344,15 +1340,15 @@ def isin(self: T_DataWithCoords, test_elements: Any) -> T_DataWithCoords:
)

def astype(
self: T_DataWithCoords,
self,
dtype,
*,
order=None,
casting=None,
subok=None,
copy=None,
keep_attrs=True,
) -> T_DataWithCoords:
) -> Self:
"""
Copy of the xarray object, with data cast to a specified type.
Leaves coordinate dtype unchanged.
Expand Down Expand Up @@ -1419,7 +1415,7 @@ def astype(
dask="allowed",
)

def __enter__(self: T_DataWithCoords) -> T_DataWithCoords:
def __enter__(self) -> Self:
return self

def __exit__(self, exc_type, exc_value, traceback) -> None:
Expand Down
8 changes: 3 additions & 5 deletions xarray/core/concat.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from collections.abc import Hashable, Iterable
from typing import TYPE_CHECKING, Any, Union, cast, overload
from typing import TYPE_CHECKING, Any, Union, overload

import numpy as np
import pandas as pd
Expand Down Expand Up @@ -504,8 +504,7 @@ def _dataset_concat(

# case where concat dimension is a coordinate or data_var but not a dimension
if (dim in coord_names or dim in data_names) and dim not in dim_names:
# TODO: Overriding type because .expand_dims has incorrect typing:
datasets = [cast(T_Dataset, ds.expand_dims(dim)) for ds in datasets]
datasets = [ds.expand_dims(dim) for ds in datasets]

# determine which variables to concatenate
concat_over, equals, concat_dim_lengths = _calc_concat_over(
Expand Down Expand Up @@ -708,8 +707,7 @@ def _dataarray_concat(
if compat == "identical":
raise ValueError("array names not identical")
else:
# TODO: Overriding type because .rename has incorrect typing:
arr = cast(T_DataArray, arr.rename(name))
arr = arr.rename(name)
datasets.append(arr._to_temp_dataset())

ds = _dataset_concat(
Expand Down
28 changes: 16 additions & 12 deletions xarray/core/coordinates.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
create_default_index_implicit,
)
from xarray.core.merge import merge_coordinates_without_align, merge_coords
from xarray.core.types import Self, T_DataArray
from xarray.core.types import Self, T_DataArray, T_Xarray
from xarray.core.utils import (
Frozen,
ReprObject,
Expand Down Expand Up @@ -425,7 +425,7 @@ def __delitem__(self, key: Hashable) -> None:
# redirect to DatasetCoordinates.__delitem__
del self._data.coords[key]

def equals(self, other: Coordinates) -> bool:
def equals(self, other: Self) -> bool:
"""Two Coordinates objects are equal if they have matching variables,
all of which are equal.
Expand All @@ -437,7 +437,7 @@ def equals(self, other: Coordinates) -> bool:
return False
return self.to_dataset().equals(other.to_dataset())

def identical(self, other: Coordinates) -> bool:
def identical(self, other: Self) -> bool:
"""Like equals, but also checks all variable attributes.
See Also
Expand Down Expand Up @@ -565,9 +565,7 @@ def update(self, other: Mapping[Any, Any]) -> None:

self._update_coords(coords, indexes)

def assign(
self, coords: Mapping | None = None, **coords_kwargs: Any
) -> Coordinates:
def assign(self, coords: Mapping | None = None, **coords_kwargs: Any) -> Self:
"""Assign new coordinates (and indexes) to a Coordinates object, returning
a new object with all the original coordinates in addition to the new ones.
Expand Down Expand Up @@ -656,16 +654,24 @@ def copy(
self,
deep: bool = False,
memo: dict[int, Any] | None = None,
) -> Coordinates:
) -> Self:
"""Return a copy of this Coordinates object."""
# do not copy indexes (may corrupt multi-coordinate indexes)
# TODO: disable variables deepcopy? it may also be problematic when they
# encapsulate index objects like pd.Index
variables = {
k: v._copy(deep=deep, memo=memo) for k, v in self.variables.items()
}
return Coordinates._construct_direct(
coords=variables, indexes=dict(self.xindexes), dims=dict(self.sizes)

# TODO: getting an error with `self._construct_direct`, possibly because of how
# a subclass implements `_construct_direct`. (This was originally the same
# runtime code, but we switched the type definitions in #8216, which
# necessitates the cast.)
return cast(
Self,
Coordinates._construct_direct(
coords=variables, indexes=dict(self.xindexes), dims=dict(self.sizes)
),
)


Expand Down Expand Up @@ -915,9 +921,7 @@ def drop_indexed_coords(
return Coordinates._construct_direct(coords=new_variables, indexes=new_indexes)


def assert_coordinate_consistent(
obj: T_DataArray | Dataset, coords: Mapping[Any, Variable]
) -> None:
def assert_coordinate_consistent(obj: T_Xarray, coords: Mapping[Any, Variable]) -> None:
"""Make sure the dimension coordinate of obj is consistent with coords.
obj: DataArray or Dataset
Expand Down
Loading

0 comments on commit 2d59cf5

Please sign in to comment.