Skip to content
366 changes: 11 additions & 355 deletions cuda_core/cuda/core/_utils/driver_cu_result_explanations.py

Large diffs are not rendered by default.

350 changes: 350 additions & 0 deletions cuda_core/cuda/core/_utils/driver_cu_result_explanations_frozen.py

Large diffs are not rendered by default.

130 changes: 130 additions & 0 deletions cuda_core/cuda/core/_utils/enum_explanations_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE

"""Internal support for error-enum explanations.

``cuda_core`` keeps frozen 13.1.1 fallback tables for older ``cuda-bindings``
releases. Driver/runtime error enums carry usable ``__doc__`` text starting in
the 12.x backport line at ``cuda-bindings`` 12.9.6, and in the mainline 13.x
series at ``cuda-bindings`` 13.2.0. This module decides which source to use
and normalizes generated docstrings so user-facing ``CUDAError`` messages stay
presentable.

The cleanup rules here were derived while validating generated enum docstrings
in PR #1805. Keep them narrow and remove them when codegen quirks or fallback
support are no longer needed.
"""

from __future__ import annotations

import importlib.metadata
import re
from collections.abc import Callable
from typing import Any

_MIN_12X_BINDING_VERSION_FOR_ENUM_DOCSTRINGS = (12, 9, 6)
_MIN_13X_BINDING_VERSION_FOR_ENUM_DOCSTRINGS = (13, 2, 0)
_RST_INLINE_ROLE_RE = re.compile(r":(?:[a-z]+:)?[a-z]+:`([^`]+)`")
_WORDWRAP_HYPHEN_AFTER_RE = re.compile(r"(?<=[0-9A-Za-z_])- (?=[0-9A-Za-z_])")
_WORDWRAP_HYPHEN_BEFORE_RE = re.compile(r"(?<=[0-9A-Za-z_]) -(?=[0-9A-Za-z_])")
_ExplanationTable = dict[int, str | tuple[str, ...]]
_ExplanationTableLoader = Callable[[], _ExplanationTable]


# ``version.pyx`` cannot be reused here (circular import via ``cuda_utils``).
def _binding_version() -> tuple[int, int, int]:
"""Return the installed ``cuda-bindings`` version, or a conservative old value."""
try:
parts = importlib.metadata.version("cuda-bindings").split(".")[:3]
except importlib.metadata.PackageNotFoundError:
return (0, 0, 0) # For very old versions of cuda-python
return tuple(int(v) for v in parts)


def _binding_version_has_usable_enum_docstrings(version: tuple[int, int, int]) -> bool:
"""Whether released bindings are known to carry usable error-enum ``__doc__`` text."""
return (
_MIN_12X_BINDING_VERSION_FOR_ENUM_DOCSTRINGS <= version < (13, 0, 0)
or version >= _MIN_13X_BINDING_VERSION_FOR_ENUM_DOCSTRINGS
)


def _fix_hyphenation_wordwrap_spacing(s: str) -> str:
"""Remove spaces around hyphens introduced by line wrapping in generated ``__doc__`` text.

This targets asymmetric wrap artifacts such as ``non- linear`` or
``GPU- Direct`` while leaving intentional ``a - b`` separators alone.
"""
prev = None
while prev != s:
prev = s
s = _WORDWRAP_HYPHEN_AFTER_RE.sub("-", s)
s = _WORDWRAP_HYPHEN_BEFORE_RE.sub("-", s)
return s


def clean_enum_member_docstring(doc: str | None) -> str | None:
"""Turn an enum member ``__doc__`` into plain text.

The generated enum docstrings are already close to user-facing prose, but
they may contain Sphinx inline roles, line wrapping, or a small known
codegen defect. Normalize only those differences so the text is suitable
for error messages.
"""
if doc is None:
return None
s = doc
# Known codegen bug on cudaErrorIncompatibleDriverContext. Remove once fixed
# in cuda-bindings code generation.
s = s.replace("\n:py:obj:`~.Interactions`", ' "Interactions ')
# Drop a leading "~." or "." after removing the surrounding RST inline role.
s = _RST_INLINE_ROLE_RE.sub(lambda m: re.sub(r"^~?\.", "", m.group(1)), s)
# Strip simple bold emphasis markers.
s = re.sub(r"\*\*([^*]+)\*\*", r"\1", s)
# Strip simple italic emphasis markers.
s = re.sub(r"\*([^*]+)\*", r"\1", s)
# Collapse wrapped lines and repeated spaces.
s = re.sub(r"\s+", " ", s).strip()
s = _fix_hyphenation_wordwrap_spacing(s)
return s
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems really brittle, but I guess I don't see a way around it. I would prefer to just depend on rst2txt or something, that but seems unmaintained.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed offline: what we have here is sufficiently simple, extensively unit tested, and in the worst case we have a cosmetic issue (unwanted sphinx markup in the error messages).

To address the "brittle" concern, I added commit 27aae00

For easy reference, copy-pasting from the commit message:

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.

I believe in combination with the rest of the extensive unit tests, there is very little wiggle room for major issues to go undetected.



class DocstringBackedExplanations:
"""Compatibility shim exposing enum-member ``__doc__`` text via ``dict.get``.

Keeps the existing ``.get(int(error))`` lookup shape used by ``cuda_utils.pyx``.
"""

__slots__ = ("_enum_type",)

def __init__(self, enum_type: Any) -> None:
self._enum_type = enum_type

def get(self, code: int, default: str | None = None) -> str | None:
try:
member = self._enum_type(code)
except ValueError:
return default

raw_doc = member.__doc__
if raw_doc is None:
return default

return clean_enum_member_docstring(raw_doc)


def get_best_available_explanations(
enum_type: Any,
fallback: _ExplanationTable | _ExplanationTableLoader,
) -> DocstringBackedExplanations | _ExplanationTable:
"""Pick one explanation source per bindings version.

Use enum-member ``__doc__`` only for bindings versions known to expose
usable per-member text (12.9.6+ in the 12.x backport line, 13.2.0+ in the
13.x mainline). Otherwise keep using the frozen 13.1.1 fallback tables.
"""
if not _binding_version_has_usable_enum_docstrings(_binding_version()):
if callable(fallback):
return fallback()
return fallback
return DocstringBackedExplanations(enum_type)
Loading
Loading