On 2006-02-08, Joel Hedlund <[EMAIL PROTECTED]> wrote: >> sys.stdin.read() will return when ... the >> underyling read() call is aborted by a signal. > > Not "return", really?
Yes, really. On a SIGWINCH, the read() will _either_ return currently buffered data or thrown an IOError exception. You need to handle either one. > Won't it just pass an exception? That seems to be the behavior if there is no buffered data to return. > I thought that was what I was catching with the "except > IOError" part there? I assumed that sys.stdin.read() would > only return a value properly at EOF? That assumption seems to be wrong. sys.stdin.read() also returns w/o an exception if there's buffered data and a SIGWINCH occurs. Whether that is "proper" or not, I don't know, but that's what it does. Hmm, here's what the library reference says about file object's read() method: read([size]) Read at most size bytes from the file (less if the read hits EOF before obtaining size bytes). If the size argument is negative or omitted, read all data until EOF is reached. The bytes are returned as a string object. An empty string is returned when EOF is encountered immediately. (For certain files, like ttys, it makes sense to continue reading after an EOF is hit.) Note that this method may call the underlying C function fread() more than once in an effort to acquire as close to size bytes as possible. Also note that when in non-blocking mode, less data than what was requested may be returned, even if no size parameter was given. There appear to be a couple problems with this description: 1) It says that read() in blocking mode without a size parameter it will read until EOF. This is not what happens when reading a terminal that receives SIGWINCH, so you're right: read() it isn't working as described. 2) It also says that it makes sense to continue to read a tty after you get an EOF. That's not true. Once you get an EOF on a tty, there's no point in reading it any more: you'll continue to get an EOF forever. > It looks to me as if sys.stderr.read() really gets an EOF at > the final linebreak fed into the terminal prior to window size > change, because the final unterminated line shows up on my > shell prompt. Python's read() (which seems to call fread()) didn't get an EOF from fread(), it got an error from fread() because the C read() call that was made by fread() returned an error because it was interrupted by a signal. In Python, EOF is when read() returns '' (the empty string). > Like so: > > $ python winch.py > moo moo > cow cowmoo moo > $ cow cow > > In this example I type moo moo[ENTER]cow cow on my keyboard > and then resize the window. > > Now that EOF has to come from somewhere There was no EOF. read() returned because of the signal, not because of an EOF. > (since there's no > IOError or other exception, or the program wouldn't terminate > nicely with nothing on stderr) and I'd like to point the blame > at the terminal. Or is there something really fishy inside > sys.stdin.read() or signal that puts EOFs into streams? > > But anyway, as long as this behavior only shows up on > interactive operation, the user will likely spot it anyway and > can react to it. So I think this code would be pretty safe to > use. What do you think? > >> Resign the terminal will abort pending I/O operations on >> that terminal. It won't terminal I/O operations pending on >> other devices/files. > > What do you mean by "abort"? I can accept that "aborting" may > lead to raising of IOError (which we can catch and retry), but > not to arbitrary insertion of EOFs into streams (which we > cannot distinguish from the real deal coming from the user). It didn't insert an EOF, it just caused read() to return "prematurely". You should call read() again until it receives a _real_ EOF and returns ''. Take another look at my example: #!/usr/bin/python import signal, os, sys _bTerminalSizeChanged = False def report_terminal_size_change(signum, frame): global _bTerminalSizeChanged _bTerminalSizeChanged = True signal.signal(signal.SIGWINCH, report_terminal_size_change) while True: try: s = sys.stdin.read() if not s: sys.stderr.write("EOF\n") break sys.stdout.write(s) except IOError: sys.stderr.write("IOError\n") if _bTerminalSizeChanged: sys.stderr.write("SIGWINCH\n") _bTerminalSizeChanged = False -- Grant Edwards grante Yow! Yow! It's a hole at all the way to downtown visi.com Burbank! -- http://mail.python.org/mailman/listinfo/python-list