Coverage for cuda/core/_utils/enum_explanations_helpers.py: 96.72%

61 statements  

« prev     ^ index     » next       coverage.py v7.16.0, created at 2026-09-03 02:41 +0000

1# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 

2# SPDX-License-Identifier: Apache-2.0 

3 

4"""Internal support for error-enum explanations. 

5 

6``cuda_core`` keeps frozen 13.1.1 fallback tables for older ``cuda-bindings`` 

7releases. Driver/runtime error enums carry usable ``__doc__`` text starting in 

8the 12.x backport line at ``cuda-bindings`` 12.9.6, and in the mainline 13.x 

9series at ``cuda-bindings`` 13.2.0. This module decides which source to use 

10and normalizes generated docstrings so user-facing ``CUDAError`` messages stay 

11presentable. 

12 

13The cleanup rules here were derived while validating generated enum docstrings 

14in PR #1805. Keep them narrow and remove them when codegen quirks or fallback 

15support are no longer needed. 

16""" 

17 

18from __future__ import annotations 

19 

20import importlib.metadata 

21import re 

22from collections.abc import Callable 

23from 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 

34def _parse_version_triple(version_str: str) -> tuple[int, int, int]: 

35 """Parse a PEP 440 version string into a (major, minor, patch) triple. 

36 

37 Strips local-version identifiers and handles pre-release suffixes such as 

38 ``0b1`` or ``0rc1`` by extracting only the leading integer from each 

39 release segment. 

40 """ 

41 parts = version_str.partition("+")[0].split(".")[:3] 

42 ints = ([int(m.group(1)) if (m := re.match(r"(\d+)", v)) else 0 for v in parts] + [0, 0, 0])[:3] 

43 return (ints[0], ints[1], ints[2]) 

44 

45 

46# ``version.pyx`` cannot be reused here (circular import via ``cuda_utils``). 

47def _binding_version() -> tuple[int, int, int]: 

48 """Return the installed ``cuda-bindings`` version, or a conservative old value.""" 

49 try: 

50 version = importlib.metadata.version("cuda-bindings") 

51 except importlib.metadata.PackageNotFoundError: 

52 return (0, 0, 0) # For very old versions of cuda-python 

53 return _parse_version_triple(version) 

54 

55 

56def _binding_version_has_usable_enum_docstrings(version: tuple[int, int, int]) -> bool: 

57 """Whether released bindings are known to carry usable error-enum ``__doc__`` text.""" 

58 return ( 1a4defg56789!YZ01bc2

59 _MIN_12X_BINDING_VERSION_FOR_ENUM_DOCSTRINGS <= version < (13, 0, 0) 

60 or version >= _MIN_13X_BINDING_VERSION_FOR_ENUM_DOCSTRINGS 

61 ) 

62 

63 

64def _fix_hyphenation_wordwrap_spacing(s: str) -> str: 

65 """Remove spaces around hyphens introduced by line wrapping in generated ``__doc__`` text. 

66 

67 This targets asymmetric wrap artifacts such as ``non- linear`` or 

68 ``GPU- Direct`` while leaving intentional ``a - b`` separators alone. 

69 """ 

70 prev = None 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUVbc

71 while prev != s: 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUVbc

72 prev = s 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUVbc

73 s = _WORDWRAP_HYPHEN_AFTER_RE.sub("-", s) 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUVbc

74 s = _WORDWRAP_HYPHEN_BEFORE_RE.sub("-", s) 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUVbc

75 return s 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUVbc

76 

77 

78def clean_enum_member_docstring(doc: str | None) -> str | None: 

79 """Turn an enum member ``__doc__`` into plain text. 

80 

81 The generated enum docstrings are already close to user-facing prose, but 

82 they may contain Sphinx inline roles, line wrapping, or a small known 

83 codegen defect. Normalize only those differences so the text is suitable 

84 for error messages. 

85 """ 

86 if doc is None: 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUV3bc

87 return None 13

88 s = doc 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUVbc

89 # Known codegen bug on cudaErrorIncompatibleDriverContext. Remove once fixed 

90 # in cuda-bindings code generation. 

91 s = s.replace("\n:py:obj:`~.Interactions`", ' "Interactions ') 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUVbc

92 # Drop a leading "~." or "." after removing the surrounding RST inline role. 

93 s = _RST_INLINE_ROLE_RE.sub(lambda m: re.sub(r"^~?\.", "", m.group(1)), s) 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUVbc

94 # Strip simple bold emphasis markers. 

95 s = re.sub(r"\*\*([^*]+)\*\*", r"\1", s) 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUVbc

96 # Strip simple italic emphasis markers. 

97 s = re.sub(r"\*([^*]+)\*", r"\1", s) 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUVbc

98 # Collapse wrapped lines and repeated spaces. 

99 s = re.sub(r"\s+", " ", s).strip() 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUVbc

100 s = _fix_hyphenation_wordwrap_spacing(s) 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUVbc

101 return s 1ijklmnopqrstuvwxyzAhdefgBCDEFGHIJKLMNOPQRSTUVbc

102 

103 

104class DocstringBackedExplanations: 

105 """Compatibility shim exposing enum-member ``__doc__`` text via ``dict.get``. 

106 

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

108 """ 

109 

110 __slots__ = ("_enum_type",) 

111 

112 def __init__(self, enum_type: Any) -> None: 

113 self._enum_type = enum_type 1aWXYbc2

114 

115 def get(self, code: int, default: str | None = None) -> str | None: 

116 try: 1ijklmnopqrstuvwxyzAhdefgBCDEFWXbc

117 member = self._enum_type(code) 1ijklmnopqrstuvwxyzAhdefgBCDEFWXbc

118 except ValueError: 1X

119 return default 1X

120 

121 raw_doc = member.__doc__ 1ijklmnopqrstuvwxyzAhdefgBCDEFWbc

122 if raw_doc is None: 1ijklmnopqrstuvwxyzAhdefgBCDEFWbc

123 return default 1hW

124 

125 return clean_enum_member_docstring(raw_doc) 1ijklmnopqrstuvwxyzAhdefgBCDEFbc

126 

127 

128def get_best_available_explanations( 

129 enum_type: Any, 

130 fallback: _ExplanationTable | _ExplanationTableLoader, 

131) -> DocstringBackedExplanations | _ExplanationTable: 

132 """Pick one explanation source per bindings version. 

133 

134 Use enum-member ``__doc__`` only for bindings versions known to expose 

135 usable per-member text (12.9.6+ in the 12.x backport line, 13.2.0+ in the 

136 13.x mainline). Otherwise keep using the frozen 13.1.1 fallback tables. 

137 """ 

138 if not _binding_version_has_usable_enum_docstrings(_binding_version()): 1aYZ01bc2

139 if callable(fallback): 1Z01

140 return fallback() 1Z

141 return fallback 101

142 return DocstringBackedExplanations(enum_type) 1aYbc2