[Tutor] Stdin email question [sys.stdin is unseekable / try StringIO]

Danny Yoo dyoo@hkn.eecs.berkeley.edu
Mon May 19 02:08:00 2003


On Sun, 18 May 2003, Magnus [iso-8859-1] Lyck=E5 wrote:

> At 14:10 2003-05-17 -0400, Daniel Nash wrote:
> >Ok so if I do this first,
> >
> >the_whole_thing =3D sys.stdin.read()
> >
> >then
> >
> >headers =3D rfc822.Message(sys.stdin)
> >
> >No longer works because of the file pointer
> >
> >How can I fix this?
>
> Just put "sys.stdin.seek(0)" between. Then you can place your reads in
> whatever order you like. "seek" will move the current position in a file
> or file-like object. It's like wind/rewind on a VCR. It has a sister
> called "tell" that informs you of the current position.


Hi everyone,


This would work... except that it's 'sys.stdin':  Python itself doesn't
know how to travel in time!

###
>>> import sys
>>> sys.stdin.seek(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
IOError: [Errno 29] Illegal seek
###

More formally, we'd say that sys.stdin is a file-like object that's not
"seekable".  So trying to rewind our standard input to the beginning is a
no-go.  I think this only affects special file-like objects like sys.stdin
and sys.stdout; if it were a regular vanilla file, the seek() would be
applicable.


(The limitation is a technical issue: if sys.stdin were seekable, then
Python would have to memorize everything that came through sys.stdin.  To
do this in the general case would be prohibitively expensive --- even with
gigabytes of memory --- so that's why it doesn't let us seek() stdin.)




> >Ok so if I do this first,
> >the_whole_thing =3D sys.stdin.read()
> >then
> >headers =3D rfc822.Message(sys.stdin)
> >
> >No longer works because of the file pointer
> >
> >How can I fix this?


We know now that sys.stdin is unseekable.  However, there is a a
workaround: one way we can fix this is to use an intermediate file object
that can be seek()ed.  There's a way of disguising a string as a file
through the "StringIO" module:

    http://www.python.org/doc/lib/module-StringIO.html


StringIO's one of those modules that looks really odd the first time we
see it, but it's useful for a case like this:


###
from StringIO import StringIO

the_whole_thing =3D sys.stdin.read()
msg_file =3D StringIO(msg_file)
headers =3D rfc822.Message(msg_file)
###


And now we can safely do a msg_file.seek(0) here to retrieve the original
message body.  Since our 'file-like' object is a string, Python has no
problems seeking through it.



Out of curiosity, though: have you seen the 'fp' attribute that's in our
message object?  rfc822.Message doesn't just give us the headers: the
message body does live in there too.  The bottom of:

    http://www.python.org/doc/lib/message-objects.html

briefly mentions it.  So we might be able to do something like this:


###
from StringIO import StringIO

the_whole_thing =3D sys.stdin.read()
msg_file =3D StringIO(msg_file)
msg =3D rfc822.Message(msg_file)

print "The body of our message is:", msg.fp.read()
print "And here are our headers:", msg.headers
###



Hope this clears things up!  If you have more questions, please feel free
to ask.