Python Forum
detect if sys.stdin is ... - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: detect if sys.stdin is ... (/thread-10606.html)



detect if sys.stdin is ... - Skaperen - May-28-2018

how to detect if sys.stdin is the controlling tty (as opposed to a pipe, or a socket, or a file, or "/dev/null", or some other tty the script was invoked to read from)? is there an equivalent in windows?


RE: detect if sys.stdin is ... - ljmetzger - May-30-2018

Results depend on the 'stdin_encoding' Codec values which are probably dependent on location (e.g. United States) and/or encoding directive (line 2 - line after Shebang). A one size fits all algorithm can probably be obtained after testing various locations and default encodings. I was able to detect the following on Python 3.6.5 using Windows 10 in the United States 'stdin' as:
a. Keyboard
b. Null Device
c. Redirected file (but not the file name)
d. Pipe

Function get_stdin_encoding() seems to work OK. Other functions are for reference purposes and seem to fail when 'stdin' is the NULL DEVICE.
# Tested using Python 3.6.5 on Windows 10
#
# Reference: https://python-forum.io/Thread-detect-if-sys-stdin-is
# Reference: https://stackoverflow.com/questions/323829/how-to-find-out-if-there-is-data-to-be-read-from-stdin-on-windows-in-python
# Reference: https://stackoverflow.com/questions/13442574/how-do-i-determine-if-sys-stdin-is-redirected-from-a-file-vs-piped-from-another

# Reference: https://docs.python.org/3/library/os.html
# NOTE:  os.ttyname(sys.stdin.fileno()) is NOT available on Windows

# Reference: https://docs.python.org/3/library/codecs.html  (Codec values in section 7.2.3 Standard Encodings)

##################################
##################################
#NOTE: The only method that seems to work on Windows is get_stdin_encoding().
#      The other methods FAIL when stdin is the NULL DEVICE
##################################
##################################

import os
import stat
import sys

def is_stdin_keyboard():
    #NOTE: This returns INCORRECT results when 'stdin' is the NULL DEVICE
    return os.isatty( sys.stdin.fileno())

def get_stdin_from_stat():
    #NOTE: this function is NOT USED - incorporated into get_stdin_encoding()
    mode = os.fstat(0).st_mode
    if stat.S_ISFIFO(mode):
        return 'Pipe'
    elif stat.S_ISREG(mode):
        return 'Redirected'
    else:
        return 'Keyboard'

def get_stdin_encoding():
    # NOTE: Results depend on the 'stdin_encoding' values which are probably dependent 
    # on location (e.g. United States) and/or encoding directive (line 2 - line after Shebang).
    # See https://docs.python.org/3/library/codecs.html  (Codec values in section 7.2.3 Standard Encodings)
    stdin_encoding = getattr(sys, 'stdin').encoding
    if stdin_encoding == 'cp437':
        stdin_source = 'Null Device'
    elif stdin_encoding == 'cp1252':
        #return 'file or pipe'
        mode = os.fstat(0).st_mode
        if stat.S_ISFIFO(mode):
            stdin_source =  'Pipe'
        else:
            stdin_source =  'Redirected'
    elif stdin_encoding == 'utf-8':
        stdin_source =  'Keyboard'
    else:
        stdin_source =  'Encoding=' + stdin_encoding
    return stdin_source + " (" + stdin_encoding + ")"
        
print("get_stdin_encoding() results: Stdin device type is: {}.".format(get_stdin_encoding()))    
        
if is_stdin_keyboard():
    print("is_stdin_keyboard()  results: Stdin is the Keyboard")
else:
    print("is_stdin_keyboard()  results: Stdin is NOT the Keyboard")

print("sys.stdin.isatty()   results: {}".format(sys.stdin.isatty()))
The following Windows cmd.exe script was used to test the code (e.g. file abc.bat):
NOTE: The follow is NOT Python code but a Windows .bat file
@echo off

echo Testing stdin           >ScratchStdOut.txt 
echo.                       >>ScratchStdOut.txt 

echo ######################   >>ScratchStdOut.txt 
echo Testing 'Keyboard' stdin >>ScratchStdOut.txt 
python redirectStdin-001.py   >>ScratchStdOut.txt 


echo ######################      >>ScratchStdOut.txt 
echo Testing 'Null Device' stdin >>ScratchStdOut.txt 
python redirectStdin-001.py      >>ScratchStdOut.txt  <nul


echo ###################### >>ScratchStdOut.txt 
rem NOTE: Windows prevents this from running if the redirected 'stdin' file DOES NOT EXIST
rem This creates and deletes file 'Scratch00.txt'
echo Testing 'Redirected' File stdin >>ScratchStdOut.txt 
echo Hello >Scratch00.txt
python redirectStdin-001.py >>ScratchStdOut.txt  <Scratch00.txt 
if exist Scratch00.txt del Scratch00.txt

echo ###################### >>ScratchStdOut.txt 
echo Testing 'Pipe' stdin   >>ScratchStdOut.txt 
echo hello | python redirectStdin-001.py >>ScratchStdOut.txt  


echo ###################### >>ScratchStdOut.txt 

type ScratchStdOut.txt 
pause
exit
Results using the .bat file:
Output:
Testing stdin ###################### Testing 'Keyboard' stdin get_stdin_encoding() results: Stdin device type is: Keyboard (utf-8). is_stdin_keyboard() results: Stdin is the Keyboard sys.stdin.isatty() results: True ###################### Testing 'Null Device' stdin get_stdin_encoding() results: Stdin device type is: Null Device (cp437). is_stdin_keyboard() results: Stdin is the Keyboard sys.stdin.isatty() results: True ###################### Testing 'Redirected' File stdin get_stdin_encoding() results: Stdin device type is: Redirected (cp1252). is_stdin_keyboard() results: Stdin is NOT the Keyboard sys.stdin.isatty() results: False ###################### Testing 'Pipe' stdin get_stdin_encoding() results: Stdin device type is: Pipe (cp1252). is_stdin_keyboard() results: Stdin is NOT the Keyboard sys.stdin.isatty() results: False ######################
Lewis

Added .zip file attachment containing:
a. RedirectStdin-001.bat
b. RedirectStdin-001.py


RE: detect if sys.stdin is ... - Skaperen - May-30-2018

i have a script that modifies its stdin input and outputs it. the nature of the script has no value to typing in directly from the terminal where it was started. what i want to do is detect that it was run with no input and output a message and quit.


RE: detect if sys.stdin is ... - ljmetzger - May-30-2018

The following was tested on Python 3.6.5 using Windows 10 in the United States:
# Tested using Python 3.6.5 on Windows 10 in the United States
#
# Reference: https://python-forum.io/Thread-detect-if-sys-stdin-is

import sys

if sys.stdin.isatty():
    print ("Do Nothing - stdin is either 'tty' or 'null device'.")
else:
    print ("Process 'stdin' from 'pipe' or from 'file redirection'.")
    for i, dataline in enumerate(sys.stdin, start=1):
        print(i, dataline)
The following Windows cmd.exe script was used to test the code (e.g. file abc.bat):
NOTE: The follow is NOT Python code but a Windows .bat file
@echo off

echo Testing stdin           >ScratchStdOut.txt 
echo.                       >>ScratchStdOut.txt 

echo ######################   >>ScratchStdOut.txt 
echo Testing 'Keyboard' stdin >>ScratchStdOut.txt 
python redirectStdin-002.py   >>ScratchStdOut.txt 


echo ######################      >>ScratchStdOut.txt 
echo Testing 'Null Device' stdin >>ScratchStdOut.txt 
python redirectStdin-002.py      >>ScratchStdOut.txt  <nul


echo ###################### >>ScratchStdOut.txt 
rem NOTE: Windows prevents this from running if the redirected 'stdin' file DOES NOT EXIST
rem This creates and deletes file 'Scratch00.txt'
echo Testing 'Redirected' File stdin >>ScratchStdOut.txt 
echo Hello >Scratch00.txt
echo World >>Scratch00.txt
python redirectStdin-002.py >>ScratchStdOut.txt  <Scratch00.txt 
if exist Scratch00.txt del Scratch00.txt

echo ###################### >>ScratchStdOut.txt 
echo Testing 'Pipe' stdin   >>ScratchStdOut.txt 
echo Pipe stdin text - Hello World | python redirectStdin-002.py >>ScratchStdOut.txt  


echo ###################### >>ScratchStdOut.txt 

type ScratchStdOut.txt 
pause
exit
Results using the .bat file:
Output:
Testing stdin ###################### Testing 'Keyboard' stdin Do Nothing - stdin is either 'tty' or 'null device'. ###################### Testing 'Null Device' stdin Do Nothing - stdin is either 'tty' or 'null device'. ###################### Testing 'Redirected' File stdin Process 'stdin' from 'pipe' or from 'file redirection'. 1 Hello 2 World ###################### Testing 'Pipe' stdin Process 'stdin' from 'pipe' or from 'file redirection'. 1 Pipe stdin text - Hello World ######################
See the .zip file attachment containing:
a. RedirectStdin-002.bat
b. RedirectStdin-002.py

Lewis


RE: detect if sys.stdin is ... - Skaperen - May-30-2018

but if the user runs this program to read from some other tty (that may be a controlling tty for other processes) besides his own (e.g is not this process' controlling tty) then i want it to treat that as valid input. so the test needs to be "is my stdin the same devive as my controlling tty." i don't expect to be able to resolve program < /dev/tty vs. program.