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

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: Updated accessors, tests and added base.py & test_base.py Created 1 year, 4 months ago
Right Patch Set: Fixed minor issues 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.
69 67
70 @group Source: *source* 68 @group Source: *source*
71 @group Target: *target* 69 @group Target: *target*
72 @group PrevSource: *PrevSource*
73 @group PrevContext: *PrevContext*
74 @group Notes: *note* 70 @group Notes: *note*
75 @group Locations: *location* 71 @group Locations: *location*
76 @group Errors: *error* 72 @group Errors: *error*
77 """ 73 """
78 74
79 def __init__(self, source): 75 def __init__(self, source):
80 """Constructs a TranslationUnit containing the given source string.""" 76 """Constructs a TranslationUnit containing the given source string."""
81 77
78 self._store = None
82 self.source = source 79 self.source = source
83 self.target = None 80 self.target = None
84 self.prev_source = None
85 self.prev_context = None
86 self.notes = "" 81 self.notes = ""
87 super(TranslationUnit, self).__init__() 82 super(TranslationUnit, self).__init__()
88 83
89 def __eq__(self, other): 84 def __eq__(self, other):
90 """Compares two TranslationUnits. 85 """Compares two TranslationUnits.
91 86
92 @type other: L{TranslationUnit} 87 @type other: L{TranslationUnit}
93 @param other: Another L{TranslationUnit} 88 @param other: Another L{TranslationUnit}
94 @rtype: Boolean 89 @rtype: Boolean
95 @return: Returns True if the supplied TranslationUnit equals this unit. 90 @return: Returns True if the supplied TranslationUnit equals this unit.
96 91
97 """ 92 """
98 93
99 return self.source == other.source and self.target == other.target 94 return self.source == other.source and self.target == other.target
100 95
101 def settarget(self, target): 96 def settarget(self, target):
102 """Sets the target string to the given value.""" 97 """Sets the target string to the given value."""
103 98
104 self.target = target 99 self.target = target
105 100
106 def gettargetlen(self): 101 def gettargetlen(self):
107 """Returns the length of the target string. 102 """Returns the length of the target string.
108 103
109 @note: Plural forms might be combined. 104 @note: Plural forms might be combined.
110 @rtype: Integer 105 @rtype: Integer
111 106
112 """ 107 """
113 108
114 length = len(self.target or "") 109 length = len(self.target or "")
115 strings = getattr(self.target, "strings", []) 110 strings = getattr(self.target, "strings", [])
116 if strings: 111 if strings:
117 length += sum([len(pluralform) for pluralform in strings[1:]]) 112 length += sum([len(pluralform) for pluralform in strings[1:]])
118 return length 113 return length
119 114
120 def getid(self): 115 def getid(self):
121 """A unique identifier for this unit. 116 """A unique identifier for this unit.
122 117
123 @rtype: string 118 @rtype: string
124 @return: an identifier for this unit that is unique in the store 119 @return: an identifier for this unit that is unique in the store
125 120
126 Derived classes should override this in a way that guarantees a unique 121 Derived classes should override this in a way that guarantees a unique
127 identifier for each unit in the store. 122 identifier for each unit in the store.
128 """ 123 """
129 return self.source 124 return self.source
130 125
131 def getlocations(self): 126 def getlocations(self):
132 """A list of source code locations. 127 """A list of source code locations.
133 128
134 @note: Shouldn't be implemented if the format doesn't support it. 129 @note: Shouldn't be implemented if the format doesn't support it.
135 @rtype: List 130 @rtype: List
(...skipping 99 matching lines...) Show 10 above Show 10 below
235 to ensure that other classes can implement more functionality 230 to ensure that other classes can implement more functionality
236 (as XLIFF does). 231 (as XLIFF does).
237 232
238 """ 233 """
239 234
240 return bool(self.target) and not self.isfuzzy() 235 return bool(self.target) and not self.isfuzzy()
241 236
242 def istranslatable(self): 237 def istranslatable(self):
243 """Indicates whether this unit can be translated. 238 """Indicates whether this unit can be translated.
244 239
245 This should be used to distinguish real units for translation from 240 This should be used to distinguish real units for translation from
246 header, obsolete, binary or other blank units. 241 header, obsolete, binary or other blank units.
247 """ 242 """
248 return True 243 return True
249 244
250 def isfuzzy(self): 245 def isfuzzy(self):
251 """Indicates whether this unit is fuzzy.""" 246 """Indicates whether this unit is fuzzy."""
252 247
253 return False 248 return False
254 249
255 def markfuzzy(self, value=True): 250 def markfuzzy(self, value=True):
256 """Marks the unit as fuzzy or not.""" 251 """Marks the unit as fuzzy or not."""
257 pass 252 pass
258 253
259 def isheader(self): 254 def isheader(self):
260 """Indicates whether this unit is a header.""" 255 """Indicates whether this unit is a header."""
261 256
262 return False 257 return False
263 258
264 def isreview(self): 259 def isreview(self):
265 """Indicates whether this unit needs review.""" 260 """Indicates whether this unit needs review."""
266 return False 261 return False
267 262
268 263
269 def isblank(self): 264 def isblank(self):
270 """Used to see if this unit has no source or target string. 265 """Used to see if this unit has no source or target string.
271 266
272 @note: This is probably used more to find translatable units, 267 @note: This is probably used more to find translatable units,
273 and we might want to move in that direction rather and get rid of this. 268 and we might want to move in that direction rather and get rid of this.
274 269
275 """ 270 """
276 271
277 return not (self.source or self.target) 272 return not (self.source or self.target)
278 273
279 def hasplural(self): 274 def hasplural(self):
280 """Tells whether or not this specific unit has plural strings.""" 275 """Tells whether or not this specific unit has plural strings."""
281 276
282 #TODO: Reconsider 277 #TODO: Reconsider
283 return False 278 return False
284 279
280 def getsourcelanguage(self):
281 return getattr(self._store, "sourcelanguage", "en")
282
283 def gettargetlanguage(self):
284 return getattr(self._store, "targetlanguage", None)
285
285 def merge(self, otherunit, overwrite=False, comments=True): 286 def merge(self, otherunit, overwrite=False, comments=True):
286 """Do basic format agnostic merging.""" 287 """Do basic format agnostic merging."""
287 288
288 if self.target == "" or overwrite: 289 if self.target == "" or overwrite:
289 self.target = otherunit.target 290 self.target = otherunit.target
290 291
291 def unit_iter(self): 292 def unit_iter(self):
292 """Iterator that only returns this unit.""" 293 """Iterator that only returns this unit."""
293 yield self 294 yield self
294 295
295 def getunits(self): 296 def getunits(self):
296 """This unit in a list.""" 297 """This unit in a list."""
297 return [self] 298 return [self]
298 299
299 def setprev_source(self, source): 300 def setprev_source(self, source):
300 """Sets the previous source message for this unit""" 301 """Sets the previous source message for this unit"""
301 self.prev_source = source 302 pass
302 303
303 def getprev_source(self): 304 def getprev_source(self):
304 """Gets the previous source message for this unit""" 305 """Gets the previous source message for this unit"""
305 return self.prev_source 306 pass
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)
306 309
307 def setprev_context(self, context): 310 def setprev_context(self, context):
308 """Sets the previous context of this unit""" 311 """Sets the previous context of this unit"""
309 self.prev_context = context 312 pass
310 313
311 def getprev_context(self): 314 def getprev_context(self):
312 """Gets the previous context of this unit""" 315 """Gets the previous context of this unit"""
313 return self.prev_context 316 pass
317
318 prev_context = property(getprev_context, setprev_context)
314 319
315 def set_as_previous(self): 320 def set_as_previous(self):
316 """Sets this unit as a previous unit message""" 321 """Sets this unit as a previous unit message"""
317 if self.isfuzzy(): 322 if self.isfuzzy():
318 return 323 return
319 self.setprev_context(self.getcontext()) 324 self.setprev_context(self.getcontext())
320 self.setprev_source(self.source) 325 self.setprev_source(self.source)
321 self.markfuzzy() 326 self.markfuzzy()
322 327
323 def buildfromunit(cls, unit): 328 def buildfromunit(cls, unit):
324 """Build a native unit from a foreign unit, preserving as much 329 """Build a native unit from a foreign unit, preserving as much
325 information as possible.""" 330 information as possible."""
326 331
327 if type(unit) == cls and hasattr(unit, "copy") and callable(unit.copy): 332 if type(unit) == cls and hasattr(unit, "copy") and callable(unit.copy):
328 return unit.copy() 333 return unit.copy()
329 newunit = cls(unit.source) 334 newunit = cls(unit.source)
330 newunit.target = unit.target 335 newunit.target = unit.target
331 newunit.markfuzzy(unit.isfuzzy()) 336 newunit.markfuzzy(unit.isfuzzy())
332 locations = unit.getlocations() 337 locations = unit.getlocations()
333 if locations: 338 if locations:
334 newunit.addlocations(locations) 339 newunit.addlocations(locations)
335 notes = unit.getnotes() 340 notes = unit.getnotes()
336 if notes: 341 if notes:
337 newunit.addnote(notes) 342 newunit.addnote(notes)
338 return newunit 343 return newunit
339 buildfromunit = classmethod(buildfromunit) 344 buildfromunit = classmethod(buildfromunit)
340 345
341 class TranslationStore(object): 346 class TranslationStore(object):
342 """Base class for stores for multiple translation units of type UnitClass."" " 347 """Base class for stores for multiple translation units of type UnitClass."" "
343 348
344 UnitClass = TranslationUnit 349 UnitClass = TranslationUnit
345 Mimetypes = None 350 Mimetypes = None
346 Extensions = None 351 Extensions = None
347 352
348 def __init__(self, unitclass=None): 353 def __init__(self, unitclass=None):
349 """Constructs a blank TranslationStore.""" 354 """Constructs a blank TranslationStore."""
350 355
351 self.units = [] 356 self.units = []
352 self.filepath = None 357 self.filepath = None
353 self.translator = "" 358 self.translator = ""
354 self.date = "" 359 self.date = ""
355 self.sourcelanguage = None 360 self.sourcelanguage = None
356 self.targetlanguage = None 361 self.targetlanguage = None
357 if unitclass: 362 if unitclass:
358 self.UnitClass = unitclass 363 self.UnitClass = unitclass
359 super(TranslationStore, self).__init__() 364 super(TranslationStore, self).__init__()
360 365
361 def setsourcelanguage(self, sourcelanguage): 366 def setsourcelanguage(self, sourcelanguage):
362 """Sets the source language for this store""" 367 """Sets the source language for this store"""
363 self.sourcelanguage = sourcelanguage 368 self.sourcelanguage = sourcelanguage
364 369
365 def settargetlanguage(self, targetlanguage): 370 def settargetlanguage(self, targetlanguage):
366 """Sets the target language for this store""" 371 """Sets the target language for this store"""
367 self.targetlanguage = targetlanguage 372 self.targetlanguage = targetlanguage
368 373
369 def unit_iter(self): 374 def unit_iter(self):
370 """Iterator over all the units in this store.""" 375 """Iterator over all the units in this store."""
371 for unit in self.units: 376 for unit in self.units:
372 yield unit 377 yield unit
373 378
374 def getunits(self): 379 def getunits(self):
375 """Return a list of all units in this store.""" 380 """Return a list of all units in this store."""
376 return [unit for unit in self.unit_iter()] 381 return [unit for unit in self.unit_iter()]
377 382
378 def addunit(self, unit): 383 def addunit(self, unit):
379 """Appends the given unit to the object's list of units. 384 """Appends the given unit to the object's list of units.
380 385
381 This method should always be used rather than trying to modify the 386 This method should always be used rather than trying to modify the
382 list manually. 387 list manually.
383 388
384 @type unit: L{TranslationUnit} 389 @type unit: L{TranslationUnit}
385 @param unit: The unit that will be added. 390 @param unit: The unit that will be added.
386 391
387 """ 392 """
388 393 unit._store = self
389 self.units.append(unit) 394 self.units.append(unit)
390 395
391 def addsourceunit(self, source): 396 def addsourceunit(self, source):
392 """Adds and returns a new unit with the given source string. 397 """Adds and returns a new unit with the given source string.
393 398
394 @rtype: L{TranslationUnit} 399 @rtype: L{TranslationUnit}
395 400
396 """ 401 """
397 402
398 unit = self.UnitClass(source) 403 unit = self.UnitClass(source)
399 self.addunit(unit) 404 self.addunit(unit)
400 return unit 405 return unit
401 406
402 def findunit(self, source): 407 def findunit(self, source):
403 """Finds the unit with the given source string. 408 """Finds the unit with the given source string.
404 409
405 @rtype: L{TranslationUnit} or None 410 @rtype: L{TranslationUnit} or None
406 411
407 """ 412 """
408 413
409 if len(getattr(self, "sourceindex", [])): 414 if len(getattr(self, "sourceindex", [])):
410 if source in self.sourceindex: 415 if source in self.sourceindex:
411 return self.sourceindex[source] 416 return self.sourceindex[source]
412 else: 417 else:
413 for unit in self.units: 418 for unit in self.units:
414 if unit.source == source: 419 if unit.source == source:
415 return unit 420 return unit
416 return None 421 return None
417 422
418 def translate(self, source): 423 def translate(self, source):
419 """Returns the translated string for a given source string. 424 """Returns the translated string for a given source string.
420 425
421 @rtype: String or None 426 @rtype: String or None
422 427
423 """ 428 """
424 429
425 unit = self.findunit(source) 430 unit = self.findunit(source)
426 if unit and unit.target: 431 if unit and unit.target:
427 return unit.target 432 return unit.target
428 else: 433 else:
429 return None 434 return None
430 435
431 def makeindex(self): 436 def makeindex(self):
432 """Indexes the items in this store. At least .sourceindex should be usef ull.""" 437 """Indexes the items in this store. At least .sourceindex should be usef ull."""
433 438
434 self.locationindex = {} 439 self.locationindex = {}
435 self.sourceindex = {} 440 self.sourceindex = {}
436 for unit in self.units: 441 for unit in self.units:
437 # Do we need to test if unit.source exists? 442 # Do we need to test if unit.source exists?
438 self.sourceindex[unit.source] = unit 443 self.sourceindex[unit.source] = unit
439 if unit.hasplural(): 444 if unit.hasplural():
440 for nounform in unit.source.strings[1:]: 445 for nounform in unit.source.strings[1:]:
441 self.sourceindex[nounform] = unit 446 self.sourceindex[nounform] = unit
442 for location in unit.getlocations(): 447 for location in unit.getlocations():
443 if location in self.locationindex: 448 if location in self.locationindex:
444 # if sources aren't unique, don't use them 449 # if sources aren't unique, don't use them
445 self.locationindex[location] = None 450 self.locationindex[location] = None
446 else: 451 else:
447 self.locationindex[location] = unit 452 self.locationindex[location] = unit
448 453
449 def __str__(self): 454 def __str__(self):
450 """Converts to a string representation that can be parsed back using L{p arsestring()}.""" 455 """Converts to a string representation that can be parsed back using L{p arsestring()}."""
451 456
452 # We can't pickle fileobj if it is there, so let's hide it for a while. 457 # We can't pickle fileobj if it is there, so let's hide it for a while.
453 fileobj = getattr(self, "fileobj", None) 458 fileobj = getattr(self, "fileobj", None)
454 self.fileobj = None 459 self.fileobj = None
455 dump = pickle.dumps(self) 460 dump = pickle.dumps(self)
456 self.fileobj = fileobj 461 self.fileobj = fileobj
457 return dump 462 return dump
458 463
459 def isempty(self): 464 def isempty(self):
460 """Returns True if the object doesn't contain any translation units.""" 465 """Returns True if the object doesn't contain any translation units."""
461 466
462 if len(self.units) == 0: 467 if len(self.units) == 0:
463 return True 468 return True
464 for unit in self.units: 469 for unit in self.units:
465 if not (unit.isblank() or unit.isheader()): 470 if not (unit.isblank() or unit.isheader()):
466 return False 471 return False
467 return True 472 return True
468 473
469 def _assignname(self): 474 def _assignname(self):
470 """Tries to work out what the name of the filesystem file is and 475 """Tries to work out what the name of the filesystem file is and
471 assigns it to .filename.""" 476 assigns it to .filename."""
472 fileobj = getattr(self, "fileobj", None) 477 fileobj = getattr(self, "fileobj", None)
473 if fileobj: 478 if fileobj:
474 filename = getattr(fileobj, "name", getattr(fileobj, "filename", Non e)) 479 filename = getattr(fileobj, "name", getattr(fileobj, "filename", Non e))
475 if filename: 480 if filename:
476 self.filename = filename 481 self.filename = filename
477 482
478 def parsestring(cls, storestring): 483 def parsestring(cls, storestring):
479 """Converts the string representation back to an object.""" 484 """Converts the string representation back to an object."""
480 newstore = cls() 485 newstore = cls()
481 if storestring: 486 if storestring:
482 newstore.parse(storestring) 487 newstore.parse(storestring)
483 return newstore 488 return newstore
484 parsestring = classmethod(parsestring) 489 parsestring = classmethod(parsestring)
485 490
486 def parse(self, data): 491 def parse(self, data):
487 """parser to process the given source string""" 492 """parser to process the given source string"""
488 self.units = pickle.loads(data).units 493 self.units = pickle.loads(data).units
489 494
490 def savefile(self, storefile): 495 def savefile(self, storefile):
491 """Writes the string representation to the given file (or filename).""" 496 """Writes the string representation to the given file (or filename)."""
492 if isinstance(storefile, basestring): 497 if isinstance(storefile, basestring):
493 storefile = open(storefile, "w") 498 storefile = open(storefile, "w")
494 self.fileobj = storefile 499 self.fileobj = storefile
495 self._assignname() 500 self._assignname()
496 storestring = str(self) 501 storestring = str(self)
497 storefile.write(storestring) 502 storefile.write(storestring)
498 storefile.close() 503 storefile.close()
499 504
500 def save(self): 505 def save(self):
501 """Save to the file that data was originally read from, if available.""" 506 """Save to the file that data was originally read from, if available."""
502 fileobj = getattr(self, "fileobj", None) 507 fileobj = getattr(self, "fileobj", None)
503 if not fileobj: 508 if not fileobj:
504 filename = getattr(self, "filename", None) 509 filename = getattr(self, "filename", None)
505 if filename: 510 if filename:
506 fileobj = file(filename, "w") 511 fileobj = file(filename, "w")
507 else: 512 else:
508 fileobj.close() 513 fileobj.close()
509 filename = getattr(fileobj, "name", getattr(fileobj, "filename", Non e)) 514 filename = getattr(fileobj, "name", getattr(fileobj, "filename", Non e))
510 if not filename: 515 if not filename:
511 raise ValueError("No file or filename to save to") 516 raise ValueError("No file or filename to save to")
512 fileobj = fileobj.__class__(filename, "w") 517 fileobj = fileobj.__class__(filename, "w")
513 self.savefile(fileobj) 518 self.savefile(fileobj)
514 519
515 def parsefile(cls, storefile): 520 def parsefile(cls, storefile):
516 """Reads the given file (or opens the given filename) and parses back to an object.""" 521 """Reads the given file (or opens the given filename) and parses back to an object."""
517 522
518 if isinstance(storefile, basestring): 523 if isinstance(storefile, basestring):
519 storefile = open(storefile, "r") 524 storefile = open(storefile, "r")
520 mode = getattr(storefile, "mode", "r") 525 mode = getattr(storefile, "mode", "r")
521 #For some reason GzipFile returns 1, so we have to test for that here 526 #For some reason GzipFile returns 1, so we have to test for that here
522 if mode == 1 or "r" in mode: 527 if mode == 1 or "r" in mode:
523 storestring = storefile.read() 528 storestring = storefile.read()
524 storefile.close() 529 storefile.close()
525 else: 530 else:
526 storestring = "" 531 storestring = ""
527 newstore = cls.parsestring(storestring) 532 newstore = cls.parsestring(storestring)
528 newstore.fileobj = storefile 533 newstore.fileobj = storefile
529 newstore._assignname() 534 newstore._assignname()
530 return newstore 535 return newstore
531 parsefile = classmethod(parsefile) 536 parsefile = classmethod(parsefile)
532 537
LEFTRIGHT

Powered by Google App Engine
This is Rietveld r159