PY3(BF): config reader -- handle __name__ interpolation

pull/185/head
Yaroslav Halchenko 12 years ago
parent d05e7a5746
commit 203ddb370a

@ -28,15 +28,45 @@ __copyright__ = 'Copyright (c) 2007 Yaroslav Halchenko'
__license__ = 'GPL' __license__ = 'GPL'
import logging, os, sys import logging, os, sys
if sys.version_info >= (3,2): # pragma: no cover if sys.version_info >= (3,2): # pragma: no cover
# SafeConfigParser deprecitated from python 3.2 (renamed ConfigParser)
from configparser import ConfigParser as SafeConfigParser # SafeConfigParser deprecated from Python 3.2 (renamed to ConfigParser)
from configparser import ConfigParser as SafeConfigParser, \
BasicInterpolation
# And interpolation of __name__ was simply removed, thus we need to
# decorate default interpolator to handle it
class BasicInterpolationWithName(BasicInterpolation):
"""Decorator to bring __name__ interpolation back.
Original handling of __name__ was removed because of
functional deficiencies: http://bugs.python.org/issue10489
commit v3.2a4-105-g61f2761
Author: Lukasz Langa <lukasz@langa.pl>
Date: Sun Nov 21 13:41:35 2010 +0000
Issue #10489: removed broken `__name__` support from configparser
But should be fine to reincarnate for our use case
"""
def _interpolate_some(self, parser, option, accum, rest, section, map,
depth):
if section and not (__name__ in map):
map = map.copy() # just to be safe
map['__name__'] = section
return super(BasicInterpolationWithName, self)._interpolate_some(
parser, option, accum, rest, section, map, depth)
else: # pragma: no cover else: # pragma: no cover
from ConfigParser import SafeConfigParser from ConfigParser import SafeConfigParser
# Gets the instance of the logger. # Gets the instance of the logger.
logSys = logging.getLogger(__name__) logSys = logging.getLogger(__name__)
__all__ = ['SafeConfigParserWithIncludes']
class SafeConfigParserWithIncludes(SafeConfigParser): class SafeConfigParserWithIncludes(SafeConfigParser):
""" """
Class adds functionality to SafeConfigParser to handle included Class adds functionality to SafeConfigParser to handle included
@ -68,6 +98,14 @@ after = 1.conf
SECTION_NAME = "INCLUDES" SECTION_NAME = "INCLUDES"
if sys.version_info >= (3,2):
# overload constructor only for fancy new Python3's
def __init__(self, *args, **kwargs):
kwargs = kwargs.copy()
kwargs['interpolation'] = BasicInterpolationWithName()
super(SafeConfigParserWithIncludes, self).__init__(
*args, **kwargs)
#@staticmethod #@staticmethod
def getIncludes(resource, seen = []): def getIncludes(resource, seen = []):
""" """

@ -21,7 +21,7 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko" __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2011-2013 Yaroslav Halchenko"
__license__ = "GPL" __license__ = "GPL"
import os, shutil, tempfile, unittest import os, shutil, sys, tempfile, unittest
from fail2ban.client.configreader import ConfigReader from fail2ban.client.configreader import ConfigReader
from fail2ban.client.jailreader import JailReader from fail2ban.client.jailreader import JailReader
@ -47,7 +47,7 @@ class ConfigReaderTest(unittest.TestCase):
"""Call after every test case.""" """Call after every test case."""
shutil.rmtree(self.d) shutil.rmtree(self.d)
def _write(self, fname, value): def _write(self, fname, value=None, content=None):
# verify if we don't need to create .d directory # verify if we don't need to create .d directory
if os.path.sep in fname: if os.path.sep in fname:
d = os.path.dirname(fname) d = os.path.dirname(fname)
@ -55,10 +55,13 @@ class ConfigReaderTest(unittest.TestCase):
if not os.path.exists(d_): if not os.path.exists(d_):
os.makedirs(d_) os.makedirs(d_)
f = open("%s/%s" % (self.d, fname), "w") f = open("%s/%s" % (self.d, fname), "w")
f.write(""" if value is not None:
f.write("""
[section] [section]
option = %s option = %s
""" % value) """ % value)
if content is not None:
f.write(content)
f.close() f.close()
def _remove(self, fname): def _remove(self, fname):
@ -105,6 +108,28 @@ option = %s
self._remove("c.local") self._remove("c.local")
self.assertEqual(self._getoption(), 1) self.assertEqual(self._getoption(), 1)
def testInterpolations(self):
self.assertFalse(self.c.read('i')) # nothing is there yet
self._write("i.conf", value=None, content="""
[DEFAULT]
b = a
zz = the%(__name__)s
[section]
y = 4%(b)s
e = 5${b}
z = %(__name__)s
[section2]
z = 3%(__name__)s
""")
self.assertTrue(self.c.read('i'))
self.assertEqual(self.c.sections(), ['section', 'section2'])
self.assertEqual(self.c.get('section', 'y'), '4a') # basic interpolation works
self.assertEqual(self.c.get('section', 'e'), '5${b}') # no extended interpolation
self.assertEqual(self.c.get('section', 'z'), 'section') # __name__ works
self.assertEqual(self.c.get('section', 'zz'), 'thesection') # __name__ works even 'delayed'
self.assertEqual(self.c.get('section2', 'z'), '3section2') # and differs per section ;)
class JailReaderTest(unittest.TestCase): class JailReaderTest(unittest.TestCase):

Loading…
Cancel
Save