Examples¶
Getting started¶
Attempt to load a system-wide configuration file, whose settings will be overwritten by a user preferences files.
Missing files are silently ignored.
from ihih import IHIH
conf = IHIH(
(
'/etc/example.conf',
os.path.join(os.path.expanduser('~'), '.example.conf')
),
debug='1'
)
if conf.get_float('debug', errors='ignore'):
print 'i am running in debug mode'
Reloading the conf¶
Assuming conf is a IHIH
instance.
# reload on SIGHUP
import signal
signal.signal(signal.SIGHUP, lambda s, f: conf.reload())
Configuration format¶
By default, IHIH
parse files using the following rules:
- the key is before the first
=
character - the value is everything after the first
=
character - the value might be empty
- key and value have their leading and trailing spaces stripped
- values can be quoted (between
'
or"
) - quoted values have their quotes automatically removed (ie:
"my value"
becomesmy value
) - single quotes are considered as a character
- lines not matching the key / separator / value are ignored
- comments (beginning with a
#
or//
) are ignored and deleted from the value except if they are escaped or quoted - specials characters (
\'"#/
) can be escaped by prefixing them with a backslash (\
) to not be treated specially - other (non-special) characters preceded by the escape character are not treated specially and the escape character is preserved
By default, IHIHI
parse files accordingly the following rules:
- same-same than
IHIH
- add dollar (
$
) in the special character list - every word prefixed by a non-escaped dollar and not embraced by
single-quotes (
'
) is considered as a variable - strings beginning with
${
and ending with}
are also variables, this let you define variables containing non-word characters such as dots hyphens, or spaces - variables interpolation is done when using the variable, this let you define (or change) the variable content later
- when a variable is not found, it resolve as an empty string
- variable recursion resolve to an empty string
Which mean that it could parse, to a certain extent (see Single-line only), subset of:
- shell script
- Postfix main.cf
- Python
- INI (will ignore the sections)
That could be convenient if you have to share a configuration file between scripts, given you pay attention to respect both formats.
Examples of configuration files¶
Parsing a shell script:
# as in shell
FOO="bar"
FOOBAR=foo-$FOO # resolve as: foo-bar
FOOBAR="foo-$FOO" # resolve as: foo-bar
FOOBAR='foo-$FOO' # resolve as: foo-$FOO
BAR=${FOO} # resolve as: bar
ABC="a" 'b' c # resolve as: a b c
C=hello # world # resolve as: hello
D=hello \# world # resolve as: hello # world
# different
DATE=$(date) # resolve as: $(date)
Parsing a main.cf:
smtpd_banner = $myhostname ESMTP
myhostname = foo.example.net
Parsing some Python:
# same
a = 'AA'
b = "BB"
# notably different
c = 'A' "B" # resolve as: A B
d = c # resolve as: c
Parsing an INI file:
; section is ignored
[uwsgi]
http-socket = :9090
processes = 4
; different, resolve as: localhost:9000
URL = localhost${http-socket}
Examples in the examples directory¶
You can see / run the examples in the examples directory.
Extending the parsers to parse INI¶
#!/usr/bin/python
# vim:set fileencoding=utf8:
'''INI parsing with ihih - proof of concept
A quick-and-dirty, incomplete, INI parsing proof-of-concept using :mod:`ihih`.
'''
import os
import re
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from ihih import IHIH, IHIHI
class _IHIHI(IHIHI):
_escaped_chars = r'[\\\'\"\#/\;]'
_comment = r'(\s*%(escape)s(?:\#|//|\;))'
class IHIHINI(IHIH):
_section = r'^%(escape)s\[(?P<section>.+?)%(escape)s\]'
_escaped_chars = r'[\\\'\"\#/\;]'
_comment = _IHIHI._comment
_separator = r'[\=\:]'
def __init__(self, *args, **kwargs):
self.r_section = re.compile(
self._section % {'escape': self._escape},
re.U
)
super(IHIHINI, self).__init__(*args, **kwargs)
__setitem__ = dict.__setitem__
__getitem__ = dict.__getitem__
def parse(self, filename, force=False, ignore_IOError=True):
section = None
try:
fo = open(filename)
except IOError:
if ignore_IOError:
return False
raise
for line in fo:
results = self.r_section.match(line)
if results:
section = results.group(1)
continue
results = self.r_extract.match(line)
if results:
if section is None:
raise KeyError('not in a section')
elif section not in self:
self[section] = _IHIHI(())
self[section][results.group('key')] = results \
.group('value').rstrip()
return True
if __name__ == '__main__':
import tempfile
with tempfile.NamedTemporaryFile() as tmp:
tmp.write('[My section]\nfoodir: $dir/whatever\ndir=frob\n')
tmp.write('key = "value" ; a comment')
tmp.flush()
conf = IHIHINI(tmp.name)
for section in conf:
print('%s:' % section)
for k in conf[section]:
print('\t%s = %s' % (k, conf[section].get_unicode(k)))