Reputation: 31570
I have env vars that looks like this:
CONFIG-SOMEKEY-SOMEOTHERKEY = val345
CONFIG-SOMEKEY-SOMEOTHEROTHERKEY = val678
CONFIG-ANOTHERKEY = val222
I want to create a dictionary out of them that would look like:
{
'SOMEKEY': {
'SOMEOTHERKEY': 'val3242',
'SOMEOTHEROTHERKEY': 'val678'
}
'ANOTHERKEY': 'val222'
}
"CONFIG-" is a prefix to denote which vars this should be done with- so I can filter them easily like this:
config_fields = [i for i in os.environ if i.startswith("CONFIG-")]
But I'm unsure of how to loop over the string, split on "-" and build a dict.
While looping I was thinking I could check if its the last item and assign the value but how would it know the full path of keys it's on?
I suspect this is a job for recursion I'm just now sure exactly how to implement it
Upvotes: 2
Views: 1098
Reputation: 61910
You could do:
data = ['CONFIG-SOMEKEY-SOMEOTHERKEY = val345',
'CONFIG-SOMEKEY-SOMEOTHEROTHERKEY = val678',
'CONFIG-ANOTHERKEY = val222']
result = {}
for e in data:
key, value = e.split(" = ") # split into key and value
path = key.split("-") # split the key into parts
ref = result
for part in path[1:-1]:
ref[part] = part in ref and ref[part] or {}
ref = ref[part]
ref[path[-1]] = value # take the last part of key and set the value
print(result)
Output
{'SOMEKEY': {'SOMEOTHERKEY': 'val345', 'SOMEOTHEROTHERKEY': 'val678'}, 'ANOTHERKEY': 'val222'}
This part:
ref = result
for part in path[1:-1]:
ref[part] = part in ref and ref[part] or {}
ref = ref[part]
ref[path[-1]] = value
will create the nested dictionaries, is equivalent to:
for part in path[1:-1]:
if part not in ref:
ref[part] = {}
ref = ref[part]
So if the part
is in the dictionary you set ref as the value corresponding to part
otherwise you create a new dictionary.
Upvotes: 2
Reputation: 11681
You can use the assoc_in
function from toolz. Split the name on -
and slice off the prefix.
import os
from toolz.dictoolz import assoc_in
CONFIG={}
for k, v in os.environ.items():
if k.startswith("CONFIG-"):
assoc_in(CONFIG, k.split('-')[1:], v)
If you don't want to add a dependency, you can see the implementation of assoc_in
here. A simpler substitute might be something like
def assoc_in(d, ks, v):
for k in ks[:-1]:
d = d.setdefault(k, {})
d[ks[-1]] = v
This uses the .setdefault()
method to get the nested dicts, which will add a new one if it doesn't exist yet.
Upvotes: 2
Reputation: 51673
You can get your environment variables like so:
import os
text = [f"{k} = {v}" for k,v in os.environ.items() if k.startswith("CONFIG-")]
print(env)
(inspired by How to access environment variable values? - especially this answer)
Then you can use dicts to iterativly splitting your values:
text = """CONFIG-SOMEKEY-SOMEOTHERKEY = val345
CONFIG-SOMEKEY-SOMEOTHEROTHERKEY = val678
CONFIG-ANOTHERKEY = val222"""
text = text.split("\n")
d = {}
curr_d = d
for part in text:
while "-" in part:
a, b = part.split("-",1)
if '-' in b:
curr_d [a] = curr_d.get(a,{})
curr_d = curr_d[a]
part = b
a, b = part.split("=",1)
curr_d[a] = b
curr_d = d
print(d)
Output:
{'CONFIG': {'SOMEOTHERKEY ': ' val345',
'SOMEOTHEROTHERKEY ': ' val678'},
'ANOTHERKEY ': ' val222'}
Upvotes: 1