From: Armin Ronacher Date: Sat, 6 Jul 2013 14:12:55 +0000 (+0200) Subject: First pass on python 3 support X-Git-Tag: 1.0~96 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9e75cf4228b7b35308c8889999f0bffdbcdfd8f1;p=thirdparty%2Fbabel.git First pass on python 3 support --- diff --git a/babel/_compat.py b/babel/_compat.py index f7104928..c4e04478 100644 --- a/babel/_compat.py +++ b/babel/_compat.py @@ -29,7 +29,7 @@ if not PY2: iteritems = lambda d: iter(d.items()) from io import StringIO - import cPickle as pickle + import pickle def reraise(tp, value, tb=None): if value.__traceback__ is not tb: @@ -38,6 +38,9 @@ if not PY2: implements_to_string = _identity + izip = zip + imap = map + else: text_type = unicode string_types = (str, unicode) @@ -48,7 +51,7 @@ else: iteritems = lambda d: d.iteritems() from cStringIO import StringIO - import pickle + import cPickle as pickle exec('def reraise(tp, value, tb=None):\n raise tp, value, tb') @@ -56,3 +59,5 @@ else: cls.__unicode__ = cls.__str__ cls.__str__ = lambda x: x.__unicode__().encode('utf-8') return cls + + from itertools import izip, imap diff --git a/babel/localedata.py b/babel/localedata.py index 7257f6fd..d6e47039 100644 --- a/babel/localedata.py +++ b/babel/localedata.py @@ -19,7 +19,7 @@ import os import threading -from UserDict import DictMixin +from collections import MutableMapping from babel._compat import pickle @@ -178,19 +178,25 @@ class Alias(object): return data -class LocaleDataDict(DictMixin, dict): +class LocaleDataDict(MutableMapping): """Dictionary wrapper that automatically resolves aliases to the actual values. """ def __init__(self, data, base=None): - dict.__init__(self, data) + self._data = data if base is None: base = data self.base = base + def __len__(self): + return len(self._data) + + def __iter__(self): + return iter(self._data) + def __getitem__(self, key): - orig = val = dict.__getitem__(self, key) + orig = val = self._data[key] if isinstance(val, Alias): # resolve an alias val = val.resolve(self.base) if isinstance(val, tuple): # Merge a partial dict with an alias @@ -200,8 +206,14 @@ class LocaleDataDict(DictMixin, dict): if type(val) is dict: # Return a nested alias-resolving dict val = LocaleDataDict(val, base=self.base) if val is not orig: - self[key] = val + self._data[key] = val return val + def __setitem__(self, key, value): + self._data[key] = value + + def __delitem__(self, key): + del self._data[key] + def copy(self): - return LocaleDataDict(dict.copy(self), base=self.base) + return LocaleDataDict(self._data.copy(), base=self.base) diff --git a/babel/plural.py b/babel/plural.py index 47655935..6e3d274d 100644 --- a/babel/plural.py +++ b/babel/plural.py @@ -168,7 +168,8 @@ def to_python(rule): for tag, ast in PluralRule.parse(rule).abstract: result.append(' if (%s): return %r' % (to_python(ast), tag)) result.append(' return %r' % _fallback_tag) - exec '\n'.join(result) in namespace + code = compile('\n'.join(result), '', 'exec') + eval(code, namespace) return namespace['evaluate'] @@ -405,7 +406,8 @@ class _Compiler(object): output formats. """ - def compile(self, (op, args)): + def compile(self, arg): + op, args = arg return getattr(self, 'compile_' + op)(*args) compile_n = lambda x: 'n' diff --git a/babel/util.py b/babel/util.py index d392d1ca..2004f846 100644 --- a/babel/util.py +++ b/babel/util.py @@ -18,7 +18,7 @@ from datetime import timedelta, tzinfo import os import re import textwrap -from itertools import izip, imap +from babel._compat import izip, imap missing = object() diff --git a/scripts/import_cldr.py b/scripts/import_cldr.py index 6586a044..84a6dc7b 100755 --- a/scripts/import_cldr.py +++ b/scripts/import_cldr.py @@ -24,7 +24,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), '..')) from babel import dates, numbers from babel.plural import PluralRule from babel.localedata import Alias -from babel._compat import pickle +from babel._compat import pickle, text_type parse = ElementTree.parse weekdays = {'mon': 0, 'tue': 1, 'wed': 2, 'thu': 3, 'fri': 4, 'sat': 5, @@ -54,7 +54,8 @@ NAME_MAP = { def log(message, *args): if args: message = message % args - print >> sys.stderr, message + sys.stderr.write(message + '\r\n') + sys.stderr.flush() def error(message, *args): @@ -64,7 +65,7 @@ def error(message, *args): def need_conversion(dst_filename, data_dict, source_filename): with open(source_filename, 'rb') as f: blob = f.read(4096) - version = int(re.search(r'version number="\$Revision: (\d+)', blob).group(1)) + version = int(re.search(b'version number="\\$Revision: (\\d+)', blob).group(1)) data_dict['_version'] = version if not os.path.isfile(dst_filename): @@ -160,8 +161,7 @@ def main(): # Resolve territory containment territory_containment = {} - region_items = regions.items() - region_items.sort() + region_items = sorted(regions.items()) for group, territory_list in region_items: for territory in territory_list: containers = territory_containment.setdefault(territory, set([])) @@ -175,14 +175,14 @@ def main(): for elem in prsup.findall('.//plurals/pluralRules'): rules = [] for rule in elem.findall('pluralRule'): - rules.append((rule.attrib['count'], unicode(rule.text))) + rules.append((rule.attrib['count'], text_type(rule.text))) pr = PluralRule(rules) for locale in elem.attrib['locales'].split(): plural_rules[locale] = pr filenames = os.listdir(os.path.join(srcdir, 'main')) filenames.remove('root.xml') - filenames.sort(lambda a,b: len(a)-len(b)) + filenames.sort(key=len) filenames.insert(0, 'root.xml') for filename in filenames: @@ -281,20 +281,20 @@ def main(): zone_formats = data.setdefault('zone_formats', {}) for elem in tree.findall('.//timeZoneNames/gmtFormat'): if 'draft' not in elem.attrib and 'alt' not in elem.attrib: - zone_formats['gmt'] = unicode(elem.text).replace('{0}', '%s') + zone_formats['gmt'] = text_type(elem.text).replace('{0}', '%s') break for elem in tree.findall('.//timeZoneNames/regionFormat'): if 'draft' not in elem.attrib and 'alt' not in elem.attrib: - zone_formats['region'] = unicode(elem.text).replace('{0}', '%s') + zone_formats['region'] = text_type(elem.text).replace('{0}', '%s') break for elem in tree.findall('.//timeZoneNames/fallbackFormat'): if 'draft' not in elem.attrib and 'alt' not in elem.attrib: - zone_formats['fallback'] = unicode(elem.text) \ + zone_formats['fallback'] = text_type(elem.text) \ .replace('{0}', '%(0)s').replace('{1}', '%(1)s') break for elem in tree.findall('.//timeZoneNames/fallbackRegionFormat'): if 'draft' not in elem.attrib and 'alt' not in elem.attrib: - zone_formats['fallback_region'] = unicode(elem.text) \ + zone_formats['fallback_region'] = text_type(elem.text) \ .replace('{0}', '%(0)s').replace('{1}', '%(1)s') break @@ -303,11 +303,11 @@ def main(): info = {} city = elem.findtext('exemplarCity') if city: - info['city'] = unicode(city) + info['city'] = text_type(city) for child in elem.findall('long/*'): - info.setdefault('long', {})[child.tag] = unicode(child.text) + info.setdefault('long', {})[child.tag] = text_type(child.text) for child in elem.findall('short/*'): - info.setdefault('short', {})[child.tag] = unicode(child.text) + info.setdefault('short', {})[child.tag] = text_type(child.text) time_zones[elem.attrib['type']] = info meta_zones = data.setdefault('meta_zones', {}) @@ -315,11 +315,11 @@ def main(): info = {} city = elem.findtext('exemplarCity') if city: - info['city'] = unicode(city) + info['city'] = text_type(city) for child in elem.findall('long/*'): - info.setdefault('long', {})[child.tag] = unicode(child.text) + info.setdefault('long', {})[child.tag] = text_type(child.text) for child in elem.findall('short/*'): - info.setdefault('short', {})[child.tag] = unicode(child.text) + info.setdefault('short', {})[child.tag] = text_type(child.text) meta_zones[elem.attrib['type']] = info for calendar in tree.findall('.//calendars/calendar'): @@ -339,7 +339,7 @@ def main(): if ('draft' in elem.attrib or 'alt' in elem.attrib) \ and int(elem.attrib['type']) in widths: continue - widths[int(elem.attrib.get('type'))] = unicode(elem.text) + widths[int(elem.attrib.get('type'))] = text_type(elem.text) elif elem.tag == 'alias': ctxts[width_type] = Alias( _translate_alias(['months', ctxt_type, width_type], @@ -359,7 +359,7 @@ def main(): if ('draft' in elem.attrib or 'alt' not in elem.attrib) \ and dtype in widths: continue - widths[dtype] = unicode(elem.text) + widths[dtype] = text_type(elem.text) elif elem.tag == 'alias': ctxts[width_type] = Alias( _translate_alias(['days', ctxt_type, width_type], @@ -378,7 +378,7 @@ def main(): if ('draft' in elem.attrib or 'alt' in elem.attrib) \ and int(elem.attrib['type']) in widths: continue - widths[int(elem.attrib['type'])] = unicode(elem.text) + widths[int(elem.attrib['type'])] = text_type(elem.text) elif elem.tag == 'alias': ctxts[width_type] = Alias( _translate_alias(['quarters', ctxt_type, width_type], @@ -394,7 +394,7 @@ def main(): if ('draft' in elem.attrib or 'alt' in elem.attrib) \ and int(elem.attrib['type']) in widths: continue - widths[int(elem.attrib.get('type'))] = unicode(elem.text) + widths[int(elem.attrib.get('type'))] = text_type(elem.text) elif elem.tag == 'alias': eras[width_type] = Alias( _translate_alias(['eras', width_type], @@ -408,7 +408,7 @@ def main(): if day_period_width.attrib['type'] == 'wide': for day_period in day_period_width.findall('dayPeriod'): if 'alt' not in day_period.attrib: - periods[day_period.attrib['type']] = unicode( + periods[day_period.attrib['type']] = text_type( day_period.text) date_formats = data.setdefault('date_formats', {}) @@ -420,7 +420,7 @@ def main(): continue try: date_formats[elem.attrib.get('type')] = \ - dates.parse_pattern(unicode(elem.findtext('dateFormat/pattern'))) + dates.parse_pattern(text_type(elem.findtext('dateFormat/pattern'))) except ValueError as e: error(e) elif elem.tag == 'alias': @@ -437,7 +437,7 @@ def main(): continue try: time_formats[elem.attrib.get('type')] = \ - dates.parse_pattern(unicode(elem.findtext('timeFormat/pattern'))) + dates.parse_pattern(text_type(elem.findtext('timeFormat/pattern'))) except ValueError as e: error(e) elif elem.tag == 'alias': @@ -454,7 +454,7 @@ def main(): continue try: datetime_formats[elem.attrib.get('type')] = \ - unicode(elem.findtext('dateTimeFormat/pattern')) + text_type(elem.findtext('dateTimeFormat/pattern')) except ValueError as e: error(e) elif elem.tag == 'alias': @@ -468,7 +468,7 @@ def main(): for elem in tree.findall('.//numbers/symbols/*'): if ('draft' in elem.attrib or 'alt' in elem.attrib): continue - number_symbols[elem.tag] = unicode(elem.text) + number_symbols[elem.tag] = text_type(elem.text) decimal_formats = data.setdefault('decimal_formats', {}) for elem in tree.findall('.//decimalFormats/decimalFormatLength'): @@ -478,7 +478,7 @@ def main(): if elem.findall('./alias'): # TODO map the alias to its target continue - pattern = unicode(elem.findtext('./decimalFormat/pattern')) + pattern = text_type(elem.findtext('./decimalFormat/pattern')) decimal_formats[elem.attrib.get('type')] = numbers.parse_pattern(pattern) scientific_formats = data.setdefault('scientific_formats', {}) @@ -486,7 +486,7 @@ def main(): if ('draft' in elem.attrib or 'alt' in elem.attrib) \ and elem.attrib.get('type') in scientific_formats: continue - pattern = unicode(elem.findtext('scientificFormat/pattern')) + pattern = text_type(elem.findtext('scientificFormat/pattern')) scientific_formats[elem.attrib.get('type')] = numbers.parse_pattern(pattern) currency_formats = data.setdefault('currency_formats', {}) @@ -494,7 +494,7 @@ def main(): if ('draft' in elem.attrib or 'alt' in elem.attrib) \ and elem.attrib.get('type') in currency_formats: continue - pattern = unicode(elem.findtext('currencyFormat/pattern')) + pattern = text_type(elem.findtext('currencyFormat/pattern')) currency_formats[elem.attrib.get('type')] = numbers.parse_pattern(pattern) percent_formats = data.setdefault('percent_formats', {}) @@ -502,7 +502,7 @@ def main(): if ('draft' in elem.attrib or 'alt' in elem.attrib) \ and elem.attrib.get('type') in percent_formats: continue - pattern = unicode(elem.findtext('percentFormat/pattern')) + pattern = text_type(elem.findtext('percentFormat/pattern')) percent_formats[elem.attrib.get('type')] = numbers.parse_pattern(pattern) currency_names = data.setdefault('currency_names', {}) @@ -515,14 +515,14 @@ def main(): continue if 'count' in name.attrib: currency_names_plural.setdefault(code, {})[name.attrib['count']] = \ - unicode(name.text) + text_type(name.text) else: - currency_names[code] = unicode(name.text) + currency_names[code] = text_type(name.text) # TODO: support choice patterns for currency symbol selection symbol = elem.find('symbol') if symbol is not None and 'draft' not in symbol.attrib \ and 'choice' not in symbol.attrib: - currency_symbols[code] = unicode(symbol.text) + currency_symbols[code] = text_type(symbol.text) # @@ -534,7 +534,7 @@ def main(): if 'alt' in pattern.attrib: box += ':' + pattern.attrib['alt'] unit_patterns.setdefault(box, {})[pattern.attrib['count']] = \ - unicode(pattern.text) + text_type(pattern.text) outfile = open(data_filename, 'wb') try: