classification
Title: WindowsConsoleIO misbehavior when Ctrl+C is ignored
Type: behavior Stage: patch review
Components: IO, Library (Lib), Windows Versions: Python 3.9, Python 3.8, Python 3.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: ZackerySpytz, eryksun, paul.moore, steve.dower, tim.golden, valer, zach.ware
Priority: normal Keywords: patch

Created on 2016-09-15 08:10 by eryksun, last changed 2020-01-13 20:16 by eryksun.

Pull Requests
URL Status Linked Edit
PR 8344 closed valer, 2018-07-20 05:06
PR 17976 open ZackerySpytz, 2020-01-13 06:54
Messages (4)
msg276530 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2016-09-15 08:10
_PyOS_WindowsConsoleReadline should continue to read when interrupted by Ctrl+C if SIGINT is ignored or the handler doesn't raise an exception. Currently it breaks out of the read loop, which looks like an EOF:

    >>> import signal
    >>> signal.signal(signal.SIGINT, signal.SIG_IGN)
    <built-in function default_int_handler>
    >>> input()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    EOFError 

Also, in this case Ctrl+C quits the REPL. 

Similarly sys.stdin.buffer.raw should retry a read. Instead a read(1) returns an empty string and readall() raises an exception:

    >>> sys.stdin.buffer.raw.read(1)
    b''

    >>> sys.stdin.buffer.raw.read()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    OSError: [WinError 87] The parameter is incorrect
msg321979 - (view) Author: Valeriya Sinevich (valer) * Date: 2018-07-20 05:15
I posted a PR but the problem with it is that all the input before the ignored Ctrl+C is lost.
msg322003 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2018-07-20 12:44
> all the input before the ignored Ctrl+C is lost

The console host process doesn't know that Python is ignoring Ctrl+C, so it cancels the read and flushes the input buffer. For now, we have to accept this as a limitation of relying on the high-level console API (i.e. ReadConsoleW with the default settings), which implements command-line editing, aliases and history completely in the console host process. Restarting the read with a flushed input buffer is better than raising EOFError or exiting the REPL.

In the future, Python's console readline implementation could hook deeper into the operation by temporarily disabling the console's ENABLE_PROCESSED_INPUT mode and using the pInputControl parameter to handle ^C and ^H (backspace). This would be fairly involved but still an imperfect solution because ^C will replace whichever character is under the cursor (fine if the cursor is at the end of the line, but otherwise pretty clunky). The only way to have complete control is to use the low-level ReadConsoleInput function. pyreadline implements this via ctypes.
msg359933 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2020-01-13 20:16
On second thought, I think the fact that the console leaves the previously entered text on the line is ugly and confusing. The text isn't in the input buffer, so it won't be read. Yet there's no way for the user to even clear it -- not by escape or backspace. I think the user is better served if we settle for less. 

We can try to write a CRLF to the input buffer via WriteConsoleInputW and then continue. The next read will return immediately, and we'll drop out of the loop, retaining however much was read prior to the canceled read. The console's cooked read will take care of advancing the cursor to the next line for us. If WriteConsoleInputW fails (e.g. the file is "CON", opened with only generic-read access), we can fall back on directly writing "\r\n" to the buffer instead of continuing. However this won't advance the cursor to the next line.

I think we should also merge in the CancelSynchronousIo abort case, i.e. where n_read is still the initial value of (DWORD)-1.
History
Date User Action Args
2020-01-13 20:16:51eryksunsetmessages: + msg359933
2020-01-13 07:05:36ZackerySpytzsetnosy: + ZackerySpytz

versions: + Python 3.8, Python 3.9, - Python 3.6
2020-01-13 06:54:51ZackerySpytzsetpull_requests: + pull_request17383
2018-07-20 12:44:22eryksunsetmessages: + msg322003
2018-07-20 05:15:13valersetnosy: + valer
messages: + msg321979
2018-07-20 05:06:52valersetkeywords: + patch
stage: test needed -> patch review
pull_requests: + pull_request7878
2016-09-15 08:10:25eryksuncreate