diff --git a/src/array_api_compat/numpy/_info.py b/src/array_api_compat/numpy/_info.py index 9ba004da..d5fd5d7c 100644 --- a/src/array_api_compat/numpy/_info.py +++ b/src/array_api_compat/numpy/_info.py @@ -13,7 +13,6 @@ from numpy import ( complex64, complex128, - dtype, float32, float64, int8, @@ -186,10 +185,10 @@ def default_dtypes( f' {device}' ) return { - "real floating": dtype(float64), - "complex floating": dtype(complex128), - "integral": dtype(intp), - "indexing": dtype(intp), + "real floating": float64, + "complex floating": complex128, + "integral": intp, + "indexing": intp, } def dtypes( @@ -259,71 +258,71 @@ def dtypes( ) if kind is None: return { - "bool": dtype(bool), - "int8": dtype(int8), - "int16": dtype(int16), - "int32": dtype(int32), - "int64": dtype(int64), - "uint8": dtype(uint8), - "uint16": dtype(uint16), - "uint32": dtype(uint32), - "uint64": dtype(uint64), - "float32": dtype(float32), - "float64": dtype(float64), - "complex64": dtype(complex64), - "complex128": dtype(complex128), + "bool": bool, + "int8": int8, + "int16": int16, + "int32": int32, + "int64": int64, + "uint8": uint8, + "uint16": uint16, + "uint32": uint32, + "uint64": uint64, + "float32": float32, + "float64": float64, + "complex64": complex64, + "complex128": complex128, } if kind == "bool": - return {"bool": dtype(bool)} + return {"bool": bool} if kind == "signed integer": return { - "int8": dtype(int8), - "int16": dtype(int16), - "int32": dtype(int32), - "int64": dtype(int64), + "int8": int8, + "int16": int16, + "int32": int32, + "int64": int64, } if kind == "unsigned integer": return { - "uint8": dtype(uint8), - "uint16": dtype(uint16), - "uint32": dtype(uint32), - "uint64": dtype(uint64), + "uint8": uint8, + "uint16": uint16, + "uint32": uint32, + "uint64": uint64, } if kind == "integral": return { - "int8": dtype(int8), - "int16": dtype(int16), - "int32": dtype(int32), - "int64": dtype(int64), - "uint8": dtype(uint8), - "uint16": dtype(uint16), - "uint32": dtype(uint32), - "uint64": dtype(uint64), + "int8": int8, + "int16": int16, + "int32": int32, + "int64": int64, + "uint8": uint8, + "uint16": uint16, + "uint32": uint32, + "uint64": uint64, } if kind == "real floating": return { - "float32": dtype(float32), - "float64": dtype(float64), + "float32": float32, + "float64": float64, } if kind == "complex floating": return { - "complex64": dtype(complex64), - "complex128": dtype(complex128), + "complex64": complex64, + "complex128": complex128, } if kind == "numeric": return { - "int8": dtype(int8), - "int16": dtype(int16), - "int32": dtype(int32), - "int64": dtype(int64), - "uint8": dtype(uint8), - "uint16": dtype(uint16), - "uint32": dtype(uint32), - "uint64": dtype(uint64), - "float32": dtype(float32), - "float64": dtype(float64), - "complex64": dtype(complex64), - "complex128": dtype(complex128), + "int8": int8, + "int16": int16, + "int32": int32, + "int64": int64, + "uint8": uint8, + "uint16": uint16, + "uint32": uint32, + "uint64": uint64, + "float32": float32, + "float64": float64, + "complex64": complex64, + "complex128": complex128, } if isinstance(kind, tuple): res: dict[str, DType] = {} diff --git a/tests/test_numpy.py b/tests/test_numpy.py index f8d45e2d..b020d3e3 100644 --- a/tests/test_numpy.py +++ b/tests/test_numpy.py @@ -154,3 +154,26 @@ def test_reshape_copy_false_returns_a_view_without_deprecation(): def test_reshape_copy_false_rejects_an_input_that_needs_a_copy(): with pytest.raises((ValueError, AttributeError)): xp.reshape(np.arange(12).reshape(3, 4).T, (2, 6), copy=False) + + +def test_inspection_dtypes_do_not_compare_equal_to_none(): + """`dtypes()`/`default_dtypes()` must return the scalar types, not + `np.dtype` objects. gh-359. + + `np.dtype(None)` is `float64` in NumPy, so `dtypes()["float64"] == None` + is True and a caller cannot tell "unsupported" from "supported". And + `np.dtype` objects have no `__name__`, so they are unusable for the + ordinary introspection callers do on the returned values. + """ + info = xp.__array_namespace_info__() + + assert info.dtypes()["float64"] is np.float64 + assert info.default_dtypes()["real floating"] is np.float64 + + for dt in info.dtypes().values(): + assert not (dt == None) # noqa: E711 + assert isinstance(dt.__name__, str) + + for dt in info.default_dtypes().values(): + assert not (dt == None) # noqa: E711 + assert isinstance(dt.__name__, str)