raw_input() and sys.stdin misbehaves on CTRL-C
exception, python, raw-input
Solution
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 (i.e. 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).
Problem
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' ```