--- Python-2.5.2.orig/Lib/decimal.py 2008-12-01 23:39:58.000000000 -0430 +++ Python-2.5.2.orig/Lib/decimal.py 2008-12-01 23:43:17.000000000 -0430 @@ -146,6 +146,13 @@ ROUND_HALF_DOWN = 'ROUND_HALF_DOWN' ROUND_05UP = 'ROUND_05UP' +import string + +def ascii_upper(s): + trans_table = string.maketrans(string.ascii_lowercase, string.ascii_uppercase) + return s.translate(trans_table) + + # Errors class DecimalException(ArithmeticError): @@ -3354,7 +3361,7 @@ if name.startswith('_round_')] for name in rounding_functions: # name is like _round_half_even, goes to the global ROUND_HALF_EVEN value. - globalname = name[1:].upper() + globalname = ascii_upper(name[1:]) val = globals()[globalname] Decimal._pick_rounding_function[val] = name --- Python-2.5.2.orig/Lib/email/__init__.py 2008-12-01 23:39:57.000000000 -0430 +++ Python-2.5.2.orig/Lib/email/__init__.py 2008-12-06 15:14:43.000000000 -0430 @@ -109,15 +109,18 @@ 'Text', ] +import string +lower_map = string.maketrans(string.ascii_uppercase, string.ascii_lowercase) + for _name in _LOWERNAMES: - importer = LazyImporter(_name.lower()) + importer = LazyImporter(_name.translate(lower_map)) sys.modules['email.' + _name] = importer setattr(sys.modules['email'], _name, importer) import email.mime for _name in _MIMENAMES: - importer = LazyImporter('mime.' + _name.lower()) + importer = LazyImporter('mime.' + _name.translate(lower_map)) sys.modules['email.MIME' + _name] = importer setattr(sys.modules['email'], 'MIME' + _name, importer) setattr(sys.modules['email.mime'], _name, importer) --- Python-2.5.2.orig/Lib/locale.py 2008-12-01 23:39:57.000000000 -0430 +++ Python-2.5.2.orig/Lib/locale.py 2008-12-06 15:18:26.000000000 -0430 @@ -278,6 +278,15 @@ # overridden below) _setlocale = setlocale +# Avoid relying on the locale-dependent .lower() method +# (see bug #1813). +_ascii_lower_map = ''.join( + chr(x + 32 if x >= ord('A') and x <= ord('Z') else x) + for x in range(256) +) + + + def normalize(localename): """ Returns a normalized locale code for the given locale @@ -295,7 +304,7 @@ """ # Normalize the locale name and extract the encoding - fullname = localename.lower() + fullname = localename.translate(_ascii_lower_map) if ':' in fullname: # ':' is sometimes used as encoding delimiter. fullname = fullname.replace(':', '.') --- Python-2.5.2.orig/Lib/test/test_codecs.py 2008-12-01 23:39:57.000000000 -0430 +++ Python-2.5.2.orig/Lib/test/test_codecs.py 2008-12-06 15:21:02.000000000 -0430 @@ -1,6 +1,7 @@ from __future__ import with_statement from test import test_support import unittest +import locale import codecs import sys, StringIO, _testcapi @@ -938,6 +939,16 @@ self.assertRaises(LookupError, codecs.lookup, "__spam__") self.assertRaises(LookupError, codecs.lookup, " ") + def test_lookup_with_locale(self): + # Bug #1813: when normalizing codec name, lowercasing must be locale + # agnostic, otherwise the looked up codec name might end up wrong. + try: + locale.setlocale(locale.LC_CTYPE, 'tr') + except locale.Error: + # SKIPped test + return + codecs.lookup('ISO8859_1') + def test_getencoder(self): self.assertRaises(TypeError, codecs.getencoder) self.assertRaises(LookupError, codecs.getencoder, "__spam__") --- Python-2.5.2.orig/Python/codecs.c 2008-12-01 23:39:58.000000000 -0430 +++ Python-2.5.2.orig/Python/codecs.c 2008-12-01 23:41:58.000000000 -0430 @@ -45,6 +45,12 @@ return -1; } +/* isupper() forced into the ASCII Locale */ +#define ascii_isupper(x) (((x) >= 0x41) && ((x) <= 0x5A)) +/* tolower() forced into the ASCII Locale */ +#define ascii_tolower(x) (ascii_isupper(x) ? ((x) + 0x20) : (x)) + + /* Convert a string to a normalized Python string: all characters are converted to lower case, spaces are replaced with underscores. */ @@ -70,7 +76,7 @@ if (ch == ' ') ch = '-'; else - ch = tolower(Py_CHARMASK(ch)); + ch = ascii_tolower(Py_CHARMASK(ch)); p[i] = ch; } return v;