@@ -66,6 +66,8 @@ def __hash__(self):
6666
6767_default = object ()
6868
69+ _allow_array = False
70+
6971class Array :
7072 """
7173 n-d array object for the array API namespace.
@@ -145,30 +147,35 @@ def __repr__(self: Array, /) -> str:
145147 mid = np .array2string (self ._array , separator = ', ' , prefix = prefix , suffix = suffix )
146148 return prefix + mid + suffix
147149
148- # This function is not required by the spec, but we implement it here for
149- # convenience so that np.asarray(array_api_strict.Array) will work.
150+ # Disallow __array__, meaning calling `np.func()` on an array_api_strict
151+ # array will give an error. If we don't explicitly disallow it, NumPy
152+ # defaults to creating an object dtype array, which would lead to
153+ # confusing error messages at best and surprising bugs at worst.
154+ #
155+ # The alternative of course is to just support __array__, which is what we
156+ # used to do. But this isn't actually supported by the standard, so it can
157+ # lead to code assuming np.asarray(other_array) would always work in the
158+ # standard.
150159 def __array__ (self , dtype : None | np .dtype [Any ] = None , copy : None | bool = None ) -> npt .NDArray [Any ]:
151- """
152- Warning: this method is NOT part of the array API spec. Implementers
153- of other libraries need not include it, and users should not assume it
154- will be present in other implementations.
155-
156- """
157- if self ._device != CPU_DEVICE :
158- raise RuntimeError (f"Can not convert array on the '{ self ._device } ' device to a Numpy array." )
159- # copy keyword is new in 2.0.0; for older versions don't use it
160- # retry without that keyword.
161- if np .__version__ [0 ] < '2' :
162- return np .asarray (self ._array , dtype = dtype )
163- elif np .__version__ .startswith ('2.0.0-dev0' ):
164- # Handle dev version for which we can't know based on version
165- # number whether or not the copy keyword is supported.
166- try :
167- return np .asarray (self ._array , dtype = dtype , copy = copy )
168- except TypeError :
160+ # We have to allow this to be internally enabled as there's no other
161+ # easy way to parse a list of Array objects in asarray().
162+ if _allow_array :
163+ if self ._device != CPU_DEVICE :
164+ raise RuntimeError (f"Can not convert array on the '{ self ._device } ' device to a Numpy array." )
165+ # copy keyword is new in 2.0.0; for older versions don't use it
166+ # retry without that keyword.
167+ if np .__version__ [0 ] < '2' :
169168 return np .asarray (self ._array , dtype = dtype )
170- else :
171- return np .asarray (self ._array , dtype = dtype , copy = copy )
169+ elif np .__version__ .startswith ('2.0.0-dev0' ):
170+ # Handle dev version for which we can't know based on version
171+ # number whether or not the copy keyword is supported.
172+ try :
173+ return np .asarray (self ._array , dtype = dtype , copy = copy )
174+ except TypeError :
175+ return np .asarray (self ._array , dtype = dtype )
176+ else :
177+ return np .asarray (self ._array , dtype = dtype , copy = copy )
178+ raise ValueError ("Conversion from an array_api_strict array to a NumPy ndarray is not supported" )
172179
173180 # These are various helper functions to make the array behavior match the
174181 # spec in places where it either deviates from or is more strict than
0 commit comments