diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml index 4611204..6eb1a32 100644 --- a/.github/workflows/ruff.yml +++ b/.github/workflows/ruff.yml @@ -13,7 +13,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install "ruff<0.16" + pip install "ruff" # Update output format to enable automatic inline annotations. - name: Run Ruff run: ruff check --output-format=github . diff --git a/array_api_strict/_array_object.py b/array_api_strict/_array_object.py index 4d55245..4738d02 100644 --- a/array_api_strict/_array_object.py +++ b/array_api_strict/_array_object.py @@ -394,9 +394,8 @@ def _validate_index( "zero-dimensional integer arrays and boolean arrays " "are specified in the Array API." ) - if op == "setitem": - if isinstance(i, Array) and i.dtype in _integer_dtypes: - raise IndexError("Fancy indexing __setitem__ is not supported.") + if op == "setitem" and isinstance(i, Array) and i.dtype in _integer_dtypes: + raise IndexError("Fancy indexing __setitem__ is not supported.") nonexpanding_key = [] single_axes = [] @@ -530,8 +529,8 @@ def __add__(self, other: Array | complex, /) -> Array: other = self._check_allowed_dtypes(other, "numeric", "__add__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__add__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__add__(other._array) return self.__class__._new(res, device=self.device) def __and__(self, other: Array | int, /) -> Array: @@ -542,8 +541,8 @@ def __and__(self, other: Array | int, /) -> Array: other = self._check_allowed_dtypes(other, "integer or boolean", "__and__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__and__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__and__(other._array) return self.__class__._new(res, device=self.device) def __array_namespace__(self, /, *, api_version: str | None = None) -> ModuleType: @@ -641,8 +640,8 @@ def __eq__(self, other: Array | complex, /) -> Array: # type: ignore[override] other = self._check_allowed_dtypes(other, "all", "__eq__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__eq__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__eq__(other._array) return self.__class__._new(res, device=self.device) def __float__(self) -> float: @@ -665,8 +664,8 @@ def __floordiv__(self, other: Array | float, /) -> Array: other = self._check_allowed_dtypes(other, "real numeric", "__floordiv__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__floordiv__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__floordiv__(other._array) return self.__class__._new(res, device=self.device) def __ge__(self, other: Array | float, /) -> Array: @@ -677,8 +676,8 @@ def __ge__(self, other: Array | float, /) -> Array: other = self._check_allowed_dtypes(other, "real numeric", "__ge__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__ge__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__ge__(other._array) return self.__class__._new(res, device=self.device) def __getitem__( @@ -729,8 +728,8 @@ def __gt__(self, other: Array | float, /) -> Array: other = self._check_allowed_dtypes(other, "real numeric", "__gt__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__gt__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__gt__(other._array) return self.__class__._new(res, device=other.device) def __int__(self) -> int: @@ -784,8 +783,8 @@ def __le__(self, other: Array | float, /) -> Array: other = self._check_allowed_dtypes(other, "real numeric", "__le__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__le__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__le__(other._array) return self.__class__._new(res, device=self.device) def __lshift__(self, other: Array | int, /) -> Array: @@ -796,8 +795,8 @@ def __lshift__(self, other: Array | int, /) -> Array: other = self._check_allowed_dtypes(other, "integer", "__lshift__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__lshift__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__lshift__(other._array) return self.__class__._new(res, device=self.device) def __lt__(self, other: Array | float, /) -> Array: @@ -808,8 +807,8 @@ def __lt__(self, other: Array | float, /) -> Array: other = self._check_allowed_dtypes(other, "real numeric", "__lt__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__lt__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__lt__(other._array) return self.__class__._new(res, device=self.device) def __matmul__(self, other: Array, /) -> Array: @@ -833,8 +832,8 @@ def __mod__(self, other: Array | float, /) -> Array: other = self._check_allowed_dtypes(other, "real numeric", "__mod__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__mod__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__mod__(other._array) return self.__class__._new(res, device=self.device) def __mul__(self, other: Array | complex, /) -> Array: @@ -845,8 +844,8 @@ def __mul__(self, other: Array | complex, /) -> Array: other = self._check_allowed_dtypes(other, "numeric", "__mul__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__mul__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__mul__(other._array) return self.__class__._new(res, device=self.device) def __ne__(self, other: Array | complex, /) -> Array: # type: ignore[override] @@ -857,8 +856,8 @@ def __ne__(self, other: Array | complex, /) -> Array: # type: ignore[override] other = self._check_allowed_dtypes(other, "all", "__ne__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__ne__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__ne__(other._array) return self.__class__._new(res, device=self.device) def __neg__(self) -> Array: @@ -878,8 +877,8 @@ def __or__(self, other: Array | int, /) -> Array: other = self._check_allowed_dtypes(other, "integer or boolean", "__or__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__or__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__or__(other._array) return self.__class__._new(res, device=self.device) def __pos__(self) -> Array: @@ -913,8 +912,8 @@ def __rshift__(self, other: Array | int, /) -> Array: other = self._check_allowed_dtypes(other, "integer", "__rshift__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__rshift__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__rshift__(other._array) return self.__class__._new(res, device=self.device) def __setitem__( @@ -962,8 +961,8 @@ def __sub__(self, other: Array | complex, /) -> Array: other = self._check_allowed_dtypes(other, "numeric", "__sub__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__sub__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__sub__(other._array) return self.__class__._new(res, device=self.device) # PEP 484 requires int to be a subtype of float, but __truediv__ should @@ -976,8 +975,8 @@ def __truediv__(self, other: Array | complex, /) -> Array: other = self._check_allowed_dtypes(other, "floating-point", "__truediv__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__truediv__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__truediv__(other._array) return self.__class__._new(res, device=self.device) def __xor__(self, other: Array | int, /) -> Array: @@ -988,8 +987,8 @@ def __xor__(self, other: Array | int, /) -> Array: other = self._check_allowed_dtypes(other, "integer or boolean", "__xor__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__xor__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__xor__(other._array) return self.__class__._new(res, device=self.device) def __iadd__(self, other: Array | complex, /) -> Self: @@ -1011,8 +1010,8 @@ def __radd__(self, other: Array | complex, /) -> Array: other = self._check_allowed_dtypes(other, "numeric", "__radd__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__radd__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__radd__(other._array) return self.__class__._new(res, device=self.device) def __iand__(self, other: Array | int, /) -> Self: @@ -1034,8 +1033,8 @@ def __rand__(self, other: Array | int, /) -> Array: other = self._check_allowed_dtypes(other, "integer or boolean", "__rand__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__rand__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__rand__(other._array) return self.__class__._new(res, device=self.device) def __ifloordiv__(self, other: Array | float, /) -> Self: @@ -1057,8 +1056,8 @@ def __rfloordiv__(self, other: Array | float, /) -> Array: other = self._check_allowed_dtypes(other, "real numeric", "__rfloordiv__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__rfloordiv__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__rfloordiv__(other._array) return self.__class__._new(res, device=self.device) def __ilshift__(self, other: Array | int, /) -> Self: @@ -1080,8 +1079,8 @@ def __rlshift__(self, other: Array | int, /) -> Array: other = self._check_allowed_dtypes(other, "integer", "__rlshift__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__rlshift__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__rlshift__(other._array) return self.__class__._new(res, device=self.device) def __imatmul__(self, other: Array, /) -> Self: @@ -1129,8 +1128,8 @@ def __rmod__(self, other: Array | float, /) -> Array: if other is NotImplemented: return other self._check_type_device(other) - self, other = self._normalize_two_args(self, other) - res = self._array.__rmod__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__rmod__(other._array) return self.__class__._new(res, device=self.device) def __imul__(self, other: Array | complex, /) -> Self: @@ -1152,8 +1151,8 @@ def __rmul__(self, other: Array | complex, /) -> Array: if other is NotImplemented: return other self._check_type_device(other) - self, other = self._normalize_two_args(self, other) - res = self._array.__rmul__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__rmul__(other._array) return self.__class__._new(res, device=self.device) def __ior__(self, other: Array | int, /) -> Self: @@ -1175,8 +1174,8 @@ def __ror__(self, other: Array | int, /) -> Array: other = self._check_allowed_dtypes(other, "integer or boolean", "__ror__") if other is NotImplemented: return other - self, other = self._normalize_two_args(self, other) - res = self._array.__ror__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__ror__(other._array) return self.__class__._new(res, device=self.device) def __ipow__(self, other: Array | complex, /) -> Self: @@ -1223,8 +1222,8 @@ def __rrshift__(self, other: Array | int, /) -> Array: if other is NotImplemented: return other self._check_type_device(other) - self, other = self._normalize_two_args(self, other) - res = self._array.__rrshift__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__rrshift__(other._array) return self.__class__._new(res, device=self.device) def __isub__(self, other: Array | complex, /) -> Self: @@ -1246,8 +1245,8 @@ def __rsub__(self, other: Array | complex, /) -> Array: if other is NotImplemented: return other self._check_type_device(other) - self, other = self._normalize_two_args(self, other) - res = self._array.__rsub__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__rsub__(other._array) return self.__class__._new(res, device=self.device) def __itruediv__(self, other: Array | complex, /) -> Self: @@ -1269,8 +1268,8 @@ def __rtruediv__(self, other: Array | complex, /) -> Array: if other is NotImplemented: return other self._check_type_device(other) - self, other = self._normalize_two_args(self, other) - res = self._array.__rtruediv__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__rtruediv__(other._array) return self.__class__._new(res, device=self.device) def __ixor__(self, other: Array | int, /) -> Self: @@ -1292,8 +1291,8 @@ def __rxor__(self, other: Array | int, /) -> Array: if other is NotImplemented: return other self._check_type_device(other) - self, other = self._normalize_two_args(self, other) - res = self._array.__rxor__(other._array) + _self, other = self._normalize_two_args(self, other) + res = _self._array.__rxor__(other._array) return self.__class__._new(res, device=self.device) def to_device(self, device: Device, /, stream: None = None) -> Array: diff --git a/array_api_strict/_manipulation_functions.py b/array_api_strict/_manipulation_functions.py index 02dcf16..53197a3 100644 --- a/array_api_strict/_manipulation_functions.py +++ b/array_api_strict/_manipulation_functions.py @@ -142,7 +142,7 @@ def roll( See its docstring for more information. """ if not isinstance(shift, int | tuple): - raise ValueError( + raise TypeError( f"`shift` can only be an int or a tuple, got {type(shift)=} instead." ) return Array._new(np.roll(x._array, shift, axis=axis), device=x.device) diff --git a/array_api_strict/tests/test_array_object.py b/array_api_strict/tests/test_array_object.py index 94cd87b..fd09276 100644 --- a/array_api_strict/tests/test_array_object.py +++ b/array_api_strict/tests/test_array_object.py @@ -365,7 +365,8 @@ def _array_vals(): _op.startswith("__i") and result_type(x.dtype, y.dtype) != x.dtype ): - assert_raises(TypeError, lambda: getattr(x, _op)(y)) + with assert_raises(TypeError): + getattr(x, _op)(y) # Ensure only those dtypes that are required for every operator are allowed. elif (dtypes == "all" and (x.dtype in _boolean_dtypes and y.dtype in _boolean_dtypes or x.dtype in _numeric_dtypes and y.dtype in _numeric_dtypes) @@ -379,7 +380,8 @@ def _array_vals(): ): getattr(x, _op)(y) else: - assert_raises(TypeError, lambda: getattr(x, _op)(y)) + with assert_raises(TypeError): + getattr(x, _op)(y) # finally, test that array op ndarray raises # XXX: as long as there is __array__ or __buffer__, __rop__s # still return ndarrays @@ -399,7 +401,8 @@ def _array_vals(): # Only test for no error getattr(a, op)() else: - assert_raises(TypeError, lambda: getattr(a, op)()) + with assert_raises(TypeError): + getattr(a, op)() # Finally, matmul() must be tested separately, because it works a bit # different from the other operations. @@ -418,9 +421,11 @@ def _matmul_array_vals(): or type(s) == int and a.dtype in _integer_dtypes): # Type promotion is valid, but @ is not allowed on 0-D # inputs, so the error is a ValueError - assert_raises(ValueError, lambda: getattr(a, _op)(s)) + with assert_raises(ValueError): + getattr(a, _op)(s) else: - assert_raises(TypeError, lambda: getattr(a, _op)(s)) + with assert_raises(TypeError): + getattr(a, _op)(s) for x in _matmul_array_vals(): for y in _matmul_array_vals(): @@ -433,24 +438,33 @@ def _matmul_array_vals(): or x.dtype in _boolean_dtypes or y.dtype in _boolean_dtypes ): - assert_raises(TypeError, lambda: x.__matmul__(y)) - assert_raises(TypeError, lambda: y.__rmatmul__(x)) - assert_raises(TypeError, lambda: x.__imatmul__(y)) + with assert_raises(TypeError): + x.__matmul__(y) + with assert_raises(TypeError): + y.__rmatmul__(x) + with assert_raises(TypeError): + x.__imatmul__(y) elif x.shape == () or y.shape == () or x.shape[1] != y.shape[0]: - assert_raises(ValueError, lambda: x.__matmul__(y)) - assert_raises(ValueError, lambda: y.__rmatmul__(x)) + with assert_raises(ValueError): + x.__matmul__(y) + with assert_raises(ValueError): + y.__rmatmul__(x) if result_type(x.dtype, y.dtype) != x.dtype: - assert_raises(TypeError, lambda: x.__imatmul__(y)) + with assert_raises(TypeError): + x.__imatmul__(y) else: - assert_raises(ValueError, lambda: x.__imatmul__(y)) + with assert_raises(ValueError): + x.__imatmul__(y) else: x.__matmul__(y) y.__rmatmul__(x) if result_type(x.dtype, y.dtype) != x.dtype: - assert_raises(TypeError, lambda: x.__imatmul__(y)) + with assert_raises(TypeError): + x.__imatmul__(y) elif y.shape[0] != y.shape[1]: # This one fails because x @ y has a different shape from x - assert_raises(ValueError, lambda: x.__imatmul__(y)) + with assert_raises(ValueError): + x.__imatmul__(y) else: x.__imatmul__(y) diff --git a/array_api_strict/tests/test_creation_functions.py b/array_api_strict/tests/test_creation_functions.py index 2ea4445..acee119 100644 --- a/array_api_strict/tests/test_creation_functions.py +++ b/array_api_strict/tests/test_creation_functions.py @@ -78,7 +78,8 @@ def test_asarray_copy(): for obj in [True, 0, 0.0, 0j, [0], [[0]]]: asarray(obj, copy=True) # No error asarray(obj, copy=None) # No error - assert_raises(ValueError, lambda: asarray(obj, copy=False)) + with assert_raises(ValueError): + asarray(obj, copy=False) # Buffer protocol a = np.array([1]) @@ -226,11 +227,11 @@ def test_meshgrid_dtype_errors(): def _full(a, *args, **kwds): - return full(a, fill_value=42.0, *args, **kwds) + return full(a, *args, fill_value=42.0, **kwds) def _full_like(a, *args, **kwds): - return full_like(a, fill_value=42.0, *args, **kwds) + return full_like(a, *args, fill_value=42.0, **kwds) class TestDefaultDType: diff --git a/array_api_strict/tests/test_flags.py b/array_api_strict/tests/test_flags.py index b834db4..eb0dd6a 100644 --- a/array_api_strict/tests/test_flags.py +++ b/array_api_strict/tests/test_flags.py @@ -434,20 +434,20 @@ def test_disabled_extensions(): assert 'linalg' in xp.__all__ assert 'fft' in xp.__all__ - xp.linalg # No error - xp.fft # No error + xp.linalg # No error # noqa: B018 + xp.fft # No error # noqa: B018 ns = {} - exec('from array_api_strict import *', ns) + exec('from array_api_strict import *', ns) # noqa: S102 assert 'linalg' in ns assert 'fft' in ns set_array_api_strict_flags(enabled_extensions=('linalg',)) assert 'linalg' in xp.__all__ assert 'fft' not in xp.__all__ - xp.linalg # No error + xp.linalg # No error # noqa: B018 pytest.raises(AttributeError, lambda: xp.fft) ns = {} - exec('from array_api_strict import *', ns) + exec('from array_api_strict import *', ns) # noqa: S102 assert 'linalg' in ns assert 'fft' not in ns @@ -455,9 +455,9 @@ def test_disabled_extensions(): assert 'linalg' not in xp.__all__ assert 'fft' in xp.__all__ pytest.raises(AttributeError, lambda: xp.linalg) - xp.fft # No error + xp.fft # No error # noqa: B018 ns = {} - exec('from array_api_strict import *', ns) + exec('from array_api_strict import *', ns) # noqa: S102 assert 'linalg' not in ns assert 'fft' in ns @@ -467,17 +467,17 @@ def test_disabled_extensions(): pytest.raises(AttributeError, lambda: xp.linalg) pytest.raises(AttributeError, lambda: xp.fft) ns = {} - exec('from array_api_strict import *', ns) + exec('from array_api_strict import *', ns) # noqa: S102 assert 'linalg' not in ns assert 'fft' not in ns reset_array_api_strict_flags() assert 'linalg' in xp.__all__ assert 'fft' in xp.__all__ - xp.linalg # No error - xp.fft # No error + xp.linalg # No error # noqa: B018 + xp.fft # No error # noqa: B018 ns = {} - exec('from array_api_strict import *', ns) + exec('from array_api_strict import *', ns) # noqa: S102 assert 'linalg' in ns assert 'fft' in ns diff --git a/ruff.toml b/ruff.toml index 68780a5..af682d1 100644 --- a/ruff.toml +++ b/ruff.toml @@ -8,6 +8,8 @@ ignore = [ "SIM117", # Keep nested if statements "SIM102", + # Allow lambdas in loops + "B023", ] [lint.isort] combine-as-imports = true