PyXR

c:\python24\lib \ multifile.py



0001 """A readline()-style interface to the parts of a multipart message.
0002 
0003 The MultiFile class makes each part of a multipart message "feel" like
0004 an ordinary file, as long as you use fp.readline().  Allows recursive
0005 use, for nested multipart messages.  Probably best used together
0006 with module mimetools.
0007 
0008 Suggested use:
0009 
0010 real_fp = open(...)
0011 fp = MultiFile(real_fp)
0012 
0013 "read some lines from fp"
0014 fp.push(separator)
0015 while 1:
0016         "read lines from fp until it returns an empty string" (A)
0017         if not fp.next(): break
0018 fp.pop()
0019 "read remaining lines from fp until it returns an empty string"
0020 
0021 The latter sequence may be used recursively at (A).
0022 It is also allowed to use multiple push()...pop() sequences.
0023 
0024 If seekable is given as 0, the class code will not do the bookkeeping
0025 it normally attempts in order to make seeks relative to the beginning of the
0026 current file part.  This may be useful when using MultiFile with a non-
0027 seekable stream object.
0028 """
0029 
0030 __all__ = ["MultiFile","Error"]
0031 
0032 class Error(Exception):
0033     pass
0034 
0035 class MultiFile:
0036 
0037     seekable = 0
0038 
0039     def __init__(self, fp, seekable=1):
0040         self.fp = fp
0041         self.stack = []
0042         self.level = 0
0043         self.last = 0
0044         if seekable:
0045             self.seekable = 1
0046             self.start = self.fp.tell()
0047             self.posstack = []
0048 
0049     def tell(self):
0050         if self.level > 0:
0051             return self.lastpos
0052         return self.fp.tell() - self.start
0053 
0054     def seek(self, pos, whence=0):
0055         here = self.tell()
0056         if whence:
0057             if whence == 1:
0058                 pos = pos + here
0059             elif whence == 2:
0060                 if self.level > 0:
0061                     pos = pos + self.lastpos
0062                 else:
0063                     raise Error, "can't use whence=2 yet"
0064         if not 0 <= pos <= here or \
0065                         self.level > 0 and pos > self.lastpos:
0066             raise Error, 'bad MultiFile.seek() call'
0067         self.fp.seek(pos + self.start)
0068         self.level = 0
0069         self.last = 0
0070 
0071     def readline(self):
0072         if self.level > 0:
0073             return ''
0074         line = self.fp.readline()
0075         # Real EOF?
0076         if not line:
0077             self.level = len(self.stack)
0078             self.last = (self.level > 0)
0079             if self.last:
0080                 raise Error, 'sudden EOF in MultiFile.readline()'
0081             return ''
0082         assert self.level == 0
0083         # Fast check to see if this is just data
0084         if self.is_data(line):
0085             return line
0086         else:
0087             # Ignore trailing whitespace on marker lines
0088             marker = line.rstrip()
0089         # No?  OK, try to match a boundary.
0090         # Return the line (unstripped) if we don't.
0091         for i, sep in enumerate(reversed(self.stack)):
0092             if marker == self.section_divider(sep):
0093                 self.last = 0
0094                 break
0095             elif marker == self.end_marker(sep):
0096                 self.last = 1
0097                 break
0098         else:
0099             return line
0100         # We only get here if we see a section divider or EOM line
0101         if self.seekable:
0102             self.lastpos = self.tell() - len(line)
0103         self.level = i+1
0104         if self.level > 1:
0105             raise Error,'Missing endmarker in MultiFile.readline()'
0106         return ''
0107 
0108     def readlines(self):
0109         list = []
0110         while 1:
0111             line = self.readline()
0112             if not line: break
0113             list.append(line)
0114         return list
0115 
0116     def read(self): # Note: no size argument -- read until EOF only!
0117         return ''.join(self.readlines())
0118 
0119     def next(self):
0120         while self.readline(): pass
0121         if self.level > 1 or self.last:
0122             return 0
0123         self.level = 0
0124         self.last = 0
0125         if self.seekable:
0126             self.start = self.fp.tell()
0127         return 1
0128 
0129     def push(self, sep):
0130         if self.level > 0:
0131             raise Error, 'bad MultiFile.push() call'
0132         self.stack.append(sep)
0133         if self.seekable:
0134             self.posstack.append(self.start)
0135             self.start = self.fp.tell()
0136 
0137     def pop(self):
0138         if self.stack == []:
0139             raise Error, 'bad MultiFile.pop() call'
0140         if self.level <= 1:
0141             self.last = 0
0142         else:
0143             abslastpos = self.lastpos + self.start
0144         self.level = max(0, self.level - 1)
0145         self.stack.pop()
0146         if self.seekable:
0147             self.start = self.posstack.pop()
0148             if self.level > 0:
0149                 self.lastpos = abslastpos - self.start
0150 
0151     def is_data(self, line):
0152         return line[:2] != '--'
0153 
0154     def section_divider(self, str):
0155         return "--" + str
0156 
0157     def end_marker(self, str):
0158         return "--" + str + "--"
0159 

Generated by PyXR 0.9.4
SourceForge.net Logo