From 6e57d829cb6628610e163524f203245b247a2839 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Wed, 4 Aug 2021 16:47:05 -0600 Subject: Rename numpy._array_api to numpy.array_api Instead of the leading underscore, the experimentalness of the module will be indicated by omitting a warning on import. That we, we do not have to change the API from underscore to no underscore when the module is no longer experimental. --- numpy/array_api/tests/__init__.py | 7 + numpy/array_api/tests/test_array_object.py | 250 +++++++++++++++++++++ numpy/array_api/tests/test_creation_functions.py | 103 +++++++++ .../array_api/tests/test_elementwise_functions.py | 110 +++++++++ 4 files changed, 470 insertions(+) create mode 100644 numpy/array_api/tests/__init__.py create mode 100644 numpy/array_api/tests/test_array_object.py create mode 100644 numpy/array_api/tests/test_creation_functions.py create mode 100644 numpy/array_api/tests/test_elementwise_functions.py (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/__init__.py b/numpy/array_api/tests/__init__.py new file mode 100644 index 000000000..536062e38 --- /dev/null +++ b/numpy/array_api/tests/__init__.py @@ -0,0 +1,7 @@ +""" +Tests for the array API namespace. + +Note, full compliance with the array API can be tested with the official array API test +suite https://github.com/data-apis/array-api-tests. This test suite primarily +focuses on those things that are not tested by the official test suite. +""" diff --git a/numpy/array_api/tests/test_array_object.py b/numpy/array_api/tests/test_array_object.py new file mode 100644 index 000000000..22078bbee --- /dev/null +++ b/numpy/array_api/tests/test_array_object.py @@ -0,0 +1,250 @@ +from numpy.testing import assert_raises +import numpy as np + +from .. import ones, asarray, result_type +from .._dtypes import (_all_dtypes, _boolean_dtypes, _floating_dtypes, + _integer_dtypes, _integer_or_boolean_dtypes, + _numeric_dtypes, int8, int16, int32, int64, uint64) + +def test_validate_index(): + # The indexing tests in the official array API test suite test that the + # array object correctly handles the subset of indices that are required + # by the spec. But the NumPy array API implementation specifically + # disallows any index not required by the spec, via Array._validate_index. + # This test focuses on testing that non-valid indices are correctly + # rejected. See + # https://data-apis.org/array-api/latest/API_specification/indexing.html + # and the docstring of Array._validate_index for the exact indexing + # behavior that should be allowed. This does not test indices that are + # already invalid in NumPy itself because Array will generally just pass + # such indices directly to the underlying np.ndarray. + + a = ones((3, 4)) + + # Out of bounds slices are not allowed + assert_raises(IndexError, lambda: a[:4]) + assert_raises(IndexError, lambda: a[:-4]) + assert_raises(IndexError, lambda: a[:3:-1]) + assert_raises(IndexError, lambda: a[:-5:-1]) + assert_raises(IndexError, lambda: a[3:]) + assert_raises(IndexError, lambda: a[-4:]) + assert_raises(IndexError, lambda: a[3::-1]) + assert_raises(IndexError, lambda: a[-4::-1]) + + assert_raises(IndexError, lambda: a[...,:5]) + assert_raises(IndexError, lambda: a[...,:-5]) + assert_raises(IndexError, lambda: a[...,:4:-1]) + assert_raises(IndexError, lambda: a[...,:-6:-1]) + assert_raises(IndexError, lambda: a[...,4:]) + assert_raises(IndexError, lambda: a[...,-5:]) + assert_raises(IndexError, lambda: a[...,4::-1]) + assert_raises(IndexError, lambda: a[...,-5::-1]) + + # Boolean indices cannot be part of a larger tuple index + assert_raises(IndexError, lambda: a[a[:,0]==1,0]) + assert_raises(IndexError, lambda: a[a[:,0]==1,...]) + assert_raises(IndexError, lambda: a[..., a[0]==1]) + assert_raises(IndexError, lambda: a[[True, True, True]]) + assert_raises(IndexError, lambda: a[(True, True, True),]) + + # Integer array indices are not allowed (except for 0-D) + idx = asarray([[0, 1]]) + assert_raises(IndexError, lambda: a[idx]) + assert_raises(IndexError, lambda: a[idx,]) + assert_raises(IndexError, lambda: a[[0, 1]]) + assert_raises(IndexError, lambda: a[(0, 1), (0, 1)]) + assert_raises(IndexError, lambda: a[[0, 1]]) + assert_raises(IndexError, lambda: a[np.array([[0, 1]])]) + + # np.newaxis is not allowed + assert_raises(IndexError, lambda: a[None]) + assert_raises(IndexError, lambda: a[None, ...]) + assert_raises(IndexError, lambda: a[..., None]) + +def test_operators(): + # For every operator, we test that it works for the required type + # combinations and raises TypeError otherwise + binary_op_dtypes ={ + '__add__': 'numeric', + '__and__': 'integer_or_boolean', + '__eq__': 'all', + '__floordiv__': 'numeric', + '__ge__': 'numeric', + '__gt__': 'numeric', + '__le__': 'numeric', + '__lshift__': 'integer', + '__lt__': 'numeric', + '__mod__': 'numeric', + '__mul__': 'numeric', + '__ne__': 'all', + '__or__': 'integer_or_boolean', + '__pow__': 'floating', + '__rshift__': 'integer', + '__sub__': 'numeric', + '__truediv__': 'floating', + '__xor__': 'integer_or_boolean', + } + + # Recompute each time because of in-place ops + def _array_vals(): + for d in _integer_dtypes: + yield asarray(1, dtype=d) + for d in _boolean_dtypes: + yield asarray(False, dtype=d) + for d in _floating_dtypes: + yield asarray(1., dtype=d) + + for op, dtypes in binary_op_dtypes.items(): + ops = [op] + if op not in ['__eq__', '__ne__', '__le__', '__ge__', '__lt__', '__gt__']: + rop = '__r' + op[2:] + iop = '__i' + op[2:] + ops += [rop, iop] + for s in [1, 1., False]: + for _op in ops: + for a in _array_vals(): + # Test array op scalar. From the spec, the following combinations + # are supported: + + # - Python bool for a bool array dtype, + # - a Python int within the bounds of the given dtype for integer array dtypes, + # - a Python int or float for floating-point array dtypes + + # We do not do bounds checking for int scalars, but rather use the default + # NumPy behavior for casting in that case. + + if ((dtypes == "all" + or dtypes == "numeric" and a.dtype in _numeric_dtypes + or dtypes == "integer" and a.dtype in _integer_dtypes + or dtypes == "integer_or_boolean" and a.dtype in _integer_or_boolean_dtypes + or dtypes == "boolean" and a.dtype in _boolean_dtypes + or dtypes == "floating" and a.dtype in _floating_dtypes + ) + # bool is a subtype of int, which is why we avoid + # isinstance here. + and (a.dtype in _boolean_dtypes and type(s) == bool + or a.dtype in _integer_dtypes and type(s) == int + or a.dtype in _floating_dtypes and type(s) in [float, int] + )): + # Only test for no error + getattr(a, _op)(s) + else: + assert_raises(TypeError, lambda: getattr(a, _op)(s)) + + # Test array op array. + for _op in ops: + for x in _array_vals(): + for y in _array_vals(): + # See the promotion table in NEP 47 or the array + # API spec page on type promotion. Mixed kind + # promotion is not defined. + if (x.dtype == uint64 and y.dtype in [int8, int16, int32, int64] + or y.dtype == uint64 and x.dtype in [int8, int16, int32, int64] + or x.dtype in _integer_dtypes and y.dtype not in _integer_dtypes + or y.dtype in _integer_dtypes and x.dtype not in _integer_dtypes + or x.dtype in _boolean_dtypes and y.dtype not in _boolean_dtypes + or y.dtype in _boolean_dtypes and x.dtype not in _boolean_dtypes + or x.dtype in _floating_dtypes and y.dtype not in _floating_dtypes + or y.dtype in _floating_dtypes and x.dtype not in _floating_dtypes + ): + assert_raises(TypeError, lambda: getattr(x, _op)(y)) + # Ensure in-place operators only promote to the same dtype as the left operand. + elif _op.startswith('__i') and result_type(x.dtype, y.dtype) != x.dtype: + assert_raises(TypeError, lambda: 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) + or (dtypes == "numeric" and x.dtype in _numeric_dtypes and y.dtype in _numeric_dtypes) + or dtypes == "integer" and x.dtype in _integer_dtypes and y.dtype in _numeric_dtypes + or dtypes == "integer_or_boolean" and (x.dtype in _integer_dtypes and y.dtype in _integer_dtypes + or x.dtype in _boolean_dtypes and y.dtype in _boolean_dtypes) + or dtypes == "boolean" and x.dtype in _boolean_dtypes and y.dtype in _boolean_dtypes + or dtypes == "floating" and x.dtype in _floating_dtypes and y.dtype in _floating_dtypes + ): + getattr(x, _op)(y) + else: + assert_raises(TypeError, lambda: getattr(x, _op)(y)) + + unary_op_dtypes ={ + '__abs__': 'numeric', + '__invert__': 'integer_or_boolean', + '__neg__': 'numeric', + '__pos__': 'numeric', + } + for op, dtypes in unary_op_dtypes.items(): + for a in _array_vals(): + if (dtypes == "numeric" and a.dtype in _numeric_dtypes + or dtypes == "integer_or_boolean" and a.dtype in _integer_or_boolean_dtypes + ): + # Only test for no error + getattr(a, op)() + else: + assert_raises(TypeError, lambda: getattr(a, op)()) + + # Finally, matmul() must be tested separately, because it works a bit + # different from the other operations. + def _matmul_array_vals(): + for a in _array_vals(): + yield a + for d in _all_dtypes: + yield ones((3, 4), dtype=d) + yield ones((4, 2), dtype=d) + yield ones((4, 4), dtype=d) + + # Scalars always error + for _op in ['__matmul__', '__rmatmul__', '__imatmul__']: + for s in [1, 1., False]: + for a in _matmul_array_vals(): + if (type(s) in [float, int] and a.dtype in _floating_dtypes + 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)) + else: + assert_raises(TypeError, lambda: getattr(a, _op)(s)) + + for x in _matmul_array_vals(): + for y in _matmul_array_vals(): + if (x.dtype == uint64 and y.dtype in [int8, int16, int32, int64] + or y.dtype == uint64 and x.dtype in [int8, int16, int32, int64] + or x.dtype in _integer_dtypes and y.dtype not in _integer_dtypes + or y.dtype in _integer_dtypes and x.dtype not in _integer_dtypes + or x.dtype in _floating_dtypes and y.dtype not in _floating_dtypes + or y.dtype in _floating_dtypes and x.dtype not in _floating_dtypes + 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)) + 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)) + if result_type(x.dtype, y.dtype) != x.dtype: + assert_raises(TypeError, lambda: x.__imatmul__(y)) + else: + assert_raises(ValueError, lambda: 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)) + 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)) + else: + x.__imatmul__(y) + +def test_python_scalar_construtors(): + a = asarray(False) + b = asarray(0) + c = asarray(0.) + + assert bool(a) == bool(b) == bool(c) == False + assert int(a) == int(b) == int(c) == 0 + assert float(a) == float(b) == float(c) == 0. + + # bool/int/float should only be allowed on 0-D arrays. + assert_raises(TypeError, lambda: bool(asarray([False]))) + assert_raises(TypeError, lambda: int(asarray([0]))) + assert_raises(TypeError, lambda: float(asarray([0.]))) diff --git a/numpy/array_api/tests/test_creation_functions.py b/numpy/array_api/tests/test_creation_functions.py new file mode 100644 index 000000000..654f1d9b3 --- /dev/null +++ b/numpy/array_api/tests/test_creation_functions.py @@ -0,0 +1,103 @@ +from numpy.testing import assert_raises +import numpy as np + +from .. import all +from .._creation_functions import (asarray, arange, empty, empty_like, eye, from_dlpack, full, full_like, linspace, meshgrid, ones, ones_like, zeros, zeros_like) +from .._array_object import Array +from .._dtypes import (_all_dtypes, _boolean_dtypes, _floating_dtypes, + _integer_dtypes, _integer_or_boolean_dtypes, + _numeric_dtypes, int8, int16, int32, int64, uint64) + +def test_asarray_errors(): + # Test various protections against incorrect usage + assert_raises(TypeError, lambda: Array([1])) + assert_raises(TypeError, lambda: asarray(['a'])) + assert_raises(ValueError, lambda: asarray([1.], dtype=np.float16)) + assert_raises(OverflowError, lambda: asarray(2**100)) + # Preferably this would be OverflowError + # assert_raises(OverflowError, lambda: asarray([2**100])) + assert_raises(TypeError, lambda: asarray([2**100])) + asarray([1], device='cpu') # Doesn't error + assert_raises(ValueError, lambda: asarray([1], device='gpu')) + + assert_raises(ValueError, lambda: asarray([1], dtype=int)) + assert_raises(ValueError, lambda: asarray([1], dtype='i')) + +def test_asarray_copy(): + a = asarray([1]) + b = asarray(a, copy=True) + a[0] = 0 + assert all(b[0] == 1) + assert all(a[0] == 0) + # Once copy=False is implemented, replace this with + # a = asarray([1]) + # b = asarray(a, copy=False) + # a[0] = 0 + # assert all(b[0] == 0) + assert_raises(NotImplementedError, lambda: asarray(a, copy=False)) + +def test_arange_errors(): + arange(1, device='cpu') # Doesn't error + assert_raises(ValueError, lambda: arange(1, device='gpu')) + assert_raises(ValueError, lambda: arange(1, dtype=int)) + assert_raises(ValueError, lambda: arange(1, dtype='i')) + +def test_empty_errors(): + empty((1,), device='cpu') # Doesn't error + assert_raises(ValueError, lambda: empty((1,), device='gpu')) + assert_raises(ValueError, lambda: empty((1,), dtype=int)) + assert_raises(ValueError, lambda: empty((1,), dtype='i')) + +def test_empty_like_errors(): + empty_like(asarray(1), device='cpu') # Doesn't error + assert_raises(ValueError, lambda: empty_like(asarray(1), device='gpu')) + assert_raises(ValueError, lambda: empty_like(asarray(1), dtype=int)) + assert_raises(ValueError, lambda: empty_like(asarray(1), dtype='i')) + +def test_eye_errors(): + eye(1, device='cpu') # Doesn't error + assert_raises(ValueError, lambda: eye(1, device='gpu')) + assert_raises(ValueError, lambda: eye(1, dtype=int)) + assert_raises(ValueError, lambda: eye(1, dtype='i')) + +def test_full_errors(): + full((1,), 0, device='cpu') # Doesn't error + assert_raises(ValueError, lambda: full((1,), 0, device='gpu')) + assert_raises(ValueError, lambda: full((1,), 0, dtype=int)) + assert_raises(ValueError, lambda: full((1,), 0, dtype='i')) + +def test_full_like_errors(): + full_like(asarray(1), 0, device='cpu') # Doesn't error + assert_raises(ValueError, lambda: full_like(asarray(1), 0, device='gpu')) + assert_raises(ValueError, lambda: full_like(asarray(1), 0, dtype=int)) + assert_raises(ValueError, lambda: full_like(asarray(1), 0, dtype='i')) + +def test_linspace_errors(): + linspace(0, 1, 10, device='cpu') # Doesn't error + assert_raises(ValueError, lambda: linspace(0, 1, 10, device='gpu')) + assert_raises(ValueError, lambda: linspace(0, 1, 10, dtype=float)) + assert_raises(ValueError, lambda: linspace(0, 1, 10, dtype='f')) + +def test_ones_errors(): + ones((1,), device='cpu') # Doesn't error + assert_raises(ValueError, lambda: ones((1,), device='gpu')) + assert_raises(ValueError, lambda: ones((1,), dtype=int)) + assert_raises(ValueError, lambda: ones((1,), dtype='i')) + +def test_ones_like_errors(): + ones_like(asarray(1), device='cpu') # Doesn't error + assert_raises(ValueError, lambda: ones_like(asarray(1), device='gpu')) + assert_raises(ValueError, lambda: ones_like(asarray(1), dtype=int)) + assert_raises(ValueError, lambda: ones_like(asarray(1), dtype='i')) + +def test_zeros_errors(): + zeros((1,), device='cpu') # Doesn't error + assert_raises(ValueError, lambda: zeros((1,), device='gpu')) + assert_raises(ValueError, lambda: zeros((1,), dtype=int)) + assert_raises(ValueError, lambda: zeros((1,), dtype='i')) + +def test_zeros_like_errors(): + zeros_like(asarray(1), device='cpu') # Doesn't error + assert_raises(ValueError, lambda: zeros_like(asarray(1), device='gpu')) + assert_raises(ValueError, lambda: zeros_like(asarray(1), dtype=int)) + assert_raises(ValueError, lambda: zeros_like(asarray(1), dtype='i')) diff --git a/numpy/array_api/tests/test_elementwise_functions.py b/numpy/array_api/tests/test_elementwise_functions.py new file mode 100644 index 000000000..994cb0bf0 --- /dev/null +++ b/numpy/array_api/tests/test_elementwise_functions.py @@ -0,0 +1,110 @@ +from inspect import getfullargspec + +from numpy.testing import assert_raises + +from .. import asarray, _elementwise_functions +from .._elementwise_functions import bitwise_left_shift, bitwise_right_shift +from .._dtypes import (_all_dtypes, _boolean_dtypes, _floating_dtypes, + _integer_dtypes, _integer_or_boolean_dtypes, + _numeric_dtypes) + +def nargs(func): + return len(getfullargspec(func).args) + +def test_function_types(): + # Test that every function accepts only the required input types. We only + # test the negative cases here (error). The positive cases are tested in + # the array API test suite. + + elementwise_function_input_types = { + 'abs': 'numeric', + 'acos': 'floating', + 'acosh': 'floating', + 'add': 'numeric', + 'asin': 'floating', + 'asinh': 'floating', + 'atan': 'floating', + 'atan2': 'floating', + 'atanh': 'floating', + 'bitwise_and': 'integer_or_boolean', + 'bitwise_invert': 'integer_or_boolean', + 'bitwise_left_shift': 'integer', + 'bitwise_or': 'integer_or_boolean', + 'bitwise_right_shift': 'integer', + 'bitwise_xor': 'integer_or_boolean', + 'ceil': 'numeric', + 'cos': 'floating', + 'cosh': 'floating', + 'divide': 'floating', + 'equal': 'all', + 'exp': 'floating', + 'expm1': 'floating', + 'floor': 'numeric', + 'floor_divide': 'numeric', + 'greater': 'numeric', + 'greater_equal': 'numeric', + 'isfinite': 'numeric', + 'isinf': 'numeric', + 'isnan': 'numeric', + 'less': 'numeric', + 'less_equal': 'numeric', + 'log': 'floating', + 'logaddexp': 'floating', + 'log10': 'floating', + 'log1p': 'floating', + 'log2': 'floating', + 'logical_and': 'boolean', + 'logical_not': 'boolean', + 'logical_or': 'boolean', + 'logical_xor': 'boolean', + 'multiply': 'numeric', + 'negative': 'numeric', + 'not_equal': 'all', + 'positive': 'numeric', + 'pow': 'floating', + 'remainder': 'numeric', + 'round': 'numeric', + 'sign': 'numeric', + 'sin': 'floating', + 'sinh': 'floating', + 'sqrt': 'floating', + 'square': 'numeric', + 'subtract': 'numeric', + 'tan': 'floating', + 'tanh': 'floating', + 'trunc': 'numeric', + } + + _dtypes = { + 'all': _all_dtypes, + 'numeric': _numeric_dtypes, + 'integer': _integer_dtypes, + 'integer_or_boolean': _integer_or_boolean_dtypes, + 'boolean': _boolean_dtypes, + 'floating': _floating_dtypes, + } + + def _array_vals(): + for d in _integer_dtypes: + yield asarray(1, dtype=d) + for d in _boolean_dtypes: + yield asarray(False, dtype=d) + for d in _floating_dtypes: + yield asarray(1., dtype=d) + + for x in _array_vals(): + for func_name, types in elementwise_function_input_types.items(): + dtypes = _dtypes[types] + func = getattr(_elementwise_functions, func_name) + if nargs(func) == 2: + for y in _array_vals(): + if x.dtype not in dtypes or y.dtype not in dtypes: + assert_raises(TypeError, lambda: func(x, y)) + else: + if x.dtype not in dtypes: + assert_raises(TypeError, lambda: func(x)) + +def test_bitwise_shift_error(): + # bitwise shift functions should raise when the second argument is negative + assert_raises(ValueError, lambda: bitwise_left_shift(asarray([1, 1]), asarray([1, -1]))) + assert_raises(ValueError, lambda: bitwise_right_shift(asarray([1, 1]), asarray([1, -1]))) -- cgit v1.2.1 From bc20d334b575f897157b1cf3eecda77f3e40e049 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Wed, 4 Aug 2021 20:01:11 -0600 Subject: Move the array API dtype categories into the top level They are not an official part of the spec but are useful for various parts of the implementation. --- numpy/array_api/tests/test_elementwise_functions.py | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_elementwise_functions.py b/numpy/array_api/tests/test_elementwise_functions.py index 994cb0bf0..2a5ddbc87 100644 --- a/numpy/array_api/tests/test_elementwise_functions.py +++ b/numpy/array_api/tests/test_elementwise_functions.py @@ -4,9 +4,8 @@ from numpy.testing import assert_raises from .. import asarray, _elementwise_functions from .._elementwise_functions import bitwise_left_shift, bitwise_right_shift -from .._dtypes import (_all_dtypes, _boolean_dtypes, _floating_dtypes, - _integer_dtypes, _integer_or_boolean_dtypes, - _numeric_dtypes) +from .._dtypes import (_dtype_categories, _boolean_dtypes, _floating_dtypes, + _integer_dtypes) def nargs(func): return len(getfullargspec(func).args) @@ -75,15 +74,6 @@ def test_function_types(): 'trunc': 'numeric', } - _dtypes = { - 'all': _all_dtypes, - 'numeric': _numeric_dtypes, - 'integer': _integer_dtypes, - 'integer_or_boolean': _integer_or_boolean_dtypes, - 'boolean': _boolean_dtypes, - 'floating': _floating_dtypes, - } - def _array_vals(): for d in _integer_dtypes: yield asarray(1, dtype=d) @@ -94,7 +84,7 @@ def test_function_types(): for x in _array_vals(): for func_name, types in elementwise_function_input_types.items(): - dtypes = _dtypes[types] + dtypes = _dtype_categories[types] func = getattr(_elementwise_functions, func_name) if nargs(func) == 2: for y in _array_vals(): -- cgit v1.2.1 From fcdadee7815cbb72a1036c0ef144d73e916eae6d Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Fri, 6 Aug 2021 16:09:23 -0600 Subject: Fix some dictionary key mismatches in the array API tests --- .../array_api/tests/test_elementwise_functions.py | 54 +++++++++++----------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_elementwise_functions.py b/numpy/array_api/tests/test_elementwise_functions.py index 2a5ddbc87..ec76cb7a7 100644 --- a/numpy/array_api/tests/test_elementwise_functions.py +++ b/numpy/array_api/tests/test_elementwise_functions.py @@ -17,27 +17,27 @@ def test_function_types(): elementwise_function_input_types = { 'abs': 'numeric', - 'acos': 'floating', - 'acosh': 'floating', + 'acos': 'floating-point', + 'acosh': 'floating-point', 'add': 'numeric', - 'asin': 'floating', - 'asinh': 'floating', - 'atan': 'floating', - 'atan2': 'floating', - 'atanh': 'floating', - 'bitwise_and': 'integer_or_boolean', - 'bitwise_invert': 'integer_or_boolean', + 'asin': 'floating-point', + 'asinh': 'floating-point', + 'atan': 'floating-point', + 'atan2': 'floating-point', + 'atanh': 'floating-point', + 'bitwise_and': 'integer or boolean', + 'bitwise_invert': 'integer or boolean', 'bitwise_left_shift': 'integer', - 'bitwise_or': 'integer_or_boolean', + 'bitwise_or': 'integer or boolean', 'bitwise_right_shift': 'integer', - 'bitwise_xor': 'integer_or_boolean', + 'bitwise_xor': 'integer or boolean', 'ceil': 'numeric', - 'cos': 'floating', - 'cosh': 'floating', - 'divide': 'floating', + 'cos': 'floating-point', + 'cosh': 'floating-point', + 'divide': 'floating-point', 'equal': 'all', - 'exp': 'floating', - 'expm1': 'floating', + 'exp': 'floating-point', + 'expm1': 'floating-point', 'floor': 'numeric', 'floor_divide': 'numeric', 'greater': 'numeric', @@ -47,11 +47,11 @@ def test_function_types(): 'isnan': 'numeric', 'less': 'numeric', 'less_equal': 'numeric', - 'log': 'floating', - 'logaddexp': 'floating', - 'log10': 'floating', - 'log1p': 'floating', - 'log2': 'floating', + 'log': 'floating-point', + 'logaddexp': 'floating-point', + 'log10': 'floating-point', + 'log1p': 'floating-point', + 'log2': 'floating-point', 'logical_and': 'boolean', 'logical_not': 'boolean', 'logical_or': 'boolean', @@ -60,17 +60,17 @@ def test_function_types(): 'negative': 'numeric', 'not_equal': 'all', 'positive': 'numeric', - 'pow': 'floating', + 'pow': 'floating-point', 'remainder': 'numeric', 'round': 'numeric', 'sign': 'numeric', - 'sin': 'floating', - 'sinh': 'floating', - 'sqrt': 'floating', + 'sin': 'floating-point', + 'sinh': 'floating-point', + 'sqrt': 'floating-point', 'square': 'numeric', 'subtract': 'numeric', - 'tan': 'floating', - 'tanh': 'floating', + 'tan': 'floating-point', + 'tanh': 'floating-point', 'trunc': 'numeric', } -- cgit v1.2.1 From 8f7d00ed447174d9398af3365709222b529c1cad Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Fri, 6 Aug 2021 18:22:00 -0600 Subject: Run (selective) black on the array_api submodule I've omitted a few changes from black that messed up the readability of some complicated if statements that were organized logically line-by-line, and some changes that use unnecessary operator spacing. --- numpy/array_api/tests/test_array_object.py | 101 +++++++++------- numpy/array_api/tests/test_creation_functions.py | 122 ++++++++++++------- .../array_api/tests/test_elementwise_functions.py | 133 +++++++++++---------- 3 files changed, 212 insertions(+), 144 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_array_object.py b/numpy/array_api/tests/test_array_object.py index 22078bbee..088e09b9f 100644 --- a/numpy/array_api/tests/test_array_object.py +++ b/numpy/array_api/tests/test_array_object.py @@ -2,9 +2,20 @@ from numpy.testing import assert_raises import numpy as np from .. import ones, asarray, result_type -from .._dtypes import (_all_dtypes, _boolean_dtypes, _floating_dtypes, - _integer_dtypes, _integer_or_boolean_dtypes, - _numeric_dtypes, int8, int16, int32, int64, uint64) +from .._dtypes import ( + _all_dtypes, + _boolean_dtypes, + _floating_dtypes, + _integer_dtypes, + _integer_or_boolean_dtypes, + _numeric_dtypes, + int8, + int16, + int32, + int64, + uint64, +) + def test_validate_index(): # The indexing tests in the official array API test suite test that the @@ -61,28 +72,29 @@ def test_validate_index(): assert_raises(IndexError, lambda: a[None, ...]) assert_raises(IndexError, lambda: a[..., None]) + def test_operators(): # For every operator, we test that it works for the required type # combinations and raises TypeError otherwise - binary_op_dtypes ={ - '__add__': 'numeric', - '__and__': 'integer_or_boolean', - '__eq__': 'all', - '__floordiv__': 'numeric', - '__ge__': 'numeric', - '__gt__': 'numeric', - '__le__': 'numeric', - '__lshift__': 'integer', - '__lt__': 'numeric', - '__mod__': 'numeric', - '__mul__': 'numeric', - '__ne__': 'all', - '__or__': 'integer_or_boolean', - '__pow__': 'floating', - '__rshift__': 'integer', - '__sub__': 'numeric', - '__truediv__': 'floating', - '__xor__': 'integer_or_boolean', + binary_op_dtypes = { + "__add__": "numeric", + "__and__": "integer_or_boolean", + "__eq__": "all", + "__floordiv__": "numeric", + "__ge__": "numeric", + "__gt__": "numeric", + "__le__": "numeric", + "__lshift__": "integer", + "__lt__": "numeric", + "__mod__": "numeric", + "__mul__": "numeric", + "__ne__": "all", + "__or__": "integer_or_boolean", + "__pow__": "floating", + "__rshift__": "integer", + "__sub__": "numeric", + "__truediv__": "floating", + "__xor__": "integer_or_boolean", } # Recompute each time because of in-place ops @@ -92,15 +104,15 @@ def test_operators(): for d in _boolean_dtypes: yield asarray(False, dtype=d) for d in _floating_dtypes: - yield asarray(1., dtype=d) + yield asarray(1.0, dtype=d) for op, dtypes in binary_op_dtypes.items(): ops = [op] - if op not in ['__eq__', '__ne__', '__le__', '__ge__', '__lt__', '__gt__']: - rop = '__r' + op[2:] - iop = '__i' + op[2:] + if op not in ["__eq__", "__ne__", "__le__", "__ge__", "__lt__", "__gt__"]: + rop = "__r" + op[2:] + iop = "__i" + op[2:] ops += [rop, iop] - for s in [1, 1., False]: + for s in [1, 1.0, False]: for _op in ops: for a in _array_vals(): # Test array op scalar. From the spec, the following combinations @@ -149,7 +161,10 @@ def test_operators(): ): assert_raises(TypeError, lambda: getattr(x, _op)(y)) # Ensure in-place operators only promote to the same dtype as the left operand. - elif _op.startswith('__i') and result_type(x.dtype, y.dtype) != x.dtype: + elif ( + _op.startswith("__i") + and result_type(x.dtype, y.dtype) != x.dtype + ): assert_raises(TypeError, lambda: 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 @@ -165,17 +180,20 @@ def test_operators(): else: assert_raises(TypeError, lambda: getattr(x, _op)(y)) - unary_op_dtypes ={ - '__abs__': 'numeric', - '__invert__': 'integer_or_boolean', - '__neg__': 'numeric', - '__pos__': 'numeric', + unary_op_dtypes = { + "__abs__": "numeric", + "__invert__": "integer_or_boolean", + "__neg__": "numeric", + "__pos__": "numeric", } for op, dtypes in unary_op_dtypes.items(): for a in _array_vals(): - if (dtypes == "numeric" and a.dtype in _numeric_dtypes - or dtypes == "integer_or_boolean" and a.dtype in _integer_or_boolean_dtypes - ): + if ( + dtypes == "numeric" + and a.dtype in _numeric_dtypes + or dtypes == "integer_or_boolean" + and a.dtype in _integer_or_boolean_dtypes + ): # Only test for no error getattr(a, op)() else: @@ -192,8 +210,8 @@ def test_operators(): yield ones((4, 4), dtype=d) # Scalars always error - for _op in ['__matmul__', '__rmatmul__', '__imatmul__']: - for s in [1, 1., False]: + for _op in ["__matmul__", "__rmatmul__", "__imatmul__"]: + for s in [1, 1.0, False]: for a in _matmul_array_vals(): if (type(s) in [float, int] and a.dtype in _floating_dtypes or type(s) == int and a.dtype in _integer_dtypes): @@ -235,16 +253,17 @@ def test_operators(): else: x.__imatmul__(y) + def test_python_scalar_construtors(): a = asarray(False) b = asarray(0) - c = asarray(0.) + c = asarray(0.0) assert bool(a) == bool(b) == bool(c) == False assert int(a) == int(b) == int(c) == 0 - assert float(a) == float(b) == float(c) == 0. + assert float(a) == float(b) == float(c) == 0.0 # bool/int/float should only be allowed on 0-D arrays. assert_raises(TypeError, lambda: bool(asarray([False]))) assert_raises(TypeError, lambda: int(asarray([0]))) - assert_raises(TypeError, lambda: float(asarray([0.]))) + assert_raises(TypeError, lambda: float(asarray([0.0]))) diff --git a/numpy/array_api/tests/test_creation_functions.py b/numpy/array_api/tests/test_creation_functions.py index 654f1d9b3..3cb8865cd 100644 --- a/numpy/array_api/tests/test_creation_functions.py +++ b/numpy/array_api/tests/test_creation_functions.py @@ -2,26 +2,53 @@ from numpy.testing import assert_raises import numpy as np from .. import all -from .._creation_functions import (asarray, arange, empty, empty_like, eye, from_dlpack, full, full_like, linspace, meshgrid, ones, ones_like, zeros, zeros_like) +from .._creation_functions import ( + asarray, + arange, + empty, + empty_like, + eye, + from_dlpack, + full, + full_like, + linspace, + meshgrid, + ones, + ones_like, + zeros, + zeros_like, +) from .._array_object import Array -from .._dtypes import (_all_dtypes, _boolean_dtypes, _floating_dtypes, - _integer_dtypes, _integer_or_boolean_dtypes, - _numeric_dtypes, int8, int16, int32, int64, uint64) +from .._dtypes import ( + _all_dtypes, + _boolean_dtypes, + _floating_dtypes, + _integer_dtypes, + _integer_or_boolean_dtypes, + _numeric_dtypes, + int8, + int16, + int32, + int64, + uint64, +) + def test_asarray_errors(): # Test various protections against incorrect usage assert_raises(TypeError, lambda: Array([1])) - assert_raises(TypeError, lambda: asarray(['a'])) - assert_raises(ValueError, lambda: asarray([1.], dtype=np.float16)) + assert_raises(TypeError, lambda: asarray(["a"])) + assert_raises(ValueError, lambda: asarray([1.0], dtype=np.float16)) assert_raises(OverflowError, lambda: asarray(2**100)) # Preferably this would be OverflowError # assert_raises(OverflowError, lambda: asarray([2**100])) assert_raises(TypeError, lambda: asarray([2**100])) - asarray([1], device='cpu') # Doesn't error - assert_raises(ValueError, lambda: asarray([1], device='gpu')) + asarray([1], device="cpu") # Doesn't error + assert_raises(ValueError, lambda: asarray([1], device="gpu")) assert_raises(ValueError, lambda: asarray([1], dtype=int)) - assert_raises(ValueError, lambda: asarray([1], dtype='i')) + assert_raises(ValueError, lambda: asarray([1], dtype="i")) + def test_asarray_copy(): a = asarray([1]) @@ -36,68 +63,79 @@ def test_asarray_copy(): # assert all(b[0] == 0) assert_raises(NotImplementedError, lambda: asarray(a, copy=False)) + def test_arange_errors(): - arange(1, device='cpu') # Doesn't error - assert_raises(ValueError, lambda: arange(1, device='gpu')) + arange(1, device="cpu") # Doesn't error + assert_raises(ValueError, lambda: arange(1, device="gpu")) assert_raises(ValueError, lambda: arange(1, dtype=int)) - assert_raises(ValueError, lambda: arange(1, dtype='i')) + assert_raises(ValueError, lambda: arange(1, dtype="i")) + def test_empty_errors(): - empty((1,), device='cpu') # Doesn't error - assert_raises(ValueError, lambda: empty((1,), device='gpu')) + empty((1,), device="cpu") # Doesn't error + assert_raises(ValueError, lambda: empty((1,), device="gpu")) assert_raises(ValueError, lambda: empty((1,), dtype=int)) - assert_raises(ValueError, lambda: empty((1,), dtype='i')) + assert_raises(ValueError, lambda: empty((1,), dtype="i")) + def test_empty_like_errors(): - empty_like(asarray(1), device='cpu') # Doesn't error - assert_raises(ValueError, lambda: empty_like(asarray(1), device='gpu')) + empty_like(asarray(1), device="cpu") # Doesn't error + assert_raises(ValueError, lambda: empty_like(asarray(1), device="gpu")) assert_raises(ValueError, lambda: empty_like(asarray(1), dtype=int)) - assert_raises(ValueError, lambda: empty_like(asarray(1), dtype='i')) + assert_raises(ValueError, lambda: empty_like(asarray(1), dtype="i")) + def test_eye_errors(): - eye(1, device='cpu') # Doesn't error - assert_raises(ValueError, lambda: eye(1, device='gpu')) + eye(1, device="cpu") # Doesn't error + assert_raises(ValueError, lambda: eye(1, device="gpu")) assert_raises(ValueError, lambda: eye(1, dtype=int)) - assert_raises(ValueError, lambda: eye(1, dtype='i')) + assert_raises(ValueError, lambda: eye(1, dtype="i")) + def test_full_errors(): - full((1,), 0, device='cpu') # Doesn't error - assert_raises(ValueError, lambda: full((1,), 0, device='gpu')) + full((1,), 0, device="cpu") # Doesn't error + assert_raises(ValueError, lambda: full((1,), 0, device="gpu")) assert_raises(ValueError, lambda: full((1,), 0, dtype=int)) - assert_raises(ValueError, lambda: full((1,), 0, dtype='i')) + assert_raises(ValueError, lambda: full((1,), 0, dtype="i")) + def test_full_like_errors(): - full_like(asarray(1), 0, device='cpu') # Doesn't error - assert_raises(ValueError, lambda: full_like(asarray(1), 0, device='gpu')) + full_like(asarray(1), 0, device="cpu") # Doesn't error + assert_raises(ValueError, lambda: full_like(asarray(1), 0, device="gpu")) assert_raises(ValueError, lambda: full_like(asarray(1), 0, dtype=int)) - assert_raises(ValueError, lambda: full_like(asarray(1), 0, dtype='i')) + assert_raises(ValueError, lambda: full_like(asarray(1), 0, dtype="i")) + def test_linspace_errors(): - linspace(0, 1, 10, device='cpu') # Doesn't error - assert_raises(ValueError, lambda: linspace(0, 1, 10, device='gpu')) + linspace(0, 1, 10, device="cpu") # Doesn't error + assert_raises(ValueError, lambda: linspace(0, 1, 10, device="gpu")) assert_raises(ValueError, lambda: linspace(0, 1, 10, dtype=float)) - assert_raises(ValueError, lambda: linspace(0, 1, 10, dtype='f')) + assert_raises(ValueError, lambda: linspace(0, 1, 10, dtype="f")) + def test_ones_errors(): - ones((1,), device='cpu') # Doesn't error - assert_raises(ValueError, lambda: ones((1,), device='gpu')) + ones((1,), device="cpu") # Doesn't error + assert_raises(ValueError, lambda: ones((1,), device="gpu")) assert_raises(ValueError, lambda: ones((1,), dtype=int)) - assert_raises(ValueError, lambda: ones((1,), dtype='i')) + assert_raises(ValueError, lambda: ones((1,), dtype="i")) + def test_ones_like_errors(): - ones_like(asarray(1), device='cpu') # Doesn't error - assert_raises(ValueError, lambda: ones_like(asarray(1), device='gpu')) + ones_like(asarray(1), device="cpu") # Doesn't error + assert_raises(ValueError, lambda: ones_like(asarray(1), device="gpu")) assert_raises(ValueError, lambda: ones_like(asarray(1), dtype=int)) - assert_raises(ValueError, lambda: ones_like(asarray(1), dtype='i')) + assert_raises(ValueError, lambda: ones_like(asarray(1), dtype="i")) + def test_zeros_errors(): - zeros((1,), device='cpu') # Doesn't error - assert_raises(ValueError, lambda: zeros((1,), device='gpu')) + zeros((1,), device="cpu") # Doesn't error + assert_raises(ValueError, lambda: zeros((1,), device="gpu")) assert_raises(ValueError, lambda: zeros((1,), dtype=int)) - assert_raises(ValueError, lambda: zeros((1,), dtype='i')) + assert_raises(ValueError, lambda: zeros((1,), dtype="i")) + def test_zeros_like_errors(): - zeros_like(asarray(1), device='cpu') # Doesn't error - assert_raises(ValueError, lambda: zeros_like(asarray(1), device='gpu')) + zeros_like(asarray(1), device="cpu") # Doesn't error + assert_raises(ValueError, lambda: zeros_like(asarray(1), device="gpu")) assert_raises(ValueError, lambda: zeros_like(asarray(1), dtype=int)) - assert_raises(ValueError, lambda: zeros_like(asarray(1), dtype='i')) + assert_raises(ValueError, lambda: zeros_like(asarray(1), dtype="i")) diff --git a/numpy/array_api/tests/test_elementwise_functions.py b/numpy/array_api/tests/test_elementwise_functions.py index ec76cb7a7..a9274aec9 100644 --- a/numpy/array_api/tests/test_elementwise_functions.py +++ b/numpy/array_api/tests/test_elementwise_functions.py @@ -4,74 +4,80 @@ from numpy.testing import assert_raises from .. import asarray, _elementwise_functions from .._elementwise_functions import bitwise_left_shift, bitwise_right_shift -from .._dtypes import (_dtype_categories, _boolean_dtypes, _floating_dtypes, - _integer_dtypes) +from .._dtypes import ( + _dtype_categories, + _boolean_dtypes, + _floating_dtypes, + _integer_dtypes, +) + def nargs(func): return len(getfullargspec(func).args) + def test_function_types(): # Test that every function accepts only the required input types. We only # test the negative cases here (error). The positive cases are tested in # the array API test suite. elementwise_function_input_types = { - 'abs': 'numeric', - 'acos': 'floating-point', - 'acosh': 'floating-point', - 'add': 'numeric', - 'asin': 'floating-point', - 'asinh': 'floating-point', - 'atan': 'floating-point', - 'atan2': 'floating-point', - 'atanh': 'floating-point', - 'bitwise_and': 'integer or boolean', - 'bitwise_invert': 'integer or boolean', - 'bitwise_left_shift': 'integer', - 'bitwise_or': 'integer or boolean', - 'bitwise_right_shift': 'integer', - 'bitwise_xor': 'integer or boolean', - 'ceil': 'numeric', - 'cos': 'floating-point', - 'cosh': 'floating-point', - 'divide': 'floating-point', - 'equal': 'all', - 'exp': 'floating-point', - 'expm1': 'floating-point', - 'floor': 'numeric', - 'floor_divide': 'numeric', - 'greater': 'numeric', - 'greater_equal': 'numeric', - 'isfinite': 'numeric', - 'isinf': 'numeric', - 'isnan': 'numeric', - 'less': 'numeric', - 'less_equal': 'numeric', - 'log': 'floating-point', - 'logaddexp': 'floating-point', - 'log10': 'floating-point', - 'log1p': 'floating-point', - 'log2': 'floating-point', - 'logical_and': 'boolean', - 'logical_not': 'boolean', - 'logical_or': 'boolean', - 'logical_xor': 'boolean', - 'multiply': 'numeric', - 'negative': 'numeric', - 'not_equal': 'all', - 'positive': 'numeric', - 'pow': 'floating-point', - 'remainder': 'numeric', - 'round': 'numeric', - 'sign': 'numeric', - 'sin': 'floating-point', - 'sinh': 'floating-point', - 'sqrt': 'floating-point', - 'square': 'numeric', - 'subtract': 'numeric', - 'tan': 'floating-point', - 'tanh': 'floating-point', - 'trunc': 'numeric', + "abs": "numeric", + "acos": "floating-point", + "acosh": "floating-point", + "add": "numeric", + "asin": "floating-point", + "asinh": "floating-point", + "atan": "floating-point", + "atan2": "floating-point", + "atanh": "floating-point", + "bitwise_and": "integer or boolean", + "bitwise_invert": "integer or boolean", + "bitwise_left_shift": "integer", + "bitwise_or": "integer or boolean", + "bitwise_right_shift": "integer", + "bitwise_xor": "integer or boolean", + "ceil": "numeric", + "cos": "floating-point", + "cosh": "floating-point", + "divide": "floating-point", + "equal": "all", + "exp": "floating-point", + "expm1": "floating-point", + "floor": "numeric", + "floor_divide": "numeric", + "greater": "numeric", + "greater_equal": "numeric", + "isfinite": "numeric", + "isinf": "numeric", + "isnan": "numeric", + "less": "numeric", + "less_equal": "numeric", + "log": "floating-point", + "logaddexp": "floating-point", + "log10": "floating-point", + "log1p": "floating-point", + "log2": "floating-point", + "logical_and": "boolean", + "logical_not": "boolean", + "logical_or": "boolean", + "logical_xor": "boolean", + "multiply": "numeric", + "negative": "numeric", + "not_equal": "all", + "positive": "numeric", + "pow": "floating-point", + "remainder": "numeric", + "round": "numeric", + "sign": "numeric", + "sin": "floating-point", + "sinh": "floating-point", + "sqrt": "floating-point", + "square": "numeric", + "subtract": "numeric", + "tan": "floating-point", + "tanh": "floating-point", + "trunc": "numeric", } def _array_vals(): @@ -80,7 +86,7 @@ def test_function_types(): for d in _boolean_dtypes: yield asarray(False, dtype=d) for d in _floating_dtypes: - yield asarray(1., dtype=d) + yield asarray(1.0, dtype=d) for x in _array_vals(): for func_name, types in elementwise_function_input_types.items(): @@ -94,7 +100,12 @@ def test_function_types(): if x.dtype not in dtypes: assert_raises(TypeError, lambda: func(x)) + def test_bitwise_shift_error(): # bitwise shift functions should raise when the second argument is negative - assert_raises(ValueError, lambda: bitwise_left_shift(asarray([1, 1]), asarray([1, -1]))) - assert_raises(ValueError, lambda: bitwise_right_shift(asarray([1, 1]), asarray([1, -1]))) + assert_raises( + ValueError, lambda: bitwise_left_shift(asarray([1, 1]), asarray([1, -1])) + ) + assert_raises( + ValueError, lambda: bitwise_right_shift(asarray([1, 1]), asarray([1, -1])) + ) -- cgit v1.2.1 From 45dbdc9d8fd3fa7fbabbddf690f6c892cc24aa1d Mon Sep 17 00:00:00 2001 From: czgdp1807 Date: Fri, 3 Sep 2021 15:10:23 +0530 Subject: CopyMode added to np.array_api --- numpy/array_api/tests/test_creation_functions.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_creation_functions.py b/numpy/array_api/tests/test_creation_functions.py index 3cb8865cd..b0c99cd45 100644 --- a/numpy/array_api/tests/test_creation_functions.py +++ b/numpy/array_api/tests/test_creation_functions.py @@ -56,12 +56,17 @@ def test_asarray_copy(): a[0] = 0 assert all(b[0] == 1) assert all(a[0] == 0) - # Once copy=False is implemented, replace this with - # a = asarray([1]) - # b = asarray(a, copy=False) - # a[0] = 0 - # assert all(b[0] == 0) + a = asarray([1]) + b = asarray(a, copy=np._CopyMode.ALWAYS) + a[0] = 0 + assert all(b[0] == 1) + assert all(a[0] == 0) + a = asarray([1]) + b = asarray(a, copy=np._CopyMode.NEVER) + a[0] = 0 + assert all(b[0] == 0) assert_raises(NotImplementedError, lambda: asarray(a, copy=False)) + assert_raises(NotImplementedError, lambda: asarray(a, copy=np._CopyMode.NEVER)) def test_arange_errors(): -- cgit v1.2.1 From a39312cf4eca9dc9573737a01f16fee24efb6c0a Mon Sep 17 00:00:00 2001 From: czgdp1807 Date: Fri, 3 Sep 2021 15:15:18 +0530 Subject: fixed linting issues --- numpy/array_api/tests/test_creation_functions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_creation_functions.py b/numpy/array_api/tests/test_creation_functions.py index b0c99cd45..9d2909e91 100644 --- a/numpy/array_api/tests/test_creation_functions.py +++ b/numpy/array_api/tests/test_creation_functions.py @@ -66,7 +66,8 @@ def test_asarray_copy(): a[0] = 0 assert all(b[0] == 0) assert_raises(NotImplementedError, lambda: asarray(a, copy=False)) - assert_raises(NotImplementedError, lambda: asarray(a, copy=np._CopyMode.NEVER)) + assert_raises(NotImplementedError, lambda: asarray(a, + copy=np._CopyMode.NEVER)) def test_arange_errors(): -- cgit v1.2.1 From c2acd5b25a04783fbbe3ba32426039e4dbe9207e Mon Sep 17 00:00:00 2001 From: czgdp1807 Date: Fri, 3 Sep 2021 15:17:58 +0530 Subject: fixed linting issues --- numpy/array_api/tests/test_creation_functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_creation_functions.py b/numpy/array_api/tests/test_creation_functions.py index 9d2909e91..7182209dc 100644 --- a/numpy/array_api/tests/test_creation_functions.py +++ b/numpy/array_api/tests/test_creation_functions.py @@ -66,8 +66,8 @@ def test_asarray_copy(): a[0] = 0 assert all(b[0] == 0) assert_raises(NotImplementedError, lambda: asarray(a, copy=False)) - assert_raises(NotImplementedError, lambda: asarray(a, - copy=np._CopyMode.NEVER)) + assert_raises(NotImplementedError, + lambda: asarray(a, copy=np._CopyMode.NEVER)) def test_arange_errors(): -- cgit v1.2.1 From 56647dd47345a7fd24b4ee8d9d52025fcdc3b9ae Mon Sep 17 00:00:00 2001 From: czgdp1807 Date: Sat, 4 Sep 2021 22:33:52 +0530 Subject: Addressed reviews --- numpy/array_api/tests/test_creation_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_creation_functions.py b/numpy/array_api/tests/test_creation_functions.py index 7182209dc..2ee23a47b 100644 --- a/numpy/array_api/tests/test_creation_functions.py +++ b/numpy/array_api/tests/test_creation_functions.py @@ -67,7 +67,7 @@ def test_asarray_copy(): assert all(b[0] == 0) assert_raises(NotImplementedError, lambda: asarray(a, copy=False)) assert_raises(NotImplementedError, - lambda: asarray(a, copy=np._CopyMode.NEVER)) + lambda: asarray(a, copy=np._CopyMode.IF_NEEDED)) def test_arange_errors(): -- cgit v1.2.1 From 2d112a98ed7597c4120b31908384ae09b0304659 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Sat, 25 Sep 2021 17:34:22 -0500 Subject: ENH: Updates to numpy.array_api (#19937) * Add __index__ to array_api and update __int__, __bool__, and __float__ The spec specifies that they should only work on arrays with corresponding dtypes. __index__ is new in the spec since the initial PR, and works identically to np.array.__index__. * Add the to_device method to the array_api This method is new since #18585. It does nothing in NumPy since NumPy does not support non-CPU devices. * Update transpose methods in the array_api transpose() was renamed to matrix_transpose() and now operates on stacks of matrices. A function to permute dimensions will be added once it is finalized in the spec. The attribute mT was added and the T attribute was updated to only operate on 2-dimensional arrays as per the spec. * Restrict input dtypes in the array API statistical functions * Add the dtype parameter to the array API sum() and prod() * Add the function permute_dims() to the array_api namespace permute_dims() is the replacement for transpose(), which was split into permute_dims() and matrix_transpose(). * Add tril and triu to the array API namespace * Fix the array_api Array.__repr__ to indent the array properly * Make the Device type in the array_api just accept the string "cpu" --- numpy/array_api/tests/test_array_object.py | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_array_object.py b/numpy/array_api/tests/test_array_object.py index 088e09b9f..7959f92b4 100644 --- a/numpy/array_api/tests/test_array_object.py +++ b/numpy/array_api/tests/test_array_object.py @@ -1,3 +1,5 @@ +import operator + from numpy.testing import assert_raises import numpy as np @@ -255,15 +257,31 @@ def test_operators(): def test_python_scalar_construtors(): - a = asarray(False) - b = asarray(0) - c = asarray(0.0) + b = asarray(False) + i = asarray(0) + f = asarray(0.0) - assert bool(a) == bool(b) == bool(c) == False - assert int(a) == int(b) == int(c) == 0 - assert float(a) == float(b) == float(c) == 0.0 + assert bool(b) == False + assert int(i) == 0 + assert float(f) == 0.0 + assert operator.index(i) == 0 # bool/int/float should only be allowed on 0-D arrays. assert_raises(TypeError, lambda: bool(asarray([False]))) assert_raises(TypeError, lambda: int(asarray([0]))) assert_raises(TypeError, lambda: float(asarray([0.0]))) + assert_raises(TypeError, lambda: operator.index(asarray([0]))) + + # bool/int/float should only be allowed on arrays of the corresponding + # dtype + assert_raises(ValueError, lambda: bool(i)) + assert_raises(ValueError, lambda: bool(f)) + + assert_raises(ValueError, lambda: int(b)) + assert_raises(ValueError, lambda: int(f)) + + assert_raises(ValueError, lambda: float(b)) + assert_raises(ValueError, lambda: float(i)) + + assert_raises(TypeError, lambda: operator.index(b)) + assert_raises(TypeError, lambda: operator.index(f)) -- cgit v1.2.1 From 4d23ebeb068c8d6ba6edfc11d32ab2af8bb89c74 Mon Sep 17 00:00:00 2001 From: Alessia Marcolini <98marcolini@gmail.com> Date: Fri, 8 Oct 2021 09:49:11 +0000 Subject: MAINT: remove unused imports --- numpy/array_api/tests/test_creation_functions.py | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_creation_functions.py b/numpy/array_api/tests/test_creation_functions.py index 3cb8865cd..7b633eaf1 100644 --- a/numpy/array_api/tests/test_creation_functions.py +++ b/numpy/array_api/tests/test_creation_functions.py @@ -8,30 +8,15 @@ from .._creation_functions import ( empty, empty_like, eye, - from_dlpack, full, full_like, linspace, - meshgrid, ones, ones_like, zeros, zeros_like, ) from .._array_object import Array -from .._dtypes import ( - _all_dtypes, - _boolean_dtypes, - _floating_dtypes, - _integer_dtypes, - _integer_or_boolean_dtypes, - _numeric_dtypes, - int8, - int16, - int32, - int64, - uint64, -) def test_asarray_errors(): -- cgit v1.2.1 From bc087bb2b3104547b097e03e669fb5fa77b16f05 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Wed, 3 Nov 2021 11:09:28 +0000 Subject: TST: Add a test for device property in `array_api` namespace (#20271) --- numpy/array_api/tests/test_array_object.py | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_array_object.py b/numpy/array_api/tests/test_array_object.py index 7959f92b4..fb42cf621 100644 --- a/numpy/array_api/tests/test_array_object.py +++ b/numpy/array_api/tests/test_array_object.py @@ -285,3 +285,14 @@ def test_python_scalar_construtors(): assert_raises(TypeError, lambda: operator.index(b)) assert_raises(TypeError, lambda: operator.index(f)) + + +def test_device_property(): + a = ones((3, 4)) + assert a.device == 'cpu' + + assert np.array_equal(a.to_device('cpu'), a) + assert_raises(ValueError, lambda: a.to_device('gpu')) + + assert np.array_equal(asarray(a, device='cpu'), a) + assert_raises(ValueError, lambda: asarray(a, device='gpu')) -- cgit v1.2.1 From ff2e2a1e7eea29d925063b13922e096d14331222 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Fri, 12 Nov 2021 08:07:23 -0700 Subject: MAINT: A few updates to the array_api (#20066) * Allow casting in the array API asarray() * Restrict multidimensional indexing in the array API namespace The spec has recently been updated to only require multiaxis (i.e., tuple) indices in the case where every axis is indexed, meaning there are either as many indices as axes or the index has an ellipsis. * Fix type promotion for numpy.array_api.where where does value-based promotion for 0-dimensional arrays, so we use the same trick as in the Array operators to avoid this. * Print empty array_api arrays using empty() Printing behavior isn't required by the spec. This is just to make things easier to understand, especially with the array API test suite. * Fix an incorrect slice bounds guard in the array API * Disallow multiple different dtypes in the input to np.array_api.meshgrid * Remove DLPack support from numpy.array_api.asarray() from_dlpack() should be used to create arrays using DLPack. * Remove __len__ from the array API array object * Add astype() to numpy.array_api * Update the unique_* functions in numpy.array_api unique() in the array API was replaced with three separate functions, unique_all(), unique_inverse(), and unique_values(), in order to avoid polymorphic return types. Additionally, it should be noted that these functions to not currently conform to the spec with respect to NaN behavior. The spec requires multiple NaNs to be returned, but np.unique() returns a single NaN. Since this is currently an open issue in NumPy to possibly revert, I have not yet worked around this. See https://github.com/numpy/numpy/issues/20326. * Add the stream argument to the array API to_device method This does nothing in NumPy, and is just present so that the signature is valid according to the spec. * Use the NamedTuple classes for the type signatures * Add unique_counts to the array API namespace * Remove some unused imports * Update the array_api indexing restrictions The "multiaxis indexing must index every axis explicitly or use an ellipsis" was supposed to include any type of index, not just tuple indices. * Use a simpler type annotation for the array API to_device method * Fix a test failure in the array_api submodule The array_api cannot use the NumPy testing functions because array_api arrays do not mix with NumPy arrays, and also NumPy testing functions may use APIs that aren't supported in the array API. * Add dlpack support to the array_api submodule --- numpy/array_api/tests/test_array_object.py | 21 +++++++++++++-------- numpy/array_api/tests/test_creation_functions.py | 10 ++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_array_object.py b/numpy/array_api/tests/test_array_object.py index fb42cf621..12479d765 100644 --- a/numpy/array_api/tests/test_array_object.py +++ b/numpy/array_api/tests/test_array_object.py @@ -3,7 +3,7 @@ import operator from numpy.testing import assert_raises import numpy as np -from .. import ones, asarray, result_type +from .. import ones, asarray, result_type, all, equal from .._dtypes import ( _all_dtypes, _boolean_dtypes, @@ -39,18 +39,18 @@ def test_validate_index(): assert_raises(IndexError, lambda: a[:-4]) assert_raises(IndexError, lambda: a[:3:-1]) assert_raises(IndexError, lambda: a[:-5:-1]) - assert_raises(IndexError, lambda: a[3:]) + assert_raises(IndexError, lambda: a[4:]) assert_raises(IndexError, lambda: a[-4:]) - assert_raises(IndexError, lambda: a[3::-1]) + assert_raises(IndexError, lambda: a[4::-1]) assert_raises(IndexError, lambda: a[-4::-1]) assert_raises(IndexError, lambda: a[...,:5]) assert_raises(IndexError, lambda: a[...,:-5]) - assert_raises(IndexError, lambda: a[...,:4:-1]) + assert_raises(IndexError, lambda: a[...,:5:-1]) assert_raises(IndexError, lambda: a[...,:-6:-1]) - assert_raises(IndexError, lambda: a[...,4:]) + assert_raises(IndexError, lambda: a[...,5:]) assert_raises(IndexError, lambda: a[...,-5:]) - assert_raises(IndexError, lambda: a[...,4::-1]) + assert_raises(IndexError, lambda: a[...,5::-1]) assert_raises(IndexError, lambda: a[...,-5::-1]) # Boolean indices cannot be part of a larger tuple index @@ -74,6 +74,11 @@ def test_validate_index(): assert_raises(IndexError, lambda: a[None, ...]) assert_raises(IndexError, lambda: a[..., None]) + # Multiaxis indices must contain exactly as many indices as dimensions + assert_raises(IndexError, lambda: a[()]) + assert_raises(IndexError, lambda: a[0,]) + assert_raises(IndexError, lambda: a[0]) + assert_raises(IndexError, lambda: a[:]) def test_operators(): # For every operator, we test that it works for the required type @@ -291,8 +296,8 @@ def test_device_property(): a = ones((3, 4)) assert a.device == 'cpu' - assert np.array_equal(a.to_device('cpu'), a) + assert all(equal(a.to_device('cpu'), a)) assert_raises(ValueError, lambda: a.to_device('gpu')) - assert np.array_equal(asarray(a, device='cpu'), a) + assert all(equal(asarray(a, device='cpu'), a)) assert_raises(ValueError, lambda: asarray(a, device='gpu')) diff --git a/numpy/array_api/tests/test_creation_functions.py b/numpy/array_api/tests/test_creation_functions.py index 7b633eaf1..ebbb6aab3 100644 --- a/numpy/array_api/tests/test_creation_functions.py +++ b/numpy/array_api/tests/test_creation_functions.py @@ -11,11 +11,13 @@ from .._creation_functions import ( full, full_like, linspace, + meshgrid, ones, ones_like, zeros, zeros_like, ) +from .._dtypes import float32, float64 from .._array_object import Array @@ -124,3 +126,11 @@ def test_zeros_like_errors(): assert_raises(ValueError, lambda: zeros_like(asarray(1), device="gpu")) assert_raises(ValueError, lambda: zeros_like(asarray(1), dtype=int)) assert_raises(ValueError, lambda: zeros_like(asarray(1), dtype="i")) + +def test_meshgrid_dtype_errors(): + # Doesn't raise + meshgrid() + meshgrid(asarray([1.], dtype=float32)) + meshgrid(asarray([1.], dtype=float32), asarray([1.], dtype=float32)) + + assert_raises(ValueError, lambda: meshgrid(asarray([1.], dtype=float32), asarray([1.], dtype=float64))) -- cgit v1.2.1 From 18fe695dbc66df660039aca9f76a949de8b9348e Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Wed, 1 Dec 2021 17:02:43 -0700 Subject: Add tests for T and mT in array_api --- numpy/array_api/tests/test_array_object.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_array_object.py b/numpy/array_api/tests/test_array_object.py index 12479d765..deab50693 100644 --- a/numpy/array_api/tests/test_array_object.py +++ b/numpy/array_api/tests/test_array_object.py @@ -4,6 +4,7 @@ from numpy.testing import assert_raises import numpy as np from .. import ones, asarray, result_type, all, equal +from .._array_object import Array from .._dtypes import ( _all_dtypes, _boolean_dtypes, @@ -301,3 +302,16 @@ def test_device_property(): assert all(equal(asarray(a, device='cpu'), a)) assert_raises(ValueError, lambda: asarray(a, device='gpu')) + +def test_array_properties(): + a = ones((1, 2, 3)) + b = ones((2, 3)) + assert_raises(ValueError, lambda: a.T) + + assert isinstance(b.T, Array) + assert b.T.shape == (3, 2) + + assert isinstance(a.mT, Array) + assert a.mT.shape == (1, 3, 2) + assert isinstance(b.mT, Array) + assert b.mT.shape == (3, 2) -- cgit v1.2.1 From 74a3ee7a8b75bf6dc271c9a1a4b55d2ad9758420 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Mon, 6 Dec 2021 13:59:08 -0700 Subject: ENH: Add __array__ to the array_api Array object This is *NOT* part of the array API spec (so it should not be relied on for portable code). However, without this, np.asarray(np.array_api.Array) produces an object array instead of doing the conversion to a NumPy array as expected. This would work once np.asarray() implements dlpack support, but until then, it seems reasonable to make the conversion work. Note that the reverse, calling np.array_api.asarray(np.array), already works because np.array_api.asarray() is just a wrapper for np.asarray(). --- numpy/array_api/tests/test_array_object.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_array_object.py b/numpy/array_api/tests/test_array_object.py index deab50693..b980bacca 100644 --- a/numpy/array_api/tests/test_array_object.py +++ b/numpy/array_api/tests/test_array_object.py @@ -315,3 +315,10 @@ def test_array_properties(): assert a.mT.shape == (1, 3, 2) assert isinstance(b.mT, Array) assert b.mT.shape == (3, 2) + +def test___array__(): + a = ones((2, 3), dtype=int16) + assert np.asarray(a) is a._array + b = np.asarray(a, dtype=np.float64) + assert np.all(np.equal(b, np.ones((2, 3), dtype=np.float64))) + assert b.dtype == np.float64 -- cgit v1.2.1 From e3406ed3ef83f7de0f3419361e85bd8634d0fd2b Mon Sep 17 00:00:00 2001 From: Matthew Date: Fri, 7 Jan 2022 11:53:09 +0000 Subject: BUG: Allow integer inputs for pow-related functions in `array_api` Updates `xp.power()`, `x.__pow__()`, `x.__ipow()__` and `x.__rpow()__` --- numpy/array_api/tests/test_array_object.py | 2 +- numpy/array_api/tests/test_elementwise_functions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_array_object.py b/numpy/array_api/tests/test_array_object.py index b980bacca..1fe1dfddf 100644 --- a/numpy/array_api/tests/test_array_object.py +++ b/numpy/array_api/tests/test_array_object.py @@ -98,7 +98,7 @@ def test_operators(): "__mul__": "numeric", "__ne__": "all", "__or__": "integer_or_boolean", - "__pow__": "floating", + "__pow__": "numeric", "__rshift__": "integer", "__sub__": "numeric", "__truediv__": "floating", diff --git a/numpy/array_api/tests/test_elementwise_functions.py b/numpy/array_api/tests/test_elementwise_functions.py index a9274aec9..b2fb44e76 100644 --- a/numpy/array_api/tests/test_elementwise_functions.py +++ b/numpy/array_api/tests/test_elementwise_functions.py @@ -66,7 +66,7 @@ def test_function_types(): "negative": "numeric", "not_equal": "all", "positive": "numeric", - "pow": "floating-point", + "pow": "numeric", "remainder": "numeric", "round": "numeric", "sign": "numeric", -- cgit v1.2.1 From d7a43dfa91cc1363db64da8915db2b4b6c847b81 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Wed, 12 Jan 2022 16:20:33 +0000 Subject: BUG: `array_api.argsort(descending=True)` respects relative sort order (#20788) * BUG: `array_api.argsort(descending=True)` respects relative order * Regression test for stable descending `array_api.argsort()` --- numpy/array_api/tests/test_sorting_functions.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 numpy/array_api/tests/test_sorting_functions.py (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_sorting_functions.py b/numpy/array_api/tests/test_sorting_functions.py new file mode 100644 index 000000000..9848bbfeb --- /dev/null +++ b/numpy/array_api/tests/test_sorting_functions.py @@ -0,0 +1,23 @@ +import pytest + +from numpy import array_api as xp + + +@pytest.mark.parametrize( + "obj, axis, expected", + [ + ([0, 0], -1, [0, 1]), + ([0, 1, 0], -1, [1, 0, 2]), + ([[0, 1], [1, 1]], 0, [[1, 0], [0, 1]]), + ([[0, 1], [1, 1]], 1, [[1, 0], [0, 1]]), + ], +) +def test_stable_desc_argsort(obj, axis, expected): + """ + Indices respect relative order of a descending stable-sort + + See https://github.com/numpy/numpy/issues/20778 + """ + x = xp.asarray(obj) + out = xp.argsort(x, axis=axis, stable=True, descending=True) + assert xp.all(out == xp.asarray(expected)) -- cgit v1.2.1 From ccc1091360639de76fab1c1e2a8b31fda81855fb Mon Sep 17 00:00:00 2001 From: Matthew Date: Thu, 13 Jan 2022 10:03:49 +0000 Subject: Regression test for inverse indices in `array_api` set functions --- numpy/array_api/tests/test_set_functions.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 numpy/array_api/tests/test_set_functions.py (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_set_functions.py b/numpy/array_api/tests/test_set_functions.py new file mode 100644 index 000000000..b8eb65d43 --- /dev/null +++ b/numpy/array_api/tests/test_set_functions.py @@ -0,0 +1,19 @@ +import pytest +from hypothesis import given +from hypothesis.extra.array_api import make_strategies_namespace + +from numpy import array_api as xp + +xps = make_strategies_namespace(xp) + + +@pytest.mark.parametrize("func", [xp.unique_all, xp.unique_inverse]) +@given(xps.arrays(dtype=xps.scalar_dtypes(), shape=xps.array_shapes())) +def test_inverse_indices_shape(func, x): + """ + Inverse indices share shape of input array + + See https://github.com/numpy/numpy/issues/20638 + """ + out = func(x) + assert out.inverse_indices.shape == x.shape -- cgit v1.2.1 From 8eac9a4bb5b497ca29ebb852f21169ecfd0191e1 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Mon, 24 Jan 2022 10:20:20 +0000 Subject: BUG: Fix `np.array_api.can_cast()` by not relying on `np.can_cast()` --- numpy/array_api/tests/test_data_type_functions.py | 21 ++++++++++++++++++ numpy/array_api/tests/test_validation.py | 27 +++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 numpy/array_api/tests/test_data_type_functions.py create mode 100644 numpy/array_api/tests/test_validation.py (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_data_type_functions.py b/numpy/array_api/tests/test_data_type_functions.py new file mode 100644 index 000000000..3f01bb311 --- /dev/null +++ b/numpy/array_api/tests/test_data_type_functions.py @@ -0,0 +1,21 @@ +import pytest + +from numpy import array_api as xp + + +@pytest.mark.parametrize( + "from_, to, expected", + [ + (xp.int8, xp.int16, True), + (xp.int16, xp.int8, False), + # np.can_cast has discrepancies with the Array API + # See https://github.com/numpy/numpy/issues/20870 + (xp.bool, xp.int8, False), + (xp.asarray(0, dtype=xp.uint8), xp.int8, False), + ], +) +def test_can_cast(from_, to, expected): + """ + can_cast() returns correct result + """ + assert xp.can_cast(from_, to) == expected diff --git a/numpy/array_api/tests/test_validation.py b/numpy/array_api/tests/test_validation.py new file mode 100644 index 000000000..0dd100d15 --- /dev/null +++ b/numpy/array_api/tests/test_validation.py @@ -0,0 +1,27 @@ +from typing import Callable + +import pytest + +from numpy import array_api as xp + + +def p(func: Callable, *args, **kwargs): + f_sig = ", ".join( + [str(a) for a in args] + [f"{k}={v}" for k, v in kwargs.items()] + ) + id_ = f"{func.__name__}({f_sig})" + return pytest.param(func, args, kwargs, id=id_) + + +@pytest.mark.parametrize( + "func, args, kwargs", + [ + p(xp.can_cast, 42, xp.int8), + p(xp.can_cast, xp.int8, 42), + p(xp.result_type, 42), + ], +) +def test_raises_on_invalid_types(func, args, kwargs): + """Function raises TypeError when passed invalidly-typed inputs""" + with pytest.raises(TypeError): + func(*args, **kwargs) -- cgit v1.2.1 From 995f5464b6c5d8569e159a96c6af106721a4e6d5 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Wed, 9 Feb 2022 08:35:21 +0000 Subject: Note `np.array_api.can_cast()` does not use `np.can_cast()` --- numpy/array_api/tests/test_data_type_functions.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_data_type_functions.py b/numpy/array_api/tests/test_data_type_functions.py index 3f01bb311..efe3d0abd 100644 --- a/numpy/array_api/tests/test_data_type_functions.py +++ b/numpy/array_api/tests/test_data_type_functions.py @@ -8,8 +8,6 @@ from numpy import array_api as xp [ (xp.int8, xp.int16, True), (xp.int16, xp.int8, False), - # np.can_cast has discrepancies with the Array API - # See https://github.com/numpy/numpy/issues/20870 (xp.bool, xp.int8, False), (xp.asarray(0, dtype=xp.uint8), xp.int8, False), ], -- cgit v1.2.1 From befef7b26773eddd2b656a3ab87f504e6cc173db Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Fri, 6 May 2022 09:27:27 +0000 Subject: API: Allow newaxis indexing for `array_api` arrays (#21377) * TST: Add test checking if newaxis indexing works for `array_api` Also removes previous check against newaxis indexing, which is now outdated * TST, BUG: Allow `None` in `array_api` indexing Introduces test for validating flat indexing when `None` is present * MAINT,DOC,TST: Rework of `_validate_index()` in `numpy.array_api` _validate_index() is now called as self._validate_index(shape), and does not return a key. This rework removes the recursive pattern used. Tests are introduced to cover some edge cases. Additionally, its internal docstring reflects new behaviour, and extends the flat indexing note. * MAINT: `advance` -> `advanced` (integer indexing) Co-authored-by: Aaron Meurer * BUG: array_api arrays use internal arrays from array_api array keys When an array_api array is passed as the key for get/setitem, we access the key's internal np.ndarray array to be used as the key for the internal get/setitem operation. This behaviour was initially removed when `_validate_index()` was reworked. * MAINT: Better flat indexing error message for `array_api` arrays Also better semantics for its prior ellipsis count condition Co-authored-by: Sebastian Berg * MAINT: `array_api` arrays don't special case multi-ellipsis errors This gets handled by NumPy-proper. Co-authored-by: Aaron Meurer Co-authored-by: Sebastian Berg --- numpy/array_api/tests/test_array_object.py | 63 +++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 6 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_array_object.py b/numpy/array_api/tests/test_array_object.py index 1fe1dfddf..ba9223532 100644 --- a/numpy/array_api/tests/test_array_object.py +++ b/numpy/array_api/tests/test_array_object.py @@ -2,8 +2,9 @@ import operator from numpy.testing import assert_raises import numpy as np +import pytest -from .. import ones, asarray, result_type, all, equal +from .. import ones, asarray, reshape, result_type, all, equal from .._array_object import Array from .._dtypes import ( _all_dtypes, @@ -17,6 +18,7 @@ from .._dtypes import ( int32, int64, uint64, + bool as bool_, ) @@ -70,11 +72,6 @@ def test_validate_index(): assert_raises(IndexError, lambda: a[[0, 1]]) assert_raises(IndexError, lambda: a[np.array([[0, 1]])]) - # np.newaxis is not allowed - assert_raises(IndexError, lambda: a[None]) - assert_raises(IndexError, lambda: a[None, ...]) - assert_raises(IndexError, lambda: a[..., None]) - # Multiaxis indices must contain exactly as many indices as dimensions assert_raises(IndexError, lambda: a[()]) assert_raises(IndexError, lambda: a[0,]) @@ -322,3 +319,57 @@ def test___array__(): b = np.asarray(a, dtype=np.float64) assert np.all(np.equal(b, np.ones((2, 3), dtype=np.float64))) assert b.dtype == np.float64 + +def test_allow_newaxis(): + a = ones(5) + indexed_a = a[None, :] + assert indexed_a.shape == (1, 5) + +def test_disallow_flat_indexing_with_newaxis(): + a = ones((3, 3, 3)) + with pytest.raises(IndexError): + a[None, 0, 0] + +def test_disallow_mask_with_newaxis(): + a = ones((3, 3, 3)) + with pytest.raises(IndexError): + a[None, asarray(True)] + +@pytest.mark.parametrize("shape", [(), (5,), (3, 3, 3)]) +@pytest.mark.parametrize("index", ["string", False, True]) +def test_error_on_invalid_index(shape, index): + a = ones(shape) + with pytest.raises(IndexError): + a[index] + +def test_mask_0d_array_without_errors(): + a = ones(()) + a[asarray(True)] + +@pytest.mark.parametrize( + "i", [slice(5), slice(5, 0), asarray(True), asarray([0, 1])] +) +def test_error_on_invalid_index_with_ellipsis(i): + a = ones((3, 3, 3)) + with pytest.raises(IndexError): + a[..., i] + with pytest.raises(IndexError): + a[i, ...] + +def test_array_keys_use_private_array(): + """ + Indexing operations convert array keys before indexing the internal array + + Fails when array_api array keys are not converted into NumPy-proper arrays + in __getitem__(). This is achieved by passing array_api arrays with 0-sized + dimensions, which NumPy-proper treats erroneously - not sure why! + + TODO: Find and use appropiate __setitem__() case. + """ + a = ones((0, 0), dtype=bool_) + assert a[a].shape == (0,) + + a = ones((0,), dtype=bool_) + key = ones((0, 0), dtype=bool_) + with pytest.raises(IndexError): + a[key] -- cgit v1.2.1 From 81b97607339ac68b27cf72ba7923345d58e2895e Mon Sep 17 00:00:00 2001 From: "M. Eric Irrgang" Date: Sat, 16 Jul 2022 15:27:38 -0500 Subject: Add unit testing. --- numpy/array_api/tests/test_asarray.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 numpy/array_api/tests/test_asarray.py (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_asarray.py b/numpy/array_api/tests/test_asarray.py new file mode 100644 index 000000000..d9bbc675b --- /dev/null +++ b/numpy/array_api/tests/test_asarray.py @@ -0,0 +1,24 @@ +import numpy as np + + +def test_fast_return(): + """""" + a = np.array([1, 2, 3], dtype='i') + assert np.asarray(a) is a + assert np.asarray(a, dtype='i') is a + # This may produce a new view or a copy, but is never the same object. + assert np.asarray(a, dtype='l') is not a + + unequal_type = np.dtype('i', metadata={'spam': True}) + b = np.asarray(a, dtype=unequal_type) + assert b is not a + assert b.base is a + + equivalent_requirement = np.dtype('i', metadata={'spam': True}) + c = np.asarray(b, dtype=equivalent_requirement) + # A quirk of the metadata test is that equivalent metadata dicts are still + # separate objects and so don't evaluate as the same array type description. + assert unequal_type == equivalent_requirement + assert unequal_type is not equivalent_requirement + assert c is not b + assert c.dtype is equivalent_requirement -- cgit v1.2.1 From 5651445944bce163a2c3f746d6ac1acd9ae76032 Mon Sep 17 00:00:00 2001 From: "M. Eric Irrgang" Date: Sat, 16 Jul 2022 15:51:51 -0500 Subject: Update comment and obey formatting requirements. --- numpy/array_api/tests/test_asarray.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_asarray.py b/numpy/array_api/tests/test_asarray.py index d9bbc675b..bd1859d71 100644 --- a/numpy/array_api/tests/test_asarray.py +++ b/numpy/array_api/tests/test_asarray.py @@ -16,8 +16,8 @@ def test_fast_return(): equivalent_requirement = np.dtype('i', metadata={'spam': True}) c = np.asarray(b, dtype=equivalent_requirement) - # A quirk of the metadata test is that equivalent metadata dicts are still - # separate objects and so don't evaluate as the same array type description. + # The descriptors are equivalent, but we have created + # distinct dtype instances. assert unequal_type == equivalent_requirement assert unequal_type is not equivalent_requirement assert c is not b -- cgit v1.2.1 From e286f461b54c43e2a16b3f6fc6d829936ea28c27 Mon Sep 17 00:00:00 2001 From: "M. Eric Irrgang" Date: Sun, 17 Jul 2022 10:49:56 -0500 Subject: Expand test_asarray.py. * Improve comments/docs. * Improve descriptiveness of variable names. * Add additional test expressions that would not pass without this patch. --- numpy/array_api/tests/test_asarray.py | 46 +++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 13 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_asarray.py b/numpy/array_api/tests/test_asarray.py index bd1859d71..fdcc77506 100644 --- a/numpy/array_api/tests/test_asarray.py +++ b/numpy/array_api/tests/test_asarray.py @@ -1,24 +1,44 @@ import numpy as np -def test_fast_return(): - """""" - a = np.array([1, 2, 3], dtype='i') - assert np.asarray(a) is a - assert np.asarray(a, dtype='i') is a - # This may produce a new view or a copy, but is never the same object. - assert np.asarray(a, dtype='l') is not a +def test_dtype_identity(): + """Confirm the intended behavior for ``asarray`` results. + The result of ``asarray()`` should have the dtype provided through the + keyword argument, when used. This forces unique array handles to be + produced for unique np.dtype objects, but (for equivalent dtypes), the + underlying data (the base object) is shared with the original array object. + + Ref https://github.com/numpy/numpy/issues/1468 + """ + int_array = np.array([1, 2, 3], dtype='i') + assert np.asarray(int_array) is int_array + + # The character code resolves to the singleton dtype object provided + # by the numpy package. + assert np.asarray(int_array, dtype='i') is int_array + + # Derive a dtype from n.dtype('i'), but add a metadata object to force + # the dtype to be distinct. unequal_type = np.dtype('i', metadata={'spam': True}) - b = np.asarray(a, dtype=unequal_type) - assert b is not a - assert b.base is a + annotated_int_array = np.asarray(int_array, dtype=unequal_type) + assert annotated_int_array is not int_array + assert annotated_int_array.base is int_array + + # These ``asarray()`` calls may produce a new view or a copy, + # but never the same object. + long_int_array = np.asarray(int_array, dtype='l') + assert long_int_array is not int_array + assert np.asarray(int_array, dtype='q') is not int_array + assert np.asarray(long_int_array, dtype='q') is not long_int_array + assert np.asarray(int_array, dtype='l') is not np.asarray(int_array, dtype='l') + assert np.asarray(int_array, dtype='l').base is np.asarray(int_array, dtype='l').base equivalent_requirement = np.dtype('i', metadata={'spam': True}) - c = np.asarray(b, dtype=equivalent_requirement) + annotated_int_array_alt = np.asarray(annotated_int_array, dtype=equivalent_requirement) # The descriptors are equivalent, but we have created # distinct dtype instances. assert unequal_type == equivalent_requirement assert unequal_type is not equivalent_requirement - assert c is not b - assert c.dtype is equivalent_requirement + assert annotated_int_array_alt is not annotated_int_array + assert annotated_int_array_alt.dtype is equivalent_requirement -- cgit v1.2.1 From 01438a848b029b4fb3d3509c7fd313bc0588bd38 Mon Sep 17 00:00:00 2001 From: "M. Eric Irrgang" Date: Sun, 17 Jul 2022 10:55:59 -0500 Subject: Lint. Shorten some lines. --- numpy/array_api/tests/test_asarray.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_asarray.py b/numpy/array_api/tests/test_asarray.py index fdcc77506..4a9dd77a0 100644 --- a/numpy/array_api/tests/test_asarray.py +++ b/numpy/array_api/tests/test_asarray.py @@ -31,11 +31,12 @@ def test_dtype_identity(): assert long_int_array is not int_array assert np.asarray(int_array, dtype='q') is not int_array assert np.asarray(long_int_array, dtype='q') is not long_int_array - assert np.asarray(int_array, dtype='l') is not np.asarray(int_array, dtype='l') - assert np.asarray(int_array, dtype='l').base is np.asarray(int_array, dtype='l').base + assert long_int_array is not np.asarray(int_array, dtype='l') + assert long_int_array.base is np.asarray(int_array, dtype='l').base equivalent_requirement = np.dtype('i', metadata={'spam': True}) - annotated_int_array_alt = np.asarray(annotated_int_array, dtype=equivalent_requirement) + annotated_int_array_alt = np.asarray(annotated_int_array, + dtype=equivalent_requirement) # The descriptors are equivalent, but we have created # distinct dtype instances. assert unequal_type == equivalent_requirement -- cgit v1.2.1 From b1a8ff8fa73b744416e12cdd4bb70594717b5336 Mon Sep 17 00:00:00 2001 From: "M. Eric Irrgang" Date: Sun, 17 Jul 2022 13:12:31 -0500 Subject: Add release note and further clarify tests. --- numpy/array_api/tests/test_asarray.py | 43 +++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 12 deletions(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_asarray.py b/numpy/array_api/tests/test_asarray.py index 4a9dd77a0..5c269823f 100644 --- a/numpy/array_api/tests/test_asarray.py +++ b/numpy/array_api/tests/test_asarray.py @@ -1,3 +1,5 @@ +import itertools + import numpy as np @@ -24,22 +26,39 @@ def test_dtype_identity(): annotated_int_array = np.asarray(int_array, dtype=unequal_type) assert annotated_int_array is not int_array assert annotated_int_array.base is int_array - - # These ``asarray()`` calls may produce a new view or a copy, - # but never the same object. - long_int_array = np.asarray(int_array, dtype='l') - assert long_int_array is not int_array - assert np.asarray(int_array, dtype='q') is not int_array - assert np.asarray(long_int_array, dtype='q') is not long_int_array - assert long_int_array is not np.asarray(int_array, dtype='l') - assert long_int_array.base is np.asarray(int_array, dtype='l').base - + # Create an equivalent descriptor with a new and distinct dtype instance. equivalent_requirement = np.dtype('i', metadata={'spam': True}) annotated_int_array_alt = np.asarray(annotated_int_array, dtype=equivalent_requirement) - # The descriptors are equivalent, but we have created - # distinct dtype instances. assert unequal_type == equivalent_requirement assert unequal_type is not equivalent_requirement assert annotated_int_array_alt is not annotated_int_array assert annotated_int_array_alt.dtype is equivalent_requirement + + # Check the same logic for a pair of C types whose equivalence may vary + # between computing environments. + # Find an equivalent pair. + integer_type_codes = ('i', 'l', 'q') + integer_dtypes = [np.dtype(code) for code in integer_type_codes] + typeA = None + typeB = None + for typeA, typeB in itertools.permutations(integer_dtypes, r=2): + if typeA == typeB: + assert typeA is not typeB + break + assert isinstance(typeA, np.dtype) and isinstance(typeB, np.dtype) + + # These ``asarray()`` calls may produce a new view or a copy, + # but never the same object. + long_int_array = np.asarray(int_array, dtype='l') + long_long_int_array = np.asarray(int_array, dtype='q') + assert long_int_array is not int_array + assert long_long_int_array is not int_array + assert np.asarray(long_int_array, dtype='q') is not long_int_array + array_a = np.asarray(int_array, dtype=typeA) + assert typeA == typeB + assert typeA is not typeB + assert array_a.dtype is typeA + assert array_a is not np.asarray(array_a, dtype=typeB) + assert np.asarray(array_a, dtype=typeB).dtype is typeB + assert array_a is np.asarray(array_a, dtype=typeB).base -- cgit v1.2.1 From 7c8e1134ae86f8a8c002e1068337bec63ddf7f0d Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Tue, 2 Aug 2022 19:26:42 +0900 Subject: MAINT: fix typo in test_array_object test description (#22071) --- numpy/array_api/tests/test_array_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_array_object.py b/numpy/array_api/tests/test_array_object.py index ba9223532..f6efacefa 100644 --- a/numpy/array_api/tests/test_array_object.py +++ b/numpy/array_api/tests/test_array_object.py @@ -364,7 +364,7 @@ def test_array_keys_use_private_array(): in __getitem__(). This is achieved by passing array_api arrays with 0-sized dimensions, which NumPy-proper treats erroneously - not sure why! - TODO: Find and use appropiate __setitem__() case. + TODO: Find and use appropriate __setitem__() case. """ a = ones((0, 0), dtype=bool_) assert a[a].shape == (0,) -- cgit v1.2.1 From 4d4fca0cef2e5594a50c1d10a9db6f21aaba0a58 Mon Sep 17 00:00:00 2001 From: "M. Eric Irrgang" Date: Tue, 13 Sep 2022 09:20:45 +0300 Subject: TST: Move new `asarray` test to a more appropriate place. (#22251) As noted at #21995 (comment), the new test from #21995 was placed in a directory intended for the Array API, and unrelated to the change. * Consolidate test_dtype_identity into an existing test file. Remove `test_asarray.py`. Create a new `TestAsArray` suite in `test_array_coercion.py` * Linting. Wrap some comments that got too long after function became a method (with additional indentation). --- numpy/array_api/tests/test_asarray.py | 64 ----------------------------------- 1 file changed, 64 deletions(-) delete mode 100644 numpy/array_api/tests/test_asarray.py (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_asarray.py b/numpy/array_api/tests/test_asarray.py deleted file mode 100644 index 5c269823f..000000000 --- a/numpy/array_api/tests/test_asarray.py +++ /dev/null @@ -1,64 +0,0 @@ -import itertools - -import numpy as np - - -def test_dtype_identity(): - """Confirm the intended behavior for ``asarray`` results. - - The result of ``asarray()`` should have the dtype provided through the - keyword argument, when used. This forces unique array handles to be - produced for unique np.dtype objects, but (for equivalent dtypes), the - underlying data (the base object) is shared with the original array object. - - Ref https://github.com/numpy/numpy/issues/1468 - """ - int_array = np.array([1, 2, 3], dtype='i') - assert np.asarray(int_array) is int_array - - # The character code resolves to the singleton dtype object provided - # by the numpy package. - assert np.asarray(int_array, dtype='i') is int_array - - # Derive a dtype from n.dtype('i'), but add a metadata object to force - # the dtype to be distinct. - unequal_type = np.dtype('i', metadata={'spam': True}) - annotated_int_array = np.asarray(int_array, dtype=unequal_type) - assert annotated_int_array is not int_array - assert annotated_int_array.base is int_array - # Create an equivalent descriptor with a new and distinct dtype instance. - equivalent_requirement = np.dtype('i', metadata={'spam': True}) - annotated_int_array_alt = np.asarray(annotated_int_array, - dtype=equivalent_requirement) - assert unequal_type == equivalent_requirement - assert unequal_type is not equivalent_requirement - assert annotated_int_array_alt is not annotated_int_array - assert annotated_int_array_alt.dtype is equivalent_requirement - - # Check the same logic for a pair of C types whose equivalence may vary - # between computing environments. - # Find an equivalent pair. - integer_type_codes = ('i', 'l', 'q') - integer_dtypes = [np.dtype(code) for code in integer_type_codes] - typeA = None - typeB = None - for typeA, typeB in itertools.permutations(integer_dtypes, r=2): - if typeA == typeB: - assert typeA is not typeB - break - assert isinstance(typeA, np.dtype) and isinstance(typeB, np.dtype) - - # These ``asarray()`` calls may produce a new view or a copy, - # but never the same object. - long_int_array = np.asarray(int_array, dtype='l') - long_long_int_array = np.asarray(int_array, dtype='q') - assert long_int_array is not int_array - assert long_long_int_array is not int_array - assert np.asarray(long_int_array, dtype='q') is not long_int_array - array_a = np.asarray(int_array, dtype=typeA) - assert typeA == typeB - assert typeA is not typeB - assert array_a.dtype is typeA - assert array_a is not np.asarray(array_a, dtype=typeB) - assert np.asarray(array_a, dtype=typeB).dtype is typeB - assert array_a is np.asarray(array_a, dtype=typeB).base -- cgit v1.2.1 From f07d55b27671a4575e3b9b2fc7ca9ec897d4db9e Mon Sep 17 00:00:00 2001 From: Alex Rogozhnikov Date: Sun, 26 Feb 2023 07:56:47 +0000 Subject: add support for xp.take --- numpy/array_api/tests/test_indexing_functions.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 numpy/array_api/tests/test_indexing_functions.py (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_indexing_functions.py b/numpy/array_api/tests/test_indexing_functions.py new file mode 100644 index 000000000..26667e32f --- /dev/null +++ b/numpy/array_api/tests/test_indexing_functions.py @@ -0,0 +1,24 @@ +import pytest + +from numpy import array_api as xp + + +@pytest.mark.parametrize( + "x, indices, axis, expected", + [ + ([2, 3], [1, 1, 0], 0, [3, 3, 2]), + ([2, 3], [1, 1, 0], -1, [3, 3, 2]), + ([[2, 3]], [1], -1, [[3]]), + ([[2, 3]], [0, 0], 0, [[2, 3], [2, 3]]), + ], +) +def test_stable_desc_argsort(x, indices, axis, expected): + """ + Indices respect relative order of a descending stable-sort + + See https://github.com/numpy/numpy/issues/20778 + """ + x = xp.asarray(x) + indices = xp.asarray(indices) + out = xp.take(x, indices, axis=axis) + assert xp.all(out == xp.asarray(expected)) -- cgit v1.2.1 From 786bd366b22675b1e4067653d4729031c258f35f Mon Sep 17 00:00:00 2001 From: Alex Rogozhnikov Date: Sun, 26 Feb 2023 08:19:45 +0000 Subject: rename test function --- numpy/array_api/tests/test_indexing_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'numpy/array_api/tests') diff --git a/numpy/array_api/tests/test_indexing_functions.py b/numpy/array_api/tests/test_indexing_functions.py index 26667e32f..9e05c6386 100644 --- a/numpy/array_api/tests/test_indexing_functions.py +++ b/numpy/array_api/tests/test_indexing_functions.py @@ -12,7 +12,7 @@ from numpy import array_api as xp ([[2, 3]], [0, 0], 0, [[2, 3], [2, 3]]), ], ) -def test_stable_desc_argsort(x, indices, axis, expected): +def test_take_function(x, indices, axis, expected): """ Indices respect relative order of a descending stable-sort -- cgit v1.2.1