From 7f13e6b3e2546a7d6402f969113d928cc1d58dfc Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 31 Aug 2007 10:37:15 +0000 Subject: [PATCH] string.maketrans() now produces translation tables for bytes.translate() -- wrong module? Fix all remaining instances that did bad things with the new str.translate(). --- Doc/library/stdtypes.rst | 7 +++---- Doc/library/string.rst | 24 ++++++++-------------- Lib/distutils/command/install.py | 5 ++--- Lib/distutils/fancy_getopt.py | 8 ++++---- Lib/string.py | 35 +++++++++++++------------------- Lib/test/test_bigmem.py | 3 +-- Lib/test/test_string.py | 7 ++++--- Lib/textwrap.py | 7 +------ Lib/urllib.py | 5 +---- 9 files changed, 39 insertions(+), 62 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index dab3476b160..084c07cb808 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1549,10 +1549,10 @@ further useful methods also found on strings. b'example' -.. method:: bytes.translate(table[, deletechars]) +.. method:: bytes.translate(table[, delete]) Return a copy of the bytes object where all bytes occurring in the optional - argument *deletechars* are removed, and the remaining bytes have been mapped + argument *delete* are removed, and the remaining bytes have been mapped through the given translation table, which must be a bytes object of length 256. @@ -1560,8 +1560,7 @@ further useful methods also found on strings. create a translation table. .. XXX a None table doesn't seem to be supported - For string objects, set the *table* argument to - ``None`` for translations that only delete characters:: + Set the *table* argument to ``None`` for translations that only delete characters:: >>> 'read this short text'.translate(None, 'aeiou') 'rd ths shrt txt' diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 4d7974904a5..2e1b529a8eb 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -128,10 +128,11 @@ formatting behaviors using the same implementation as the built-in .. method:: get_field(field_name, args, kwargs, used_args) Given *field_name* as returned by :meth:`parse` (see above), convert it to - an object to be formatted. The default version takes strings of the form - defined in :pep:`3101`, such as "0[name]" or "label.title". It records - which args have been used in *used_args*. *args* and *kwargs* are as - passed in to :meth:`vformat`. + an object to be formatted. Returns a tuple (obj, used_key). The default + version takes strings of the form defined in :pep:`3101`, such as + "0[name]" or "label.title". *args* and *kwargs* are as passed in to + :meth:`vformat`. The return value *used_key* has the same meaning as the + *key* parameter to :meth:`get_value`. .. method:: get_value(key, args, kwargs) @@ -554,15 +555,8 @@ They are not available as string methods. leading and trailing whitespace. -.. XXX is obsolete with unicode.translate -.. function:: maketrans(from, to) +.. function:: maketrans(frm, to) - Return a translation table suitable for passing to :func:`translate`, that will - map each character in *from* into the character at the same position in *to*; - *from* and *to* must have the same length. - - .. warning:: - - Don't use strings derived from :const:`lowercase` and :const:`uppercase` as - arguments; in some locales, these don't have the same length. For case - conversions, always use :func:`lower` and :func:`upper`. + Return a translation table suitable for passing to :meth:`bytes.translate`, + that will map each character in *from* into the character at the same + position in *to*; *from* and *to* must have the same length. diff --git a/Lib/distutils/command/install.py b/Lib/distutils/command/install.py index 29cda1ebb7f..ffd68db2694 100644 --- a/Lib/distutils/command/install.py +++ b/Lib/distutils/command/install.py @@ -348,11 +348,10 @@ class install (Command): if opt_name[-1] == "=": opt_name = opt_name[0:-1] if self.negative_opt.has_key(opt_name): - opt_name = self.negative_opt[opt_name].translate( - longopt_xlate) + opt_name = longopt_xlate(self.negative_opt[opt_name]) val = not getattr(self, opt_name) else: - opt_name = opt_name.translate(longopt_xlate) + opt_name = longopt_xlate(opt_name) val = getattr(self, opt_name) print(" %s: %s" % (opt_name, val)) diff --git a/Lib/distutils/fancy_getopt.py b/Lib/distutils/fancy_getopt.py index 5434334e79d..15cbdd71622 100644 --- a/Lib/distutils/fancy_getopt.py +++ b/Lib/distutils/fancy_getopt.py @@ -26,7 +26,7 @@ neg_alias_re = re.compile("^(%s)=!(%s)$" % (longopt_pat, longopt_pat)) # This is used to translate long options to legitimate Python identifiers # (for use as attributes of some object). -longopt_xlate = string.maketrans('-', '_') +longopt_xlate = lambda s: s.replace('-', '_') class FancyGetopt: """Wrapper around the standard 'getopt()' module that provides some @@ -107,7 +107,7 @@ class FancyGetopt: """Translate long option name 'long_option' to the form it has as an attribute of some object: ie., translate hyphens to underscores.""" - return long_option.translate(longopt_xlate) + return longopt_xlate(long_option) def _check_alias_dict(self, aliases, what): assert isinstance(aliases, dict) @@ -372,7 +372,7 @@ def fancy_getopt(options, negative_opt, object, args): return parser.getopt(args, object) -WS_TRANS = string.maketrans(string.whitespace, ' ' * len(string.whitespace)) +WS_TRANS = {ord(_wschar) : ' ' for _wschar in string.whitespace} def wrap_text(text, width): """wrap_text(text : string, width : int) -> [string] @@ -432,7 +432,7 @@ def translate_longopt(opt): """Convert a long option name to a valid Python identifier by changing "-" to "_". """ - return opt.translate(longopt_xlate) + return longopt_xlate(opt) class OptionDummy: diff --git a/Lib/string.py b/Lib/string.py index f60753fde29..ff21eb1944d 100644 --- a/Lib/string.py +++ b/Lib/string.py @@ -25,10 +25,6 @@ octdigits = '01234567' punctuation = """!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~""" printable = digits + ascii_letters + punctuation + whitespace -# Case conversion helpers -# Use str to convert Unicode literal in case of -U -_idmap = str('').join(chr(c) for c in range(256)) - # Functions which aren't available as string methods. # Capitalize the words in a string, e.g. " aBc dEf " -> "Abc Def". @@ -44,26 +40,23 @@ def capwords(s, sep=None): return (sep or ' ').join([x.capitalize() for x in s.split(sep)]) -# Construct a translation string -_idmapL = None -def maketrans(fromstr, tostr): - """maketrans(frm, to) -> string - - Return a translation table (a string of 256 bytes long) - suitable for use in string.translate. The strings frm and to - must be of the same length. +# Construct a translation map for bytes.translate +def maketrans(frm, to): + """maketrans(frm, to) -> bytes + Return a translation table (a bytes object of length 256) + suitable for use in bytes.translate where each byte in frm is + mapped to the byte at the same position in to. + The strings frm and to must be of the same length. """ - if len(fromstr) != len(tostr): + if len(frm) != len(to): raise ValueError("maketrans arguments must have same length") - global _idmapL - if not _idmapL: - _idmapL = list(_idmap) - L = _idmapL[:] - for i, c in enumerate(fromstr): - L[ord(c)] = tostr[i] - return ''.join(L) - + if not (isinstance(frm, bytes) and isinstance(to, bytes)): + raise TypeError("maketrans arguments must be bytes objects") + L = bytes(range(256)) + for i, c in enumerate(frm): + L[c] = to[i] + return L #################################################################### diff --git a/Lib/test/test_bigmem.py b/Lib/test/test_bigmem.py index a6a7c24b8f3..7244e1be141 100644 --- a/Lib/test/test_bigmem.py +++ b/Lib/test/test_bigmem.py @@ -3,7 +3,6 @@ from test.test_support import bigmemtest, _1G, _2G import unittest import operator -import string import sys # Bigmem testing houserules: @@ -376,7 +375,7 @@ class StrTest(unittest.TestCase): @bigmemtest(minsize=_2G, memuse=2) def test_translate(self, size): - trans = string.maketrans('.aZ', '-!$') + trans = {ord('.'):'-', ord('a'):'!', ord('Z'):'$'} SUBSTR = 'aZz.z.Aaz.' sublen = len(SUBSTR) repeats = size // sublen + 2 diff --git a/Lib/test/test_string.py b/Lib/test/test_string.py index b3af6858409..4c3c964509f 100644 --- a/Lib/test/test_string.py +++ b/Lib/test/test_string.py @@ -103,10 +103,11 @@ class ModuleTest(unittest.TestCase): def test_maketrans(self): - transtable = '\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037 !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`xyzdefghijklmnopqrstuvwxyz{|}~\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377' + transtable = b'\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037 !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`xyzdefghijklmnopqrstuvwxyz{|}~\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377' - self.assertEqual(string.maketrans('abc', 'xyz'), transtable) - self.assertRaises(ValueError, string.maketrans, 'abc', 'xyzq') + self.assertEqual(string.maketrans(b'abc', b'xyz'), transtable) + self.assertRaises(ValueError, string.maketrans, b'abc', b'xyzq') + self.assertRaises(TypeError, string.maketrans, 'abc', 'def') def test_main(): test_support.run_unittest(ModuleTest) diff --git a/Lib/textwrap.py b/Lib/textwrap.py index 3fc14f0c8c3..e6e1b97f288 100644 --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -59,8 +59,6 @@ class TextWrapper: Drop leading and trailing whitespace from lines. """ - whitespace_trans = string.maketrans(_whitespace, ' ' * len(_whitespace)) - unicode_whitespace_trans = {} uspace = ord(' ') for x in _whitespace: @@ -116,10 +114,7 @@ class TextWrapper: if self.expand_tabs: text = text.expandtabs() if self.replace_whitespace: - if isinstance(text, str8): - text = text.translate(self.whitespace_trans) - elif isinstance(text, str): - text = text.translate(self.unicode_whitespace_trans) + text = text.translate(self.unicode_whitespace_trans) return text diff --git a/Lib/urllib.py b/Lib/urllib.py index a1e26f04d22..04fd50a6ca1 100644 --- a/Lib/urllib.py +++ b/Lib/urllib.py @@ -1420,7 +1420,6 @@ def reporthook(blocknum, blocksize, totalsize): # Test program def test(args=[]): - import string if not args: args = [ '/etc/passwd', @@ -1443,9 +1442,7 @@ def test(args=[]): fp = open(fn, 'rb') data = fp.read() del fp - if '\r' in data: - table = string.maketrans("", "") - data = data.translate(table, "\r") + data = data.replace("\r", "") print(data) fn, h = None, None print('-'*40)