@@ -229,11 +229,13 @@ def _backends_kwargs_from_request(request, skip_or_xfail):
229
229
if marker .kwargs .get ('np_only' ):
230
230
kwargs ['np_only' ] = True
231
231
kwargs ['exceptions' ] = marker .kwargs .get ('exceptions' , [])
232
+ kwargs ['reason' ] = marker .kwargs .get ('reason' , None )
232
233
elif marker .kwargs .get ('cpu_only' ):
233
234
if not kwargs .get ('np_only' ):
234
235
# if np_only is given, it is certainly cpu only
235
236
kwargs ['cpu_only' ] = True
236
237
kwargs ['exceptions' ] = marker .kwargs .get ('exceptions' , [])
238
+ kwargs ['reason' ] = marker .kwargs .get ('reason' , None )
237
239
238
240
# add backends, if any
239
241
if len (marker .args ) > 0 :
@@ -291,22 +293,20 @@ def skip_or_xfail_xp_backends(xp, backends, kwargs, skip_or_xfail='skip'):
291
293
Backends to skip/xfail, e.g. ``("array_api_strict", "torch")``.
292
294
These are overriden when ``np_only`` is ``True``, and are not
293
295
necessary to provide for non-CPU backends when ``cpu_only`` is ``True``.
294
- For a custom reason to apply, you should pass a dict ``{'reason': '...'}``
295
- to a keyword matching the name of the backend.
296
- reason : str, optional
297
- A reason for the skip/xfail in the case of ``np_only=True``.
298
- If unprovided, a default reason is used. Note that it is not possible
299
- to specify a custom reason with ``cpu_only``.
296
+ For a custom reason to apply, you should pass
297
+ ``kwargs={<backend name>: {'reason': '...'}, ...}``.
300
298
np_only : bool, optional
301
299
When ``True``, the test is skipped/xfailed for all backends other
302
300
than the default NumPy backend. There is no need to provide
303
- any ``backends`` in this case. To specify a reason, pass a
304
- value to ``reason``. Default: ``False``.
301
+ any ``backends`` in this case. Default: ``False``.
305
302
cpu_only : bool, optional
306
303
When ``True``, the test is skipped/xfailed on non-CPU devices.
307
304
There is no need to provide any ``backends`` in this case,
308
305
but any ``backends`` will also be skipped on the CPU.
309
306
Default: ``False``.
307
+ reason : str, optional
308
+ A reason for the skip/xfail in the case of ``np_only=True`` or
309
+ ``cpu_only=True``. If omitted, a default reason is used.
310
310
exceptions : list, optional
311
311
A list of exceptions for use with ``cpu_only`` or ``np_only``.
312
312
This should be provided when delegation is implemented for some,
@@ -329,17 +329,32 @@ def skip_or_xfail_xp_backends(xp, backends, kwargs, skip_or_xfail='skip'):
329
329
if exceptions and not (cpu_only or np_only ):
330
330
raise ValueError ("`exceptions` is only valid alongside `cpu_only` or `np_only`" )
331
331
332
+ # Test explicit backends first so that their reason can override
333
+ # those from np_only/cpu_only
334
+ if backends is not None :
335
+ for i , backend in enumerate (backends ):
336
+ if xp .__name__ == backend :
337
+ reason = kwargs [backend ].get ('reason' )
338
+ if not reason :
339
+ reason = f"do not run with array API backend: { backend } "
340
+
341
+ skip_or_xfail (reason = reason )
342
+
332
343
if np_only :
333
- reason = kwargs .get ("reason" , "do not run with non-NumPy backends." )
334
- if not isinstance ( reason , str ) and len ( reason ) > 1 :
335
- raise ValueError ( "please provide a singleton `reason` "
336
- "when using `np_only`" )
344
+ reason = kwargs .get ("reason" )
345
+ if not reason :
346
+ reason = "do not run with non-NumPy backends "
347
+
337
348
if xp .__name__ != 'numpy' and xp .__name__ not in exceptions :
338
349
skip_or_xfail (reason = reason )
339
350
return
351
+
340
352
if cpu_only :
341
- reason = ("no array-agnostic implementation or delegation available "
342
- "for this backend and device" )
353
+ reason = kwargs .get ("reason" )
354
+ if not reason :
355
+ reason = ("no array-agnostic implementation or delegation available "
356
+ "for this backend and device" )
357
+
343
358
exceptions = [] if exceptions is None else exceptions
344
359
if SCIPY_ARRAY_API and SCIPY_DEVICE != 'cpu' :
345
360
if xp .__name__ == 'cupy' and 'cupy' not in exceptions :
@@ -352,15 +367,6 @@ def skip_or_xfail_xp_backends(xp, backends, kwargs, skip_or_xfail='skip'):
352
367
if 'cpu' not in d .device_kind :
353
368
skip_or_xfail (reason = reason )
354
369
355
- if backends is not None :
356
- for i , backend in enumerate (backends ):
357
- if xp .__name__ == backend :
358
- reason = kwargs [backend ].get ('reason' )
359
- if not reason :
360
- reason = f"do not run with array API backend: { backend } "
361
-
362
- skip_or_xfail (reason = reason )
363
-
364
370
365
371
# Following the approach of NumPy's conftest.py...
366
372
# Use a known and persistent tmpdir for hypothesis' caches, which
0 commit comments