33"""
44
55import logging
6- import os
7- import re
86from pathlib import Path
9- from typing import Dict , List , Tuple , Optional
7+ from typing import Optional
108
119logger = logging .getLogger (__name__ )
1210
11+
1312def strip_comment (val ):
14- return val .split ('#' , 1 )[0 ].strip ()
13+ return val .split ("#" , 1 )[0 ].strip ()
14+
1515
1616class EnvValidator :
1717 """Validates environment variable configurations and reports discrepancies."""
@@ -31,7 +31,7 @@ def __init__(self, project_root: Optional[str] = None):
3131 self .project_root = project_root
3232 self .env_dir = project_root / "env"
3333
34- def _parse_env_file (self , file_path : Path ) -> Dict [str , dict ]:
34+ def _parse_env_file (self , file_path : Path ) -> dict [str , dict ]:
3535 """
3636 Parse an environment file and return a dictionary of key-value pairs and any noqa-style directives.
3737
@@ -47,12 +47,12 @@ def _parse_env_file(self, file_path: Path) -> Dict[str, dict]:
4747 return env_vars
4848
4949 try :
50- with open (file_path , 'r' , encoding = ' utf-8' ) as f :
50+ with open (file_path , encoding = " utf-8" ) as f :
5151 for line_num , line in enumerate (f , 1 ):
5252 line = line .strip ()
5353
5454 # Skip empty lines and comments
55- if not line or line .startswith ('#' ):
55+ if not line or line .startswith ("#" ):
5656 continue
5757
5858 # Check for noqa-style directive at end of line
@@ -65,21 +65,21 @@ def _parse_env_file(self, file_path: Path) -> Dict[str, dict]:
6565 line = line [: - len ("# suppress-warning" )].rstrip ()
6666
6767 # Parse regular env variables
68- if '=' in line :
69- key , value = line .split ('=' , 1 )
68+ if "=" in line :
69+ key , value = line .split ("=" , 1 )
7070 key = key .strip ()
7171 value = value .strip ()
7272
73- env_vars [key ] = {' value' : value }
73+ env_vars [key ] = {" value" : value }
7474 if directive :
75- env_vars [key ][' directive' ] = directive
75+ env_vars [key ][" directive" ] = directive
7676
7777 except Exception as e :
7878 logger .warning (f"Error parsing env file { file_path } : { e } " )
7979
8080 return env_vars
8181
82- def _get_env_file_pairs (self ) -> List [ Tuple [str , Path , Path , Path ]]:
82+ def _get_env_file_pairs (self ) -> list [ tuple [str , Path , Path , Path ]]:
8383 """
8484 Get pairs of environment files to compare.
8585
@@ -90,8 +90,18 @@ def _get_env_file_pairs(self) -> List[Tuple[str, Path, Path, Path]]:
9090
9191 # Define the environment file patterns
9292 env_patterns = [
93- ("backend" , "backend.env" , "backend.local.env" , "backend.local.example.env" ),
94- ("frontend" , "frontend.env" , "frontend.local.env" , "frontend.local.example.env" ),
93+ (
94+ "backend" ,
95+ "backend.env" ,
96+ "backend.local.env" ,
97+ "backend.local.example.env" ,
98+ ),
99+ (
100+ "frontend" ,
101+ "frontend.env" ,
102+ "frontend.local.env" ,
103+ "frontend.local.example.env" ,
104+ ),
95105 ("shared" , "shared.env" , "shared.local.env" , "shared.local.example.env" ),
96106 ]
97107
@@ -106,7 +116,7 @@ def _get_env_file_pairs(self) -> List[Tuple[str, Path, Path, Path]]:
106116
107117 return pairs
108118
109- def check_example_overrides (self ) -> List [str ]:
119+ def check_example_overrides (self ) -> list [str ]:
110120 """
111121 Check for settings present in example files but not in base env files.
112122 This identifies non-standard settings that are overridden in the environment.
@@ -130,8 +140,8 @@ def check_example_overrides(self) -> List[str]:
130140 if local_path .exists ():
131141 local_vars = self ._parse_env_file (local_path )
132142 if var_name in local_vars :
133- example_value = example_vars [var_name ][' value' ]
134- local_value = local_vars [var_name ][' value' ]
143+ example_value = example_vars [var_name ][" value" ]
144+ local_value = local_vars [var_name ][" value" ]
135145 if strip_comment (local_value ) == strip_comment (example_value ):
136146 continue
137147 warnings .append (
@@ -142,7 +152,7 @@ def check_example_overrides(self) -> List[str]:
142152 )
143153 return warnings
144154
145- def check_local_overrides (self ) -> List [str ]:
155+ def check_local_overrides (self ) -> list [str ]:
146156 """
147157 Check for settings in local files that differ from or are absent in base files.
148158
@@ -159,8 +169,8 @@ def check_local_overrides(self) -> List[str]:
159169 local_vars = self ._parse_env_file (local_path )
160170
161171 for var_name , local_info in local_vars .items ():
162- local_value = local_info [' value' ]
163- suppress = local_info .get (' directive' ) == ' suppress-warning'
172+ local_value = local_info [" value" ]
173+ suppress = local_info .get (" directive" ) == " suppress-warning"
164174 if var_name not in base_vars :
165175 if suppress :
166176 continue
@@ -170,12 +180,12 @@ def check_local_overrides(self) -> List[str]:
170180 f"Consider adding a default value to { base_path .name } if this should be a standard setting."
171181 )
172182 else :
173- base_value = base_vars [var_name ][' value' ]
183+ base_value = base_vars [var_name ][" value" ]
174184 # Compare values ignoring anything after a "#" symbol
175185 if strip_comment (base_value ) == strip_comment (local_value ):
176186 continue # No warning if values match (ignoring comments)
177187 # Suppress warning if base file has # local-required
178- if base_vars [var_name ].get (' directive' ) == ' local-required' :
188+ if base_vars [var_name ].get (" directive" ) == " local-required" :
179189 continue
180190 warnings .append (
181191 f"⚠️ { env_type .upper ()} : Variable '{ var_name } ' is overridden locally. "
@@ -184,7 +194,7 @@ def check_local_overrides(self) -> List[str]:
184194 )
185195 return warnings
186196
187- def validate_all (self ) -> List [str ]:
197+ def validate_all (self ) -> list [str ]:
188198 """
189199 Run all environment validation checks.
190200
@@ -196,15 +206,17 @@ def validate_all(self) -> List[str]:
196206 warnings .extend (self .check_local_overrides ())
197207 return warnings
198208
199- def log_warnings (self , warnings : List [str ]) -> None :
209+ def log_warnings (self , warnings : list [str ]) -> None :
200210 """
201211 Log warning messages.
202212
203213 Args:
204214 warnings: List of warning messages to log
205215 """
206216 if not warnings :
207- logger .info ("✅ Environment validation passed - no configuration discrepancies found." )
217+ logger .info (
218+ "✅ Environment validation passed - no configuration discrepancies found."
219+ )
208220 return
209221
210222 logger .warning ("Environment Configuration Warnings:" )
0 commit comments