@@ -21,7 +21,8 @@ def __init__(self, project_root: Optional[str] = None):
2121 Initialize the environment validator.
2222
2323 Args:
24- project_root: Root directory of the project. Defaults to parent of current file.
24+ project_root: Root directory of the project.
25+ If None, defaults to parent of this file's directory.
2526 """
2627 if project_root is None :
2728 project_root = Path (__file__ ).parent .parent
@@ -33,49 +34,47 @@ def __init__(self, project_root: Optional[str] = None):
3334
3435 def _parse_env_file (self , file_path : Path ) -> dict [str , dict ]:
3536 """
36- Parse an environment file and return a dictionary of key-value pairs and any noqa-style directives.
37+ Parse an environment file and return a dictionary of key-value pairs
38+ and any noqa-style directives.
3739
3840 Args:
3941 file_path: Path to the environment file
4042
4143 Returns:
42- Dictionary mapping variable names to dicts with 'value' and optional 'directive'.
44+ Dictionary mapping variable names to dicts with 'value'
45+ and optional 'directive'.
4346 """
4447 env_vars = {}
4548
4649 if not file_path .exists ():
4750 return env_vars
4851
49- try :
50- with open (file_path , encoding = "utf-8" ) as f :
51- for line_num , line in enumerate (f , 1 ):
52- line = line .strip ()
53-
54- # Skip empty lines and comments
55- if not line or line .startswith ("#" ):
56- continue
57-
58- # Check for noqa-style directive at end of line
59- directive = None
60- if line .endswith ("# local-required" ):
61- directive = "local-required"
62- line = line [: - len ("# local-required" )].rstrip ()
63- elif line .endswith ("# suppress-warning" ):
64- directive = "suppress-warning"
65- line = line [: - len ("# suppress-warning" )].rstrip ()
66-
67- # Parse regular env variables
68- if "=" in line :
69- key , value = line .split ("=" , 1 )
70- key = key .strip ()
71- value = value .strip ()
72-
73- env_vars [key ] = {"value" : value }
74- if directive :
75- env_vars [key ]["directive" ] = directive
76-
77- except Exception as e :
78- logger .warning (f"Error parsing env file { file_path } : { e } " )
52+ with Path .open (file_path , encoding = "utf-8" ) as f :
53+ for original_line in f :
54+ line = original_line .strip ()
55+
56+ # Skip empty lines and comments
57+ if not line or line .startswith ("#" ):
58+ continue
59+
60+ # Check for noqa-style directive at end of line
61+ directive = None
62+ if line .endswith ("# local-required" ):
63+ directive = "local-required"
64+ line = line [: - len ("# local-required" )].rstrip ()
65+ elif line .endswith ("# suppress-warning" ):
66+ directive = "suppress-warning"
67+ line = line [: - len ("# suppress-warning" )].rstrip ()
68+
69+ # Parse regular env variables
70+ if "=" in line :
71+ key , value = line .split ("=" , 1 )
72+ key = key .strip ()
73+ value = value .strip ()
74+
75+ env_vars [key ] = {"value" : value }
76+ if directive :
77+ env_vars [key ]["directive" ] = directive
7978
8079 return env_vars
8180
@@ -110,7 +109,6 @@ def _get_env_file_pairs(self) -> list[tuple[str, Path, Path, Path]]:
110109 local_path = self .env_dir / local_name
111110 example_path = self .env_dir / example_name
112111
113- # Include if any of the files exist (we'll check existence in validation methods)
114112 if base_path .exists () or local_path .exists () or example_path .exists ():
115113 pairs .append ((env_type , base_path , local_path , example_path ))
116114
@@ -145,9 +143,12 @@ def check_example_overrides(self) -> list[str]:
145143 if strip_comment (local_value ) == strip_comment (example_value ):
146144 continue
147145 warnings .append (
148- f"⚠️ { env_type .upper ()} : Variable '{ var_name } ' is set in { local_path .name } "
149- f"but not defined in { base_path .name } . This overrides a non-standard setting "
150- f"from { example_path .name } . Local value: '{ local_value } ', "
146+ f"⚠️ { env_type .upper ()} : Variable "
147+ f"'{ var_name } ' is set in { local_path .name } "
148+ f"but not defined in { base_path .name } . "
149+ f"This overrides a non-standard setting "
150+ f"from { example_path .name } . "
151+ f"Local value: '{ local_value } ', "
151152 f"Example value: '{ example_value } '"
152153 )
153154 return warnings
@@ -161,7 +162,7 @@ def check_local_overrides(self) -> list[str]:
161162 """
162163 warnings = []
163164
164- for env_type , base_path , local_path , example_path in self ._get_env_file_pairs ():
165+ for env_type , base_path , local_path , _ in self ._get_env_file_pairs ():
165166 if not local_path .exists ():
166167 continue
167168
@@ -175,9 +176,12 @@ def check_local_overrides(self) -> list[str]:
175176 if suppress :
176177 continue
177178 warnings .append (
178- f"⚠️ { env_type .upper ()} : Variable '{ var_name } ' is set in { local_path .name } "
179- f"(value: '{ local_value } ') but not defined in { base_path .name } . "
180- f"Consider adding a default value to { base_path .name } if this should be a standard setting."
179+ f"⚠️ { env_type .upper ()} : Variable "
180+ f"'{ var_name } ' is set in { local_path .name } "
181+ f"(value: '{ local_value } ') but "
182+ f"not defined in { base_path .name } . "
183+ f"Consider adding a default value to "
184+ f"{ base_path .name } if this should be a standard setting."
181185 )
182186 else :
183187 base_value = base_vars [var_name ]["value" ]
@@ -188,8 +192,10 @@ def check_local_overrides(self) -> list[str]:
188192 if base_vars [var_name ].get ("directive" ) == "local-required" :
189193 continue
190194 warnings .append (
191- f"⚠️ { env_type .upper ()} : Variable '{ var_name } ' is overridden locally. "
192- f"Base value: '{ base_value } ', Local value: '{ local_value } '. "
195+ f"⚠️ { env_type .upper ()} : Variable "
196+ f"'{ var_name } ' is overridden locally. "
197+ f"Base value: '{ base_value } ', "
198+ f"Local value: '{ local_value } '. "
193199 f"Ensure the default in { base_path .name } is appropriate."
194200 )
195201 return warnings
@@ -215,7 +221,8 @@ def log_warnings(self, warnings: list[str]) -> None:
215221 """
216222 if not warnings :
217223 logger .info (
218- "✅ Environment validation passed - no configuration discrepancies found."
224+ "✅ Environment validation passed - "
225+ "no configuration discrepancies found."
219226 )
220227 return
221228
@@ -225,14 +232,15 @@ def log_warnings(self, warnings: list[str]) -> None:
225232 logger .warning (warning )
226233 logger .warning ("=" * 60 )
227234 logger .warning (
228- f"Found { len (warnings )} environment configuration issue(s). "
229- "Review your environment files to ensure proper configuration."
235+ "Found %s environment configuration issue(s). "
236+ "Review your environment files to ensure proper configuration." ,
237+ len (warnings ),
230238 )
231239
232240
233241def validate_environment_on_startup ():
234242 """
235- Main function to validate environment configuration on startup.
243+ Validate environment configuration on startup.
236244 This can be called from Django settings or management commands.
237245 """
238246 validator = EnvValidator ()
0 commit comments