@@ -34,8 +34,8 @@ def __init__( # noqa: C901, PLR0912
3434 return
3535 for line in raw .splitlines (): # noqa: PLR1702
3636 if line .strip ():
37- if line . startswith ( "file|" ): # environment files to be handled later
38- self ._env_files .append (line [ len ( "file|" ) :] )
37+ if self . _is_file_line ( line ):
38+ self ._env_files .append (self . _parse_file_line ( line ) )
3939 else :
4040 try :
4141 key , value = self ._extract_key_value (line )
@@ -52,12 +52,20 @@ def __init__( # noqa: C901, PLR0912
5252 else :
5353 self ._raw [key ] = value
5454
55+ @staticmethod
56+ def _is_file_line (line : str ) -> bool :
57+ return line .startswith ("file|" )
58+
59+ @staticmethod
60+ def _parse_file_line (line : str ) -> str :
61+ return line [len ("file|" ) :]
62+
5563 def use_replacer (self , value : Replacer , args : ConfigLoadArgs ) -> None :
5664 self ._replacer = value
5765 for filename in self ._env_files :
58- self ._read_env_file ( filename , args )
66+ self ._raw . update ( self . _stream_env_file ( filename , args ) )
5967
60- def _read_env_file (self , filename : str , args : ConfigLoadArgs ) -> None :
68+ def _stream_env_file (self , filename : str , args : ConfigLoadArgs ) -> Iterator [ tuple [ str , str ]] :
6169 # Our rules in the documentation, some upstream environment file rules (we follow mostly the docker one):
6270 # - https://www.npmjs.com/package/dotenv#rules
6371 # - https://docs.docker.com/compose/env-file/
@@ -70,8 +78,7 @@ def _read_env_file(self, filename: str, args: ConfigLoadArgs) -> None:
7078 env_line = env_line .strip () # noqa: PLW2901
7179 if not env_line or env_line .startswith ("#" ):
7280 continue
73- key , value = self ._extract_key_value (env_line )
74- self ._raw [key ] = value
81+ yield self ._extract_key_value (env_line )
7582
7683 @staticmethod
7784 def _extract_key_value (line : str ) -> tuple [str , str ]:
@@ -100,10 +107,18 @@ def __iter__(self) -> Iterator[str]:
100107 # start with the materialized ones, maybe we don't need to materialize the raw ones
101108 yield from self ._materialized .keys ()
102109 yield from list (self ._raw .keys ()) # iterating over this may trigger materialization and change the dict
110+ args = ConfigLoadArgs ([], self ._name , self ._env_name )
103111 while self ._needs_replacement :
104112 line = self ._needs_replacement .pop (0 )
105- expanded_line = self ._replacer (line , ConfigLoadArgs ([], self ._name , self ._env_name ))
106- sub_raw = dict (self ._extract_key_value (sub_line ) for sub_line in expanded_line .splitlines () if sub_line )
113+ expanded_line = self ._replacer (line , args )
114+ sub_raw : dict [str , str ] = {}
115+ for sub_line in filter (None , expanded_line .splitlines ()):
116+ if not self ._is_file_line (sub_line ):
117+ sub_raw .__setitem__ (* self ._extract_key_value (sub_line ))
118+ else :
119+ for k , v in self ._stream_env_file (self ._parse_file_line (sub_line ), args ):
120+ if k not in self ._raw :
121+ sub_raw [k ] = v # noqa: PERF403
107122 self ._raw .update (sub_raw )
108123 self .changed = True # loading while iterating can cause these values to be missed
109124 yield from sub_raw .keys ()
0 commit comments