Interactive scripts (back on topic for once) [was Re: The "loop and a half"]
On Fri, Oct 6, 2017 at 9:48 AM, Paul Moore <p.f.moore at gmail.com> wrote:
> On 6 October 2017 at 09:36, Peter J. Holzer <hjp-usenet3 at hjp.at> wrote:
>> On 2017-10-06 08:09, Steve D'Aprano <steve+python at pearwood.info> wrote:
>>> # 1 detect input coming from a pipe.
>>> import sys
>>> import os
>>> from stat import S_ISFIFO
>>> if S_ISFIFO(os.fstat(0).st_mode):
>>> print("Reading from a pipe")
>>> # 2 detect input coming from a regular file.
>>> from stat import S_ISREG
>>> if S_ISREG(os.fstat(0).st_mode):
>>> print("Reading from a file.")
>>> # 3 detect a terminal, hopefully with a human typing at it
>>> if os.isatty(0):
>>> print("Oy noddy, wake up and type something, I'm waiting for you!")
> All of these work on Windows, I just tested. Which surprised me, as I
> thought things like S_ISFIFO were Unix specific. Today I learned...
The fstat implementation for Windows calls GetFileType to look for
FILE_TYPE_CHAR (i.e. S_IFCHR) and FILE_TYPE_PIPE (i.e. S_IFIFO).
The C runtime's isatty() on Windows checks for for a character device,
not a console. If we're using this to test for interactive mode, we'll
get a false positive on Windows if StandardInput is redirected to the
DOS "NUL" device (i.e. NT "\Device\Null") or a COM port (rarely).
As to using fd 0 instead of stdin.fileno(), for a non-console process
(e.g. pythonw.exe), the C runtime doesn't initialize the standard file
descriptors beyond their static definitions, and isatty(0) will return
true even though it's not a valid file descriptor (i.e. the mapped
Windows handle is INVALID_HANDLE_VALUE). We need to rely on the C
stdin FILE stream being invalid, in which case sys.stdin is set to