Coverage for backend/pinch_service/OpenPinch/src/utils/decorators.py: 72%

35 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-11-06 23:27 +0000

1import logging 

2from time import perf_counter as timer 

3from functools import wraps 

4import atexit 

5from collections import defaultdict 

6from ..lib import config 

7 

8# Configure logging to both console and file 

9logging.basicConfig( 

10 level=logging.INFO, 

11 format='%(asctime)s - %(levelname)s - %(message)s', 

12 handlers=[ 

13 logging.FileHandler("timing.log"), 

14 logging.StreamHandler() 

15 ] 

16) 

17 

18logger = logging.getLogger(__name__) 

19 

20_function_stats = defaultdict(lambda: {"count": 0, "total_time": 0.0}) 

21 

22def timing_decorator(func=None, *, activate_overide=False): 

23 """ 

24 Decorator to measure execution time and track per-function totals. 

25 Supports both @timing_decorator and @timing_decorator(activate_overide=True) 

26 """ 

27 

28 def decorator(f): 

29 @wraps(f) 

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

31 if not (config.ACTIVATE_TIMING or activate_overide): 31 ↛ 32line 31 didn't jump to line 32 because the condition on line 31 was never true

32 return f(*args, **kwargs) 

33 

34 start_time = timer() 

35 result = f(*args, **kwargs) 

36 end_time = timer() 

37 exec_time = end_time - start_time 

38 

39 stats = _function_stats[f.__name__] 

40 stats["count"] += 1 

41 stats["total_time"] += exec_time 

42 

43 if config.LOG_TIMING: 43 ↛ 44line 43 didn't jump to line 44 because the condition on line 43 was never true

44 logger.info(f"Function '{f.__name__}' executed in {exec_time:.6f} seconds.") 

45 

46 return result 

47 return wrapper 

48 

49 # Handle both @timing_decorator and @timing_decorator(activate_overide=True) 

50 if callable(func): 50 ↛ 52line 50 didn't jump to line 52 because the condition on line 50 was always true

51 return decorator(func) 

52 return decorator 

53 

54@atexit.register 

55def print_summary(): 

56 logger.info("==== Execution Time Summary ====") 

57 for func_name, stats in _function_stats.items(): 

58 avg_time = stats["total_time"] / stats["count"] 

59 logger.info( 

60 f"{func_name}: {stats['count']} calls, " 

61 f"total {stats['total_time']:.6f}s, " 

62 f"average {avg_time:.6f}s" 

63 )