1 """A readline()-style interface to the parts of a multipart message.
3 The MultiFile class makes each part of a multipart message "feel" like
4 an ordinary file, as long as you use fp.readline(). Allows recursive
5 use, for nested multipart messages. Probably best used together
11 fp = MultiFile(real_fp)
13 "read some lines from fp"
16 "read lines from fp until it returns an empty string" (A)
17 if not fp.next(): break
19 "read remaining lines from fp until it returns an empty string"
21 The latter sequence may be used recursively at (A).
22 It is also allowed to use multiple push()...pop() sequences.
24 If seekable is given as 0, the class code will not do the bookkeeping
25 it normally attempts in order to make seeks relative to the beginning of the
26 current file part. This may be useful when using MultiFile with a non-
27 seekable stream object.
29 from warnings
import warn
30 warn("the multifile module has been deprecated since Python 2.5",
31 DeprecationWarning, stacklevel
=2)
34 __all__
= ["MultiFile","Error"]
36 class Error(Exception):
43 def __init__(self
, fp
, seekable
=1):
50 self
.start
= self
.fp
.tell()
56 return self
.fp
.tell() - self
.start
58 def seek(self
, pos
, whence
=0):
65 pos
= pos
+ self
.lastpos
67 raise Error
, "can't use whence=2 yet"
68 if not 0 <= pos
<= here
or \
69 self
.level
> 0 and pos
> self
.lastpos
:
70 raise Error
, 'bad MultiFile.seek() call'
71 self
.fp
.seek(pos
+ self
.start
)
78 line
= self
.fp
.readline()
81 self
.level
= len(self
.stack
)
82 self
.last
= (self
.level
> 0)
84 raise Error
, 'sudden EOF in MultiFile.readline()'
86 assert self
.level
== 0
87 # Fast check to see if this is just data
88 if self
.is_data(line
):
91 # Ignore trailing whitespace on marker lines
92 marker
= line
.rstrip()
93 # No? OK, try to match a boundary.
94 # Return the line (unstripped) if we don't.
95 for i
, sep
in enumerate(reversed(self
.stack
)):
96 if marker
== self
.section_divider(sep
):
99 elif marker
== self
.end_marker(sep
):
104 # We only get here if we see a section divider or EOM line
106 self
.lastpos
= self
.tell() - len(line
)
109 raise Error
,'Missing endmarker in MultiFile.readline()'
115 line
= self
.readline()
120 def read(self
): # Note: no size argument -- read until EOF only!
121 return ''.join(self
.readlines())
124 while self
.readline(): pass
125 if self
.level
> 1 or self
.last
:
130 self
.start
= self
.fp
.tell()
135 raise Error
, 'bad MultiFile.push() call'
136 self
.stack
.append(sep
)
138 self
.posstack
.append(self
.start
)
139 self
.start
= self
.fp
.tell()
143 raise Error
, 'bad MultiFile.pop() call'
147 abslastpos
= self
.lastpos
+ self
.start
148 self
.level
= max(0, self
.level
- 1)
151 self
.start
= self
.posstack
.pop()
153 self
.lastpos
= abslastpos
- self
.start
155 def is_data(self
, line
):
156 return line
[:2] != '--'
158 def section_divider(self
, str):
161 def end_marker(self
, str):
162 return "--" + str + "--"