Package translate :: Package storage :: Module cpo
[hide private]
[frames] | no frames]

Source Code for Module translate.storage.cpo

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3  #  
  4  # Copyright 2002-2007 Zuza Software Foundation 
  5  #  
  6  # This file is part of translate. 
  7  # 
  8  # translate is free software; you can redistribute it and/or modify 
  9  # it under the terms of the GNU General Public License as published by 
 10  # the Free Software Foundation; either version 2 of the License, or 
 11  # (at your option) any later version. 
 12  #  
 13  # translate is distributed in the hope that it will be useful, 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16  # GNU General Public License for more details. 
 17  # 
 18  # You should have received a copy of the GNU General Public License 
 19  # along with translate; if not, write to the Free Software 
 20  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 21   
 22  """Classes that hold units of .po files (pounit) or entire files (pofile). 
 23   
 24  Gettext-style .po (or .pot) files are used in translations for KDE, GNOME and 
 25  many other projects. 
 26   
 27  This uses libgettextpo from the gettext package. Any version before 0.17 will 
 28  at least cause some subtle bugs or may not work at all. Developers might want 
 29  to have a look at gettext-tools/libgettextpo/gettext-po.h from the gettext 
 30  package for the public API of the library. 
 31  """ 
 32   
 33  from translate.misc.multistring import multistring 
 34  from translate.storage import pocommon 
 35  from translate.misc import quote 
 36  from translate.lang import data 
 37  from ctypes import * 
 38  import ctypes.util 
 39  try: 
 40      import cStringIO as StringIO 
 41  except ImportError: 
 42      import StringIO 
 43  import os 
 44  import pypo 
 45  import re 
 46  import sys 
 47   
 48  lsep = " " 
 49  """Seperator for #: entries""" 
 50   
 51  STRING = c_char_p 
 52   
 53  # Structures 
54 -class po_message(Structure):
55 _fields_ = []
56 57 # Function prototypes 58 xerror_prototype = CFUNCTYPE(None, c_int, POINTER(po_message), STRING, c_uint, c_uint, c_int, STRING) 59 xerror2_prototype = CFUNCTYPE(None, c_int, POINTER(po_message), STRING, c_uint, c_uint, c_int, STRING, POINTER(po_message), STRING, c_uint, c_uint, c_int, STRING) 60 61 62 # Structures (error handler)
63 -class po_xerror_handler(Structure):
64 _fields_ = [('xerror', xerror_prototype), 65 ('xerror2', xerror2_prototype)]
66
67 -class po_error_handler(Structure):
68 _fields_ = [ 69 ('error', CFUNCTYPE(None, c_int, c_int, STRING)), 70 ('error_at_line', CFUNCTYPE(None, c_int, c_int, STRING, c_uint, STRING)), 71 ('multiline_warning', CFUNCTYPE(None, STRING, STRING)), 72 ('multiline_error', CFUNCTYPE(None, STRING, STRING)), 73 ]
74 75 # Callback functions for po_xerror_handler
76 -def xerror_cb(severity, message, filename, lineno, column, multilint_p, message_text):
77 print >> sys.stderr, "xerror_cb", severity, message, filename, lineno, column, multilint_p, message_text 78 if severity >= 1: 79 raise ValueError(message_text)
80
81 -def xerror2_cb(severity, message1, filename1, lineno1, column1, multiline_p1, message_text1, message2, filename2, lineno2, column2, multiline_p2, message_text2):
82 print >> sys.stderr, "xerror2_cb", severity, message1, filename1, lineno1, column1, multiline_p1, message_text1, message2, filename2, lineno2, column2, multiline_p2, message_text2 83 if severity >= 1: 84 raise ValueError(message_text1)
85 86 87 88 # Load libgettextpo 89 gpo = None 90 # 'gettextpo' is recognised on Unix, while only 'libgettextpo' is recognised on 91 # windows. Therefore we test both. 92 names = ['gettextpo', 'libgettextpo'] 93 for name in names: 94 lib_location = ctypes.util.find_library(name) 95 if lib_location: 96 gpo = cdll.LoadLibrary(lib_location) 97 if gpo: 98 break 99 else: 100 # Now we are getting desperate, so let's guess a unix type DLL that might 101 # be in LD_LIBRARY_PATH or loaded with LD_PRELOAD 102 try: 103 gpo = cdll.LoadLibrary('libgettextpo.so') 104 except OSError, e: 105 raise ImportError("gettext PO library not found") 106 107 # Setup return and paramater types 108 # File access 109 gpo.po_file_read_v3.argtypes = [STRING, POINTER(po_xerror_handler)] 110 gpo.po_file_write_v2.argtypes = [c_int, STRING, POINTER(po_xerror_handler)] 111 gpo.po_file_write_v2.retype = c_int 112 113 # Header 114 gpo.po_file_domain_header.restype = STRING 115 gpo.po_header_field.restype = STRING 116 gpo.po_header_field.argtypes = [STRING, STRING] 117 118 # Locations (filepos) 119 gpo.po_filepos_file.restype = STRING 120 gpo.po_message_filepos.restype = c_int 121 gpo.po_message_filepos.argtypes = [c_int, c_int] 122 gpo.po_message_add_filepos.argtypes = [c_int, STRING, c_int] 123 124 # Message (get methods) 125 gpo.po_message_comments.restype = STRING 126 gpo.po_message_extracted_comments.restype = STRING 127 gpo.po_message_prev_msgctxt.restype = STRING 128 gpo.po_message_prev_msgid.restype = STRING 129 gpo.po_message_prev_msgid_plural.restype = STRING 130 gpo.po_message_is_format.restype = c_int 131 gpo.po_message_msgctxt.restype = STRING 132 gpo.po_message_msgid.restype = STRING 133 gpo.po_message_msgid_plural.restype = STRING 134 gpo.po_message_msgstr.restype = STRING 135 gpo.po_message_msgstr_plural.restype = STRING 136 137 # Message (set methods) 138 gpo.po_message_set_comments.argtypes = [c_int, STRING] 139 gpo.po_message_set_extracted_comments.argtypes = [c_int, STRING] 140 gpo.po_message_set_fuzzy.argtypes = [c_int, c_int] 141 gpo.po_message_set_msgctxt.argtypes = [c_int, STRING] 142 143 # Setup the po_xerror_handler 144 xerror_handler = po_xerror_handler() 145 xerror_handler.xerror = xerror_prototype(xerror_cb) 146 xerror_handler.xerror2 = xerror2_prototype(xerror2_cb) 147
148 -def escapeforpo(text):
149 return pypo.escapeforpo(text)
150
151 -def quoteforpo(text):
152 return pypo.quoteforpo(text)
153
154 -def unquotefrompo(postr, joinwithlinebreak=False):
155 return pypo.unquotefrompo(postr, joinwithlinebreak)
156
157 -def encodingToUse(encoding):
158 return pypo.encodingToUse(encoding)
159
160 -class pounit(pocommon.pounit):
161 - def __init__(self, source=None, encoding='utf-8', gpo_message=None):
162 self._encoding = encoding 163 if not gpo_message: 164 self._gpo_message = gpo.po_message_create() 165 if source or source == "": 166 self.source = source 167 self.target = "" 168 elif gpo_message: 169 self._gpo_message = gpo_message
170
171 - def setmsgidcomment(self, msgidcomment):
172 if msgidcomment: 173 newsource = "_: " + msgidcomment + "\n" + self.source 174 self.source = newsource
175 msgidcomment = property(None, setmsgidcomment) 176
177 - def setmsgid_plural(self, msgid_plural):
178 if isinstance(msgid_plural, list): 179 msgid_plural = "".join(msgid_plural) 180 gpo.po_message_set_msgid_plural(self._gpo_message, msgid_plural)
181 msgid_plural = property(None, setmsgid_plural) 182
183 - def getsource(self):
184 def remove_msgid_comments(text): 185 if not text: 186 return text 187 if text.startswith("_:"): 188 remainder = re.search(r"_: .*\n(.*)", text) 189 if remainder: 190 return remainder.group(1) 191 else: 192 return u"" 193 else: 194 return text
195 singular = remove_msgid_comments(gpo.po_message_msgid(self._gpo_message)) 196 if singular: 197 multi = multistring(singular, self._encoding) 198 if self.hasplural(): 199 pluralform = gpo.po_message_msgid_plural(self._gpo_message) 200 if isinstance(pluralform, str): 201 pluralform = pluralform.decode(self._encoding) 202 multi.strings.append(pluralform) 203 return multi 204 else: 205 return u"" 206
207 - def setsource(self, source):
208 if isinstance(source, multistring): 209 source = source.strings 210 if isinstance(source, unicode): 211 source = source.encode(self._encoding) 212 if isinstance(source, list): 213 gpo.po_message_set_msgid(self._gpo_message, str(source[0])) 214 if len(source) > 1: 215 gpo.po_message_set_msgid_plural(self._gpo_message, str(source[1])) 216 else: 217 gpo.po_message_set_msgid(self._gpo_message, source) 218 gpo.po_message_set_msgid_plural(self._gpo_message, None)
219 220 source = property(getsource, setsource) 221
222 - def gettarget(self):
223 if self.hasplural(): 224 plurals = [] 225 nplural = 0 226 plural = gpo.po_message_msgstr_plural(self._gpo_message, nplural) 227 while plural: 228 plurals.append(plural) 229 nplural += 1 230 plural = gpo.po_message_msgstr_plural(self._gpo_message, nplural) 231 if plurals: 232 multi = multistring(plurals, encoding=self._encoding) 233 else: 234 multi = multistring(u"") 235 else: 236 multi = multistring(gpo.po_message_msgstr(self._gpo_message) or u"", encoding=self._encoding) 237 return multi
238
239 - def settarget(self, target):
240 if self.hasplural(): 241 if isinstance(target, multistring): 242 target = target.strings 243 elif isinstance(target, basestring): 244 target = [target] 245 elif isinstance(target,(dict, list)): 246 if len(target) == 1: 247 target = target[0] 248 else: 249 raise ValueError("po msgid element has no plural but msgstr has %d elements (%s)" % (len(target), target)) 250 if isinstance(target, (dict, list)): 251 i = 0 252 message = gpo.po_message_msgstr_plural(self._gpo_message, i) 253 while message is not None: 254 gpo.po_message_set_msgstr_plural(self._gpo_message, i, None) 255 i += 1 256 message = gpo.po_message_msgstr_plural(self._gpo_message, i) 257 if isinstance(target, list): 258 for i in range(len(target)): 259 targetstring = target[i] 260 if isinstance(targetstring, unicode): 261 targetstring = targetstring.encode(self._encoding) 262 gpo.po_message_set_msgstr_plural(self._gpo_message, i, targetstring) 263 elif isinstance(target, dict): 264 for i, targetstring in enumerate(target.itervalues()): 265 gpo.po_message_set_msgstr_plural(self._gpo_message, i, targetstring) 266 else: 267 if isinstance(target, unicode): 268 target = target.encode(self._encoding) 269 if target is None: 270 gpo.po_message_set_msgstr(self._gpo_message, "") 271 else: 272 gpo.po_message_set_msgstr(self._gpo_message, target)
273 target = property(gettarget, settarget) 274
275 - def getid(self):
276 """The unique identifier for this unit according to the convensions in 277 .mo files.""" 278 id = gpo.po_message_msgid(self._gpo_message) 279 # Gettext does not consider the plural to determine duplicates, only 280 # the msgid. For generation of .mo files, we might want to use this 281 # code to generate the entry for the hash table, but for now, it is 282 # commented out for conformance to gettext. 283 # plural = gpo.po_message_msgid_plural(self._gpo_message) 284 # if not plural is None: 285 # id = '%s\0%s' % (id, plural) 286 context = gpo.po_message_msgctxt(self._gpo_message) 287 if context: 288 id = "%s\04%s" % (context, id) 289 return id or ""
290
291 - def getnotes(self, origin=None):
292 if origin == None: 293 comments = gpo.po_message_comments(self._gpo_message) + \ 294 gpo.po_message_extracted_comments(self._gpo_message) 295 elif origin == "translator": 296 comments = gpo.po_message_comments(self._gpo_message) 297 elif origin in ["programmer", "developer", "source code"]: 298 comments = gpo.po_message_extracted_comments(self._gpo_message) 299 else: 300 raise ValueError("Comment type not valid") 301 # FIXME this fixes a bug in Gettext that returns leading space with comments 302 if comments: 303 comments = "\n".join([line[1:] for line in comments.split("\n")]) 304 # Let's drop the last newline 305 return comments[:-1].decode(self._encoding)
306
307 - def addnote(self, text, origin=None, position="append"):
308 if not text: 309 return 310 text = data.forceunicode(text) 311 oldnotes = self.getnotes(origin) 312 newnotes = None 313 if oldnotes: 314 if position == "append": 315 newnotes = oldnotes + "\n" + text 316 elif position == "merge": 317 if oldnotes != text: 318 oldnoteslist = oldnotes.split("\n") 319 for newline in text.split("\n"): 320 newline = newline.rstrip() 321 # avoid duplicate comment lines (this might cause some problems) 322 if newline not in oldnotes or len(newline) < 5: 323 oldnoteslist.append(newline) 324 newnotes = "\n".join(oldnoteslist) 325 else: 326 newnotes = text + '\n' + oldnotes 327 else: 328 newnotes = "\n".join([line.rstrip() for line in text.split("\n")]) 329 # FIXME; workaround the need for leading spaces when adding comments to PO files in libgettexpo 330 if newnotes: 331 newlines = [] 332 for line in newnotes.split("\n"): 333 if line: 334 newlines.append(" " + line) 335 else: 336 newlines.append(line) 337 newnotes = "\n".join(newlines) 338 if origin in ["programmer", "developer", "source code"]: 339 gpo.po_message_set_extracted_comments(self._gpo_message, newnotes) 340 else: 341 gpo.po_message_set_comments(self._gpo_message, newnotes)
342
343 - def removenotes(self):
344 gpo.po_message_set_comments(self._gpo_message, "")
345
346 - def copy(self):
347 newpo = self.__class__() 348 newpo._gpo_message = self._gpo_message 349 return newpo
350
351 - def merge(self, otherpo, overwrite=False, comments=True, authoritative=False):
352 """Merges the otherpo (with the same msgid) into this one. 353 354 Overwrite non-blank self.msgstr only if overwrite is True 355 merge comments only if comments is True 356 357 """ 358 359 if not isinstance(otherpo, pounit): 360 super(pounit, self).merge(otherpo, overwrite, comments) 361 return 362 if comments: 363 self.addnote(otherpo.getnotes("translator"), origin="translator", position="merge") 364 # FIXME mergelists(self.typecomments, otherpo.typecomments) 365 if not authoritative: 366 # We don't bring across otherpo.automaticcomments as we consider ourself 367 # to be the the authority. Same applies to otherpo.msgidcomments 368 self.addnote(otherpo.getnotes("developer"), origin="developer", position="merge") 369 self.msgidcomment = otherpo._extract_msgidcomments() or None 370 self.addlocations(otherpo.getlocations()) 371 if not self.istranslated() or overwrite: 372 # Remove kde-style comments from the translation (if any). 373 if self._extract_msgidcomments(otherpo.target): 374 otherpo.target = otherpo.target.replace('_: ' + otherpo._extract_msgidcomments()+ '\n', '') 375 self.target = otherpo.target 376 if self.source != otherpo.source: 377 self.markfuzzy() 378 else: 379 self.markfuzzy(otherpo.isfuzzy()) 380 elif not otherpo.istranslated(): 381 if self.source != otherpo.source: 382 self.markfuzzy() 383 else: 384 if self.target != otherpo.target: 385 self.markfuzzy()
386
387 - def isheader(self):
388 #return self.source == u"" and self.target != u"" 389 # we really want to make sure that there is no msgidcomment or msgctxt 390 return self.getid() == "" and len(self.target) > 0
391
392 - def isblank(self):
393 return len(self.source) == 0 and len(self.target) == 0
394
395 - def hastypecomment(self, typecomment):
396 return gpo.po_message_is_format(self._gpo_message, typecomment)
397
398 - def hasmarkedcomment(self, commentmarker):
399 commentmarker = "(%s)" % commentmarker 400 for comment in self.getnotes("translator").split("\n"): 401 if comment.startswith(commentmarker): 402 return True 403 return False
404
405 - def istranslated(self):
406 return super(pounit, self).istranslated() and not self.isobsolete()
407
408 - def istranslatable(self):
409 return not (self.isheader() or self.isblank() or self.isobsolete())
410
411 - def isfuzzy(self):
412 return gpo.po_message_is_fuzzy(self._gpo_message)
413
414 - def markfuzzy(self, present=True):
415 gpo.po_message_set_fuzzy(self._gpo_message, present)
416
417 - def isreview(self):
418 return self.hasmarkedcomment("review") or self.hasmarkedcomment("pofilter")
419
420 - def isobsolete(self):
421 return gpo.po_message_is_obsolete(self._gpo_message)
422
423 - def makeobsolete(self):
424 # FIXME: libgettexpo currently does not reset other data, we probably want to do that 425 # but a better solution would be for libgettextpo to output correct data on serialisation 426 gpo.po_message_set_obsolete(self._gpo_message, True)
427
428 - def resurrect(self):
429 gpo.po_message_set_obsolete(self._gpo_message, False)
430
431 - def hasplural(self):
432 return gpo.po_message_msgid_plural(self._gpo_message) is not None
433
434 - def _extract_msgidcomments(self, text=None):
435 """Extract KDE style msgid comments from the unit. 436 437 @rtype: String 438 @return: Returns the extracted msgidcomments found in this unit's msgid. 439 440 """ 441 442 if not text: 443 text = gpo.po_message_msgid(self._gpo_message) 444 if text: 445 msgidcomment = re.search("_: (.*)\n", text) 446 if msgidcomment: 447 return msgidcomment.group(1).decode(self._encoding) 448 return u""
449
450 - def __str__(self):
451 pf = pofile() 452 pf.addunit(self) 453 return str(pf)
454
455 - def getlocations(self):
456 locations = [] 457 i = 0 458 location = gpo.po_message_filepos(self._gpo_message, i) 459 while location: 460 locname = gpo.po_filepos_file(location) 461 locline = gpo.po_filepos_start_line(location) 462 if locline == -1: 463 locstring = locname 464 else: 465 locstring = locname + ":" + str(locline) 466 locations.append(locstring) 467 i += 1 468 location = gpo.po_message_filepos(self._gpo_message, i) 469 return locations
470
471 - def addlocation(self, location):
472 for loc in location.split(): 473 parts = loc.split(":") 474 file = parts[0] 475 if len(parts) == 2: 476 line = int(parts[1]) 477 else: 478 line = -1 479 gpo.po_message_add_filepos(self._gpo_message, file, line)
480
481 - def getcontext(self):
482 msgctxt = gpo.po_message_msgctxt(self._gpo_message) 483 msgidcomment = self._extract_msgidcomments() 484 if msgctxt: 485 return msgctxt + msgidcomment 486 else: 487 return msgidcomment
488
489 -class pofile(pocommon.pofile):
490 UnitClass = pounit
491 - def __init__(self, inputfile=None, encoding=None, unitclass=pounit):
492 self.UnitClass = unitclass 493 pocommon.pofile.__init__(self, unitclass=unitclass) 494 self._gpo_memory_file = None 495 self._gpo_message_iterator = None 496 self._encoding = encodingToUse(encoding) 497 if inputfile is not None: 498 self.parse(inputfile) 499 else: 500 self._gpo_memory_file = gpo.po_file_create() 501 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memory_file, None)
502
503 - def addunit(self, unit):
504 gpo.po_message_insert(self._gpo_message_iterator, unit._gpo_message) 505 self.units.append(unit)
506
507 - def removeduplicates(self, duplicatestyle="merge"):
508 """make sure each msgid is unique ; merge comments etc from duplicates into original""" 509 msgiddict = {} 510 uniqueunits = [] 511 # we sometimes need to keep track of what has been marked 512 # TODO: this is using a list as the pos aren't hashable, but this is slow... 513 markedpos = [] 514 def addcomment(thepo): 515 thepo.msgidcomment = " ".join(thepo.getlocations()) 516 markedpos.append(thepo)
517 for thepo in self.units: 518 if thepo.isheader(): 519 uniqueunits.append(thepo) 520 continue 521 if duplicatestyle.startswith("msgid_comment"): 522 msgid = thepo._extract_msgidcomments() + thepo.source 523 else: 524 msgid = thepo.source 525 if duplicatestyle == "msgid_comment_all": 526 addcomment(thepo) 527 uniqueunits.append(thepo) 528 elif msgid in msgiddict: 529 if duplicatestyle == "merge": 530 if msgid: 531 msgiddict[msgid].merge(thepo) 532 else: 533 addcomment(thepo) 534 uniqueunits.append(thepo) 535 elif duplicatestyle == "keep": 536 uniqueunits.append(thepo) 537 elif duplicatestyle == "msgid_comment": 538 origpo = msgiddict[msgid] 539 if origpo not in markedpos: 540 addcomment(origpo) 541 addcomment(thepo) 542 uniqueunits.append(thepo) 543 elif duplicatestyle == "msgctxt": 544 origpo = msgiddict[msgid] 545 if origpo not in markedpos: 546 gpo.po_message_set_msgctxt(origpo._gpo_message, " ".join(origpo.getlocations())) 547 markedpos.append(thepo) 548 gpo.po_message_set_msgctxt(thepo._gpo_message, " ".join(thepo.getlocations())) 549 uniqueunits.append(thepo) 550 else: 551 if not msgid and duplicatestyle != "keep": 552 addcomment(thepo) 553 msgiddict[msgid] = thepo 554 uniqueunits.append(thepo) 555 new_gpo_memory_file = gpo.po_file_create() 556 new_gpo_message_iterator = gpo.po_message_iterator(new_gpo_memory_file, None) 557 for unit in uniqueunits: 558 gpo.po_message_insert(new_gpo_message_iterator, unit._gpo_message) 559 gpo.po_message_iterator_free(self._gpo_message_iterator) 560 self._gpo_message_iterator = new_gpo_message_iterator 561 self._gpo_memory_file = new_gpo_memory_file 562 self.units = uniqueunits
563
564 - def __str__(self):
565 def obsolete_workaround(): 566 # Remove all items that are not output by msgmerge when a unit is obsolete. This is a work 567 # around for bug in libgettextpo 568 # FIXME Do version test in case they fix this bug 569 for unit in self.units: 570 if unit.isobsolete(): 571 gpo.po_message_set_extracted_comments(unit._gpo_message, "") 572 location = gpo.po_message_filepos(unit._gpo_message, 0) 573 while location: 574 gpo.po_message_remove_filepos(unit._gpo_message, 0) 575 location = gpo.po_message_filepos(unit._gpo_message, 0)
576 outputstring = "" 577 if self._gpo_memory_file: 578 obsolete_workaround() 579 outputfile = os.tmpnam() 580 f = open(outputfile, "w") 581 self._gpo_memory_file = gpo.po_file_write_v2(self._gpo_memory_file, outputfile, xerror_handler) 582 f.close() 583 f = open(outputfile, "r") 584 outputstring = f.read() 585 f.close() 586 os.remove(outputfile) 587 return outputstring 588
589 - def isempty(self):
590 """Returns True if the object doesn't contain any translation units.""" 591 if len(self.units) == 0: 592 return True 593 # Skip the first unit if it is a header. 594 if self.units[0].isheader(): 595 units = self.units[1:] 596 else: 597 units = self.units 598 599 for unit in units: 600 if not unit.isblank() and not unit.isobsolete(): 601 return False 602 return True
603
604 - def parse(self, input):
605 if hasattr(input, 'name'): 606 self.filename = input.name 607 elif not getattr(self, 'filename', ''): 608 self.filename = '' 609 if hasattr(input, "read"): 610 posrc = input.read() 611 input.close() 612 input = posrc 613 needtmpfile = not os.path.isfile(input) 614 if needtmpfile: 615 # This is not a file - we write the string to a temporary file 616 tmpfile = os.tmpnam() 617 f = open(tmpfile, "w") 618 f.write(input) 619 f.close() 620 input = tmpfile 621 self._gpo_memory_file = gpo.po_file_read_v3(input, xerror_handler) 622 if self._gpo_memory_file is None: 623 print >> sys.stderr, "Error:" 624 if needtmpfile: 625 os.remove(tmpfile) 626 # Handle xerrors here 627 self._header = gpo.po_file_domain_header(self._gpo_memory_file, None) 628 if self._header: 629 charset = gpo.po_header_field(self._header, "Content-Type") 630 if charset: 631 charset = re.search("charset=([^\\s]+)", charset).group(1) 632 self._encoding = encodingToUse(charset) 633 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memory_file, None) 634 newmessage = gpo.po_next_message(self._gpo_message_iterator) 635 while newmessage: 636 newunit = pounit(gpo_message=newmessage) 637 self.units.append(newunit) 638 newmessage = gpo.po_next_message(self._gpo_message_iterator) 639 self._free_iterator()
640
641 - def __del__(self):
642 # We currently disable this while we still get segmentation faults. 643 # Note that this is definitely leaking memory because of this. 644 return 645 self._free_iterator() 646 if self._gpo_memory_file is not None: 647 gpo.po_file_free(self._gpo_memory_file) 648 self._gpo_memory_file = None
649
650 - def _free_iterator(self):
651 # We currently disable this while we still get segmentation faults. 652 # Note that this is definitely leaking memory because of this. 653 return 654 if self._gpo_message_iterator is not None: 655 gpo.po_message_iterator_free(self._gpo_message_iterator) 656 self._gpo_message_iterator = None
657