22
33"""ONNX backend test initialization."""
44
5+ import functools
56import importlib
67import os
78import unittest
89
910import onnx .backend .test
11+ import onnx .backend .test .runner as onnx_test_runner
1012
1113
1214def import_backend (onnx_backend_module ):
@@ -24,17 +26,90 @@ def import_backend(onnx_backend_module):
2426 return backend
2527
2628
29+ def _device_test_name (test_name , device ):
30+ """Build the unittest-style test name for a specific device."""
31+ return f"{ test_name } _{ device .lower ()} "
32+
33+
34+ def _guard_duplicate_test (test_items , category , device_test_name ):
35+ """Reject duplicate test registrations from the ONNX runner."""
36+ if device_test_name in test_items [category ]:
37+ raise ValueError (
38+ f'Duplicated test name "{ device_test_name } " in category "{ category } "'
39+ )
40+
41+
42+ def _wrap_device_test (self , test_func , device , device_test_name , kwargs ):
43+ """Wrap a generated ONNX backend test with scoreboard-specific skip handling."""
44+
45+ @unittest .skipIf (
46+ not self .backend .supports_device (device ),
47+ f"Backend doesn't support device { device } " ,
48+ )
49+ @functools .wraps (test_func )
50+ def device_test_func (* args , ** device_test_kwarg ):
51+ try :
52+ merged_kwargs = {** kwargs , ** device_test_kwarg }
53+ return test_func (* args , device , ** merged_kwargs )
54+ except onnx_test_runner .BackendIsNotSupposedToImplementIt as err :
55+ # Surface backend opt-outs as real pytest skips so they end up
56+ # in report.json/trend.json under "skipped" instead of "passed".
57+ raise unittest .SkipTest (
58+ f"{ device_test_name } skipped by backend code: { err } "
59+ ) from err
60+
61+ return device_test_func
62+
63+
64+ def _add_test_hardened (
65+ self ,
66+ category ,
67+ test_name ,
68+ test_func ,
69+ report_item ,
70+ devices = ("CPU" , "CUDA" ),
71+ ** kwargs ,
72+ ):
73+ """Register per-device ONNX tests while preserving scoreboard skip semantics."""
74+ if not test_name .startswith ("test_" ):
75+ raise ValueError (f"Test name must start with test_: { test_name } " )
76+
77+ for device in devices :
78+ device_test_name = _device_test_name (test_name , device )
79+ _guard_duplicate_test (self ._test_items , category , device_test_name )
80+ device_test_func = _wrap_device_test (
81+ self , test_func , device , device_test_name , kwargs
82+ )
83+ self ._test_items [category ][device_test_name ] = onnx_test_runner .TestItem (
84+ device_test_func , report_item
85+ )
86+
87+
88+ def harden_backend_test_skips ():
89+ """Treat backend opt-out exceptions as explicit skips in pytest stats."""
90+ if getattr (onnx_test_runner .Runner , "_scoreboard_hardened" , False ):
91+ return
92+
93+ onnx_test_runner .Runner ._add_test = _add_test_hardened
94+ onnx_test_runner .Runner ._scoreboard_hardened = True
95+
96+
2797# Import custom backend
2898backend = import_backend (os .getenv ("ONNX_BACKEND_MODULE" ))
2999
30100# Set backend device name to be used
31101backend .backend_name = "CPU"
32102
103+ # Patch the ONNX runner before tests are materialized so backend opt-outs are
104+ # reported as skipped in report.json/trend.json.
105+ harden_backend_test_skips ()
106+
33107# This is a pytest variable to load extra plugins
34108# Enable the ONNX compatibility report
35109pytest_plugins = "onnx.backend.test.report"
36110
37- # Import all test cases at global scope to make them visible to python.unittest
111+ # Materialize ONNX-generated unittest cases at module scope so pytest can
112+ # discover and execute them normally.
38113backend_test = onnx .backend .test .BackendTest (backend , __name__ )
39114globals ().update (backend_test .enable_report ().test_cases )
40115
0 commit comments