Coverage for src/local_deep_research/settings/env_registry.py: 100%

42 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-06-03 23:15 +0000

1""" 

2Registry of all environment-only settings. 

3 

4This module creates the global registry and registers all environment settings 

5defined in the env_definitions subfolder. 

6""" 

7 

8from typing import Optional, Any 

9 

10from .env_settings import SettingsRegistry 

11from .env_definitions import ALL_SETTINGS 

12 

13 

14def _create_registry() -> SettingsRegistry: 

15 """Create and initialize the global registry with all defined settings.""" 

16 registry = SettingsRegistry() 

17 

18 # Register all setting categories 

19 for category_name, settings_list in ALL_SETTINGS.items(): 

20 registry.register_category(category_name, settings_list) 

21 

22 return registry 

23 

24 

25# Global registry instance (singleton) 

26registry = _create_registry() 

27 

28 

29# Convenience functions for direct access 

30def get_env_setting(key: str, default: Optional[Any] = None) -> Any: 

31 """ 

32 Get an environment setting value. 

33 

34 Args: 

35 key: Setting key (e.g., "testing.test_mode") 

36 default: Default value if not set 

37 

38 Returns: 

39 Setting value or default 

40 """ 

41 return registry.get(key, default) 

42 

43 

44def is_test_mode() -> bool: 

45 """Quick check for test mode.""" 

46 return bool(registry.get("testing.test_mode", False)) 

47 

48 

49def is_ci_environment() -> bool: 

50 """Quick check for CI environment.""" 

51 # CI is now an external variable, read it dynamically 

52 import os 

53 

54 return os.environ.get("CI", "false").lower() in ("true", "1", "yes") 

55 

56 

57def is_github_actions() -> bool: 

58 """Check if running in GitHub Actions.""" 

59 # GITHUB_ACTIONS is now an external variable, read it dynamically 

60 import os 

61 

62 return os.environ.get("GITHUB_ACTIONS", "false").lower() in ( 

63 "true", 

64 "1", 

65 "yes", 

66 ) 

67 

68 

69# Module-level flag so the deprecation warning fires at most once per process. 

70_legacy_disable_warned = False 

71 

72 

73def _reset_legacy_warning_flag_for_tests() -> None: 

74 """Test seam: reset the module-level deprecation-warning flag. 

75 

76 Tests that exercise the legacy `DISABLE_RATE_LIMITING` form 

77 multiple times need to verify the warning fires once per process, 

78 not once per call. Reload-based tests should also call this. 

79 """ 

80 global _legacy_disable_warned 

81 _legacy_disable_warned = False 

82 

83 

84def is_rate_limiting_enabled() -> bool: 

85 """ 

86 Check if HTTP rate limiting (Flask-Limiter) should be enabled. 

87 

88 Returns: 

89 True if rate limiting should be enabled, False otherwise 

90 

91 Logic: 

92 - Canonical: ``LDR_DISABLE_RATE_LIMITING=true`` disables rate limiting 

93 - Legacy: ``DISABLE_RATE_LIMITING=true`` (no LDR_ prefix) is still 

94 honored for backward compatibility, but emits a one-shot deprecation 

95 warning. Operators should migrate to the canonical name. 

96 - Otherwise, rate limiting is enabled (default). 

97 

98 Name-collision warning: 

99 ``LDR_RATE_LIMITING_ENABLED`` (without DISABLE_) is a DIFFERENT 

100 env var that controls the *adaptive search-engine* rate limiter 

101 (see ``rate_limiting.enabled`` setting and 

102 ``web_search_engines/rate_limiting/tracker.py``). It does NOT affect 

103 the Flask HTTP rate limiter governed by this function. Operators 

104 routinely confuse the two — see issue #3905. 

105 

106 Note: 

107 This function intentionally does NOT check the CI environment. 

108 Rate-limiting control should be explicit via the dedicated flag. 

109 """ 

110 import os 

111 from loguru import logger 

112 

113 # Canonical form takes absolute precedence when set to any value. 

114 # An explicit `LDR_DISABLE_RATE_LIMITING=false` should override a stale 

115 # legacy `DISABLE_RATE_LIMITING=true` from another tool's environment. 

116 canonical_raw = os.environ.get("LDR_DISABLE_RATE_LIMITING") 

117 if canonical_raw is not None and canonical_raw != "": 

118 if canonical_raw.lower() in ("true", "1", "yes"): 

119 logger.debug( 

120 "Rate limiting DISABLED due to LDR_DISABLE_RATE_LIMITING=true" 

121 ) 

122 return False 

123 logger.debug( 

124 "Rate limiting ENABLED (LDR_DISABLE_RATE_LIMITING set non-truthy)" 

125 ) 

126 return True 

127 

128 legacy = os.environ.get("DISABLE_RATE_LIMITING", "").lower() 

129 if legacy in ("true", "1", "yes"): 

130 global _legacy_disable_warned 

131 if not _legacy_disable_warned: 

132 logger.warning( 

133 "DISABLE_RATE_LIMITING is deprecated; use " 

134 "LDR_DISABLE_RATE_LIMITING for consistency with the LDR_ " 

135 "env-var convention. The legacy name still works but will " 

136 "be removed in a future release." 

137 ) 

138 _legacy_disable_warned = True 

139 logger.debug("Rate limiting DISABLED due to DISABLE_RATE_LIMITING=true") 

140 return False 

141 

142 logger.debug("Rate limiting ENABLED (default)") 

143 return True 

144 

145 

146# Export the registry and convenience functions 

147__all__ = [ 

148 "registry", 

149 "get_env_setting", 

150 "is_test_mode", 

151 "is_ci_environment", 

152 "is_github_actions", 

153 "is_rate_limiting_enabled", 

154 "_reset_legacy_warning_flag_for_tests", 

155]