input() and sys.stdin misbehaves on CTRL
I am trying to detect a KeyboardInterrupt exception when CTRL-C is pressed during a raw_input() prompt. Normally the following code works just fine to detect the command:
try:
input = raw_input("Input something: ")
except KeyboardInterrupt:
do_something()
The problem comes when trying to intercept the input from sys.stdin. After adding some code in between raw_input() and sys.stdin, the CTRL-C command now results in two exceptions: EOFError followed by KeyboardInterrupt a line or two later. This is the code used to test:
import sys
import traceback
class StdinReplacement(object):
def __init__(self):
self.stdin = sys.stdin
sys.stdin = self
def readline(self):
input = self.stdin.readline()
# here something could be done with input before returning it
return input
if __name__ == '__main__':
rep = StdinReplacement()
while True:
info = None
try:
try:
input = raw_input("Input something: ")
print input
except:
info = sys.exc_info()
print info
except:
print 'n'
print "0:", traceback.print_traceback(*info)
print "1:", traceback.print_exception(*sys.exc_info())
Which results in the following being printed out:
0:Traceback (most recent call last):
File "stdin_issues.py", line 19, in <module>
input = raw_input("Input something: ")
EOFError: EOF when reading a line
None
1:Traceback (most recent call last):
File "stdin_issues.py", line 23, in <module>
print info
KeyboardInterrupt
Am I missing something obvious? Maybe intercepting the input in a bad way?
Found this fairly old page which seems like the same issue. No solution though: https://mail.python.org/pipermail/python-list/2009-October/555375.html
Some environment details: Python 2.7.3 (64-bit), Windows 7 SP1 (64-bit)
------------------------------------------------------------------------
EDIT: An update to the readline method of StdinReplacement fixed the issue.
def readline(self):
input = self.stdin.readline()
# here something could be done with input before returning it
if len(input) > 0:
return input
else:
return 'n'
It seems like the problem is that your readline
method returns an empty line, thus signaling the end of file:
import sys
class Test(object):
def readline(self):
return ''
sys.stdin = Test()
raw_input('') # EOFError!
However modifying it such that it doesn't return an empty line makes the code work:
import sys
class Test(object):
def readline(self):
return 'n' # or 'a', or whatever
sys.stdin = Test()
raw_input('') # no error
The readline
method should return an empty string only when the file finished. The EOFError
is used to mean exactly this: raw_input
expected the file to contain a line, but the file ended.
This is due to the call to PyFile_GetLine
found at the end of the implementation of raw_input
:
return PyFile_GetLine(fin, -1);
According to the documentation of PyFile_GetLine(PyObject *p, int n)
:
If n
is less than 0
, however, one line is read regardless of length, but EOFError
is raised if the end of the file is reached immediately.
Since it passes -1
as n
the EOFError
is raised when the EOF
is found (ie you return an empty string from readline
).
As far as I can tell the behaviour you see is only possible if you insert the input and also create an interrupt. Pressing only Ctrl+C doesn't generate any EOFError
(at least on linux).