Skip to content
Merged
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
15 changes: 15 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,21 @@ repos:
typing-extensions>=4.1.0,
numpy,
]
# keep the mypy version used in CI (pixi.toml) in sync with the hook above, so that the
# pre-commit.ci autoupdate also updates mypy in CI
- repo: local
hooks:
- id: sync-mypy-version
name: sync the mypy version in pixi.toml
language: python
files: ^\.pre-commit-config\.yaml$
pass_filenames: false
entry: >-
python -c "import pathlib, re;
config = pathlib.Path('.pre-commit-config.yaml').read_text();
version = re.search(r'mirrors-mypy\s+rev: v?([0-9.]+)', config).group(1);
pixi = pathlib.Path('pixi.toml');
pixi.write_text(re.sub(r'(?m)^mypy = \"==[0-9.]+\"', f'mypy = \"=={version}\"', pixi.read_text()))"
- repo: https://github.com/citation-file-format/cff-converter-python
rev: 5295f87c0e261da61a7b919fc754e3a77edd98a7
hooks:
Expand Down
134 changes: 0 additions & 134 deletions _stubtest/allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,167 +6,33 @@
# Format: Each line is a regex pattern matching fully qualified names to ignore.
# See: https://mypy.readthedocs.io/en/stable/stubtest.html#allowlist

# =============================================================================
# typing module re-exports (metaclass/signature differences)
# =============================================================================

# Any has metaclass differences between stub and runtime
xarray\.core\.(dataarray|dataset|variable)\.Any$
xarray\.core\.(dataarray|dataset|variable)\.Any\.__new__$

# Callable also has metaclass differences
xarray\.core\.(dataarray|dataset|variable)\.Callable$

# Self is a TYPE_CHECKING import
xarray\.core\.(dataarray|variable)\.Self$

# TypeVar has __mro_entries__ at runtime but not in stubs
xarray\.core\.dataarray\.TypeVar\.__mro_entries__$

# =============================================================================
# TYPE_CHECKING imports - not present at runtime
# =============================================================================

# Type aliases from xarray.core.types
xarray\.core\.(dataarray|dataset|variable)\.Dims$
xarray\.core\.(dataarray|dataset)\.DatetimeLike$
xarray\.core\.(dataarray|dataset)\.DatetimeUnitOptions$
xarray\.core\.(dataarray|dataset)\.ErrorOptions$
xarray\.core\.(dataarray|dataset|variable)\.ErrorOptionsWithWarn$
xarray\.core\.(dataarray|dataset)\.GroupIndices$
xarray\.core\.(dataarray|dataset)\.GroupInput$
xarray\.core\.(dataarray|dataset)\.Grouper$
xarray\.core\.(dataarray|dataset)\.InterpOptions$
xarray\.core\.(dataarray|dataset)\.NetcdfWriteModes$
xarray\.core\.(dataarray|dataset|variable)\.PadModeOptions$
xarray\.core\.(dataarray|dataset|variable)\.PadReflectOptions$
xarray\.core\.(dataarray|dataset|variable)\.QuantileMethods$
xarray\.core\.(dataarray|dataset)\.QueryEngineOptions$
xarray\.core\.(dataarray|dataset)\.QueryParserOptions$
xarray\.core\.(dataarray|dataset)\.ReindexMethodOptions$
xarray\.core\.(dataarray|dataset)\.ResampleCompatible$
xarray\.core\.(dataarray|dataset)\.Resampler$
xarray\.core\.(dataarray|dataset)\.SideOptions$
xarray\.core\.(dataarray|dataset)\.CoarsenBoundaryOptions$
xarray\.core\.(dataarray|dataset)\.ZarrWriteModes$
xarray\.core\.(dataarray|dataset)\.ZarrStore$
xarray\.core\.(dataarray|dataset)\.ZarrStoreLike$
xarray\.core\.(dataarray|dataset)\.ArrayLike$
xarray\.core\.dataset\.CFCalendar$
xarray\.core\.dataset\.CombineAttrsOptions$
xarray\.core\.dataset\.CompatOptions$
xarray\.core\.dataset\.JoinOptions$
xarray\.core\.dataset\.CoercibleMapping$
xarray\.core\.dataset\.CoercibleValue$
xarray\.core\.dataset\.DataVars$
xarray\.core\.dataset\.DsCompatible$

# TypeVars
xarray\.core\.(dataarray|dataset)\.T_ChunkDimFreq$
xarray\.core\.(dataarray|dataset)\.T_ChunksFreq$
xarray\.core\.(dataarray|dataset|variable)\.T_Chunks$
xarray\.core\.(dataarray|dataset)\.T_NetcdfEngine$
xarray\.core\.(dataarray|dataset)\.T_NetcdfTypes$
xarray\.core\.(dataarray|dataset)\.T_Xarray$
xarray\.core\.dataarray\.T_XarrayOther$
xarray\.core\.dataset\.T_DatasetPadConstantValues$
xarray\.core\.variable\.T_DuckArray$
xarray\.core\.variable\.T_VarPadConstantValues$

# External library types (dask, delayed, etc.)
xarray\.core\.(dataarray|dataset|variable)\.ChunkManagerEntrypoint$
xarray\.core\.(dataarray|dataset)\.DaskDataFrame$
xarray\.core\.(dataarray|dataset)\.Delayed$
xarray\.core\.dataset\.AbstractDataStore$
xarray\.core\.dataarray\.iris_Cube$

# DataArray TYPE_CHECKING import in dataset module
xarray\.core\.dataset\.DataArray$

# NamedArray TYPE_CHECKING import
xarray\.core\.variable\.NamedArray$

# =============================================================================
# GroupBy/Rolling/Coarsen/Weighted/Resample classes (TYPE_CHECKING imports)
# =============================================================================

xarray\.core\.dataarray\.DataArrayGroupBy$
xarray\.core\.dataarray\.DataArrayCoarsen$
xarray\.core\.dataarray\.DataArrayRolling$
xarray\.core\.dataarray\.DataArrayWeighted$
xarray\.core\.dataarray\.DataArrayResample$
xarray\.core\.dataset\.DatasetGroupBy$
xarray\.core\.dataset\.DatasetCoarsen$
xarray\.core\.dataset\.DatasetRolling$
xarray\.core\.dataset\.DatasetWeighted$
xarray\.core\.dataset\.DatasetResample$

# =============================================================================
# CFTimeIndex properties - read-only at runtime
# =============================================================================

xarray\.core\.(dataarray|dataset)\.CFTimeIndex\.date_type$
xarray\.core\.(dataarray|dataset)\.CFTimeIndex\.day$
xarray\.core\.(dataarray|dataset)\.CFTimeIndex\.day_of_week$
xarray\.core\.(dataarray|dataset)\.CFTimeIndex\.dayofweek$
xarray\.core\.(dataarray|dataset)\.CFTimeIndex\.day_of_year$
xarray\.core\.(dataarray|dataset)\.CFTimeIndex\.dayofyear$
xarray\.core\.(dataarray|dataset)\.CFTimeIndex\.days_in_month$
xarray\.core\.(dataarray|dataset)\.CFTimeIndex\.hour$
xarray\.core\.(dataarray|dataset)\.CFTimeIndex\.microsecond$
xarray\.core\.(dataarray|dataset)\.CFTimeIndex\.minute$
xarray\.core\.(dataarray|dataset)\.CFTimeIndex\.month$
xarray\.core\.(dataarray|dataset)\.CFTimeIndex\.second$
xarray\.core\.(dataarray|dataset)\.CFTimeIndex\.year$

# =============================================================================
# Plot accessors and methods
# =============================================================================

xarray\.core\.dataarray\.DataArray\.plot$
xarray\.core\.(dataarray|dataset)\.Dataset\.plot$
xarray\.core\.dataarray\.DataArrayPlotAccessor\.(contour|contourf|imshow|line|pcolormesh|scatter|step|surface)$
xarray\.core\.dataset\.DatasetPlotAccessor\.(quiver|scatter|streamplot)$

# =============================================================================
# __array__ method - complex numpy protocol
# =============================================================================

xarray\.core\.(dataarray|dataset)\.Dataset\.__array__$

# =============================================================================
# Mapping/MutableMapping/Sequence/Iterable protocol methods
# =============================================================================

xarray\.core\.(dataarray|dataset|variable)\.Mapping\.get$
xarray\.core\.(dataarray|dataset|variable)\.Mapping\.__reversed__$
xarray\.core\.(dataarray|dataset|variable)\.Sequence\.index$
xarray\.core\.(dataarray|dataset)\.Iterable\.__class_getitem__$
xarray\.core\.(dataarray|dataset)\.MutableMapping\.(pop|setdefault)$
xarray\.core\.(dataarray|dataset)\.PathLike\.__class_getitem__$
xarray\.core\.dataset\.FrozenMappingWarningOnValuesAccess\.get$

# Number.__hash__
xarray\.core\.dataset\.Number\.__hash__$

# =============================================================================
# IO protocol (typing.IO)
# =============================================================================

xarray\.core\.dataset\.IO\.(closed|mode|name|read|readline|readlines|seek|truncate|write|writelines|__iter__|__next__)$

# =============================================================================
# Variable/IndexVariable methods inherited from numpy-like interface
# =============================================================================

xarray\.core\.(dataarray|dataset|variable)\.Variable\.(item|searchsorted)$
xarray\.core\.(dataarray|dataset|variable)\.IndexVariable\.(item|searchsorted)$
xarray\.core\.dataarray\.DataArray\.(item|searchsorted)$
xarray\.core\.dataarray\.DataArrayArithmetic\.(item|searchsorted)$
xarray\.core\.variable\.VariableArithmetic\.(item|searchsorted)$

# =============================================================================
# Subclass pattern for Variable
# =============================================================================

xarray\.core\.variable\.<subclass.*
2 changes: 1 addition & 1 deletion pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ linkcheck = { cmd = "make linkcheck", cwd = "doc", description = "Check URLs in


[feature.typing.dependencies]
mypy = "==1.19.1"
mypy = "==2.3.1"
pyright = "*"
hypothesis = "*"
lxml = "*"
Expand Down
3 changes: 0 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,12 @@ exclude = ['build', 'xarray/util/generate_.*\.py']
files = "xarray"
show_error_context = true
warn_redundant_casts = true
warn_unused_configs = true
warn_unused_ignores = true

# Much of the numerical computing stack doesn't have type annotations yet.
[[tool.mypy.overrides]]
ignore_missing_imports = true
module = [
"affine.*",
"bottleneck.*",
"cartopy.*",
"cf_units.*",
Expand All @@ -155,7 +153,6 @@ module = [
"mpl_toolkits.*",
"nc_time_axis.*",
"netCDF4.*",
"netcdftime.*",
"numcodecs.*",
"opt_einsum.*",
"pint.*",
Expand Down
5 changes: 1 addition & 4 deletions xarray/computation/computation.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,7 @@ def _cov_corr(
# Adjust covariance for degrees of freedom
valid_count = valid_values.sum(dim)
adjust = valid_count / (valid_count - ddof)
# I think the cast is required because of `T_DataArray` + `T_Xarray` (would be
# the same with `T_DatasetOrArray`)
# https://github.com/pydata/xarray/pull/8384#issuecomment-1784228026
return cast(T_DataArray, cov * adjust)
return cov * adjust

else:
# Compute std and corr
Expand Down
2 changes: 1 addition & 1 deletion xarray/core/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ def squeeze(
numpy.squeeze
"""
dims = get_squeeze_dims(self, dim, axis)
return self.isel(drop=drop, **dict.fromkeys(dims, 0))
return self.isel(dict.fromkeys(dims, 0), drop=drop)

def clip(
self,
Expand Down
1 change: 1 addition & 0 deletions xarray/core/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -9268,6 +9268,7 @@ def pad(
"""
pad_width = either_dict_or_kwargs(pad_width, pad_width_kwargs, "pad")

coord_pad_mode: PadModeOptions
if mode in ("edge", "reflect", "symmetric", "wrap"):
coord_pad_mode = mode
coord_pad_options = {
Expand Down
4 changes: 2 additions & 2 deletions xarray/indexes/nd_point_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import abc
from collections.abc import Hashable, Iterable, Mapping
from typing import TYPE_CHECKING, Any, Generic, TypeVar
from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast

import numpy as np

Expand Down Expand Up @@ -268,7 +268,7 @@ def from_variables(

tree_adapter_cls: type[T_TreeAdapter] = opts.pop("tree_adapter_cls", None)
if tree_adapter_cls is None:
tree_adapter_cls = ScipyKDTreeAdapter
tree_adapter_cls = cast(type[T_TreeAdapter], ScipyKDTreeAdapter)

points = get_points(variables.values())

Expand Down
11 changes: 7 additions & 4 deletions xarray/tests/test_dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -1328,8 +1328,7 @@ def test_thin(self) -> None:
def test_loc(self) -> None:
self.ds["x"] = ("x", np.array(list("abcdefghij")))
da = self.ds["foo"]
# typing issue: see https://github.com/python/mypy/issues/2410
assert_identical(da[:3], da.loc[:"c"]) # type: ignore[misc]
assert_identical(da[:3], da.loc[:"c"])
assert_identical(da[1], da.loc["b"])
assert_identical(da[1], da.loc[{"x": "b"}])
assert_identical(da[1], da.loc["b", ...])
Expand All @@ -1347,8 +1346,7 @@ def test_loc_assign(self) -> None:
self.ds["x"] = ("x", np.array(list("abcdefghij")))
da = self.ds["foo"]
# assignment
# typing issue: see https://github.com/python/mypy/issues/2410
da.loc["a":"j"] = 0 # type: ignore[misc]
da.loc["a":"j"] = 0
assert np.all(da.values == 0)
da.loc[{"x": slice("a", "j")}] = 2
assert np.all(da.values == 2)
Expand Down Expand Up @@ -2921,6 +2919,11 @@ def test_transpose(self) -> None:
def test_squeeze(self) -> None:
assert_equal(self.dv.variable.squeeze(), self.dv.squeeze().variable)

def test_squeeze_non_str_dim_name(self) -> None:
array = DataArray(np.zeros((1, 3)), dims=[0, "y"])
expected = DataArray(np.zeros(3), dims=["y"])
assert_identical(array.squeeze(), expected)

def test_squeeze_drop(self) -> None:
array = DataArray([1], [("x", [0])])
expected = DataArray(1)
Expand Down
22 changes: 11 additions & 11 deletions xarray/tests/test_dataarray_typing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@

da = DataArray().pipe(lambda data, arg: arg, "foo")

reveal_type(da) # N: Revealed type is "builtins.str"
reveal_type(da) # N: Revealed type is "str"

- case: test_mypy_pipe_lambda_chaining_return_type
main: |
from xarray import DataArray

answer = DataArray().pipe(lambda data, arg: arg, "foo").count("o")

reveal_type(answer) # N: Revealed type is "builtins.int"
reveal_type(answer) # N: Revealed type is "int"

- case: test_mypy_pipe_lambda_missing_arg
main: |
Expand All @@ -31,7 +31,7 @@
out: |
main:4: error: No overload variant of "pipe" of "DataWithCoords" matches argument type "Callable[[Any, Any], Any]" [call-overload]
main:4: note: Possible overload variants:
main:4: note: def [P`2, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:4: note: def [P, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:4: note: def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T

- case: test_mypy_pipe_lambda_extra_arg
Expand All @@ -43,7 +43,7 @@
out: |
main:4: error: No overload variant of "pipe" of "DataWithCoords" matches argument types "Callable[[Any], Any]", "str" [call-overload]
main:4: note: Possible overload variants:
main:4: note: def [P`2, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:4: note: def [P, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:4: note: def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T

- case: test_mypy_pipe_function_missing_posarg
Expand All @@ -58,7 +58,7 @@
out: |
main:7: error: No overload variant of "pipe" of "DataWithCoords" matches argument type "Callable[[DataArray, int], DataArray]" [call-overload]
main:7: note: Possible overload variants:
main:7: note: def [P`2, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:7: note: def [P, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:7: note: def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T

- case: test_mypy_pipe_function_extra_posarg
Expand All @@ -73,7 +73,7 @@
out: |
main:7: error: No overload variant of "pipe" of "DataWithCoords" matches argument types "Callable[[DataArray, int], DataArray]", "int", "str" [call-overload]
main:7: note: Possible overload variants:
main:7: note: def [P`2, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:7: note: def [P, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:7: note: def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T

- case: test_mypy_pipe_function_missing_kwarg
Expand All @@ -88,7 +88,7 @@
out: |
main:7: error: No overload variant of "pipe" of "DataWithCoords" matches argument types "def f(da: DataArray, arg: int, *, kwonly: int) -> DataArray", "int" [call-overload]
main:7: note: Possible overload variants:
main:7: note: def [P`2, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:7: note: def [P, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:7: note: def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T

- case: test_mypy_pipe_function_missing_keyword
Expand All @@ -103,7 +103,7 @@
out: |
main:7: error: No overload variant of "pipe" of "DataWithCoords" matches argument types "def f(da: DataArray, arg: int, *, kwonly: int) -> DataArray", "int", "int" [call-overload]
main:7: note: Possible overload variants:
main:7: note: def [P`2, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:7: note: def [P, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:7: note: def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T

- case: test_mypy_pipe_function_unexpected_keyword
Expand Down Expand Up @@ -141,7 +141,7 @@

answer = DataArray().pipe((f, "da"), 42)

reveal_type(answer) # N: Revealed type is "builtins.int"
reveal_type(answer) # N: Revealed type is "int"

- case: test_mypy_pipe_tuple_missing_arg
main: |
Expand All @@ -165,7 +165,7 @@
out: |
main:17: error: No overload variant of "pipe" of "DataWithCoords" matches argument type "Callable[[Any, Any], DataArray]" [call-overload]
main:17: note: Possible overload variants:
main:17: note: def [P`9, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:17: note: def [P, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:17: note: def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T

- case: test_mypy_pipe_tuple_extra_arg
Expand All @@ -190,5 +190,5 @@
out: |
main:17: error: No overload variant of "pipe" of "DataWithCoords" matches argument types "Callable[[Any, Any], DataArray]", "int", "str" [call-overload]
main:17: note: Possible overload variants:
main:17: note: def [P`9, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:17: note: def [P, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
main:17: note: def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T
Loading
Loading