From 498d1debcee2a1422cc14013dbb5482f62cd4f58 Mon Sep 17 00:00:00 2001 From: crusaderky Date: Wed, 2 Apr 2025 15:28:14 +0100 Subject: [PATCH 1/3] Tighten tests on iinfo/finfo --- array_api_tests/test_data_type_functions.py | 44 +++++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/array_api_tests/test_data_type_functions.py b/array_api_tests/test_data_type_functions.py index e844c432..ec95ba90 100644 --- a/array_api_tests/test_data_type_functions.py +++ b/array_api_tests/test_data_type_functions.py @@ -147,9 +147,12 @@ def test_can_cast(_from, to): assert out == expected, f"{out=}, but should be {expected} {f_func}" -@pytest.mark.parametrize("dtype", dh.real_float_dtypes) -def test_finfo(dtype): - out = xp.finfo(dtype) +@pytest.mark.parametrize("arg_type", ["dtype", "array"]) +@pytest.mark.parametrize("dtype", dh.real_float_dtypes + dh.complex_dtypes) +def test_finfo(dtype, arg_type): + arg = xp.asarray(1, dtype=dtype) if arg_type == "array" else dtype + out = xp.finfo(arg) + f_func = f"[finfo({dh.dtype_to_name[dtype]})]" for attr, stype in [ ("bits", int), @@ -164,12 +167,30 @@ def test_finfo(dtype): value, stype ), f"type(out.{attr})={type(value)!r}, but should be {stype.__name__} {f_func}" assert hasattr(out, "dtype"), f"out has no attribute 'dtype' {f_func}" - # TODO: test values + + assert isinstance(out.bits, int) + assert isinstance(out.eps, float) + assert isinstance(out.max, float) + assert isinstance(out.min, float) + assert isinstance(out.smallest_normal, float) + if dtype == xp.complex64: + assert out.dtype == xp.float32 + elif dtype == xp.complex128: + assert out.dtype == xp.float64 + else: + assert out.dtype == dtype + # Guard vs. numpy.dtype.__eq__ lax comparison + assert not isinstance(out.dtype, str) + assert out.dtype is not float + assert out.dtype is not complex -@pytest.mark.parametrize("dtype", dh.int_dtypes) -def test_iinfo(dtype): - out = xp.iinfo(dtype) +@pytest.mark.parametrize("arg_type", ["dtype", "array"]) +@pytest.mark.parametrize("dtype", dh.int_dtypes + dh.uint_dtypes) +def test_iinfo(dtype, arg_type): + arg = xp.asarray(1, dtype=dtype) if arg_type == "array" else dtype + out = xp.iinfo(arg) + f_func = f"[iinfo({dh.dtype_to_name[dtype]})]" for attr in ["bits", "max", "min"]: assert hasattr(out, attr), f"out has no attribute '{attr}' {f_func}" @@ -178,7 +199,14 @@ def test_iinfo(dtype): value, int ), f"type(out.{attr})={type(value)!r}, but should be int {f_func}" assert hasattr(out, "dtype"), f"out has no attribute 'dtype' {f_func}" - # TODO: test values + + assert isinstance(out.bits, int) + assert isinstance(out.max, int) + assert isinstance(out.min, int) + assert out.dtype == dtype + # Guard vs. numpy.dtype.__eq__ lax comparison + assert not isinstance(out.dtype, str) + assert out.dtype is not int def atomic_kinds() -> st.SearchStrategy[Union[DataType, str]]: From 2a70c49754554fdea54c7527b4f2981876750a73 Mon Sep 17 00:00:00 2001 From: crusaderky Date: Mon, 7 Apr 2025 10:24:26 +0100 Subject: [PATCH 2/3] Simplify test --- array_api_tests/test_data_type_functions.py | 80 ++++++++++----------- 1 file changed, 38 insertions(+), 42 deletions(-) diff --git a/array_api_tests/test_data_type_functions.py b/array_api_tests/test_data_type_functions.py index ec95ba90..b56bdecc 100644 --- a/array_api_tests/test_data_type_functions.py +++ b/array_api_tests/test_data_type_functions.py @@ -147,62 +147,58 @@ def test_can_cast(_from, to): assert out == expected, f"{out=}, but should be {expected} {f_func}" -@pytest.mark.parametrize("arg_type", ["dtype", "array"]) @pytest.mark.parametrize("dtype", dh.real_float_dtypes + dh.complex_dtypes) -def test_finfo(dtype, arg_type): - arg = xp.asarray(1, dtype=dtype) if arg_type == "array" else dtype - out = xp.finfo(arg) - - f_func = f"[finfo({dh.dtype_to_name[dtype]})]" - for attr, stype in [ - ("bits", int), - ("eps", float), - ("max", float), - ("min", float), - ("smallest_normal", float), - ]: - assert hasattr(out, attr), f"out has no attribute '{attr}' {f_func}" - value = getattr(out, attr) - assert isinstance( - value, stype - ), f"type(out.{attr})={type(value)!r}, but should be {stype.__name__} {f_func}" - assert hasattr(out, "dtype"), f"out has no attribute 'dtype' {f_func}" - - assert isinstance(out.bits, int) - assert isinstance(out.eps, float) - assert isinstance(out.max, float) - assert isinstance(out.min, float) - assert isinstance(out.smallest_normal, float) +def test_finfo(dtype): + for arg in ( + dtype, + xp.asarray(1, dtype=dtype), + # np.float64 and np.asarray(1, dtype=np.float64).dtype are different + xp.asarray(1, dtype=dtype).dtype, + ): + out = xp.finfo(arg) + assert isinstance(out.bits, int) + assert isinstance(out.eps, float) + assert isinstance(out.max, float) + assert isinstance(out.min, float) + assert isinstance(out.smallest_normal, float) + + +@pytest.mark.min_version("2022.12") +@pytest.mark.parametrize("dtype", dh.real_float_dtypes + dh.complex_dtypes) +def test_finfo_dtype(dtype): + out = xp.finfo(dtype) + if dtype == xp.complex64: assert out.dtype == xp.float32 elif dtype == xp.complex128: assert out.dtype == xp.float64 else: assert out.dtype == dtype + # Guard vs. numpy.dtype.__eq__ lax comparison assert not isinstance(out.dtype, str) assert out.dtype is not float assert out.dtype is not complex -@pytest.mark.parametrize("arg_type", ["dtype", "array"]) @pytest.mark.parametrize("dtype", dh.int_dtypes + dh.uint_dtypes) -def test_iinfo(dtype, arg_type): - arg = xp.asarray(1, dtype=dtype) if arg_type == "array" else dtype - out = xp.iinfo(arg) - - f_func = f"[iinfo({dh.dtype_to_name[dtype]})]" - for attr in ["bits", "max", "min"]: - assert hasattr(out, attr), f"out has no attribute '{attr}' {f_func}" - value = getattr(out, attr) - assert isinstance( - value, int - ), f"type(out.{attr})={type(value)!r}, but should be int {f_func}" - assert hasattr(out, "dtype"), f"out has no attribute 'dtype' {f_func}" - - assert isinstance(out.bits, int) - assert isinstance(out.max, int) - assert isinstance(out.min, int) +def test_iinfo(dtype): + for arg in ( + dtype, + xp.asarray(1, dtype=dtype), + # np.int64 and np.asarray(1, dtype=np.int64).dtype are different + xp.asarray(1, dtype=dtype).dtype, + ): + out = xp.iinfo(arg) + assert isinstance(out.bits, int) + assert isinstance(out.max, int) + assert isinstance(out.min, int) + + +@pytest.mark.min_version("2022.12") +@pytest.mark.parametrize("dtype", dh.int_dtypes + dh.uint_dtypes) +def test_iinfo_dtype(dtype): + out = xp.iinfo(dtype) assert out.dtype == dtype # Guard vs. numpy.dtype.__eq__ lax comparison assert not isinstance(out.dtype, str) From 3858e7028152559f3d55fa525c7b7af805ec2340 Mon Sep 17 00:00:00 2001 From: crusaderky Date: Tue, 8 Apr 2025 16:55:37 +0100 Subject: [PATCH 3/3] skip tests --- array-api-strict-skips.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/array-api-strict-skips.txt b/array-api-strict-skips.txt index 6b062c6f..afc1b845 100644 --- a/array-api-strict-skips.txt +++ b/array-api-strict-skips.txt @@ -27,3 +27,8 @@ array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is -infinity array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> -0] array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> -0] +# FIXME needs array-api-strict >=2.3.2 +array_api_tests/test_data_type_functions.py::test_finfo +array_api_tests/test_data_type_functions.py::test_finfo_dtype +array_api_tests/test_data_type_functions.py::test_iinfo +array_api_tests/test_data_type_functions.py::test_iinfo_dtype