# Python Concepts/Console Input
## Lesson

* In the context of this lesson, the word "console" implies the visual display which you see in front
* of you when you sit at your desk, and also the attached keyboard. The keyboard provides "console input"
* while the visual display provides console output.
* Other input devices such as mice, joysticks, game controllers and touch screens are not covered in this lesson.
* Python reserves one file object for console input, standard input:
* >>> import io
* >>> import sys
* >>> sys.stdin
* <_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>
* >>> isinstance(sys.stdin, io.TextIOWrapper)
* True
* The above file object is always open for reading in text mode.
* It has its associated file descriptor:
* >>> sys.stdin.fileno
* 0
* More information about sys.stdin:
* >>> sys.stdin.isatty
* True # When input is keyboard.
* >>> sys.stdin.closed
* False
* >>> sys.stdin.readable
* True
* >>> sys.stdin.seekable
* True
* >>> sys.stdin.tell
* 5296
* >>> sys.stdin.encoding
* 'UTF-8'
* >>> os.device_encoding(0)
* 'UTF-8'
* >>> os.isatty(0)
* True
* >>> os.ttyname(0)
* '/dev/ttys001'
* >>> os.get_terminal_size(0)
* os.terminal_size(columns=122, lines=47)
* >>> >>> os.get_terminal_size(0)
* os.terminal_size(columns=115, lines=42) # You can change the size of your terminal window.
* >>> os.stat(0)
* os.stat_result(st_mode=8592, st_ino=697, st_dev=202182376, st_nlink=1, st_uid=501, st_gid=4, st_size=0, ....)
* Because sys.stdin is a file object, it responds to methods applicable to file objects. However it is recommended
* that you do not attempt such methods or operations as these on sys.stdin: sys.stdin.close, sys.stdin.flush, sys.stdin.detach, os.close(0)

## Reading from stdin

* File descriptor 0 usually means standard input.
* When your python script reads from standard input, this usually means that it is reading data which you are typing on your keyboard.
* Because file descriptor 0 reads text, the new line character at the end of each line becomes significant.
* >>> a = sys.stdin.readline # The readline method waits until you type '\n'.
* The quick, brown fox ...
* >>> a
* 'The quick, brown fox ...\n'
* >>> a = sys.stdin.read(5)
* ABCD EFGH # You entered 10 characters.
* >>> a
* 'ABCD ' # a contains 5 characters. The remaining characters are waiting to be read.
* >>> b = sys.stdin.read(5)
* >>> b
* 'EFGH\n' # All input has been read.
* >>> a = sys.stdin.read(5) # Read 5 characters from stdin.
* ABCD EFGH IJKL # You entered 15.
* >>> a
* 'ABCD '
* >>> b = sys.stdin.readline # There are still 10 characters waiting to be read.
* >>> b
* 'EFGH IJKL\n' # b contains all remaining characters.
* In the real world your python script will probably read from stdin after supplying a prompt for your response.
* import sys
* import os
* print ('Enter date-of-birth [mm/dd/yyyy]: ', end='', flush=True)
* a = sys.stdin.readline
* print ('You entered', a, end='') # str a has '\n' at end.
* $ python3.6 t4.py
* Enter date-of-birth [mm/dd/yyyy]: 12/31/1967
* You entered 12/31/1967
* python's built-in function input(....) simplifies prompting and reading from stdin:
* import sys
* import readline
* s = input ('Enter date-of-birth [mm/dd/yyyy]: ')
* print ('You entered', s)
* $ python3.6 t4.py
* Enter date-of-birth [mm/dd/yyyy]: 12/31/1967
* You entered 12/31/1967
* If the readline module was loaded, then input will use it to provide elaborate line editing and history features
* similar to command line editing with emacs.

## Detecting timeout on stdin

* The python script above sends a prompt to stdout and expects a response on stdin. What should happen if the person at the keyboard
* is called away and no response is forthcoming?
* You decide to terminate the session after 30 seconds of inactivity. Here is one way to do it:
* $ cat t6.py
* import signal
* import sys
* import readline
* def handler(signum, frame):
* print ('\nOperation timed out.')
* exit (99)
* # Set the signal handler and a 30-second alarm
* signal.signal(signal.SIGALRM, handler)
* signal.alarm(30)
* status = 0
* try :
* s = input ('Enter date-of-birth [mm/dd/yyyy]: ')
* except KeyboardInterrupt :
* print ('\nKeyboardInterrupt detected.' )
* status = 98
* except SystemExit :
* print ('SystemExit detected.' )
* status = 97
* except :
* print ('\nException detected: ', str(sys.exc_info[0]) )
* status = 96
* else :
* print ('You entered', s)
* signal.alarm(0) # Disable the alarm.
* exit (status)
* $ python3.6 t6.py ; echo $?
* Enter date-of-birth [mm/dd/yyyy]: 12/31/1999 # Normal input.
* You entered 12/31/1999
* 0 # Normal exit 0.
* $ python3.6 t6.py ; echo $?
* Enter date-of-birth [mm/dd/yyyy]: # No input.
* Operation timed out.
* SystemExit detected.
* 97 # Exit with error status 97.
* $ python3.6 t6.py ; echo $?
* Enter date-of-birth [mm/dd/yyyy]: # Entered ^C.
* KeyboardInterrupt detected.
* 98 # Exit with error status 98.

## Input stream redirected

* Usually stdin is connected to the keyboard so that a command like sys.stdin.read
* reads data from the keyboard until end-of-line is detected.
* However, input can come from a pipe.
* $ cat t4.py
* import sys
* import readline
* print ('sys.stdin.isatty:', sys.stdin.isatty)
* s = input ('Enter date-of-birth [mm/dd/yyyy]: ')
* if not sys.stdin.isatty :
* print
* print ('You entered', s)
* $ python3.6 t4.py
* sys.stdin.isatty: True # This is interactive session.
* Enter date-of-birth [mm/dd/yyyy]: 12/31/1967 # Input from keyboard.
* You entered 12/31/1967
* $ echo '12/31/1988' | python3.6 t4.py # Input from a pipe.
* sys.stdin.isatty: False # Not interactive.
* Enter date-of-birth [mm/dd/yyyy]: # No input from keyboard.
* You entered 12/31/1988

## Console input from terminal

* The terminal can provide console input. On Unix the device name of the terminal is available and it behaves like a file:
* $ cat t5.py
* import os
* print ('Name of my terminal is:', os.ttyname(0))
* f = open(os.ttyname(0)) # for reading
* print ('File object opened for reading from my terminal is:', f)
* print ('Enter name of your favorite pet: ', end='',flush=True)
* pet = f.read
* f.close
* print ('Input from terminal was:', pet, end='')
* print ('len(pet) =', len(pet))
* $ python3.6 t5.py
* Name of my terminal is: /dev/ttys003
* File object opened for reading from my terminal is: <_io.TextIOWrapper name='/dev/ttys003' mode='r' encoding='UTF-8'>
* Enter name of your favorite pet: Fido # Enter 'Fido\n' then ^D for end-of-file.
* Input from terminal was: Fido
* len(pet) = 5 # String pet contains 5 characters (including the new-line) and without the ^D.

## Assignments

* How do you know if stdin contains data waiting to be read?
* If stdin contains unwanted data, how do you clear the buffer?

## Further Reading or Review

* Previous Lesson: Console Output
* This Lesson: Console Input
* Next Lesson: Files
* Course Home Page