Issue #6656: fix locale.format_string to handle escaped percents and mappings.

Refactors format_string.  Includes tests for the two problems noted in
the issue, but as far as I can see there are no other tests that confirm
that format_string conforms to normal % formatting rules.
This commit is contained in:
R. David Murray 2010-04-26 21:17:14 +00:00
parent 278d665c6a
commit 3939dcdb72
3 changed files with 45 additions and 14 deletions

View File

@ -220,22 +220,30 @@ def format_string(f, val, grouping=False):
percents = list(_percent_re.finditer(f)) percents = list(_percent_re.finditer(f))
new_f = _percent_re.sub('%s', f) new_f = _percent_re.sub('%s', f)
if isinstance(val, tuple): if operator.isMappingType(val):
new_val = list(val) new_val = []
for perc in percents:
if perc.group()[-1]=='%':
new_val.append('%')
else:
new_val.append(format(perc.group(), val, grouping))
else:
if not isinstance(val, tuple):
val = (val,)
new_val = []
i = 0 i = 0
for perc in percents: for perc in percents:
starcount = perc.group('modifiers').count('*') if perc.group()[-1]=='%':
new_val[i] = format(perc.group(), new_val[i], grouping, False, *new_val[i+1:i+1+starcount]) new_val.append('%')
del new_val[i+1:i+1+starcount] else:
i += (1 + starcount) starcount = perc.group('modifiers').count('*')
val = tuple(new_val) new_val.append(_format(perc.group(),
elif operator.isMappingType(val): val[i],
for perc in percents: grouping,
key = perc.group("key") False,
val[key] = format(perc.group(), val[key], grouping) *val[i+1:i+1+starcount]))
else: i += (1 + starcount)
# val is a single value val = tuple(new_val)
val = format(percents[0].group(), val, grouping)
return new_f % val return new_f % val

View File

@ -238,6 +238,25 @@ class TestFormatPatternArg(unittest.TestCase):
self.assertRaises(ValueError, locale.format, " %f", 'foo') self.assertRaises(ValueError, locale.format, " %f", 'foo')
self.assertRaises(ValueError, locale.format, "%fg", 'foo') self.assertRaises(ValueError, locale.format, "%fg", 'foo')
self.assertRaises(ValueError, locale.format, "%^g", 'foo') self.assertRaises(ValueError, locale.format, "%^g", 'foo')
self.assertRaises(ValueError, locale.format, "%f%%", 'foo')
class TestLocaleFormatString(unittest.TestCase):
"""General tests on locale.format_string"""
def test_percent_escape(self):
self.assertEqual(locale.format_string('%f%%', 1.0), '%f%%' % 1.0)
self.assertEqual(locale.format_string('%d %f%%d', (1, 1.0)),
'%d %f%%d' % (1, 1.0))
self.assertEqual(locale.format_string('%(foo)s %%d', {'foo': 'bar'}),
('%(foo)s %%d' % {'foo': 'bar'}))
def test_mapping(self):
self.assertEqual(locale.format_string('%(foo)s bing.', {'foo': 'bar'}),
('%(foo)s bing.' % {'foo': 'bar'}))
self.assertEqual(locale.format_string('%(foo)s', {'foo': 'bar'}),
('%(foo)s' % {'foo': 'bar'}))
class TestNumberFormatting(BaseLocalizedTest, EnUSNumberFormatting): class TestNumberFormatting(BaseLocalizedTest, EnUSNumberFormatting):
@ -382,6 +401,7 @@ def test_main():
tests = [ tests = [
TestMiscellaneous, TestMiscellaneous,
TestFormatPatternArg, TestFormatPatternArg,
TestLocaleFormatString,
TestEnUSNumberFormatting, TestEnUSNumberFormatting,
TestCNumberFormatting, TestCNumberFormatting,
TestFrFRNumberFormatting, TestFrFRNumberFormatting,

View File

@ -27,6 +27,9 @@ Core and Builtins
Library Library
------- -------
- Issue #6656: fix locale.format_string to handle escaped percents
and mappings.
- Issue #2302: Fix a race condition in SocketServer.BaseServer.shutdown, - Issue #2302: Fix a race condition in SocketServer.BaseServer.shutdown,
where the method could block indefinitely if called just before the where the method could block indefinitely if called just before the
event loop started running. This also fixes the occasional freezes event loop started running. This also fixes the occasional freezes