Skip to content

Instantly share code, notes, and snippets.

@beaugunderson
Last active Aug 29, 2015
Embed
What would you like to do?
import os
from tini import Tini
filenames = [
'./intervention.ini',
os.path.join(os.path.expanduser('~'), '.intervention.ini'),
os.path.join(os.path.expanduser('~'), '.config', '.intervention.ini'),
]
defaults = {
'intervention': {
'message': 'Am I being intentional?',
'background-color': '#293776'
}
}
parser = Tini(filenames, defaults=defaults)
settings = parser.items()
import configparser
import re
from collections import defaultdict
from distutils import util
def coerce_value(value):
"""
Try coercing values to numbers or booleans.
"""
if not isinstance(value, str):
return value
if re.match(r'^[0-9]+$', value):
return int(value)
if re.match(r'^[.0-9]+$', value):
try:
return float(value)
except ValueError:
return value
if re.match(r'^(true|false|yes|no)$', value, flags=re.IGNORECASE):
return bool(util.strtobool(value))
return value
class SimpleInterpolation(configparser.Interpolation):
"""
Strip quotes from strings.
"""
def before_read(self, parser, section, option, value):
if not isinstance(value, str):
return value
coerced_value = coerce_value(value)
if isinstance(coerced_value, str):
return coerced_value.strip('"\'')
return coerced_value
class SimpleConfigParser(configparser.ConfigParser):
u"""
A ConfigParser that:
- strips quotes from strings ('"value"' becomes 'value')
- doesn't transform option strings ('OPTION' remains upper-case)
- doesn't support weird '%' interpolation
- allows empty values ('value =' is ok)
- coerces numbers and booleans ('true' → True)
"""
def __init__(self, *args, **kwargs):
kwargs.update({
'interpolation': SimpleInterpolation(),
'allow_no_value': True
})
super(SimpleConfigParser, self).__init__(*args, **kwargs)
def optionxform(self, option_string):
return option_string
class Tini(object):
"""
Easily parse simple ini files.
"""
def __init__(self, filenames, defaults=None):
if isinstance(filenames, str):
filenames = [filenames]
self.defaults = defaultdict(dict, **(defaults if defaults else {}))
self.parser = SimpleConfigParser()
self.parser.read(filenames)
# We do this here instead of in SimpleConfigParser because we want to
# support defaults that pertain to a specific section.
def items(self):
return {
section: dict(self.defaults[section], **dict(**values))
for section, values in dict(self.parser._sections).items()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment