Commit a83da350 authored by R. David Murray's avatar R. David Murray

Fix issue 2522. locale.format now checks that it is passed

exactly one pattern, which avoids mysterious errors where it
had seemed to fail to do localization.
parent bb94d43d
......@@ -11,7 +11,11 @@
"""
import sys, encodings, encodings.aliases
import sys
import encodings
import encodings.aliases
import re
import operator
import functools
# Try importing the _locale module.
......@@ -166,6 +170,9 @@ def _strip_padding(s, amount):
amount -= 1
return s[lpos:rpos+1]
_percent_re = re.compile(r'%(?:\((?P<key>.*?)\))?'
r'(?P<modifiers>[-#0-9 +*.hlL]*?)[eEfFgGdiouxXcrs%]')
def format(percent, value, grouping=False, monetary=False, *additional):
"""Returns the locale-aware substitution of a %? specifier
(percent).
......@@ -173,9 +180,13 @@ def format(percent, value, grouping=False, monetary=False, *additional):
additional is for format strings which contain one or more
'*' modifiers."""
# this is only for one-percent-specifier strings and this should be checked
if percent[0] != '%':
raise ValueError("format() must be given exactly one %char "
"format specifier")
match = _percent_re.match(percent)
if not match or len(match.group())!= len(percent):
raise ValueError(("format() must be given exactly one %%char "
"format specifier, %s not valid") % repr(percent))
return _format(percent, value, grouping, monetary, *additional)
def _format(percent, value, grouping=False, monetary=False, *additional):
if additional:
formatted = percent % ((value,) + additional)
else:
......@@ -199,10 +210,6 @@ def format(percent, value, grouping=False, monetary=False, *additional):
formatted = _strip_padding(formatted, seps)
return formatted
import re, operator
_percent_re = re.compile(r'%(?:\((?P<key>.*?)\))?'
r'(?P<modifiers>[-#0-9 +*.hlL]*?)[eEfFgGdiouxXcrs%]')
def format_string(f, val, grouping=False):
"""Formats a string in the same way that the % formatting would use,
but takes the current locale into account.
......
......@@ -221,6 +221,19 @@ class EnUSNumberFormatting(BaseFormattingTest):
(self.sep, self.sep))
class TestFormatPatternArg(unittest.TestCase):
# Test handling of pattern argument of format
def test_onlyOnePattern(self):
# Issue 2522: accept exactly one % pattern, and no extra chars.
self.assertRaises(ValueError, locale.format, "%f\n", 'foo')
self.assertRaises(ValueError, locale.format, "%f\r", 'foo')
self.assertRaises(ValueError, locale.format, "%f\r\n", 'foo')
self.assertRaises(ValueError, locale.format, " %f", 'foo')
self.assertRaises(ValueError, locale.format, "%fg", 'foo')
self.assertRaises(ValueError, locale.format, "%^g", 'foo')
class TestNumberFormatting(BaseLocalizedTest, EnUSNumberFormatting):
# Test number formatting with a real English locale.
......@@ -351,6 +364,7 @@ class TestMiscellaneous(unittest.TestCase):
def test_main():
tests = [
TestMiscellaneous,
TestFormatPatternArg,
TestEnUSNumberFormatting,
TestCNumberFormatting,
TestFrFRNumberFormatting,
......
......@@ -480,6 +480,7 @@ Damien Miller
Chad Miller
Jay T. Miller
Roman Milner
Andrii V. Mishkovskyi
Dustin J. Mitchell
Dom Mitchell
Doug Moen
......@@ -490,6 +491,7 @@ James A Morrison
Sjoerd Mullender
Sape Mullender
Michael Muller
R. David Murray
Piotr Meyer
John Nagle
Takahiro Nakayama
......
......@@ -200,6 +200,10 @@ Core and Builtins
Library
-------
- Issue #2522: locale.format now checks its first argument to ensure it has
been passed only one pattern, avoiding mysterious errors where it appeared
that it was failing to do localization.
- Issue #5583: Added optional Extensions in Distutils. Initial patch by Georg
Brandl.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment