@@ -34,8 +34,8 @@ def __init__( # noqa: C901, PLR0912
34
34
return
35
35
for line in raw .splitlines (): # noqa: PLR1702
36
36
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 ) )
39
39
else :
40
40
try :
41
41
key , value = self ._extract_key_value (line )
@@ -52,12 +52,20 @@ def __init__( # noqa: C901, PLR0912
52
52
else :
53
53
self ._raw [key ] = value
54
54
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
+
55
63
def use_replacer (self , value : Replacer , args : ConfigLoadArgs ) -> None :
56
64
self ._replacer = value
57
65
for filename in self ._env_files :
58
- self ._read_env_file ( filename , args )
66
+ self ._raw . update ( self . _stream_env_file ( filename , args ) )
59
67
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 ]] :
61
69
# Our rules in the documentation, some upstream environment file rules (we follow mostly the docker one):
62
70
# - https://www.npmjs.com/package/dotenv#rules
63
71
# - https://docs.docker.com/compose/env-file/
@@ -70,8 +78,7 @@ def _read_env_file(self, filename: str, args: ConfigLoadArgs) -> None:
70
78
env_line = env_line .strip () # noqa: PLW2901
71
79
if not env_line or env_line .startswith ("#" ):
72
80
continue
73
- key , value = self ._extract_key_value (env_line )
74
- self ._raw [key ] = value
81
+ yield self ._extract_key_value (env_line )
75
82
76
83
@staticmethod
77
84
def _extract_key_value (line : str ) -> tuple [str , str ]:
@@ -100,10 +107,18 @@ def __iter__(self) -> Iterator[str]:
100
107
# start with the materialized ones, maybe we don't need to materialize the raw ones
101
108
yield from self ._materialized .keys ()
102
109
yield from list (self ._raw .keys ()) # iterating over this may trigger materialization and change the dict
110
+ args = ConfigLoadArgs ([], self ._name , self ._env_name )
103
111
while self ._needs_replacement :
104
112
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 key , value in self ._stream_env_file (self ._parse_file_line (sub_line ), args ):
120
+ if key not in self ._raw :
121
+ sub_raw [key ] = value # noqa: PERF403
107
122
self ._raw .update (sub_raw )
108
123
self .changed = True # loading while iterating can cause these values to be missed
109
124
yield from sub_raw .keys ()
0 commit comments