Coverage for /Users/buh/.pyenv/versions/3.12.9/envs/es-testbed/lib/python3.12/site-packages/es_testbed/debug.py: 100%

21 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-04-21 20:56 -0600

1"""Module for tiered debugging with a global TieredDebug instance. 

2 

3Provides a global `TieredDebug` instance and a `begin_end` decorator to 

4log function entry and exit at specified debug levels. Designed for use 

5in projects like ElasticKeeper and ElasticCheckpoint to trace function 

6execution with configurable stack levels. 

7 

8Examples: 

9 >>> from tiered_debug.debug import debug, begin_end 

10 >>> debug.level = 3 

11 >>> import logging 

12 >>> debug.add_handler(logging.StreamHandler()) 

13 >>> @begin_end(debug, begin=2, end=3, stacklevel=2, extra={"func": "test"}) 

14 ... def example(): 

15 ... return "Test" 

16 >>> example() 

17 'Test' 

18""" 

19 

20from functools import wraps 

21from typing import Any, Dict, Optional 

22 

23from tiered_debug import TieredDebug 

24 

25DEFAULT_BEGIN = 2 

26"""Default debug level for BEGIN messages.""" 

27 

28DEFAULT_END = 3 

29"""Default debug level for END messages.""" 

30 

31debug = TieredDebug(level=1, stacklevel=3) 

32"""Global TieredDebug instance with default level 1 and stacklevel 3.""" 

33 

34 

35def begin_end( 

36 debug_obj: Optional[TieredDebug] = None, 

37 begin: int = DEFAULT_BEGIN, 

38 end: int = DEFAULT_END, 

39 stacklevel: int = 2, 

40 extra: Optional[Dict[str, Any]] = None, 

41): 

42 """Decorator to log function entry and exit at specified debug levels. 

43 

44 Logs "BEGIN CALL" at the `begin` level and "END CALL" at the `end` 

45 level using the provided or global debug instance. Adjusts the 

46 stacklevel by 1 to report the correct caller. 

47 

48 Args: 

49 debug_obj: TieredDebug instance to use (default: global debug). 

50 begin: Debug level for BEGIN message (1-5, default 2). (int) 

51 end: Debug level for END message (1-5, default 3). (int) 

52 stacklevel: Stack level for reporting (1-9, default 2). (int) 

53 extra: Extra metadata dictionary (default None). (Dict[str, Any]) 

54 

55 Returns: 

56 Callable: Decorated function with logging. 

57 

58 Examples: 

59 >>> debug.level = 3 

60 >>> import logging 

61 >>> debug.add_handler(logging.StreamHandler()) 

62 >>> @begin_end(debug, begin=2, end=3) 

63 ... def test_func(): 

64 ... return "Result" 

65 >>> test_func() 

66 'Result' 

67 """ 

68 debug_instance = debug_obj if debug_obj is not None else debug 

69 

70 def decorator(func): 

71 @wraps(func) 

72 def wrapper(*args, **kwargs): 

73 effective_stacklevel = stacklevel + 1 

74 debug_instance.log( 

75 begin, 

76 f"BEGIN CALL: {func.__name__}()", 

77 stacklevel=effective_stacklevel, 

78 extra=extra, 

79 ) 

80 result = func(*args, **kwargs) 

81 debug_instance.log( 

82 end, 

83 f"END CALL: {func.__name__}()", 

84 stacklevel=effective_stacklevel, 

85 extra=extra, 

86 ) 

87 return result 

88 

89 return wrapper 

90 

91 return decorator