Coverage for src/config_utils.py: 100%

21 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-10-16 04:41 +0000

1"""Configuration utility functions for reusable config operations. 

2 

3This module provides low-level utilities for configuration traversal and retrieval, 

4separated from business logic to follow Single Responsibility Principle. 

5""" 

6 

7__author__ = "Mandar Patil (mandarons@pm.me)" 

8 

9from typing import Any 

10 

11 

12def config_path_to_string(config_path: list[str]) -> str: 

13 """Build config path as string for display purposes. 

14 

15 Args: 

16 config_path: List of config keys forming a path (e.g., ["app", "credentials", "username"]) 

17 

18 Returns: 

19 String representation of the config path (e.g., "app > credentials > username") 

20 """ 

21 return " > ".join(config_path) 

22 

23 

24def traverse_config_path(config: dict, config_path: list[str]) -> bool: 

25 """Traverse and validate existence of a config path. 

26 

27 Recursively checks if a path exists in the configuration dictionary. 

28 Does not retrieve values, only validates path existence. 

29 

30 Args: 

31 config: Configuration dictionary to traverse 

32 config_path: List of keys forming the path to check 

33 

34 Returns: 

35 True if path exists and is valid, False otherwise 

36 """ 

37 if len(config_path) == 0: 

38 return True 

39 if not (config and config_path[0] in config): 

40 return False 

41 return traverse_config_path(config[config_path[0]], config_path=config_path[1:]) 

42 

43 

44def get_config_value(config: dict, config_path: list[str]) -> Any: 

45 """Retrieve value from config using a path. 

46 

47 Recursively navigates the configuration dictionary to retrieve a value. 

48 Should only be called after validating path existence with traverse_config_path(). 

49 

50 Args: 

51 config: Configuration dictionary 

52 config_path: List of keys forming the path to the value 

53 

54 Returns: 

55 The configuration value at the specified path 

56 

57 Raises: 

58 KeyError: If the path doesn't exist (should be prevented by prior validation) 

59 """ 

60 if len(config_path) == 1: 

61 return config[config_path[0]] 

62 return get_config_value(config=config[config_path[0]], config_path=config_path[1:]) 

63 

64 

65def get_config_value_or_none(config: dict, config_path: list[str]) -> Any | None: 

66 """Safely retrieve config value or return None if path doesn't exist. 

67 

68 Combines path validation and value retrieval for cases where None is acceptable. 

69 

70 Args: 

71 config: Configuration dictionary 

72 config_path: List of keys forming the path to the value 

73 

74 Returns: 

75 The configuration value if path exists, None otherwise 

76 """ 

77 if not traverse_config_path(config=config, config_path=config_path): 

78 return None 

79 return get_config_value(config=config, config_path=config_path) 

80 

81 

82def get_config_value_or_default(config: dict, config_path: list[str], default: Any) -> Any: 

83 """Retrieve config value or return default if path doesn't exist. 

84 

85 Args: 

86 config: Configuration dictionary 

87 config_path: List of keys forming the path to the value 

88 default: Default value to return if path doesn't exist 

89 

90 Returns: 

91 The configuration value if path exists, default otherwise 

92 """ 

93 value = get_config_value_or_none(config=config, config_path=config_path) 

94 return value if value is not None else default