12
12
13
13
if PYVERSION >= (3 , 0 , 0 ):
14
14
from configparser import ConfigParser , NoOptionError
15
+
15
16
text_type = str
16
17
else :
17
18
from ConfigParser import SafeConfigParser as ConfigParser , NoOptionError
19
+
18
20
text_type = unicode
19
21
20
22
if PYVERSION >= (3 , 2 , 0 ):
23
25
read_config = lambda parser , file : parser .readfp (file )
24
26
25
27
26
- DEFAULT_ENCODING = ' UTF-8'
28
+ DEFAULT_ENCODING = " UTF-8"
27
29
28
30
29
31
# Python 3.10 don't have strtobool anymore. So we move it here.
30
32
TRUE_VALUES = {"y" , "yes" , "t" , "true" , "on" , "1" }
31
33
FALSE_VALUES = {"n" , "no" , "f" , "false" , "off" , "0" }
32
34
35
+
33
36
def strtobool (value ):
34
37
if isinstance (value , bool ):
35
38
return value
@@ -51,6 +54,7 @@ class Undefined(object):
51
54
"""
52
55
Class to represent undefined type.
53
56
"""
57
+
54
58
pass
55
59
56
60
@@ -71,7 +75,7 @@ def _cast_boolean(self, value):
71
75
Helper to convert config values to boolean as ConfigParser do.
72
76
"""
73
77
value = str (value )
74
- return bool (value ) if value == '' else bool (strtobool (value ))
78
+ return bool (value ) if value == "" else bool (strtobool (value ))
75
79
76
80
@staticmethod
77
81
def _cast_do_nothing (value ):
@@ -89,7 +93,11 @@ def get(self, option, default=undefined, cast=undefined):
89
93
value = self .repository [option ]
90
94
else :
91
95
if isinstance (default , Undefined ):
92
- raise UndefinedValueError ('{} not found. Declare it as envvar or define a default value.' .format (option ))
96
+ raise UndefinedValueError (
97
+ "{} not found. Declare it as envvar or define a default value." .format (
98
+ option
99
+ )
100
+ )
93
101
94
102
value = default
95
103
@@ -108,7 +116,7 @@ def __call__(self, *args, **kwargs):
108
116
109
117
110
118
class RepositoryEmpty (object ):
111
- def __init__ (self , source = '' , encoding = DEFAULT_ENCODING ):
119
+ def __init__ (self , source = "" , encoding = DEFAULT_ENCODING ):
112
120
pass
113
121
114
122
def __contains__ (self , key ):
@@ -122,16 +130,16 @@ class RepositoryIni(RepositoryEmpty):
122
130
"""
123
131
Retrieves option keys from .ini files.
124
132
"""
125
- SECTION = 'settings'
133
+
134
+ SECTION = "settings"
126
135
127
136
def __init__ (self , source , encoding = DEFAULT_ENCODING ):
128
137
self .parser = ConfigParser ()
129
138
with open (source , encoding = encoding ) as file_ :
130
139
read_config (self .parser , file_ )
131
140
132
141
def __contains__ (self , key ):
133
- return (key in os .environ or
134
- self .parser .has_option (self .SECTION , key ))
142
+ return key in os .environ or self .parser .has_option (self .SECTION , key )
135
143
136
144
def __getitem__ (self , key ):
137
145
try :
@@ -144,18 +152,21 @@ class RepositoryEnv(RepositoryEmpty):
144
152
"""
145
153
Retrieves option keys from .env files with fall back to os.environ.
146
154
"""
155
+
147
156
def __init__ (self , source , encoding = DEFAULT_ENCODING ):
148
157
self .data = {}
149
158
150
159
with open (source , encoding = encoding ) as file_ :
151
160
for line in file_ :
152
161
line = line .strip ()
153
- if not line or line .startswith ('#' ) or '=' not in line :
162
+ if not line or line .startswith ("#" ) or "=" not in line :
154
163
continue
155
- k , v = line .split ('=' , 1 )
164
+ k , v = line .split ("=" , 1 )
156
165
k = k .strip ()
157
166
v = v .strip ()
158
- if len (v ) >= 2 and ((v [0 ] == "'" and v [- 1 ] == "'" ) or (v [0 ] == '"' and v [- 1 ] == '"' )):
167
+ if len (v ) >= 2 and (
168
+ (v [0 ] == "'" and v [- 1 ] == "'" ) or (v [0 ] == '"' and v [- 1 ] == '"' )
169
+ ):
159
170
v = v [1 :- 1 ]
160
171
self .data [k ] = v
161
172
@@ -173,12 +184,12 @@ class RepositorySecret(RepositoryEmpty):
173
184
e.g. Docker swarm secrets
174
185
"""
175
186
176
- def __init__ (self , source = ' /run/secrets/' ):
187
+ def __init__ (self , source = " /run/secrets/" ):
177
188
self .data = {}
178
189
179
190
ls = os .listdir (source )
180
191
for file in ls :
181
- with open (os .path .join (source , file ), 'r' ) as f :
192
+ with open (os .path .join (source , file ), "r" ) as f :
182
193
self .data [file ] = f .read ()
183
194
184
195
def __contains__ (self , key ):
@@ -188,40 +199,41 @@ def __getitem__(self, key):
188
199
return self .data [key ]
189
200
190
201
191
- class RepositoryString ( RepositoryEmpty ):
202
+ class RepositoryGoogleSecretManager ( RepositoryEnv ):
192
203
"""
193
- Repository class to retrieve options from a string .
204
+ Repository class for retrieving configuration options from Google Secret Manager .
194
205
195
- Parses a string formatted like a `.env` file into a dictionary of options.
196
- This class is an extension of the `RepositoryEmpty` class that provides a
197
- way to read configuration keys from an environment string .
206
+ This class extends `RepositoryEnv` to specifically handle configurations stored in
207
+ Google Secret Manager. It parses strings formatted in a similar way to `.env` files,
208
+ converting them into a dictionary of configuration options .
198
209
199
210
Attributes:
200
- data (dict): A dictionary to hold the parsed key-value pairs.
211
+ data (dict): A dictionary holding the parsed key-value pairs from the Google
212
+ Secret Manager source.
201
213
"""
202
214
203
215
def __init__ (self , source ):
204
216
"""
205
- Initializes the RepositoryString with a given string source.
217
+ Initialize RepositoryGoogleSecretManager with a Google Secret Manager source.
206
218
207
- The provided string should have one "KEY=value" pair per line, similar
208
- to a `.env` file format. Lines starting with `#` are considered as
209
- comments and ignored. Surrounding whitespace is stripped from keys
210
- and values .
219
+ The source string is expected to have one "KEY=value" pair per line, akin to
220
+ the `.env` file format. Lines beginning with `#` are treated as comments and
221
+ are disregarded. Keys and values are trimmed of surrounding whitespace for
222
+ accurate parsing .
211
223
212
224
Args:
213
- source (str): The string source to parse .
225
+ source (str): The string source from Google Secret Manager to be parsed .
214
226
"""
215
227
self .data = {}
216
- source_lines = source .split (' \n ' )
228
+ source_lines = source .split (" \n " )
217
229
218
230
for line in source_lines :
219
231
line = line .strip ()
220
232
221
- if not line or line .startswith ('#' ) or '=' not in line :
233
+ if not line or line .startswith ("#" ) or "=" not in line :
222
234
continue
223
235
224
- key , value = line .split ('=' , 1 )
236
+ key , value = line .split ("=" , 1 )
225
237
key = key .strip ()
226
238
value = value .strip ()
227
239
@@ -233,33 +245,6 @@ def __init__(self, source):
233
245
234
246
self .data [key ] = value
235
247
236
- def __contains__ (self , key ):
237
- """
238
- Check if a key is present in the repository or the environment.
239
-
240
- Args:
241
- key (str): The key to check for presence.
242
-
243
- Returns:
244
- bool: True if key is in the repository or os.environ, False otherwise.
245
- """
246
- return key in os .environ or key in self .data
247
-
248
- def __getitem__ (self , key ):
249
- """
250
- Retrieve the value associated with the given key.
251
-
252
- Args:
253
- key (str): The key to retrieve the value for.
254
-
255
- Returns:
256
- str: The value associated with the key.
257
-
258
- Raises:
259
- KeyError: If the key is not found in the repository.
260
- """
261
- return self .data [key ]
262
-
263
248
264
249
class AutoConfig (object ):
265
250
"""
@@ -272,10 +257,13 @@ class AutoConfig(object):
272
257
caller's path.
273
258
274
259
"""
275
- SUPPORTED = OrderedDict ([
276
- ('settings.ini' , RepositoryIni ),
277
- ('.env' , RepositoryEnv ),
278
- ])
260
+
261
+ SUPPORTED = OrderedDict (
262
+ [
263
+ ("settings.ini" , RepositoryIni ),
264
+ (".env" , RepositoryEnv ),
265
+ ]
266
+ )
279
267
280
268
encoding = DEFAULT_ENCODING
281
269
@@ -292,18 +280,20 @@ def _find_file(self, path):
292
280
293
281
# search the parent
294
282
parent = os .path .dirname (path )
295
- if parent and os .path .normcase (parent ) != os .path .normcase (os .path .abspath (os .sep )):
283
+ if parent and os .path .normcase (parent ) != os .path .normcase (
284
+ os .path .abspath (os .sep )
285
+ ):
296
286
return self ._find_file (parent )
297
287
298
288
# reached root without finding any files.
299
- return ''
289
+ return ""
300
290
301
291
def _load (self , path ):
302
292
# Avoid unintended permission errors
303
293
try :
304
294
filename = self ._find_file (os .path .abspath (path ))
305
295
except Exception :
306
- filename = ''
296
+ filename = ""
307
297
Repository = self .SUPPORTED .get (os .path .basename (filename ), RepositoryEmpty )
308
298
309
299
self .config = Config (Repository (filename , encoding = self .encoding ))
@@ -327,12 +317,15 @@ def __call__(self, *args, **kwargs):
327
317
328
318
# Helpers
329
319
320
+
330
321
class Csv (object ):
331
322
"""
332
323
Produces a csv parser that return a list of transformed elements.
333
324
"""
334
325
335
- def __init__ (self , cast = text_type , delimiter = ',' , strip = string .whitespace , post_process = list ):
326
+ def __init__ (
327
+ self , cast = text_type , delimiter = "," , strip = string .whitespace , post_process = list
328
+ ):
336
329
"""
337
330
Parameters:
338
331
cast -- callable that transforms the item just before it's added to the list.
@@ -382,8 +375,10 @@ def __init__(self, flat=None, cast=text_type, choices=None):
382
375
def __call__ (self , value ):
383
376
transform = self .cast (value )
384
377
if transform not in self ._valid_values :
385
- raise ValueError ((
386
- 'Value not in list: {!r}; valid values are {!r}'
387
- ).format (value , self ._valid_values ))
378
+ raise ValueError (
379
+ ("Value not in list: {!r}; valid values are {!r}" ).format (
380
+ value , self ._valid_values
381
+ )
382
+ )
388
383
else :
389
384
return transform
0 commit comments