Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conflict between sys.stdin and input() - EOFError: EOF when reading a line

I can't get the following script to work without throwing an EOFError exception:

#!/usr/bin/env python3

import json
import sys

# usage:
# echo '[{"testname": "testval"}]' | python3 test.py

myjson = json.load(sys.stdin)
print(json.dumps(myjson))

answer = input("> ")  # BUG: EOFError: EOF when reading a line
print(answer)

I've read this question which seems to be related: Python STDIN User Input Issue

I think that tells me I need to clear the stdin buffer ? But I'm not sure how because print(sys.stdin.readline()) just outputs a newline and the EOFError is still there.

I also tried using the sys.stdin.flush() method (found in this question: Usage of sys.stdout.flush() method) although I still don't understand what it does because I couldn't find it in the official documentation (3.6), the closest I found was this but it doesn't mention flush: https://docs.python.org/3/library/sys.html

Please bear in mind that I'm not a programmer nor do I have a CS education or background. I just write scripts to automate parts of my, otherwise non-technical, work. So if you know any good beginner ressource on how stdin/stdout works in the shell with Python please do tell.

like image 543
rmercier Avatar asked Sep 09 '17 10:09

rmercier


1 Answers

By piping input, Python is opening sys.stdin as a FIFO. Otherwise, Python will open sys.stdin to /dev/tty or equivalent.

You can verify this with:

import os,sys,stat
print("isatty():", sys.stdin.isatty())
print("isfifo():", stat.S_ISFIFO(os.fstat(0).st_mode))

Run this twice, once piping in data, once not.

I get:

$ echo "Test" | ./test2.py
isatty(): False
isfifo(): True

$ ./test2.py
isatty(): True
isfifo(): False

So your EOF occurs because the FIFO sys.stdin is opened to is empty.

You can reopen sys.stdin to /dev/tty, however.

j = json.load(sys.stdin)
print(j)

sys.stdin = open("/dev/tty")

answer = input("> ")
print(answer)

Which would work fine:

$ echo '{"key":"val"}' | python3 ./testjson.py
{'key': 'val'}
> testing
testing
like image 104
jedwards Avatar answered Sep 30 '22 09:09

jedwards