Skip to content

Commit 014f185

Browse files
authored
cuda_core: derive error enum explanations from bindings docstrings (#1860)
* cuda_core: derive error enum explanations from bindings docstrings Use cleaned driver/runtime enum __doc__ text from cuda-bindings 13.2.0+ as the primary source for CUDA error explanations in cuda_core, while freezing the 13.1.1 explanation tables as fallback for older bindings. Centralize the version-gated selection and docstring cleanup helpers, update the driver/runtime explanation modules to use them, add tests that verify representative enums expose __doc__ and that cuda_utils attaches the explanation text, and remove the obsolete enum-reformat toolshed helper script. Made-with: Cursor * cuda_core: recognize 12.9.6 enum docstrings Treat the 12.9.6 backport line as docstring-capable and reuse the same version predicate in tests so error explanations follow the bindings releases that already expose usable enum docs. Made-with: Cursor * cuda_core: drop unused enum doc cleanup helper Remove the old Doxygen ``::`` normalization path now that error explanations no longer depend on dict-vs-docstring parity checks. This keeps the helper focused on the cleanup rules that still affect user-facing CUDAError messages. Made-with: Cursor * cuda_core: clarify enum explanation helper docs Clarify that DocstringBackedExplanations is a compatibility shim for the existing ``.get(int(error))`` lookup shape, and trim a low-value implementation note from the docstring cleanup workaround comment. Made-with: Cursor * cuda_core: trim enum explanation helper tests Remove redundant helper coverage now that DocstringBackedExplanations.get() and clean_enum_member_docstring() are already exercised elsewhere, and simplify the remaining test module imports. Made-with: Cursor * cuda_core: generalize enum doc cleanup regexes Broaden the inline-role cleanup to accept generic RST roles and widen the word-wrap hyphen fix beyond lowercase-only cases. Keep the current 13.2.x output unchanged while expanding unit coverage for the newly supported forms. Made-with: Cursor * cuda_core: document inline enum cleanup regexes Add terse comments for the remaining inline regex substitutions so the docstring cleanup steps are easier to follow without changing behavior. Made-with: Cursor * cuda_core: lazily import frozen enum explanation tables Keep cuda_utils.pyx unchanged while moving the large 13.1.1 explanation tables into frozen-only modules that are imported only for older bindings. Use loader-aware selection in enum_explanations_helpers.py and add tests that prove docstring-capable bindings skip the frozen-module imports. Made-with: Cursor * cuda_core: pin cleanup-sensitive enum doc examples Add a small set of real enum-doc cleanup examples that assert today's exact cleaned output for representative live bindings cases. Mark unexpected drift as xfail so future upstream doc changes trigger manual review without causing a hard test failure. Made-with: Cursor
1 parent 1696fcf commit 014f185

8 files changed

+1334
-1045
lines changed

cuda_core/cuda/core/_utils/driver_cu_result_explanations.py

Lines changed: 11 additions & 355 deletions
Large diffs are not rendered by default.

cuda_core/cuda/core/_utils/driver_cu_result_explanations_frozen.py

Lines changed: 350 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE
3+
4+
"""Internal support for error-enum explanations.
5+
6+
``cuda_core`` keeps frozen 13.1.1 fallback tables for older ``cuda-bindings``
7+
releases. Driver/runtime error enums carry usable ``__doc__`` text starting in
8+
the 12.x backport line at ``cuda-bindings`` 12.9.6, and in the mainline 13.x
9+
series at ``cuda-bindings`` 13.2.0. This module decides which source to use
10+
and normalizes generated docstrings so user-facing ``CUDAError`` messages stay
11+
presentable.
12+
13+
The cleanup rules here were derived while validating generated enum docstrings
14+
in PR #1805. Keep them narrow and remove them when codegen quirks or fallback
15+
support are no longer needed.
16+
"""
17+
18+
from __future__ import annotations
19+
20+
import importlib.metadata
21+
import re
22+
from collections.abc import Callable
23+
from typing import Any
24+
25+
_MIN_12X_BINDING_VERSION_FOR_ENUM_DOCSTRINGS = (12, 9, 6)
26+
_MIN_13X_BINDING_VERSION_FOR_ENUM_DOCSTRINGS = (13, 2, 0)
27+
_RST_INLINE_ROLE_RE = re.compile(r":(?:[a-z]+:)?[a-z]+:`([^`]+)`")
28+
_WORDWRAP_HYPHEN_AFTER_RE = re.compile(r"(?<=[0-9A-Za-z_])- (?=[0-9A-Za-z_])")
29+
_WORDWRAP_HYPHEN_BEFORE_RE = re.compile(r"(?<=[0-9A-Za-z_]) -(?=[0-9A-Za-z_])")
30+
_ExplanationTable = dict[int, str | tuple[str, ...]]
31+
_ExplanationTableLoader = Callable[[], _ExplanationTable]
32+
33+
34+
# ``version.pyx`` cannot be reused here (circular import via ``cuda_utils``).
35+
def _binding_version() -> tuple[int, int, int]:
36+
"""Return the installed ``cuda-bindings`` version, or a conservative old value."""
37+
try:
38+
parts = importlib.metadata.version("cuda-bindings").split(".")[:3]
39+
except importlib.metadata.PackageNotFoundError:
40+
return (0, 0, 0) # For very old versions of cuda-python
41+
return tuple(int(v) for v in parts)
42+
43+
44+
def _binding_version_has_usable_enum_docstrings(version: tuple[int, int, int]) -> bool:
45+
"""Whether released bindings are known to carry usable error-enum ``__doc__`` text."""
46+
return (
47+
_MIN_12X_BINDING_VERSION_FOR_ENUM_DOCSTRINGS <= version < (13, 0, 0)
48+
or version >= _MIN_13X_BINDING_VERSION_FOR_ENUM_DOCSTRINGS
49+
)
50+
51+
52+
def _fix_hyphenation_wordwrap_spacing(s: str) -> str:
53+
"""Remove spaces around hyphens introduced by line wrapping in generated ``__doc__`` text.
54+
55+
This targets asymmetric wrap artifacts such as ``non- linear`` or
56+
``GPU- Direct`` while leaving intentional ``a - b`` separators alone.
57+
"""
58+
prev = None
59+
while prev != s:
60+
prev = s
61+
s = _WORDWRAP_HYPHEN_AFTER_RE.sub("-", s)
62+
s = _WORDWRAP_HYPHEN_BEFORE_RE.sub("-", s)
63+
return s
64+
65+
66+
def clean_enum_member_docstring(doc: str | None) -> str | None:
67+
"""Turn an enum member ``__doc__`` into plain text.
68+
69+
The generated enum docstrings are already close to user-facing prose, but
70+
they may contain Sphinx inline roles, line wrapping, or a small known
71+
codegen defect. Normalize only those differences so the text is suitable
72+
for error messages.
73+
"""
74+
if doc is None:
75+
return None
76+
s = doc
77+
# Known codegen bug on cudaErrorIncompatibleDriverContext. Remove once fixed
78+
# in cuda-bindings code generation.
79+
s = s.replace("\n:py:obj:`~.Interactions`", ' "Interactions ')
80+
# Drop a leading "~." or "." after removing the surrounding RST inline role.
81+
s = _RST_INLINE_ROLE_RE.sub(lambda m: re.sub(r"^~?\.", "", m.group(1)), s)
82+
# Strip simple bold emphasis markers.
83+
s = re.sub(r"\*\*([^*]+)\*\*", r"\1", s)
84+
# Strip simple italic emphasis markers.
85+
s = re.sub(r"\*([^*]+)\*", r"\1", s)
86+
# Collapse wrapped lines and repeated spaces.
87+
s = re.sub(r"\s+", " ", s).strip()
88+
s = _fix_hyphenation_wordwrap_spacing(s)
89+
return s
90+
91+
92+
class DocstringBackedExplanations:
93+
"""Compatibility shim exposing enum-member ``__doc__`` text via ``dict.get``.
94+
95+
Keeps the existing ``.get(int(error))`` lookup shape used by ``cuda_utils.pyx``.
96+
"""
97+
98+
__slots__ = ("_enum_type",)
99+
100+
def __init__(self, enum_type: Any) -> None:
101+
self._enum_type = enum_type
102+
103+
def get(self, code: int, default: str | None = None) -> str | None:
104+
try:
105+
member = self._enum_type(code)
106+
except ValueError:
107+
return default
108+
109+
raw_doc = member.__doc__
110+
if raw_doc is None:
111+
return default
112+
113+
return clean_enum_member_docstring(raw_doc)
114+
115+
116+
def get_best_available_explanations(
117+
enum_type: Any,
118+
fallback: _ExplanationTable | _ExplanationTableLoader,
119+
) -> DocstringBackedExplanations | _ExplanationTable:
120+
"""Pick one explanation source per bindings version.
121+
122+
Use enum-member ``__doc__`` only for bindings versions known to expose
123+
usable per-member text (12.9.6+ in the 12.x backport line, 13.2.0+ in the
124+
13.x mainline). Otherwise keep using the frozen 13.1.1 fallback tables.
125+
"""
126+
if not _binding_version_has_usable_enum_docstrings(_binding_version()):
127+
if callable(fallback):
128+
return fallback()
129+
return fallback
130+
return DocstringBackedExplanations(enum_type)

0 commit comments

Comments
 (0)