summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/locale.py23
-rw-r--r--Lib/test/test_locale.py14
-rw-r--r--Misc/ACKS2
-rw-r--r--Misc/NEWS4
4 files changed, 35 insertions, 8 deletions
diff --git a/Lib/locale.py b/Lib/locale.py
index 17056b9..372c955 100644
--- a/Lib/locale.py
+++ b/Lib/locale.py
@@ -11,7 +11,11 @@
"""
-import sys, encodings, encodings.aliases
+import sys
+import encodings
+import encodings.aliases
+import re
+import collections
from builtins import str as _builtin_str
import functools
@@ -173,6 +177,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).
@@ -180,9 +187,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:
@@ -206,10 +217,6 @@ def format(percent, value, grouping=False, monetary=False, *additional):
formatted = _strip_padding(formatted, seps)
return formatted
-import re, collections
-_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.
diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py
index c77dc55..65639ad 100644
--- a/Lib/test/test_locale.py
+++ b/Lib/test/test_locale.py
@@ -219,6 +219,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.
@@ -314,6 +327,7 @@ class TestMiscellaneous(unittest.TestCase):
def test_main():
tests = [
TestMiscellaneous,
+ TestFormatPatternArg,
TestEnUSNumberFormatting,
TestCNumberFormatting,
TestFrFRNumberFormatting,
diff --git a/Misc/ACKS b/Misc/ACKS
index 8ca5b7f..acde815 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -482,6 +482,7 @@ Damien Miller
Chad Miller
Jay T. Miller
Roman Milner
+Andrii V. Mishkovskyi
Dustin J. Mitchell
Dom Mitchell
Doug Moen
@@ -492,6 +493,7 @@ James A Morrison
Sjoerd Mullender
Sape Mullender
Michael Muller
+R. David Murray
Piotr Meyer
John Nagle
Takahiro Nakayama
diff --git a/Misc/NEWS b/Misc/NEWS
index ee96d22..7f0808d 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -284,6 +284,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.