I'm trying to unittest
a module that gets individual keypresses from stdin. The key-getting code works perfectly, but writing exactly a character (byte?) to a subprocess' stdin is giving me some issues.
I'm using essentially what was recommended here with modifications according to the docs and other SO answers:
for ch in range(0, 128):
p = sp.Popen(
[py, "-u", TEST_HELP, "getch"],
stdin=sp.PIPE,
stdout=sp.PIPE,
stderr=sp.PIPE,
bufsize=1
)
out, err = p.communicate(input=bytes(chr(ch), "ascii"))
print(out, ",", err)
What I want is for p
to recieve exactly one ASCII character of stdin and then exit. The fact that ch
is sometimes NUL
, EOF
and other control chars is not a problem; it's exactly what I want.
The problem is that this seems to hang doing nothing until I press CTRL - C, and then it exits with a keyboard interrupt. The last line of the stack trace is in selectors.py: fd_event_list = self._poll.poll(timeout)
, which tells me it was waiting for a timeout(?), but I didn't supply the timeout=int
kwarg.
The command I'm using resolves to python3 -u helptest.py getch
, which looks like this and which works properly when I run it myself from the command line.
Here's the relevant part of helptest
:
def getch():
write_and_flush(ord(_ic._Getch()))
(write_and_flush
just runs stdout.write; stdout.flush
)
and _ic._Getch()
is:
def _Getch():
if sys.stdin.isatty():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
else:
return sys.stdin.read(1)
What am I doing wrong in the subprocess
call that breaks this?
Changing the call to:
p = sp.Popen(
[py, TEST_HELP, "getch"],
stdin=sp.PIPE,
stdout=sp.PIPE,
stderr=sp.PIPE,
)
out, err = p.communicate(input=bytes(chr(ch) + "\n", "ascii"))
by omitting bufsize
, removing the --unbuffered
option, and adding an "EOL" (and variations therein) doesn't/don't change anything.