Coverage for src / tracekit / core / debug.py: 95%

67 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-11 23:04 +0000

1"""Debug mode and verbosity control infrastructure. 

2 

3This module provides programmatic debug mode control with multiple 

4verbosity levels for troubleshooting and diagnostics. 

5 

6 

7Example: 

8 >>> from tracekit.core.debug import enable_debug, is_debug_enabled, debug_context 

9 >>> enable_debug(level='verbose') 

10 >>> if is_debug_enabled(): 

11 ... logger.debug("Extra diagnostic information") 

12 >>> with debug_context(level='trace'): 

13 ... # Temporarily increase verbosity 

14 ... analyze_complex_signal() 

15 

16References: 

17 - Debugging and diagnostic best practices 

18 - Python logging levels integration 

19""" 

20 

21from __future__ import annotations 

22 

23import contextvars 

24import logging 

25import os 

26from enum import IntEnum 

27from typing import Any, Literal 

28 

29# Context variable for debug state 

30_debug_level: contextvars.ContextVar[int] = contextvars.ContextVar("debug_level", default=0) 

31 

32 

33class DebugLevel(IntEnum): 

34 """Debug verbosity levels. 

35 

36 Levels: 

37 DISABLED: No debug output (0) 

38 MINIMAL: Basic debug info (1) 

39 NORMAL: Standard debug info (2) 

40 VERBOSE: Detailed debug info (3) 

41 TRACE: Very detailed trace info (4) 

42 

43 References: 

44 LOG-007: Programmatic Debug Mode 

45 """ 

46 

47 DISABLED = 0 

48 MINIMAL = 1 

49 NORMAL = 2 

50 VERBOSE = 3 

51 TRACE = 4 

52 

53 

54# String to enum mapping 

55_LEVEL_MAP: dict[str, DebugLevel] = { 

56 "disabled": DebugLevel.DISABLED, 

57 "minimal": DebugLevel.MINIMAL, 

58 "normal": DebugLevel.NORMAL, 

59 "verbose": DebugLevel.VERBOSE, 

60 "trace": DebugLevel.TRACE, 

61} 

62 

63 

64def enable_debug( 

65 level: Literal["minimal", "normal", "verbose", "trace"] = "normal", 

66) -> None: 

67 """Enable debug mode with specified verbosity level. 

68 

69 Sets the global debug level and adjusts logging configuration 

70 accordingly. Higher levels include all output from lower levels. 

71 

72 Args: 

73 level: Debug verbosity level. 

74 

75 Example: 

76 >>> enable_debug(level='verbose') 

77 >>> # Now all debug logging at verbose level is active 

78 

79 >>> enable_debug(level='trace') 

80 >>> # Extremely detailed trace logging 

81 

82 References: 

83 LOG-007: Programmatic Debug Mode 

84 """ 

85 debug_level = _LEVEL_MAP[level] 

86 _debug_level.set(debug_level) 

87 

88 # Adjust logging level based on debug level 

89 from tracekit.core.logging import set_log_level 

90 

91 if debug_level == DebugLevel.TRACE: 

92 set_log_level("DEBUG") # Most verbose 

93 elif debug_level >= DebugLevel.NORMAL: 

94 set_log_level("DEBUG") 

95 elif debug_level == DebugLevel.MINIMAL: 95 ↛ 98line 95 didn't jump to line 98 because the condition on line 95 was always true

96 set_log_level("INFO") 

97 else: 

98 set_log_level("WARNING") 

99 

100 

101def disable_debug() -> None: 

102 """Disable debug mode. 

103 

104 Resets debug level to DISABLED and sets logging to WARNING. 

105 

106 Example: 

107 >>> disable_debug() 

108 >>> # Debug output is now suppressed 

109 

110 References: 

111 LOG-007: Programmatic Debug Mode 

112 """ 

113 _debug_level.set(DebugLevel.DISABLED) 

114 

115 from tracekit.core.logging import set_log_level 

116 

117 set_log_level("WARNING") 

118 

119 

120def is_debug_enabled(min_level: DebugLevel = DebugLevel.MINIMAL) -> bool: 

121 """Check if debug mode is enabled at or above the specified level. 

122 

123 Args: 

124 min_level: Minimum debug level to check for. 

125 

126 Returns: 

127 True if debug is enabled at or above min_level. 

128 

129 Example: 

130 >>> enable_debug(level='verbose') 

131 >>> is_debug_enabled() 

132 True 

133 >>> is_debug_enabled(DebugLevel.TRACE) 

134 False 

135 

136 References: 

137 LOG-007: Programmatic Debug Mode 

138 """ 

139 current = _debug_level.get() 

140 return current >= min_level 

141 

142 

143def get_debug_level() -> DebugLevel: 

144 """Get the current debug level. 

145 

146 Returns: 

147 Current debug level enum value. 

148 

149 Example: 

150 >>> level = get_debug_level() 

151 >>> if level >= DebugLevel.VERBOSE: 

152 ... print("Verbose debugging enabled") 

153 

154 References: 

155 LOG-007: Programmatic Debug Mode 

156 """ 

157 return DebugLevel(_debug_level.get()) 

158 

159 

160class debug_context: 

161 """Context manager for temporary debug level changes. 

162 

163 Temporarily sets a debug level for the duration of a code block, 

164 then restores the previous level. 

165 

166 Args: 

167 level: Debug level to set within the context. 

168 

169 Example: 

170 >>> # Normal debug level 

171 >>> with debug_context(level='trace'): 

172 ... # Temporarily enable trace-level debugging 

173 ... analyze_signal(complex_data) 

174 >>> # Back to normal debug level 

175 

176 References: 

177 LOG-007: Programmatic Debug Mode 

178 """ 

179 

180 def __init__( 

181 self, 

182 level: Literal["disabled", "minimal", "normal", "verbose", "trace"], 

183 ): 

184 """Initialize debug context. 

185 

186 Args: 

187 level: Debug level to set within the context. 

188 """ 

189 self.level = _LEVEL_MAP[level] 

190 self.token: contextvars.Token | None = None # type: ignore[type-arg] 

191 self.previous_log_level: str | None = None 

192 

193 def __enter__(self) -> debug_context: 

194 """Enter the debug context and set new level.""" 

195 # Save current debug level 

196 self.token = _debug_level.set(self.level) 

197 

198 # Adjust logging 

199 from tracekit.core.logging import get_logger 

200 

201 root_logger = get_logger("tracekit") 

202 self.previous_log_level = logging.getLevelName(root_logger.level) 

203 

204 # Set appropriate log level for debug level 

205 from tracekit.core.logging import set_log_level 

206 

207 if self.level in (DebugLevel.TRACE, DebugLevel.VERBOSE, DebugLevel.NORMAL): 

208 set_log_level("DEBUG") 

209 elif self.level == DebugLevel.MINIMAL: 

210 set_log_level("INFO") 

211 else: 

212 set_log_level("WARNING") 

213 

214 return self 

215 

216 def __exit__(self, *args: Any) -> None: 

217 """Exit the debug context and restore previous level.""" 

218 # Restore debug level 

219 if self.token: 219 ↛ 223line 219 didn't jump to line 223 because the condition on line 219 was always true

220 _debug_level.reset(self.token) 

221 

222 # Restore logging level 

223 if self.previous_log_level: 223 ↛ exitline 223 didn't return from function '__exit__' because the condition on line 223 was always true

224 from tracekit.core.logging import set_log_level 

225 

226 set_log_level(self.previous_log_level) 

227 

228 

229def should_log_debug(min_level: DebugLevel = DebugLevel.NORMAL) -> bool: 

230 """Check if debug logging should occur at specified level. 

231 

232 Helper function for conditional debug logging. 

233 

234 Args: 

235 min_level: Minimum level required for logging. 

236 

237 Returns: 

238 True if current debug level meets or exceeds min_level. 

239 

240 Example: 

241 >>> if should_log_debug(DebugLevel.VERBOSE): 

242 ... logger.debug("Detailed diagnostic: %s", expensive_computation()) 

243 

244 References: 

245 LOG-007: Programmatic Debug Mode 

246 """ 

247 return is_debug_enabled(min_level) 

248 

249 

250def configure_debug_from_env() -> None: 

251 """Configure debug mode from environment variables. 

252 

253 Reads TRACEKIT_DEBUG environment variable and sets debug level 

254 accordingly. 

255 

256 Environment Variables: 

257 TRACEKIT_DEBUG: Debug level (minimal, normal, verbose, trace) 

258 

259 Example: 

260 >>> import os 

261 >>> os.environ['TRACEKIT_DEBUG'] = 'verbose' 

262 >>> configure_debug_from_env() 

263 

264 References: 

265 LOG-007: Programmatic Debug Mode 

266 """ 

267 debug_env = os.environ.get("TRACEKIT_DEBUG", "").lower() 

268 if debug_env in _LEVEL_MAP: 

269 enable_debug(level=debug_env) # type: ignore[arg-type] 

270 

271 

272def debug_log( 

273 logger: logging.Logger, 

274 message: str, 

275 min_level: DebugLevel = DebugLevel.NORMAL, 

276 **kwargs: Any, 

277) -> None: 

278 """Conditionally log debug message based on debug level. 

279 

280 Only logs if current debug level meets or exceeds min_level. 

281 

282 Args: 

283 logger: Logger to use for output. 

284 message: Message to log. 

285 min_level: Minimum debug level required. 

286 **kwargs: Additional keyword arguments for logger. 

287 

288 Example: 

289 >>> from tracekit.core.logging import get_logger 

290 >>> logger = get_logger(__name__) 

291 >>> debug_log(logger, "Processing FFT", DebugLevel.VERBOSE, samples=1000) 

292 

293 References: 

294 LOG-007: Programmatic Debug Mode 

295 """ 

296 if is_debug_enabled(min_level): 

297 logger.debug(message, **kwargs) 

298 

299 

300# Auto-configure from environment on import 

301configure_debug_from_env()