# HG changeset patch # User cmlenz # Date 1184948443 0 # Node ID 85340bec3a97b96eb4e463fb5c722e1777f3cb09 # Parent 629357c88d59fed7fcd89d99a9747cacb1fd2721 Fix tests broken by [233], and add new tests. diff --git a/babel/messages/catalog.py b/babel/messages/catalog.py --- a/babel/messages/catalog.py +++ b/babel/messages/catalog.py @@ -28,7 +28,7 @@ from babel.core import Locale from babel.dates import format_datetime from babel.messages.plurals import PLURALS -from babel.util import odict, LOCALTZ, UTC, FixedOffsetTimezone +from babel.util import odict, distinct, LOCALTZ, UTC, FixedOffsetTimezone __all__ = ['Message', 'Catalog', 'TranslationError'] __docformat__ = 'restructuredtext en' @@ -66,8 +66,8 @@ self.flags.add('python-format') else: self.flags.discard('python-format') - self.auto_comments = list(set(auto_comments)) - self.user_comments = list(set(user_comments)) + self.auto_comments = list(distinct(auto_comments)) + self.user_comments = list(distinct(user_comments)) if isinstance(previous_id, basestring): self.previous_id = [previous_id] else: diff --git a/babel/messages/pofile.py b/babel/messages/pofile.py --- a/babel/messages/pofile.py +++ b/babel/messages/pofile.py @@ -122,7 +122,7 @@ if the catalog is not bound to a locale (which basically means it's a template) :param domain: the message domain - :ignore_obsolete: whether to ignore obsolete messages in the input + :param ignore_obsolete: whether to ignore obsolete messages in the input :return: an iterator over ``(message, translation, location)`` tuples :rtype: ``iterator`` """ @@ -151,8 +151,7 @@ else: string = denormalize(translations[0][1]) message = Message(msgid, string, list(locations), set(flags), - list(set(auto_comments)), list(set(user_comments)), - lineno=offset[0] + 1) + auto_comments, user_comments, lineno=offset[0] + 1) if obsolete[0]: if not ignore_obsolete: catalog.obsolete[msgid] = message @@ -350,10 +349,12 @@ :param no_location: do not emit a location comment for every message :param omit_header: do not include the ``msgid ""`` entry at the top of the output - :sort_output: whether to sort the messages in the output by msgid - :sort_by_file: whether to sort the messages in the output by their locations - :ignore_obsolete: whether to ignore obsolete messages and not include them - in the output; by default they are included as comments + :param sort_output: whether to sort the messages in the output by msgid + :param sort_by_file: whether to sort the messages in the output by their + locations + :param ignore_obsolete: whether to ignore obsolete messages and not include + them in the output; by default they are included as + comments :param include_previous: include the old msgid as a comment when updating the catalog """ @@ -408,9 +409,9 @@ comment_header = u'\n'.join(lines) + u'\n' _write(comment_header) - for comment in list(set(message.user_comments)): + for comment in message.user_comments: _write_comment(comment) - for comment in list(set(message.auto_comments)): + for comment in message.auto_comments: _write_comment(comment, prefix='.') if not no_location: @@ -433,7 +434,7 @@ if not ignore_obsolete: for message in catalog.obsolete.values(): - for comment in list(set(message.user_comments)): + for comment in message.user_comments: _write_comment(comment) _write_message(message, prefix='#~ ') _write('\n') diff --git a/babel/messages/tests/catalog.py b/babel/messages/tests/catalog.py --- a/babel/messages/tests/catalog.py +++ b/babel/messages/tests/catalog.py @@ -53,6 +53,14 @@ cat.add(('foo', 'foos')) self.assertEqual(1, len(cat)) + def test_duplicate_auto_comment(self): + msg = catalog.Message('foo', auto_comments=['A comment', 'A comment']) + self.assertEqual(['A comment'], msg.auto_comments) + + def test_duplicate_user_comment(self): + msg = catalog.Message('foo', user_comments=['A comment', 'A comment']) + self.assertEqual(['A comment'], msg.user_comments) + def test_update_message_updates_comments(self): cat = catalog.Catalog() cat[u'foo'] = catalog.Message('foo', locations=[('main.py', 5)]) diff --git a/babel/util.py b/babel/util.py --- a/babel/util.py +++ b/babel/util.py @@ -18,11 +18,36 @@ import os import parser import re +try: + set +except NameError: + from sets import Set as set import time -__all__ = ['pathmatch', 'relpath', 'UTC', 'LOCALTZ'] +__all__ = ['distinct', 'pathmatch', 'relpath', 'odict', 'UTC', 'LOCALTZ'] __docformat__ = 'restructuredtext en' +def distinct(iterable): + """Yield all items in an iterable collection that are distinct. + + Unlike when using sets for a similar effect, the original ordering of the + items in the collection is preserved by this function. + + >>> print list(distinct([1, 2, 1, 3, 4, 4])) + [1, 2, 3, 4] + >>> print list(distinct('foobar')) + ['f', 'o', 'b', 'a', 'r'] + + :param iterable: the iterable collection providing the data + :return: the distinct items in the collection + :rtype: ``iterator`` + """ + seen = set() + for item in iter(iterable): + if item not in seen: + yield item + seen.add(item) + # Regexp to match python magic encoding line PYTHON_MAGIC_COMMENT_re = re.compile( r'[ \t\f]* \# .* coding[=:][ \t]*([-\w.]+)', re.VERBOSE) @@ -123,7 +148,7 @@ class odict(dict): """Ordered dict implementation. - :see: `http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747` + :see: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747 """ def __init__(self, data=None): dict.__init__(self, data or {})