Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(81)

Delta Between Two Patch Sets: translate/storage/base.py

Issue 62: CPO support for previous messages SVN Base: https://translate.svn.sourceforge.net/svnroot/translate/src/trunk/
Left Patch Set: Fixed minor issues Created 1 year, 4 months ago
Right Patch Set: Updated accessors, tests and added base.py & test_base.py Created 1 year, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: View regular side by side diff
Right: View regular side by side diff
LEFTRIGHT
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*- 2 # -*- coding: utf-8 -*-
3 # 3 #
4 # Copyright 2006-2008 Zuza Software Foundation 4 # Copyright 2006-2008 Zuza Software Foundation
5 # 5 #
6 # This file is part of translate. 6 # This file is part of translate.
7 # 7 #
8 # translate is free software; you can redistribute it and/or modify 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 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 10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version. 11 # (at your option) any later version.
12 # 12 #
13 # translate is distributed in the hope that it will be useful, 13 # translate is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details. 16 # GNU General Public License for more details.
17 # 17 #
18 # You should have received a copy of the GNU General Public License 18 # You should have received a copy of the GNU General Public License
19 # along with translate; if not, write to the Free Software 19 # along with translate; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 21
22 """Base classes for storage interfaces. 22 """Base classes for storage interfaces.
23 23
24 @organization: Zuza Software Foundation 24 @organization: Zuza Software Foundation
25 @copyright: 2006-2007 Zuza Software Foundation 25 @copyright: 2006-2007 Zuza Software Foundation
26 @license: U{GPL <http://www.fsf.org/licensing/licenses/gpl.html>} 26 @license: U{GPL <http://www.fsf.org/licensing/licenses/gpl.html>}
27 """ 27 """
28 28
29 try: 29 try:
30 import cPickle as pickle 30 import cPickle as pickle
31 except: 31 except:
32 import pickle 32 import pickle
33 from exceptions import NotImplementedError 33 from exceptions import NotImplementedError
34 34
35 def force_override(method, baseclass): 35 def force_override(method, baseclass):
36 """Forces derived classes to override method.""" 36 """Forces derived classes to override method."""
37 37
38 if type(method.im_self) == type(baseclass): 38 if type(method.im_self) == type(baseclass):
39 # then this is a classmethod and im_self is the actual class 39 # then this is a classmethod and im_self is the actual class
40 actualclass = method.im_self 40 actualclass = method.im_self
41 else: 41 else:
42 actualclass = method.im_class 42 actualclass = method.im_class
43 if actualclass != baseclass: 43 if actualclass != baseclass:
44 raise NotImplementedError("%s does not reimplement %s as required by %s" % (actualclass.__name__, method.__name__, baseclass.__name__)) 44 raise NotImplementedError("%s does not reimplement %s as required by %s" % (actualclass.__name__, method.__name__, baseclass.__name__))
45 45
46 class ParseError(Exception): 46 class ParseError(Exception):
47 pass 47 pass
48 48
49 class TranslationUnit(object): 49 class TranslationUnit(object):
50 """Base class for translation units. 50 """Base class for translation units.
51 51
52 Our concept of a I{translation unit} is influenced heavily by XLIFF: 52 Our concept of a I{translation unit} is influenced heavily by XLIFF:
53 U{http://www.oasis-open.org/committees/xliff/documents/xliff-specification.h tm} 53 U{http://www.oasis-open.org/committees/xliff/documents/xliff-specification.h tm}
54 54
55 As such most of the method- and variable names borrows from XLIFF terminolog y. 55 As such most of the method- and variable names borrows from XLIFF terminolog y.
56 56
57 A translation unit consists of the following: 57 A translation unit consists of the following:
58 - A I{source} string. This is the original translatable text. 58 - A I{source} string. This is the original translatable text.
59 - A I{target} string. This is the translation of the I{source}. 59 - A I{target} string. This is the translation of the I{source}.
60 - Zero or more I{notes} on the unit. Notes would typically be some 60 - Zero or more I{notes} on the unit. Notes would typically be some
61 comments from a translator on the unit, or some comments originating fro m 61 comments from a translator on the unit, or some comments originating fro m
62 the source code. 62 the source code.
63 - Zero or more I{locations}. Locations indicate where in the original 63 - Zero or more I{locations}. Locations indicate where in the original
64 source code this unit came from. 64 source code this unit came from.
65 - Zero or more I{errors}. Some tools (eg. L{pofilter <filters.pofilter>}) can run checks on 65 - Zero or more I{errors}. Some tools (eg. L{pofilter <filters.pofilter>}) can run checks on
66 translations and produce error messages. 66 translations and produce error messages.
67 - Zero or one I{prev_source} string, the old version of the translatable t ext.
68 - Zero or one I{prev_context} string, the old version of the message conte xt.
67 69
68 @group Source: *source* 70 @group Source: *source*
69 @group Target: *target* 71 @group Target: *target*
72 @group PrevSource: *PrevSource*
73 @group PrevContext: *PrevContext*
70 @group Notes: *note* 74 @group Notes: *note*
71 @group Locations: *location* 75 @group Locations: *location*
72 @group Errors: *error* 76 @group Errors: *error*
73 """ 77 """
74 78
75 def __init__(self, source): 79 def __init__(self, source):
76 """Constructs a TranslationUnit containing the given source string.""" 80 """Constructs a TranslationUnit containing the given source string."""
77 81
78 self._store = None
79 self.source = source 82 self.source = source
80 self.target = None 83 self.target = None
84 self.prev_source = None
85 self.prev_context = None
81 self.notes = "" 86 self.notes = ""
82 super(TranslationUnit, self).__init__() 87 super(TranslationUnit, self).__init__()
83 88
84 def __eq__(self, other): 89 def __eq__(self, other):
85 """Compares two TranslationUnits. 90 """Compares two TranslationUnits.
86 91
87 @type other: L{TranslationUnit} 92 @type other: L{TranslationUnit}
88 @param other: Another L{TranslationUnit} 93 @param other: Another L{TranslationUnit}
89 @rtype: Boolean 94 @rtype: Boolean
90 @return: Returns True if the supplied TranslationUnit equals this unit. 95 @return: Returns True if the supplied TranslationUnit equals this unit.
91 96
92 """ 97 """
93 98
94 return self.source == other.source and self.target == other.target 99 return self.source == other.source and self.target == other.target
95 100
96 def settarget(self, target): 101 def settarget(self, target):
97 """Sets the target string to the given value.""" 102 """Sets the target string to the given value."""
98 103
99 self.target = target 104 self.target = target
100 105
101 def gettargetlen(self): 106 def gettargetlen(self):
102 """Returns the length of the target string. 107 """Returns the length of the target string.
103 108
104 @note: Plural forms might be combined. 109 @note: Plural forms might be combined.
105 @rtype: Integer 110 @rtype: Integer
106 111
107 """ 112 """
108 113
109 length = len(self.target or "") 114 length = len(self.target or "")
110 strings = getattr(self.target, "strings", []) 115 strings = getattr(self.target, "strings", [])
111 if strings: 116 if strings:
112 length += sum([len(pluralform) for pluralform in strings[1:]]) 117 length += sum([len(pluralform) for pluralform in strings[1:]])
113 return length 118 return length
114 119
115 def getid(self): 120 def getid(self):
116 """A unique identifier for this unit. 121 """A unique identifier for this unit.
117 122
118 @rtype: string 123 @rtype: string
119 @return: an identifier for this unit that is unique in the store 124 @return: an identifier for this unit that is unique in the store
120 125
121 Derived classes should override this in a way that guarantees a unique 126 Derived classes should override this in a way that guarantees a unique
122 identifier for each unit in the store. 127 identifier for each unit in the store.
123 """ 128 """
124 return self.source 129 return self.source
125 130
126 def getlocations(self): 131 def getlocations(self):
127 """A list of source code locations. 132 """A list of source code locations.
128 133
129 @note: Shouldn't be implemented if the format doesn't support it. 134 @note: Shouldn't be implemented if the format doesn't support it.
130 @rtype: List 135 @rtype: List
(...skipping 99 matching lines...) Show 10 above Show 10 below
230 to ensure that other classes can implement more functionality 235 to ensure that other classes can implement more functionality
231 (as XLIFF does). 236 (as XLIFF does).
232 237
233 """ 238 """
234 239
235 return bool(self.target) and not self.isfuzzy() 240 return bool(self.target) and not self.isfuzzy()
236 241
237 def istranslatable(self): 242 def istranslatable(self):
238 """Indicates whether this unit can be translated. 243 """Indicates whether this unit can be translated.
239 244
240 This should be used to distinguish real units for translation from 245 This should be used to distinguish real units for translation from
241 header, obsolete, binary or other blank units. 246 header, obsolete, binary or other blank units.
242 """ 247 """
243 return True 248 return True
244 249
245 def isfuzzy(self): 250 def isfuzzy(self):
246 """Indicates whether this unit is fuzzy.""" 251 """Indicates whether this unit is fuzzy."""
247 252
248 return False 253 return False
249 254
250 def markfuzzy(self, value=True): 255 def markfuzzy(self, value=True):
251 """Marks the unit as fuzzy or not.""" 256 """Marks the unit as fuzzy or not."""
252 pass 257 pass
253 258
254 def isheader(self): 259 def isheader(self):
255 """Indicates whether this unit is a header.""" 260 """Indicates whether this unit is a header."""
256 261
257 return False 262 return False
258 263
259 def isreview(self): 264 def isreview(self):
260 """Indicates whether this unit needs review.""" 265 """Indicates whether this unit needs review."""
261 return False 266 return False
262 267
263 268
264 def isblank(self): 269 def isblank(self):
265 """Used to see if this unit has no source or target string. 270 """Used to see if this unit has no source or target string.
266 271
267 @note: This is probably used more to find translatable units, 272 @note: This is probably used more to find translatable units,
268 and we might want to move in that direction rather and get rid of this. 273 and we might want to move in that direction rather and get rid of this.
269 274
270 """ 275 """
271 276
272 return not (self.source or self.target) 277 return not (self.source or self.target)
273 278
274 def hasplural(self): 279 def hasplural(self):
275 """Tells whether or not this specific unit has plural strings.""" 280 """Tells whether or not this specific unit has plural strings."""
276 281
277 #TODO: Reconsider 282 #TODO: Reconsider
278 return False 283 return False
279 284
280 def getsourcelanguage(self):
281 return getattr(self._store, "sourcelanguage", "en")
282
283 def gettargetlanguage(self):
284 return getattr(self._store, "targetlanguage", None)
285
286 def merge(self, otherunit, overwrite=False, comments=True): 285 def merge(self, otherunit, overwrite=False, comments=True):
287 """Do basic format agnostic merging.""" 286 """Do basic format agnostic merging."""
288 287
289 if self.target == "" or overwrite: 288 if self.target == "" or overwrite:
290 self.target = otherunit.target 289 self.target = otherunit.target
291 290
292 def unit_iter(self): 291 def unit_iter(self):
293 """Iterator that only returns this unit.""" 292 """Iterator that only returns this unit."""
294 yield self 293 yield self
295 294
296 def getunits(self): 295 def getunits(self):
297 """This unit in a list.""" 296 """This unit in a list."""
298 return [self] 297 return [self]
299 298
300 def setprev_source(self, source): 299 def setprev_source(self, source):
301 """Sets the previous source message for this unit""" 300 """Sets the previous source message for this unit"""
302 pass 301 self.prev_source = source
303 302
304 def getprev_source(self): 303 def getprev_source(self):
305 """Gets the previous source message for this unit""" 304 """Gets the previous source message for this unit"""
306 pass 305 return self.prev_source
dwaynebailey 2008/07/17 12:59:27 Shouldn't the decorators be here for prev_source?
georgeyk 2008/07/18 05:15:49 On 2008/07/17 12:59:27, dwaynebailey wrote: > Shou
307
308 prev_source = property(getprev_source, setprev_source)
309 306
310 def setprev_context(self, context): 307 def setprev_context(self, context):
311 """Sets the previous context of this unit""" 308 """Sets the previous context of this unit"""
312 pass 309 self.prev_context = context
313 310
314 def getprev_context(self): 311 def getprev_context(self):
315 """Gets the previous context of this unit""" 312 """Gets the previous context of this unit"""
316 pass 313 return self.prev_context
317
318 prev_context = property(getprev_context, setprev_context)
319 314
320 def set_as_previous(self): 315 def set_as_previous(self):
321 """Sets this unit as a previous unit message""" 316 """Sets this unit as a previous unit message"""
322 if self.isfuzzy(): 317 if self.isfuzzy():
323 return 318 return
324 self.setprev_context(self.getcontext()) 319 self.setprev_context(self.getcontext())
325 self.setprev_source(self.source) 320 self.setprev_source(self.source)
326 self.markfuzzy() 321 self.markfuzzy()
327 322
328 def buildfromunit(cls, unit): 323 def buildfromunit(cls, unit):
329 """Build a native unit from a foreign unit, preserving as much 324 """Build a native unit from a foreign unit, preserving as much
330 information as possible.""" 325 information as possible."""
331 326
332 if type(unit) == cls and hasattr(unit, "copy") and callable(unit.copy): 327 if type(unit) == cls and hasattr(unit, "copy") and callable(unit.copy):
333 return unit.copy() 328 return unit.copy()
334 newunit = cls(unit.source) 329 newunit = cls(unit.source)
335 newunit.target = unit.target 330 newunit.target = unit.target
336 newunit.markfuzzy(unit.isfuzzy()) 331 newunit.markfuzzy(unit.isfuzzy())
337 locations = unit.getlocations() 332 locations = unit.getlocations()
338 if locations: 333 if locations:
339 newunit.addlocations(locations) 334 newunit.addlocations(locations)
340 notes = unit.getnotes() 335 notes = unit.getnotes()
341 if notes: 336 if notes:
342 newunit.addnote(notes) 337 newunit.addnote(notes)
343 return newunit 338 return newunit
344 buildfromunit = classmethod(buildfromunit) 339 buildfromunit = classmethod(buildfromunit)
345 340
346 class TranslationStore(object): 341 class TranslationStore(object):
347 """Base class for stores for multiple translation units of type UnitClass."" " 342 """Base class for stores for multiple translation units of type UnitClass."" "
348 343
349 UnitClass = TranslationUnit 344 UnitClass = TranslationUnit
350 Mimetypes = None 345 Mimetypes = None
351 Extensions = None 346 Extensions = None
352 347
353 def __init__(self, unitclass=None): 348 def __init__(self, unitclass=None):
354 """Constructs a blank TranslationStore.""" 349 """Constructs a blank TranslationStore."""
355 350
356 self.units = [] 351 self.units = []
357 self.filepath = None 352 self.filepath = None
358 self.translator = "" 353 self.translator = ""
359 self.date = "" 354 self.date = ""
360 self.sourcelanguage = None 355 self.sourcelanguage = None
361 self.targetlanguage = None 356 self.targetlanguage = None
362 if unitclass: 357 if unitclass:
363 self.UnitClass = unitclass 358 self.UnitClass = unitclass
364 super(TranslationStore, self).__init__() 359 super(TranslationStore, self).__init__()
365 360
366 def setsourcelanguage(self, sourcelanguage): 361 def setsourcelanguage(self, sourcelanguage):
367 """Sets the source language for this store""" 362 """Sets the source language for this store"""
368 self.sourcelanguage = sourcelanguage 363 self.sourcelanguage = sourcelanguage
369 364
370 def settargetlanguage(self, targetlanguage): 365 def settargetlanguage(self, targetlanguage):
371 """Sets the target language for this store""" 366 """Sets the target language for this store"""
372 self.targetlanguage = targetlanguage 367 self.targetlanguage = targetlanguage
373 368
374 def unit_iter(self): 369 def unit_iter(self):
375 """Iterator over all the units in this store.""" 370 """Iterator over all the units in this store."""
376 for unit in self.units: 371 for unit in self.units:
377 yield unit 372 yield unit
378 373
379 def getunits(self): 374 def getunits(self):
380 """Return a list of all units in this store.""" 375 """Return a list of all units in this store."""
381 return [unit for unit in self.unit_iter()] 376 return [unit for unit in self.unit_iter()]
382 377
383 def addunit(self, unit): 378 def addunit(self, unit):
384 """Appends the given unit to the object's list of units. 379 """Appends the given unit to the object's list of units.
385 380
386 This method should always be used rather than trying to modify the 381 This method should always be used rather than trying to modify the
387 list manually. 382 list manually.
388 383
389 @type unit: L{TranslationUnit} 384 @type unit: L{TranslationUnit}
390 @param unit: The unit that will be added. 385 @param unit: The unit that will be added.
391 386
392 """ 387 """
393 unit._store = self 388
394 self.units.append(unit) 389 self.units.append(unit)
395 390
396 def addsourceunit(self, source): 391 def addsourceunit(self, source):
397 """Adds and returns a new unit with the given source string. 392 """Adds and returns a new unit with the given source string.
398 393
399 @rtype: L{TranslationUnit} 394 @rtype: L{TranslationUnit}
400 395
401 """ 396 """
402 397
403 unit = self.UnitClass(source) 398 unit = self.UnitClass(source)
404 self.addunit(unit) 399 self.addunit(unit)
405 return unit 400 return unit
406 401
407 def findunit(self, source): 402 def findunit(self, source):
408 """Finds the unit with the given source string. 403 """Finds the unit with the given source string.
409 404
410 @rtype: L{TranslationUnit} or None 405 @rtype: L{TranslationUnit} or None
411 406
412 """ 407 """
413 408
414 if len(getattr(self, "sourceindex", [])): 409 if len(getattr(self, "sourceindex", [])):
415 if source in self.sourceindex: 410 if source in self.sourceindex:
416 return self.sourceindex[source] 411 return self.sourceindex[source]
417 else: 412 else:
418 for unit in self.units: 413 for unit in self.units:
419 if unit.source == source: 414 if unit.source == source:
420 return unit 415 return unit
421 return None 416 return None
422 417
423 def translate(self, source): 418 def translate(self, source):
424 """Returns the translated string for a given source string. 419 """Returns the translated string for a given source string.
425 420
426 @rtype: String or None 421 @rtype: String or None
427 422
428 """ 423 """
429 424
430 unit = self.findunit(source) 425 unit = self.findunit(source)
431 if unit and unit.target: 426 if unit and unit.target:
432 return unit.target 427 return unit.target
433 else: 428 else:
434 return None 429 return None
435 430
436 def makeindex(self): 431 def makeindex(self):
437 """Indexes the items in this store. At least .sourceindex should be usef ull.""" 432 """Indexes the items in this store. At least .sourceindex should be usef ull."""
438 433
439 self.locationindex = {} 434 self.locationindex = {}
440 self.sourceindex = {} 435 self.sourceindex = {}
441 for unit in self.units: 436 for unit in self.units:
442 # Do we need to test if unit.source exists? 437 # Do we need to test if unit.source exists?
443 self.sourceindex[unit.source] = unit 438 self.sourceindex[unit.source] = unit
444 if unit.hasplural(): 439 if unit.hasplural():
445 for nounform in unit.source.strings[1:]: 440 for nounform in unit.source.strings[1:]:
446 self.sourceindex[nounform] = unit 441 self.sourceindex[nounform] = unit
447 for location in unit.getlocations(): 442 for location in unit.getlocations():
448 if location in self.locationindex: 443 if location in self.locationindex:
449 # if sources aren't unique, don't use them 444 # if sources aren't unique, don't use them
450 self.locationindex[location] = None 445 self.locationindex[location] = None
451 else: 446 else:
452 self.locationindex[location] = unit 447 self.locationindex[location] = unit
453 448
454 def __str__(self): 449 def __str__(self):
455 """Converts to a string representation that can be parsed back using L{p arsestring()}.""" 450 """Converts to a string representation that can be parsed back using L{p arsestring()}."""
456 451
457 # We can't pickle fileobj if it is there, so let's hide it for a while. 452 # We can't pickle fileobj if it is there, so let's hide it for a while.
458 fileobj = getattr(self, "fileobj", None) 453 fileobj = getattr(self, "fileobj", None)
459 self.fileobj = None 454 self.fileobj = None
460 dump = pickle.dumps(self) 455 dump = pickle.dumps(self)
461 self.fileobj = fileobj 456 self.fileobj = fileobj
462 return dump 457 return dump
463 458
464 def isempty(self): 459 def isempty(self):
465 """Returns True if the object doesn't contain any translation units.""" 460 """Returns True if the object doesn't contain any translation units."""
466 461
467 if len(self.units) == 0: 462 if len(self.units) == 0:
468 return True 463 return True
469 for unit in self.units: 464 for unit in self.units:
470 if not (unit.isblank() or unit.isheader()): 465 if not (unit.isblank() or unit.isheader()):
471 return False 466 return False
472 return True 467 return True
473 468
474 def _assignname(self): 469 def _assignname(self):
475 """Tries to work out what the name of the filesystem file is and 470 """Tries to work out what the name of the filesystem file is and
476 assigns it to .filename.""" 471 assigns it to .filename."""
477 fileobj = getattr(self, "fileobj", None) 472 fileobj = getattr(self, "fileobj", None)
478 if fileobj: 473 if fileobj:
479 filename = getattr(fileobj, "name", getattr(fileobj, "filename", Non e)) 474 filename = getattr(fileobj, "name", getattr(fileobj, "filename", Non e))
480 if filename: 475 if filename:
481 self.filename = filename 476 self.filename = filename
482 477
483 def parsestring(cls, storestring): 478 def parsestring(cls, storestring):
484 """Converts the string representation back to an object.""" 479 """Converts the string representation back to an object."""
485 newstore = cls() 480 newstore = cls()
486 if storestring: 481 if storestring:
487 newstore.parse(storestring) 482 newstore.parse(storestring)
488 return newstore 483 return newstore
489 parsestring = classmethod(parsestring) 484 parsestring = classmethod(parsestring)
490 485
491 def parse(self, data): 486 def parse(self, data):
492 """parser to process the given source string""" 487 """parser to process the given source string"""
493 self.units = pickle.loads(data).units 488 self.units = pickle.loads(data).units
494 489
495 def savefile(self, storefile): 490 def savefile(self, storefile):
496 """Writes the string representation to the given file (or filename).""" 491 """Writes the string representation to the given file (or filename)."""
497 if isinstance(storefile, basestring): 492 if isinstance(storefile, basestring):
498 storefile = open(storefile, "w") 493 storefile = open(storefile, "w")
499 self.fileobj = storefile 494 self.fileobj = storefile
500 self._assignname() 495 self._assignname()
501 storestring = str(self) 496 storestring = str(self)
502 storefile.write(storestring) 497 storefile.write(storestring)
503 storefile.close() 498 storefile.close()
504 499
505 def save(self): 500 def save(self):
506 """Save to the file that data was originally read from, if available.""" 501 """Save to the file that data was originally read from, if available."""
507 fileobj = getattr(self, "fileobj", None) 502 fileobj = getattr(self, "fileobj", None)
508 if not fileobj: 503 if not fileobj:
509 filename = getattr(self, "filename", None) 504 filename = getattr(self, "filename", None)
510 if filename: 505 if filename:
511 fileobj = file(filename, "w") 506 fileobj = file(filename, "w")
512 else: 507 else:
513 fileobj.close() 508 fileobj.close()
514 filename = getattr(fileobj, "name", getattr(fileobj, "filename", Non e)) 509 filename = getattr(fileobj, "name", getattr(fileobj, "filename", Non e))
515 if not filename: 510 if not filename:
516 raise ValueError("No file or filename to save to") 511 raise ValueError("No file or filename to save to")
517 fileobj = fileobj.__class__(filename, "w") 512 fileobj = fileobj.__class__(filename, "w")
518 self.savefile(fileobj) 513 self.savefile(fileobj)
519 514
520 def parsefile(cls, storefile): 515 def parsefile(cls, storefile):
521 """Reads the given file (or opens the given filename) and parses back to an object.""" 516 """Reads the given file (or opens the given filename) and parses back to an object."""
522 517
523 if isinstance(storefile, basestring): 518 if isinstance(storefile, basestring):
524 storefile = open(storefile, "r") 519 storefile = open(storefile, "r")
525 mode = getattr(storefile, "mode", "r") 520 mode = getattr(storefile, "mode", "r")
526 #For some reason GzipFile returns 1, so we have to test for that here 521 #For some reason GzipFile returns 1, so we have to test for that here
527 if mode == 1 or "r" in mode: 522 if mode == 1 or "r" in mode:
528 storestring = storefile.read() 523 storestring = storefile.read()
529 storefile.close() 524 storefile.close()
530 else: 525 else:
531 storestring = "" 526 storestring = ""
532 newstore = cls.parsestring(storestring) 527 newstore = cls.parsestring(storestring)
533 newstore.fileobj = storefile 528 newstore.fileobj = storefile
534 newstore._assignname() 529 newstore._assignname()
535 return newstore 530 return newstore
536 parsefile = classmethod(parsefile) 531 parsefile = classmethod(parsefile)
537 532
LEFTRIGHT

Powered by Google App Engine
This is Rietveld r159