diff --git a/pyproject.toml b/pyproject.toml index 1a24a4b4eda..bdae33e4d0d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,6 +78,7 @@ files = "xarray" show_error_codes = true 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. @@ -168,26 +169,24 @@ module = [ # ref: https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options [[tool.mypy.overrides]] # Start off with these -warn_unused_configs = true -warn_redundant_casts = true warn_unused_ignores = true # Getting these passing should be easy -strict_equality = true strict_concatenate = true +strict_equality = true # Strongly recommend enabling this one as soon as you can check_untyped_defs = true # These shouldn't be too much additional work, but may be tricky to # get passing if you use a lot of untyped libraries +disallow_any_generics = true disallow_subclassing_any = true disallow_untyped_decorators = true -disallow_any_generics = true # These next few are various gradations of forcing use of type annotations -disallow_untyped_calls = true disallow_incomplete_defs = true +disallow_untyped_calls = true disallow_untyped_defs = true # This one isn't too hard to get passing, but return on investment is lower @@ -201,12 +200,12 @@ module = ["xarray.namedarray.*", "xarray.tests.test_namedarray"] [tool.pyright] # include = ["src"] # exclude = ["**/node_modules", - # "**/__pycache__", - # "src/experimental", - # "src/typestubs" +# "**/__pycache__", +# "src/experimental", +# "src/typestubs" # ] # ignore = ["src/oldstuff"] -defineConstant = { DEBUG = true } +defineConstant = {DEBUG = true} # stubPath = "src/stubs" # venv = "env367" @@ -217,10 +216,10 @@ reportMissingTypeStubs = false # pythonPlatform = "Linux" # executionEnvironments = [ - # { root = "src/web", pythonVersion = "3.5", pythonPlatform = "Windows", extraPaths = [ "src/service_libs" ] }, - # { root = "src/sdk", pythonVersion = "3.0", extraPaths = [ "src/backend" ] }, - # { root = "src/tests", extraPaths = ["src/tests/e2e", "src/sdk" ]}, - # { root = "src" } +# { root = "src/web", pythonVersion = "3.5", pythonPlatform = "Windows", extraPaths = [ "src/service_libs" ] }, +# { root = "src/sdk", pythonVersion = "3.0", extraPaths = [ "src/backend" ] }, +# { root = "src/tests", extraPaths = ["src/tests/e2e", "src/sdk" ]}, +# { root = "src" } # ] [tool.ruff] @@ -252,16 +251,16 @@ known-first-party = ["xarray"] [tool.pytest.ini_options] addopts = ["--strict-config", "--strict-markers"] -log_cli_level = "INFO" -minversion = "7" filterwarnings = [ "ignore:Using a non-tuple sequence for multidimensional indexing is deprecated:FutureWarning", ] +log_cli_level = "INFO" markers = [ "flaky: flaky tests", "network: tests requiring a network connection", "slow: slow tests", ] +minversion = "7" python_files = "test_*.py" testpaths = ["xarray/tests", "properties"] diff --git a/xarray/core/_typed_ops.py b/xarray/core/_typed_ops.py index 330d13bb217..9b79ed46a9c 100644 --- a/xarray/core/_typed_ops.py +++ b/xarray/core/_typed_ops.py @@ -4,7 +4,7 @@ from __future__ import annotations import operator -from typing import TYPE_CHECKING, Any, Callable, NoReturn, overload +from typing import TYPE_CHECKING, Any, Callable, overload from xarray.core import nputils, ops from xarray.core.types import ( @@ -446,201 +446,201 @@ def _binary_op( raise NotImplementedError @overload - def __add__(self, other: T_DataArray) -> NoReturn: + def __add__(self, other: T_DataArray) -> T_DataArray: ... @overload def __add__(self, other: VarCompatible) -> Self: ... - def __add__(self, other: VarCompatible) -> Self: + def __add__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.add) @overload - def __sub__(self, other: T_DataArray) -> NoReturn: + def __sub__(self, other: T_DataArray) -> T_DataArray: ... @overload def __sub__(self, other: VarCompatible) -> Self: ... - def __sub__(self, other: VarCompatible) -> Self: + def __sub__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.sub) @overload - def __mul__(self, other: T_DataArray) -> NoReturn: + def __mul__(self, other: T_DataArray) -> T_DataArray: ... @overload def __mul__(self, other: VarCompatible) -> Self: ... - def __mul__(self, other: VarCompatible) -> Self: + def __mul__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.mul) @overload - def __pow__(self, other: T_DataArray) -> NoReturn: + def __pow__(self, other: T_DataArray) -> T_DataArray: ... @overload def __pow__(self, other: VarCompatible) -> Self: ... - def __pow__(self, other: VarCompatible) -> Self: + def __pow__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.pow) @overload - def __truediv__(self, other: T_DataArray) -> NoReturn: + def __truediv__(self, other: T_DataArray) -> T_DataArray: ... @overload def __truediv__(self, other: VarCompatible) -> Self: ... - def __truediv__(self, other: VarCompatible) -> Self: + def __truediv__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.truediv) @overload - def __floordiv__(self, other: T_DataArray) -> NoReturn: + def __floordiv__(self, other: T_DataArray) -> T_DataArray: ... @overload def __floordiv__(self, other: VarCompatible) -> Self: ... - def __floordiv__(self, other: VarCompatible) -> Self: + def __floordiv__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.floordiv) @overload - def __mod__(self, other: T_DataArray) -> NoReturn: + def __mod__(self, other: T_DataArray) -> T_DataArray: ... @overload def __mod__(self, other: VarCompatible) -> Self: ... - def __mod__(self, other: VarCompatible) -> Self: + def __mod__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.mod) @overload - def __and__(self, other: T_DataArray) -> NoReturn: + def __and__(self, other: T_DataArray) -> T_DataArray: ... @overload def __and__(self, other: VarCompatible) -> Self: ... - def __and__(self, other: VarCompatible) -> Self: + def __and__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.and_) @overload - def __xor__(self, other: T_DataArray) -> NoReturn: + def __xor__(self, other: T_DataArray) -> T_DataArray: ... @overload def __xor__(self, other: VarCompatible) -> Self: ... - def __xor__(self, other: VarCompatible) -> Self: + def __xor__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.xor) @overload - def __or__(self, other: T_DataArray) -> NoReturn: + def __or__(self, other: T_DataArray) -> T_DataArray: ... @overload def __or__(self, other: VarCompatible) -> Self: ... - def __or__(self, other: VarCompatible) -> Self: + def __or__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.or_) @overload - def __lshift__(self, other: T_DataArray) -> NoReturn: + def __lshift__(self, other: T_DataArray) -> T_DataArray: ... @overload def __lshift__(self, other: VarCompatible) -> Self: ... - def __lshift__(self, other: VarCompatible) -> Self: + def __lshift__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.lshift) @overload - def __rshift__(self, other: T_DataArray) -> NoReturn: + def __rshift__(self, other: T_DataArray) -> T_DataArray: ... @overload def __rshift__(self, other: VarCompatible) -> Self: ... - def __rshift__(self, other: VarCompatible) -> Self: + def __rshift__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.rshift) @overload - def __lt__(self, other: T_DataArray) -> NoReturn: + def __lt__(self, other: T_DataArray) -> T_DataArray: ... @overload def __lt__(self, other: VarCompatible) -> Self: ... - def __lt__(self, other: VarCompatible) -> Self: + def __lt__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.lt) @overload - def __le__(self, other: T_DataArray) -> NoReturn: + def __le__(self, other: T_DataArray) -> T_DataArray: ... @overload def __le__(self, other: VarCompatible) -> Self: ... - def __le__(self, other: VarCompatible) -> Self: + def __le__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.le) @overload - def __gt__(self, other: T_DataArray) -> NoReturn: + def __gt__(self, other: T_DataArray) -> T_DataArray: ... @overload def __gt__(self, other: VarCompatible) -> Self: ... - def __gt__(self, other: VarCompatible) -> Self: + def __gt__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.gt) @overload - def __ge__(self, other: T_DataArray) -> NoReturn: + def __ge__(self, other: T_DataArray) -> T_DataArray: ... @overload def __ge__(self, other: VarCompatible) -> Self: ... - def __ge__(self, other: VarCompatible) -> Self: + def __ge__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, operator.ge) @overload # type:ignore[override] - def __eq__(self, other: T_DataArray) -> NoReturn: + def __eq__(self, other: T_DataArray) -> T_DataArray: ... @overload def __eq__(self, other: VarCompatible) -> Self: ... - def __eq__(self, other: VarCompatible) -> Self: + def __eq__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, nputils.array_eq) @overload # type:ignore[override] - def __ne__(self, other: T_DataArray) -> NoReturn: + def __ne__(self, other: T_DataArray) -> T_DataArray: ... @overload def __ne__(self, other: VarCompatible) -> Self: ... - def __ne__(self, other: VarCompatible) -> Self: + def __ne__(self, other: VarCompatible) -> Self | T_DataArray: return self._binary_op(other, nputils.array_ne) def __radd__(self, other: VarCompatible) -> Self: diff --git a/xarray/core/alignment.py b/xarray/core/alignment.py index 7d9ba4f4b94..732ec5d3ea6 100644 --- a/xarray/core/alignment.py +++ b/xarray/core/alignment.py @@ -604,7 +604,7 @@ def align( @overload -def align( # type: ignore[misc] +def align( obj1: T_Obj1, obj2: T_Obj2, /, @@ -619,7 +619,7 @@ def align( # type: ignore[misc] @overload -def align( # type: ignore[misc] +def align( obj1: T_Obj1, obj2: T_Obj2, obj3: T_Obj3, @@ -635,7 +635,7 @@ def align( # type: ignore[misc] @overload -def align( # type: ignore[misc] +def align( obj1: T_Obj1, obj2: T_Obj2, obj3: T_Obj3, @@ -652,7 +652,7 @@ def align( # type: ignore[misc] @overload -def align( # type: ignore[misc] +def align( obj1: T_Obj1, obj2: T_Obj2, obj3: T_Obj3, @@ -1101,14 +1101,14 @@ def broadcast( @overload -def broadcast( # type: ignore[misc] +def broadcast( obj1: T_Obj1, obj2: T_Obj2, /, *, exclude: str | Iterable[Hashable] | None = None ) -> tuple[T_Obj1, T_Obj2]: ... @overload -def broadcast( # type: ignore[misc] +def broadcast( obj1: T_Obj1, obj2: T_Obj2, obj3: T_Obj3, @@ -1120,7 +1120,7 @@ def broadcast( # type: ignore[misc] @overload -def broadcast( # type: ignore[misc] +def broadcast( obj1: T_Obj1, obj2: T_Obj2, obj3: T_Obj3, @@ -1133,7 +1133,7 @@ def broadcast( # type: ignore[misc] @overload -def broadcast( # type: ignore[misc] +def broadcast( obj1: T_Obj1, obj2: T_Obj2, obj3: T_Obj3, diff --git a/xarray/util/generate_ops.py b/xarray/util/generate_ops.py index 632ca06d295..f339470884a 100644 --- a/xarray/util/generate_ops.py +++ b/xarray/util/generate_ops.py @@ -87,13 +87,15 @@ def {method}(self, other: {other_type}) -> {return_type}:{type_ignore} return self._binary_op(other, {func})""" template_binop_overload = """ @overload{overload_type_ignore} - def {method}(self, other: {overload_type}) -> NoReturn: + def {method}(self, other: {overload_type}) -> {overload_type}: ... @overload def {method}(self, other: {other_type}) -> {return_type}: ... -""" + + def {method}(self, other: {other_type}) -> {return_type} | {overload_type}:{type_ignore} + return self._binary_op(other, {func})""" template_reflexive = """ def {method}(self, other: {other_type}) -> {return_type}: return self._binary_op(other, {func}, reflexive=True)""" @@ -123,7 +125,7 @@ def {method}(self, *args: Any, **kwargs: Any) -> Self: # # We require a "hack" to tell type checkers that e.g. Variable + DataArray = DataArray # In reality this returns NotImplementes, but this is not a valid type in python 3.9. -# Therefore, we use NoReturn which mypy seems to recognise! +# Therefore, we return DataArray. In reality this would call DataArray.__add__(Variable) # TODO: change once python 3.10 is the minimum. # # Mypy seems to require that __iadd__ and __add__ have the same signature. @@ -165,7 +167,7 @@ def binops_overload( ([(None, None)], required_method_binary, extras), ( BINOPS_NUM + BINOPS_CMP, - template_binop_overload + template_binop, + template_binop_overload, extras | { "overload_type": overload_type, @@ -175,7 +177,7 @@ def binops_overload( ), ( BINOPS_EQNE, - template_binop_overload + template_binop, + template_binop_overload, extras | { "overload_type": overload_type, @@ -233,7 +235,7 @@ def unops() -> list[OpsType]: from __future__ import annotations import operator -from typing import TYPE_CHECKING, Any, Callable, NoReturn, overload +from typing import TYPE_CHECKING, Any, Callable, overload from xarray.core import nputils, ops from xarray.core.types import (