Skip to content

Commit e803a20

Browse files
committed
refactor(env.py): streamline environment-specific value retrieval
Introduce a helper method `_get_env_specific_value` to reduce code duplication when fetching environment-specific configuration values. This change simplifies the logic in `get_database_url` and `get_bot_token` by centralizing the error handling and key selection process. Additionally, adjust the workspace root determination logic to handle different directory structures, ensuring the correct root path is set in various scenarios. This refactoring enhances code maintainability and readability by reducing redundancy and improving clarity.
1 parent 03e524c commit e803a20

File tree

1 file changed

+52
-31
lines changed

1 file changed

+52
-31
lines changed

tux/utils/env.py

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ def __init__(self, dotenv_path: Path | None = None, load_env: bool = True):
5959
"""
6060
# Core paths
6161
self.workspace_root = Path(__file__).parent.parent.parent
62+
if self.workspace_root.name == "tux":
63+
# If we're in the tux package, this is the workspace root
64+
pass
65+
elif self.workspace_root.parent.name == "tux":
66+
# If we're in tests/tux, go up one more level
67+
self.workspace_root = self.workspace_root.parent
6268
self.dotenv_path = dotenv_path or self.workspace_root / ".env"
6369

6470
# Load environment variables
@@ -128,6 +134,40 @@ def set(self, key: str, value: Any, persist: bool = False) -> None:
128134
if persist and self.dotenv_path.exists():
129135
set_key(self.dotenv_path, key, str(value))
130136

137+
def _get_env_specific_value(self, env: Environment, dev_key: str, prod_key: str, value_name: str) -> str:
138+
"""
139+
Get environment-specific configuration value.
140+
141+
Parameters
142+
----------
143+
env : Environment
144+
The environment to get value for
145+
dev_key : str
146+
Environment variable key for development
147+
prod_key : str
148+
Environment variable key for production
149+
value_name : str
150+
Human-readable name for error messages
151+
152+
Returns
153+
-------
154+
str
155+
Configuration value
156+
157+
Raises
158+
------
159+
ConfigurationError
160+
If value is not configured for environment
161+
"""
162+
key = dev_key if env.is_dev else prod_key
163+
value = self.get(key) # Don't provide a default value
164+
165+
if value is None:
166+
error_msg = f"No {value_name} found for the {env.value.upper()} environment."
167+
raise ConfigurationError(error_msg)
168+
169+
return value
170+
131171
def get_database_url(self, env: Environment) -> str:
132172
"""
133173
Get database URL for specified environment.
@@ -147,17 +187,7 @@ def get_database_url(self, env: Environment) -> str:
147187
ConfigurationError
148188
If database URL is not configured for environment
149189
"""
150-
# Get the appropriate database URL key based on the environment
151-
key = "DEV_DATABASE_URL" if env.is_dev else "PROD_DATABASE_URL"
152-
url = self.get(key, default="")
153-
154-
if not url:
155-
# If no URL is found, raise an error.
156-
# We no longer provide a default/mock URL here.
157-
error_msg = f"No database URL found for the {env.value.upper()} environment."
158-
raise ConfigurationError(error_msg)
159-
160-
return url
190+
return self._get_env_specific_value(env, "DEV_DATABASE_URL", "PROD_DATABASE_URL", "database URL")
161191

162192
def get_bot_token(self, env: Environment) -> str:
163193
"""
@@ -178,16 +208,7 @@ def get_bot_token(self, env: Environment) -> str:
178208
ConfigurationError
179209
If bot token is not configured for environment
180210
"""
181-
# Get the appropriate bot token key based on the environment
182-
key = "DEV_BOT_TOKEN" if env.is_dev else "PROD_BOT_TOKEN"
183-
token = self.get(key, default="")
184-
185-
if not token:
186-
# If no token is found, raise an error.
187-
error_msg = f"No bot token found for the {env.value.upper()} environment."
188-
raise ConfigurationError(error_msg)
189-
190-
return token
211+
return self._get_env_specific_value(env, "DEV_BOT_TOKEN", "PROD_BOT_TOKEN", "bot token")
191212

192213

193214
class EnvironmentManager:
@@ -200,22 +221,22 @@ class EnvironmentManager:
200221

201222
_instance = None
202223

224+
@classmethod
225+
def reset_for_testing(cls) -> None:
226+
"""Reset the singleton instance for testing purposes."""
227+
cls._instance = None
228+
203229
def __new__(cls, *args: Any, **kwargs: Any) -> "EnvironmentManager":
204-
"""Create or return the singleton instance."""
230+
"""Ensure singleton pattern."""
205231
if cls._instance is None:
206232
cls._instance = super().__new__(cls)
207-
cls._instance._initialized = False
208233
return cls._instance
209234

210235
def __init__(self) -> None:
211-
"""Initialize the environment manager if not already initialized."""
212-
if getattr(self, "_initialized", False):
213-
return
214-
215-
# Core configuration
216-
self._environment = Environment.DEVELOPMENT # Default to development
217-
self._config = Config()
218-
self._initialized = True
236+
"""Initialize environment manager."""
237+
if not hasattr(self, "_environment"):
238+
self._environment = Environment.DEVELOPMENT
239+
self._config = Config()
219240

220241
@property
221242
def environment(self) -> Environment:

0 commit comments

Comments
 (0)