Hello community, here is the log from the commit of package python-polib for openSUSE:Factory checked in at 2013-02-11 11:12:25 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-polib (Old) and /work/SRC/openSUSE:Factory/.python-polib.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-polib", Maintainer is "" Changes: -------- --- /work/SRC/openSUSE:Factory/python-polib/python-polib.changes 2012-09-20 15:43:55.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.python-polib.new/python-polib.changes 2013-02-11 11:12:27.000000000 +0100 @@ -1,0 +2,14 @@ +Sat Feb 9 18:47:20 UTC 2013 - [email protected] + +- Update to 1.0.3 + * Fixed issue #38: POFile.append() raised a duplicate exception when + you tried to add a new entry with the same msgid and a different msgctxt + (only when check_for_duplicates option is set to True) + * Fixed issue #39: Added __init__.py file for convenience + * Fixed issue #41: UnicodeDecodeError when running setup.py build on + python3 with C locale + * polib is now fully PEP8 compliant + * Small improvements: remove unused "typ" var, mproved Makefile, Make sure + BaseFile.__contains__ returns a boolean value + +------------------------------------------------------------------- Old: ---- polib-1.0.1.tar.bz2 New: ---- polib-1.0.3.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-polib.spec ++++++ --- /var/tmp/diff_new_pack.i4Kq6P/_old 2013-02-11 11:12:40.000000000 +0100 +++ /var/tmp/diff_new_pack.i4Kq6P/_new 2013-02-11 11:12:40.000000000 +0100 @@ -1,8 +1,8 @@ # # spec file for package python-polib # -# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. -# Copyright (c) 2011 LISA GmbH, Bingen, Germany. +# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2013 LISA GmbH, Bingen, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ Name: python-polib -Version: 1.0.1 +Version: 1.0.3 Release: 0 Url: http://bitbucket.org/izi/polib/ Summary: A library to manipulate gettext files ++++++ polib-1.0.1.tar.bz2 -> polib-1.0.3.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/polib-1.0.1/CHANGELOG new/polib-1.0.3/CHANGELOG --- old/polib-1.0.1/CHANGELOG 2012-09-11 10:54:22.000000000 +0200 +++ new/polib-1.0.3/CHANGELOG 2013-02-09 13:27:04.000000000 +0100 @@ -2,6 +2,18 @@ Changelog ========= +Version 1.0.3 (2013/02/09) +-------------------------- + - Fixed issue #38: POFile.append() raised a duplicate exception when you tried to add a new entry with the same msgid and a different msgctxt (only when check_for_duplicates option is set to True) + - Fixed issue #39: Added __init__.py file for convenience + - Fixed issue #41: UnicodeDecodeError when running setup.py build on python3 with C locale + - polib is now fully PEP8 compliant + - Small improvements: remove unused "typ" var (thanks Rodrigo Silva), mproved Makefile, Make sure _BaseFile.__contains__ returns a boolean value + +Version 1.0.2 (2012/10/23) +-------------------------- + - allow empty comments, flags or occurences lines + Version 1.0.1 (2012/09/11) -------------------------- - speed up POFile.merge method (thanks @encukou) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/polib-1.0.1/PKG-INFO new/polib-1.0.3/PKG-INFO --- old/polib-1.0.1/PKG-INFO 2012-09-11 10:56:32.000000000 +0200 +++ new/polib-1.0.3/PKG-INFO 2013-02-09 19:16:02.000000000 +0100 @@ -1,12 +1,12 @@ -Metadata-Version: 1.0 +Metadata-Version: 1.1 Name: polib -Version: 1.0.1 +Version: 1.0.3 Summary: A library to manipulate gettext files (po and mo files). Home-page: http://bitbucket.org/izi/polib/ Author: David Jean Louis Author-email: <[email protected]> License: MIT -Download-URL: http://bitbucket.org/izi/polib/downloads/polib-1.0.1.tar.gz +Download-URL: http://bitbucket.org/izi/polib/downloads/polib-1.0.3.tar.gz Description: .. contents:: Table of Contents @@ -38,6 +38,18 @@ Changelog ========= + Version 1.0.3 (2013/02/09) + -------------------------- + - Fixed issue #38: POFile.append() raised a duplicate exception when you tried to add a new entry with the same msgid and a different msgctxt (only when check_for_duplicates option is set to True) + - Fixed issue #39: Added __init__.py file for convenience + - Fixed issue #41: UnicodeDecodeError when running setup.py build on python3 with C locale + - polib is now fully PEP8 compliant + - Small improvements: remove unused "typ" var (thanks Rodrigo Silva), mproved Makefile, Make sure _BaseFile.__contains__ returns a boolean value + + Version 1.0.2 (2012/10/23) + -------------------------- + - allow empty comments, flags or occurences lines + Version 1.0.1 (2012/09/11) -------------------------- - speed up POFile.merge method (thanks @encukou) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/polib-1.0.1/__init__.py new/polib-1.0.3/__init__.py --- old/polib-1.0.1/__init__.py 1970-01-01 01:00:00.000000000 +0100 +++ new/polib-1.0.3/__init__.py 2012-12-06 11:22:45.000000000 +0100 @@ -0,0 +1,5 @@ +# This __init__.py is only here for convenience, for projects that include a +# version of polib as a mercurial sub-repository for example. +# +# This file will NOT be installed when installing polib with pip, setuptools, +# or any other mecanism based on the setup.py file. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/polib-1.0.1/polib.py new/polib-1.0.3/polib.py --- old/polib-1.0.1/polib.py 2012-09-11 10:47:55.000000000 +0200 +++ new/polib-1.0.3/polib.py 2013-02-09 19:09:48.000000000 +0100 @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -* coding: utf-8 -*- # # License: MIT (see LICENSE file provided) # vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: @@ -12,10 +12,10 @@ :func:`~polib.mofile` convenience functions. """ -__author__ = 'David Jean Louis <[email protected]>' -__version__ = '1.0.1' -__all__ = ['pofile', 'POFile', 'POEntry', 'mofile', 'MOFile', 'MOEntry', - 'detect_encoding', 'escape', 'unescape', 'detect_encoding',] +__author__ = 'David Jean Louis <[email protected]>' +__version__ = '1.0.3' +__all__ = ['pofile', 'POFile', 'POEntry', 'mofile', 'MOFile', 'MOEntry', + 'default_encoding', 'escape', 'unescape', 'detect_encoding', ] import array import codecs @@ -25,11 +25,13 @@ import sys import textwrap + # the default encoding to use when encoding cannot be detected default_encoding = 'utf-8' # python 2/3 compatibility helpers {{{ + if sys.version_info[:2] < (3, 0): PY3 = False text_type = unicode @@ -49,10 +51,10 @@ def u(s): return s - # }}} # _pofile_or_mofile {{{ + def _pofile_or_mofile(f, type, **kwargs): """ Internal function used by :func:`polib.pofile` and :func:`polib.mofile` to @@ -69,15 +71,15 @@ f, encoding=enc, check_for_duplicates=kwargs.get('check_for_duplicates', False), - klass = kwargs.get('klass') + klass=kwargs.get('klass') ) instance = parser.parse() instance.wrapwidth = kwargs.get('wrapwidth', 78) return instance - # }}} # function pofile() {{{ + def pofile(pofile, **kwargs): """ Convenience function that parses the po or pot file ``pofile`` and returns @@ -99,17 +101,17 @@ ``check_for_duplicates`` whether to check for duplicate entries when adding entries to the file (optional, default: ``False``). - + ``klass`` class which is used to instantiate the return value (optional, default: ``None``, the return value with be a :class:`~polib.POFile` instance). """ return _pofile_or_mofile(pofile, 'pofile', **kwargs) - # }}} # function mofile() {{{ + def mofile(mofile, **kwargs): """ Convenience function that parses the mo file ``mofile`` and returns a @@ -132,17 +134,17 @@ ``check_for_duplicates`` whether to check for duplicate entries when adding entries to the file (optional, default: ``False``). - + ``klass`` class which is used to instantiate the return value (optional, default: ``None``, the return value with be a :class:`~polib.POFile` instance). """ return _pofile_or_mofile(mofile, 'mofile', **kwargs) - # }}} # function detect_encoding() {{{ + def detect_encoding(file, binary_mode=False): """ Try to detect the encoding used by the ``file``. The ``file`` argument can @@ -170,7 +172,12 @@ return False return True - if not os.path.exists(file): + try: + is_file = os.path.exists(file) + except (ValueError, UnicodeEncodeError): + is_file = False + + if not is_file: match = rxt.search(file) if match: enc = match.group(1).strip() @@ -196,10 +203,10 @@ return enc f.close() return default_encoding - # }}} # function escape() {{{ + def escape(st): """ Escapes the characters ``\\\\``, ``\\t``, ``\\n``, ``\\r`` and ``"`` in @@ -210,10 +217,10 @@ .replace('\r', r'\r')\ .replace('\n', r'\n')\ .replace('\"', r'\"') - # }}} # function unescape() {{{ + def unescape(st): """ Unescapes the characters ``\\\\``, ``\\t``, ``\\n``, ``\\r`` and ``"`` in @@ -229,12 +236,12 @@ return '\r' if m == '\\': return '\\' - return m # handles escaped double quote + return m # handles escaped double quote return re.sub(r'\\(\\|n|t|r|")', unescape_repl, st) - # }}} # class _BaseFile {{{ + class _BaseFile(list): """ Common base class for the :class:`~polib.POFile` and :class:`~polib.MOFile` @@ -312,15 +319,17 @@ Overriden ``list`` method to implement the membership test (in and not in). The method considers that an entry is in the file if it finds an entry - that has the same msgid (the test is **case sensitive**). + that has the same msgid (the test is **case sensitive**) and the same + msgctxt (or none for both entries). Argument: ``entry`` an instance of :class:`~polib._BaseEntry`. """ - return self.find(entry.msgid, by='msgid') is not None - + return self.find(entry.msgid, by='msgid', msgctxt=entry.msgctxt) \ + is not None + def __eq__(self, other): return str(self) == str(other) @@ -431,7 +440,7 @@ entries = [e for e in self if not e.obsolete] for e in entries: if getattr(e, by) == st: - if msgctxt and e.msgctxt != msgctxt: + if msgctxt is not False and e.msgctxt != msgctxt: continue return e return None @@ -439,7 +448,7 @@ def ordered_metadata(self): """ Convenience method that returns an ordered version of the metadata - dictionnary. The return value is list of tuples (metadata name, + dictionary. The return value is list of tuples (metadata name, metadata_value). """ # copy the dict first @@ -475,6 +484,7 @@ """ offsets = [] entries = self.translated_entries() + # the keys are sorted in the .mo file def cmp(_self, other): # msgfmt compares entries with msgctxt if it exists @@ -511,11 +521,11 @@ msgid += self._encode(e.msgid) msgstr = self._encode(e.msgstr) offsets.append((len(ids), len(msgid), len(strs), len(msgstr))) - ids += msgid + b('\0') + ids += msgid + b('\0') strs += msgstr + b('\0') # The header is 7 32-bit unsigned integers. - keystart = 7*4+16*entries_len + keystart = 7 * 4 + 16 * entries_len # and the values start after the keys valuestart = keystart + len(ids) koffsets = [] @@ -523,8 +533,8 @@ # The string table first has the list of keys, then the list of values. # Each entry has first the size of the string, then the file offset. for o1, l1, o2, l2 in offsets: - koffsets += [l1, o1+keystart] - voffsets += [l2, o2+valuestart] + koffsets += [l1, o1 + keystart] + voffsets += [l2, o2 + valuestart] offsets = koffsets + voffsets # check endianness for magic number if struct.pack('@h', 1) == struct.pack('<h', 1): @@ -534,13 +544,19 @@ output = struct.pack( "Iiiiiii", - magic_number, # Magic number - 0, # Version - entries_len, # # of entries - 7*4, # start of key index - 7*4+entries_len*8, # start of value index - 0, keystart # size and offset of hash table - # Important: we don't use hash tables + # Magic number + magic_number, + # Version + 0, + # number of entries + entries_len, + # start of key index + 7 * 4, + # start of value index + 7 * 4 + entries_len * 8, + # size and offset of hash table, we don't use hash tables + 0, keystart + ) if PY3 and sys.version_info.minor > 1: # python 3.2 or superior output += array.array("i", offsets).tobytes() @@ -558,10 +574,10 @@ if isinstance(mixed, text_type): mixed = mixed.encode(self.encoding) return mixed - # }}} # class POFile {{{ + class POFile(_BaseFile): """ Po (or Pot) file reader/writer. @@ -617,7 +633,7 @@ """ Convenience method that returns the list of untranslated entries. """ - return [e for e in self if not e.translated() and not e.obsolete \ + return [e for e in self if not e.translated() and not e.obsolete and not 'fuzzy' in e.flags] def fuzzy_entries(self): @@ -662,22 +678,22 @@ for entry in self: if entry.msgid not in refpot_msgids: entry.obsolete = True - # }}} # class MOFile {{{ + class MOFile(_BaseFile): """ Mo file reader/writer. This class inherits the :class:`~polib._BaseFile` class and, by extension, the python ``list`` type. """ - BIG_ENDIAN = 0xde120495 + BIG_ENDIAN = 0xde120495 LITTLE_ENDIAN = 0x950412de def __init__(self, *args, **kwargs): """ - Constructor, accepts all keywords arguments accepted by + Constructor, accepts all keywords arguments accepted by :class:`~polib._BaseFile` class. """ _BaseFile.__init__(self, *args, **kwargs) @@ -735,10 +751,10 @@ Convenience method to keep the same interface with POFile instances. """ return [] - # }}} # class _BaseEntry {{{ + class _BaseEntry(object): """ Base class for :class:`~polib.POEntry` and :class:`~polib.MOEntry` classes. @@ -790,12 +806,14 @@ ret = [] # write the msgctxt if any if self.msgctxt is not None: - ret += self._str_field("msgctxt", delflag, "", self.msgctxt, wrapwidth) + ret += self._str_field("msgctxt", delflag, "", self.msgctxt, + wrapwidth) # write the msgid ret += self._str_field("msgid", delflag, "", self.msgid, wrapwidth) # write the msgid_plural if any if self.msgid_plural: - ret += self._str_field("msgid_plural", delflag, "", self.msgid_plural, wrapwidth) + ret += self._str_field("msgid_plural", delflag, "", + self.msgid_plural, wrapwidth) if self.msgstr_plural: # write the msgstr_plural if any msgstrs = self.msgstr_plural @@ -804,10 +822,12 @@ for index in keys: msgstr = msgstrs[index] plural_index = '[%s]' % index - ret += self._str_field("msgstr", delflag, plural_index, msgstr, wrapwidth) + ret += self._str_field("msgstr", delflag, plural_index, msgstr, + wrapwidth) else: # otherwise write the msgstr - ret += self._str_field("msgstr", delflag, "", self.msgstr, wrapwidth) + ret += self._str_field("msgstr", delflag, "", self.msgstr, + wrapwidth) ret.append('') ret = u('\n').join(ret) return ret @@ -821,20 +841,21 @@ Returns the string representation of the entry. """ return unicode(self).encode(self.encoding) - + def __eq__(self, other): return str(self) == str(other) - def _str_field(self, fieldname, delflag, plural_index, field, wrapwidth=78): + def _str_field(self, fieldname, delflag, plural_index, field, + wrapwidth=78): lines = field.splitlines(True) if len(lines) > 1: - lines = [''] + lines # start with initial empty line + lines = [''] + lines # start with initial empty line else: escaped_field = escape(field) specialchars_count = 0 for c in ['\\', '\n', '\r', '\t', '"']: specialchars_count += field.count(c) - # comparison must take into account fieldname length + one space + # comparison must take into account fieldname length + one space # + 2 quotes (eg. msgid "<string>") flength = len(fieldname) + 3 if plural_index: @@ -844,7 +865,7 @@ # Wrap the line but take field name into account lines = [''] + [unescape(item) for item in wrap( escaped_field, - wrapwidth - 2, # 2 for quotes "" + wrapwidth - 2, # 2 for quotes "" drop_whitespace=False, break_long_words=False )] @@ -860,10 +881,10 @@ #import pdb; pdb.set_trace() ret.append('%s"%s"' % (delflag, escape(mstr))) return ret - # }}} # class POEntry {{{ + class POEntry(_BaseEntry): """ Represents a po file entry. @@ -938,9 +959,9 @@ filelist.append(fpath) filestr = ' '.join(filelist) if wrapwidth > 0 and len(filestr) + 3 > wrapwidth: - # textwrap split words that contain hyphen, this is not - # what we want for filenames, so the dirty hack is to - # temporally replace hyphens with a char that a file cannot + # textwrap split words that contain hyphen, this is not + # what we want for filenames, so the dirty hack is to + # temporally replace hyphens with a char that a file cannot # contain, like "*" ret += [l.replace('*', '-') for l in wrap( filestr.replace('-', '*'), @@ -957,7 +978,8 @@ ret.append('#, %s' % ', '.join(self.flags)) # previous context and previous msgid/msgid_plural - fields = ['previous_msgctxt', 'previous_msgid', 'previous_msgid_plural'] + fields = ['previous_msgctxt', 'previous_msgid', + 'previous_msgid_plural'] for f in fields: val = getattr(self, f) if val: @@ -1003,8 +1025,10 @@ else: return -1 # Finally: Compare message ID - if self.msgid > other.msgid: return 1 - elif self.msgid < other.msgid: return -1 + if self.msgid > other.msgid: + return 1 + elif self.msgid < other.msgid: + return -1 return 0 def __gt__(self, other): @@ -1065,19 +1089,19 @@ self.msgstr_plural[pos] except KeyError: self.msgstr_plural[pos] = '' - # }}} # class MOEntry {{{ + class MOEntry(_BaseEntry): """ Represents a mo file entry. """ pass - # }}} # class _POFileParser {{{ + class _POFileParser(object): """ A finite state machine to parse efficiently and correctly po @@ -1157,7 +1181,7 @@ self.add('PP', all, 'PP') self.add('CT', ['ST', 'HE', 'GC', 'OC', 'FL', 'TC', 'PC', 'PM', 'PP', 'MS', 'MX'], 'CT') - self.add('MI', ['ST', 'HE', 'GC', 'OC', 'FL', 'CT', 'TC', 'PC', + self.add('MI', ['ST', 'HE', 'GC', 'OC', 'FL', 'CT', 'TC', 'PC', 'PM', 'PP', 'MS', 'MX'], 'MI') self.add('MP', ['TC', 'GC', 'PC', 'PM', 'PP', 'MI'], 'MP') self.add('MS', ['MI', 'MP', 'TC'], 'MS') @@ -1208,8 +1232,8 @@ if tokens[0] in keywords and nb_tokens > 1: line = line[len(tokens[0]):].lstrip() if re.search(r'([^\\]|^)"', line[1:-1]): - raise IOError('Syntax error in po file %s (line %s): '\ - 'unescaped double quote found' % \ + raise IOError('Syntax error in po file %s (line %s): ' + 'unescaped double quote found' % (self.instance.fpath, i)) self.current_token = line self.process(keywords[tokens[0]], i) @@ -1217,15 +1241,17 @@ self.current_token = line - if tokens[0] == '#:' and nb_tokens > 1: + if tokens[0] == '#:': + if nb_tokens <= 1: + continue # we are on a occurrences line self.process('OC', i) elif line[:1] == '"': # we are on a continuation line if re.search(r'([^\\]|^)"', line[1:-1]): - raise IOError('Syntax error in po file %s (line %s): '\ - 'unescaped double quote found' % \ + raise IOError('Syntax error in po file %s (line %s): ' + 'unescaped double quote found' % (self.instance.fpath, i)) self.process('MC', i) @@ -1233,22 +1259,27 @@ # we are on a msgstr plural self.process('MX', i) - elif tokens[0] == '#,' and nb_tokens >= 1: + elif tokens[0] == '#,': + if nb_tokens <= 1: + continue # we are on a flags line self.process('FL', i) elif tokens[0] == '#' or tokens[0].startswith('##'): - if line == '#': line += ' ' + if line == '#': + line += ' ' # we are on a translator comment line self.process('TC', i) - elif tokens[0] == '#.' and nb_tokens >= 1: + elif tokens[0] == '#.': + if nb_tokens <= 1: + continue # we are on a generated comment line self.process('GC', i) elif tokens[0] == '#|': - if nb_tokens < 2: - raise IOError('Syntax error in po file %s (line %s)' % \ + if nb_tokens <= 1: + raise IOError('Syntax error in po file %s (line %s)' % (self.instance.fpath, i)) # Remove the marker and any whitespace right after that. @@ -1262,15 +1293,15 @@ if nb_tokens == 2: # Invalid continuation line. - raise IOError('Syntax error in po file %s (line %s): '\ - 'invalid continuation line' % \ + raise IOError('Syntax error in po file %s (line %s): ' + 'invalid continuation line' % (self.instance.fpath, i)) # we are on a "previous translation" comment line, if tokens[1] not in prev_keywords: # Unknown keyword in previous translation comment. - raise IOError('Syntax error in po file %s (line %s): '\ - 'unknown keyword %s' % \ + raise IOError('Syntax error in po file %s (line %s): ' + 'unknown keyword %s' % (self.instance.fpath, i, tokens[1])) # Remove the keyword and any whitespace @@ -1280,17 +1311,17 @@ self.process(prev_keywords[tokens[1]], i) else: - raise IOError('Syntax error in po file %s (line %s)' % \ + raise IOError('Syntax error in po file %s (line %s)' % (self.instance.fpath, i)) if self.current_entry: # since entries are added when another entry is found, we must add # the last entry here (only if there are lines) self.instance.append(self.current_entry) - # before returning the instance, check if there's metadata and if + # before returning the instance, check if there's metadata and if # so extract it in a dict metadataentry = self.instance.find('') - if metadataentry: # metadata found + if metadataentry: # metadata found # remove the entry self.instance.remove(metadataentry) self.instance.metadata_is_fuzzy = metadataentry.flags @@ -1299,9 +1330,9 @@ try: key, val = msg.split(':', 1) self.instance.metadata[key] = val.strip() - except: + except (ValueError, KeyError): if key is not None: - self.instance.metadata[key] += '\n'+ msg.strip() + self.instance.metadata[key] += '\n' + msg.strip() # close opened file if not isinstance(self.fhandle, list): # must be file self.fhandle.close() @@ -1389,10 +1420,10 @@ try: fil, line = occurrence.split(':') if not line.isdigit(): - fil = fil + line + fil = fil + line line = '' self.current_entry.occurrences.append((fil, line)) - except: + except (ValueError, AttributeError): self.current_entry.occurrences.append((occurrence, '')) return True @@ -1469,38 +1500,30 @@ """Handle a msgid or msgstr continuation line.""" token = unescape(self.current_token[1:-1]) if self.current_state == 'CT': - typ = 'msgctxt' self.current_entry.msgctxt += token elif self.current_state == 'MI': - typ = 'msgid' self.current_entry.msgid += token elif self.current_state == 'MP': - typ = 'msgid_plural' self.current_entry.msgid_plural += token elif self.current_state == 'MS': - typ = 'msgstr' self.current_entry.msgstr += token elif self.current_state == 'MX': - typ = 'msgstr[%s]' % self.msgstr_index self.current_entry.msgstr_plural[self.msgstr_index] += token elif self.current_state == 'PP': - typ = 'previous_msgid_plural' token = token[3:] self.current_entry.previous_msgid_plural += token elif self.current_state == 'PM': - typ = 'previous_msgid' token = token[3:] self.current_entry.previous_msgid += token elif self.current_state == 'PC': - typ = 'previous_msgctxt' token = token[3:] self.current_entry.previous_msgctxt += token # don't change the current state return False - # }}} # class _MOFileParser {{{ + class _MOFileParser(object): """ A class to parse binary mo files. @@ -1570,7 +1593,7 @@ self.fhandle.seek(msgstrs_index[i][1]) msgstr = self.fhandle.read(msgstrs_index[i][0]) - if i == 0: # metadata + if i == 0: # metadata raw_metadata, metadata = msgstr.split(b('\n')), {} for line in raw_metadata: tokens = line.split(b(':'), 1) @@ -1589,7 +1612,8 @@ entry = self._build_entry( msgid=msgid_tokens[0], msgid_plural=msgid_tokens[1], - msgstr_plural=dict((k,v) for k,v in enumerate(msgstr.split(b('\0')))) + msgstr_plural=dict((k, v) for k, v in + enumerate(msgstr.split(b('\0')))) ) else: entry = self._build_entry(msgid=msgid, msgstr=msgstr) @@ -1605,7 +1629,7 @@ if len(msgctxt_msgid) > 1: kwargs = { 'msgctxt': msgctxt_msgid[0].decode(encoding), - 'msgid' : msgctxt_msgid[1].decode(encoding), + 'msgid': msgctxt_msgid[1].decode(encoding), } else: kwargs = {'msgid': msgid.decode(encoding)} @@ -1629,17 +1653,17 @@ if len(tup) == 1: return tup[0] return tup - # }}} # class TextWrapper {{{ + class TextWrapper(textwrap.TextWrapper): """ Subclass of textwrap.TextWrapper that backport the drop_whitespace option. """ def __init__(self, *args, **kwargs): - drop_whitespace = kwargs.pop('drop_whitespace', True) + drop_whitespace = kwargs.pop('drop_whitespace', True) textwrap.TextWrapper.__init__(self, *args, **kwargs) self.drop_whitespace = drop_whitespace @@ -1703,7 +1727,7 @@ self._handle_long_word(chunks, cur_line, cur_len, width) # If the last chunk on this line is all whitespace, drop it. - if self.drop_whitespace and cur_line and cur_line[-1].strip() == '': + if self.drop_whitespace and cur_line and not cur_line[-1].strip(): del cur_line[-1] # Convert current line back to a string and store it in list @@ -1712,10 +1736,10 @@ lines.append(indent + ''.join(cur_line)) return lines - # }}} # function wrap() {{{ + def wrap(text, width=70, **kwargs): """ Wrap a single paragraph of text, returning a list of wrapped lines. @@ -1724,4 +1748,4 @@ return TextWrapper(width=width, **kwargs).wrap(text) return textwrap.wrap(text, width=width, **kwargs) -#}}} +# }}} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/polib-1.0.1/setup.py new/polib-1.0.3/setup.py --- old/polib-1.0.1/setup.py 2012-06-08 21:48:16.000000000 +0200 +++ new/polib-1.0.3/setup.py 2013-02-09 18:33:22.000000000 +0100 @@ -11,20 +11,28 @@ __author__ = 'David Jean Louis <[email protected]>' from distutils.core import setup +import codecs + import polib author_data = __author__.split(' ') maintainer = ' '.join(author_data[0:-1]) maintainer_email = author_data[-1] desc = 'A library to manipulate gettext files (po and mo files).' -long_desc = ''' + +if polib.PY3: + mode = 'rb' +else: + mode = 'r' + +long_desc = r''' .. contents:: Table of Contents %s %s -''' % (open('README.rst').read(), open('CHANGELOG').read()) +''' % (open('README.rst', mode).read(), open('CHANGELOG', mode).read()) if __name__ == '__main__': setup( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/polib-1.0.1/tests/test_pofile_helpers.po new/polib-1.0.3/tests/test_pofile_helpers.po --- old/polib-1.0.1/tests/test_pofile_helpers.po 2011-08-01 18:45:10.000000000 +0200 +++ new/polib-1.0.3/tests/test_pofile_helpers.po 2012-12-06 11:11:00.000000000 +0100 @@ -26,6 +26,13 @@ msgid "and" msgstr "y" +#: db/models/manipulators.py:310 contrib/admin/views/main.py:342 +#: contrib/admin/views/main.py:344 contrib/admin/views/main.py:346 +#: core/validators.py:275 +msgctxt "some context" +msgid "and" +msgstr "y" + #: db/models/fields/__init__.py:49 #, python-format msgid "%(optname)s with this %(fieldname)s already exists." diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/polib-1.0.1/tests/test_utf8.po new/polib-1.0.3/tests/test_utf8.po --- old/polib-1.0.1/tests/test_utf8.po 2012-09-11 10:13:42.000000000 +0200 +++ new/polib-1.0.3/tests/test_utf8.po 2012-10-23 12:33:30.000000000 +0200 @@ -38,6 +38,12 @@ msgid "Some msgid" msgstr "Some msgstr" +#. test generated comments +#. +#. more tests... +msgid "Test generated comments" +msgstr "Test generated comments" + # Added for previous msgid/msgid_plural/msgctxt testing #| msgctxt "@previous_context" #| msgid "" @@ -60,12 +66,14 @@ ## Some comment starting with two '#' #: db/models/manipulators.py:309 #, python-format +#, msgid "%(object)s with this %(type)s already exists for the given %(field)s." msgstr "%(object)s de este %(type)s ya existen en este %(field)s." #: db/models/manipulators.py:310 contrib/admin/views/main.py:342 #: contrib/admin/views/main.py:344 contrib/admin/views/main.py:346 #: core/validators.py:275 +#: msgid "and" msgstr "y" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/polib-1.0.1/tests/tests.py new/polib-1.0.3/tests/tests.py --- old/polib-1.0.1/tests/tests.py 2012-09-11 10:13:12.000000000 +0200 +++ new/polib-1.0.3/tests/tests.py 2013-02-09 18:21:20.000000000 +0100 @@ -185,9 +185,14 @@ """ Test with utf8 data (no file). """ - f = open('tests/test_utf8.po','r') + if polib.PY3: + f = open('tests/test_utf8.po', 'rb') + data = str(f.read(), 'utf-8') + else: + f = open('tests/test_utf8.po', 'r') + data = f.read() try: - self.assertEqual(polib.detect_encoding(f.read()), 'UTF-8') + self.assertEqual(polib.detect_encoding(data), 'UTF-8') finally: f.close() @@ -264,9 +269,21 @@ def test_append2(self): def add_duplicate(): pofile = polib.pofile('tests/test_pofile_helpers.po', check_for_duplicates=True) - pofile.append(polib.POEntry(msgid="and", msgstr="y")) + pofile.append(polib.POEntry(msgid="and")) + self.assertRaises(ValueError, add_duplicate) + + def test_append3(self): + def add_duplicate(): + pofile = polib.pofile('tests/test_pofile_helpers.po', check_for_duplicates=True) + pofile.append(polib.POEntry(msgid="and", msgctxt="some context")) self.assertRaises(ValueError, add_duplicate) + def test_append4(self): + pofile = polib.pofile('tests/test_pofile_helpers.po', check_for_duplicates=True) + entry = polib.POEntry(msgid="and", msgctxt="some different context") + pofile.append(entry) + self.assertTrue(entry in pofile) + def test_insert1(self): pofile = polib.pofile('tests/test_pofile_helpers.po') entry = polib.POEntry(msgid="Foo", msgstr="Bar", msgctxt="Some context") @@ -445,6 +462,13 @@ """ Test for the POFile.save_as_mofile() method. """ + import distutils.spawn + msgfmt = distutils.spawn.find_executable('msgfmt') + if msgfmt is None: + try: + return unittest.skip('msgfmt is not installed') + except AttributeError: + return reffiles = ['tests/test_utf8.po', 'tests/test_iso-8859-15.po'] encodings = ['utf-8', 'iso-8859-15'] for reffile, encoding in zip(reffiles, encodings): @@ -454,7 +478,7 @@ os.close(fd) po = polib.pofile(reffile, autodetect_encoding=False, encoding=encoding) po.save_as_mofile(tmpfile1) - subprocess.call(['msgfmt', '--no-hash', '-o', tmpfile2, reffile]) + subprocess.call([msgfmt, '--no-hash', '-o', tmpfile2, reffile]) try: f = open(tmpfile1, 'rb') s1 = f.read() @@ -476,13 +500,13 @@ def test_percent_translated(self): po = polib.pofile('tests/test_pofile_helpers.po') - self.assertEqual(po.percent_translated(), 50) + self.assertEqual(po.percent_translated(), 53) po = polib.POFile() self.assertEqual(po.percent_translated(), 100) def test_translated_entries(self): po = polib.pofile('tests/test_pofile_helpers.po') - self.assertEqual(len(po.translated_entries()), 6) + self.assertEqual(len(po.translated_entries()), 7) def test_untranslated_entries(self): po = polib.pofile('tests/test_pofile_helpers.po') @@ -530,10 +554,16 @@ mo = polib.mofile('tests/test_utf8.mo', wrapwidth=78) mo.save_as_pofile(tmpfile) try: - f = open(tmpfile) + if polib.PY3: + f = open(tmpfile, encoding='utf-8') + else: + f = open(tmpfile) s1 = f.read() f.close() - f = open('tests/test_save_as_pofile.po') + if polib.PY3: + f = open('tests/test_save_as_pofile.po', encoding='utf-8') + else: + f = open('tests/test_save_as_pofile.po') s2 = f.read() f.close() self.assertEqual(s1, s2) -- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
