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
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-03 23:15 +0000
1"""
2Registry of all environment-only settings.
4This module creates the global registry and registers all environment settings
5defined in the env_definitions subfolder.
6"""
8from typing import Optional, Any
10from .env_settings import SettingsRegistry
11from .env_definitions import ALL_SETTINGS
14def _create_registry() -> SettingsRegistry:
15 """Create and initialize the global registry with all defined settings."""
16 registry = SettingsRegistry()
18 # Register all setting categories
19 for category_name, settings_list in ALL_SETTINGS.items():
20 registry.register_category(category_name, settings_list)
22 return registry
25# Global registry instance (singleton)
26registry = _create_registry()
29# Convenience functions for direct access
30def get_env_setting(key: str, default: Optional[Any] = None) -> Any:
31 """
32 Get an environment setting value.
34 Args:
35 key: Setting key (e.g., "testing.test_mode")
36 default: Default value if not set
38 Returns:
39 Setting value or default
40 """
41 return registry.get(key, default)
44def is_test_mode() -> bool:
45 """Quick check for test mode."""
46 return bool(registry.get("testing.test_mode", False))
49def is_ci_environment() -> bool:
50 """Quick check for CI environment."""
51 # CI is now an external variable, read it dynamically
52 import os
54 return os.environ.get("CI", "false").lower() in ("true", "1", "yes")
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
62 return os.environ.get("GITHUB_ACTIONS", "false").lower() in (
63 "true",
64 "1",
65 "yes",
66 )
69# Module-level flag so the deprecation warning fires at most once per process.
70_legacy_disable_warned = False
73def _reset_legacy_warning_flag_for_tests() -> None:
74 """Test seam: reset the module-level deprecation-warning flag.
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
84def is_rate_limiting_enabled() -> bool:
85 """
86 Check if HTTP rate limiting (Flask-Limiter) should be enabled.
88 Returns:
89 True if rate limiting should be enabled, False otherwise
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).
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.
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
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
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
142 logger.debug("Rate limiting ENABLED (default)")
143 return True
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]