Interactive scripts (back on topic for once) [was Re: The "loop and a half"]

eryk sun eryksun at gmail.com
Fri Oct 6 11:01:04 EDT 2017


On Fri, Oct 6, 2017 at 1:31 PM, Thomas Jollans <tjol at tjol.eu> wrote:
> On 2017-10-06 12:33, Ben Bacarisse wrote:
>
>> A general solution to the (rather odd) complaint about silent waiting
>> should really check any input fileno to see if a prompt is needed.  You
>> could argue, though, that anyone who's re-arranged a program's input so
>> that some non-zero input fileno is attached to a terminal won't need the
>> prompt!
>
> stdin is ALWAYS fileno 0, whether the input is attached to a tty or not.
> The only situation where sys.stdin.fileno() != 0 is when sys.stdin has
> been reassigned from within python.
>
> $ python -c 'import sys; print(sys.stdin.fileno())' < /dev/zero
> 0
>
> This should be true for all platforms, or at least all platforms python
> supports.

POSIX defines STDIN_FILENO as 0, and the Windows C runtime reserves FD
0 to map to the native StandardInput handle. But as I noted in a
previous message, on Windows isatty(0) returns true if a process isn't
executed with a valid StandardInput. In this case sys.stdin will be
None, so call sys.stdin.fileno() and handle the exception if that
fails.

If you really need to know that stdin is interactive for something
critical, then isatty() is the wrong function on Windows. You need to
check for a console, which is most easily done by using ctypes to call
GetConsoleMode. For example:

    import os

    if os.name == 'posix':
        from os import isatty

    elif os.name == 'nt':
        import ctypes
        import msvcrt
        kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

        def isatty(fd):
            """Return True if the fd is connected to a console."""
            try:
                handle = ctypes.c_void_p(msvcrt.get_osfhandle(fd))
            except (OSError, IOError):
                return False
            mode = ctypes.c_ulong()
            success = kernel32.GetConsoleMode(handle, ctypes.byref(mode))
            return bool(success)



More information about the Python-list mailing list