You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Address PR #2714 review findings 1-8 and sharpen the test guidance:
* Drop GLException from the GL-unavailable set; restrict the skip catch to context creation so GL allocation errors propagate.
* Recognize Linux GL/EGL ImportError and Windows opengl32 FileNotFoundError/AttributeError as genuine GL-unavailable cases.
* Consolidate the GL availability predicate into cuda_python_test_helpers/graphics.py with focused tests.
* Fix supports_ipc_mempool to inspect the raw CUresult; only CUDA_ERROR_NOT_SUPPORTED means unsupported.
* Fix nvfatbin and NVRTC probes to catch loader/symbol failures (DynamicLibNotFoundError/FunctionNotFoundError), let genuine API errors propagate (2, 3).
* Clean up partial GL resources on setup failure.
* Share the conditional-handle skip helper between helpers/graph_kernels.py and the integration tests.
* Move is_gl_context_unavailable tests to cuda_core/tests/test_helpers.py with provenance markers so CI runs them.
* Update AGENTS.md with the corrected examples and new guidance.
- Search `tests/helpers/` and `cuda_python_test_helpers/` for prior art
87
+
before adding a new helper; consolidate duplicates across
88
+
89
+
packages into `cuda_python_test_helpers` (both `cuda_core` and
90
+
`cuda_bindings` test environments already depend on it).
86
91
- Fixtures in a nested `conftest.py` are available to tests in its directory
87
92
and descendants; fixtures from applicable parent `conftest.py` files remain
88
93
available.
89
94
- Do not add `__init__.py` solely because a test directory contains a
90
95
`conftest.py`.
91
96
- In directories without `__init__.py`, keep test-module basenames unique
92
97
within this test suite.
98
+
99
+
## Skip only real setup failures
100
+
101
+
`pytest.skip(reason)` records the test as SKIPPED with `reason` in the
102
+
report. A helper that wraps `yield` in `except Exception: pytest.skip(...)`
103
+
therefore records every test-body failure as a skip — a real regression, a
104
+
`TypeError`, an `AttributeError` all become "SKIPPED: <reason>" instead of
105
+
"FAILED", and the suite goes green regardless of whether the code under
106
+
test works.
107
+
108
+
Catch only the specific exception that legitimately means "not available",
109
+
and only around the setup call — never around `yield`:
110
+
111
+
```python
112
+
@contextlib.contextmanager
113
+
def_gl_context():
114
+
try:
115
+
win, tex_id = _setup_gl_texture() # setup only
116
+
except (pyglet.NoSuchConfigException, GLContextError) as e:
117
+
pytest.skip(f"GL unavailable: {e}")
118
+
try:
119
+
yield tex_id # body exceptions propagate
120
+
finally:
121
+
_cleanup(win, tex_id)
122
+
```
123
+
124
+
The exception names in the example are illustrative — `GLContextError`
125
+
is not a real pyglet class. Match real pyglet exception names by type, or
126
+
use the shared `is_gl_context_unavailable` helper in
127
+
`cuda_python_test_helpers.graphics`.
128
+
129
+
`GLException` is pyglet's generic GL-error class, raised after any GL call that reports an error
130
+
(`GL_INVALID_ENUM`, etc.). Do **not** include it in the "GL unavailable" set — it hides real bugs in GL allocation code as skips.
131
+
132
+
Platform-specific "library not loadable" manifestations (genuine "GL unavailable"):
133
+
134
+
- Linux without libGL/libEGL: `ImportError('Library "GL" not found.')` / `ImportError('Library "EGL" not found.')` from `pyglet/lib.py`.
135
+
- Windows without opengl32.dll: `FileNotFoundError` from `ctypes.windll.opengl32`; on Python 3.12+ `ctypes.LibraryLoader` re-raises `AttributeError("opengl32")`.
136
+
137
+
When a CUDA call's error means "feature refused by this driver" (e.g.
138
+
`CUDA_ERROR_OPERATING_SYSTEM` for CUDA-GL interop on WSL), skip at the call
139
+
site with a narrow catch on the specific error, not inside the GL helper —
140
+
see `_register_gl_buffer` / `_register_gl_image` in `tests/test_graphics.py`.
141
+
142
+
## `importorskip` is for optional dependencies only
143
+
144
+
`pytest.importorskip("X")` is correct when `X` is genuinely optional
145
+
(platform-gated binding, parametrized "test each available module"). It is
146
+
dead code when `X` is a declared test or runtime dependency: the skip then
147
+
fires only when the environment is broken, which is the case you want to fail
148
+
loudly, not hide. Use a bare top-level `import` for declared deps.
149
+
150
+
Before adding `importorskip`, check `cuda_core/pyproject.toml`'s `test`
151
+
and `test-cu*` groups and `cuda_core`'s `dependencies`. If the target is
152
+
listed, import it directly.
153
+
154
+
## Capability probes must not swallow real bugs
155
+
156
+
A probe function that answers "is feature X available?" by catching
157
+
`Exception` and returning `False` will report "not available" even when the
158
+
probed API failed for a real, unexpected reason — silently enabling a skip
159
+
that hides the bug. Catch only the exception that genuinely means "not
160
+
available", and split the checks so each catch is narrow:
161
+
162
+
```python
163
+
def_is_nvfatbin_available():
164
+
from cuda.bindings._internal.utils import FunctionNotFoundError
165
+
from cuda.pathfinder import DynamicLibNotFoundError
0 commit comments