Archive
Convert a nested OrderedDict to normal dict
Problem
You have a nested OrderedDict object and you want to convert it to a normal dict.
Today I was playing with the configparser module. It reads an .ini file and builds a dict-like object. However, I prefer normal dict objects. With a configparser object’s “._sections” you can access the underlying dictionary object, but it’s a nested OrderedDict object.
Example:
; preferences.ini [GENERAL] onekey = "value in some words" [SETTINGS] resolution = '1024 x 768'
import configparser
from pprint import pprint
config = configparser.ConfigParser()
config.read("preferences.ini")
pprint(config._sections)
Sample output:
OrderedDict([('GENERAL', OrderedDict([('onekey', '"value in some words"')])),
('SETTINGS', OrderedDict([('resolution', "'1024 x 768'")]))])
Solution
JSON to the rescue! Convert the nested OrderedDict to json, thus you lose the order. Then, convert the json back to a dictionary. Voilá, you have a plain dict object.
def to_dict(self, config):
"""
Nested OrderedDict to normal dict.
"""
return json.loads(json.dumps(config))
Output:
{'GENERAL': {'onekey': '"value in some words"'},
'SETTINGS': {'resolution': "'1024 x 768'"}}
As you can see, quotes around string values are kept by configparser. If you want to remove them, see my previous post.
I found this solution here @ SO.
Using ConfigParser, read an .ini file to a dict and remove quotes around string values
Problem
In Python you can read .ini files easily with the configparser module.
An .ini file looks like this:
[OPTIONS] name = Jabba
As you can see, string values are not quoted. However, for me it looks lame. IMO a string must be between quotes or apostrophes. With quotes you can also add whitespace characters to the beginning or the end of a string. So I prefer writing this:
[OPTIONS] name = "Jabba"
But now quotes become part of the string. If you read it with configparser, the value of name is '"Jabba"' instead of 'Jabba'.
Solution
When using configparser, it builds a dict-like object. I prefer to work with normal dictionaries. So first I read the .ini file, then convert the configparser object to dict, and finally I remove quotes (or apostrophes) from string values. Here is my solution:
preferences.ini
[GENERAL] onekey = "value in some words" [SETTINGS] resolution = '1024 x 768'
example.py
#!/usr/bin/env python3
from pprint import pprint
import preferences
prefs = preferences.Preferences("preferences.ini")
d = prefs.as_dict()
pprint(d)
preferences.py
import sys
import configparser
import json
from pprint import pprint
def remove_quotes(original):
d = original.copy()
for key, value in d.items():
if isinstance(value, str):
s = d[key]
if s.startswith(('"', "'")):
s = s[1:]
if s.endswith(('"', "'")):
s = s[:-1]
d[key] = s
# print(f"string found: {s}")
if isinstance(value, dict):
d[key] = remove_quotes(value)
#
return d
class Preferences:
def __init__(self, preferences_ini):
self.preferences_ini = preferences_ini
self.config = configparser.ConfigParser()
self.config.read(preferences_ini)
self.d = self.to_dict(self.config._sections)
def as_dict(self):
return self.d
def to_dict(self, config):
"""
Nested OrderedDict to normal dict.
Also, remove the annoying quotes (apostrophes) from around string values.
"""
d = json.loads(json.dumps(config))
d = remove_quotes(d)
return d
The line d = remove_quotes(d) is responsible for removing the quotes. Comment / uncomment this line to see the difference.
Output:
$ ./example.py
{'GENERAL': {'onekey': 'value in some words'},
'SETTINGS': {'resolution': '1024 x 768'}}
I also posted this to SO (link here).
