1

Normally, you process a file line by line in Python using a loop like:

import sys
for s in sys.stdin:
    # do something with the line in s

or

import sys
while True:
    line = sys,stdin.readline()
    if len(line) == 0: break
    # process input line

Of course, you can also use raw_input() in soemthing like this:

try:
    while True:
        s = raw_input()
        # process input line
except EOFError:
    # there's EOF.

Of course in all these cases, if there's no input ready to be read, the underlying read() operation suspends waiting for I/O.

What I want to do is see if there is input pending without suspending, so I can read until input is exhausted and then go do something else. That is, I'd like to be able to do something like

while "there is input pending":
    #get the input

but when no more input is pending, break the loop.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
  • What platform is the code supposed to run on? – Sven Marnach Jun 13 '12 at 22:06
  • Exact duplicate: http://stackoverflow.com/questions/4936594/how-can-you-tell-if-a-python-program-has-anything-to-read-from-stdin – Pavel Strakhov Jun 13 '12 at 22:07
  • I'd rather find something that's platform independent, that's why I didn't specify. – Charlie Martin Jun 13 '12 at 22:16
  • Hm. The question is similar to the linked question, which then links *another* question, which leads to a fairly atrocious 20-odd lines of code using `Queue.nowait()` and a separate thread. Is there really no simpler way to just look? – Charlie Martin Jun 13 '12 at 22:22
  • @CharlieMartin: If you want to support basically all operating systems except for Windows, there are several ways. If you also want to support Windows, you have to use threads. – Sven Marnach Jun 13 '12 at 22:23

2 Answers2

1

If you are using some variant of Unix, and your standard input is a pipe and not a file, you can use the select module to check to see whether there is waiting input. At a minimum, the code might look like:

import select

rlist, wlist, elist = select.select([sys.stdin], [], [])
if rlist:
    s = raw_input()
else:
    pass # no input ready right now
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • well, I'd like to be independent of the platform, and the input might well be a file or /dev/tty. – Charlie Martin Jun 13 '12 at 22:19
  • @CharlieMartin: On Unix, you can actually `select()` on any file descriptor., but the semantics for files will be slightly different than for pipes. Anyway, this is not platform-indepedent. – Sven Marnach Jun 13 '12 at 22:22
1

Okay, here's something that works well on UNIX:

import sys
import select
import tty
import termios


def isData():
    return select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], [])

old_settings = termios.tcgetattr(sys.stdin)
try:
    tty.setcbreak(sys.stdin.fileno())

    i = 0
    while 1:
        print i
        i += 1

        if isData():
            c = sys.stdin.read(1)
            if c == '\x1b':         # x1b is ESC
                break

finally:
    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)

I'll modify/extend this answer when I have a chance to make a somewhat better test program. I'm (so far) unclear on how well tty and termios work on Windows.

Update: Grmph. This depends on select. There are reasons I don't like Windows.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263