我试图unittest
一个从stdin获取单独按键的模块。获取密钥的代码完美无缺,但是将一个字符(字节?)写入子进程'斯坦丁给了我一些问题。
根据文档和其他SO答案,我基本上使用了推荐here的内容进行了修改:
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)
我想要的是p
只收到stdin的一个ASCII字符然后退出。 ch
有时NUL
,EOF
和其他控制字符不是问题;它正是我想要的。
问题是,在按 CTRL - C 之前,这似乎没有任何作用,然后它会以键盘中断退出。堆栈跟踪的最后一行是in selectors.py: fd_event_list = self._poll.poll(timeout)
,它告诉我它正在等待超时(?),但我没有提供timeout=int
kwarg。
我使用的命令解析为python3 -u helptest.py getch
,它看起来像这样,当我自己从命令行运行它时它可以正常工作。
这是helptest
的相关部分:
def getch():
write_and_flush(ord(_ic._Getch()))
(write_and_flush
只运行stdout.write; stdout.flush
)
和_ic._Getch()
是:
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)
我在subprocess
电话中做错了什么?
将通话更改为:
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"))
省略bufsize
,删除--unbuffered
选项,然后添加" EOL" (以及其中的变化)不会改变任何东西。
答案 0 :(得分:-1)
最后一次打印调用应该有Flush=True
。
答案 1 :(得分:-1)
p.communicate()
代码是正确的。问题是您的helptest.py
。
Ctrl + C 行为表示helptest.py
尝试直接从控制台读取而不是使用stdin
。您似乎使用_Getch()
from here在Windows上使用msvcrt.getch()
,即它可以从控制台而不是stdin
读取。
此外,sys.stdin.read(1)
可能会读取多个字节 - sys.stdin
默认情况下处于文本模式。要从stdin读取字节,您可以使用b = os.read(0, 1)
或以二进制模式重新打开sys.stdin
,例如,在Python 3上调用sys.stdin.detach()
。
如果您的目的是阅读密钥,那么您可以使用use readchar
package。最好在一个地方修复可能的(微妙的)问题。
不相关:如果您使用.communicate()
,缓冲区无关紧要,即您可以删除-u
,bufsize
。除非子进程被破坏,input=s
的行为应与input=s + newline
类似(即,EOF是隐式EOL)。
答案 2 :(得分:-2)
您的代码建议您希望bufsize=1
将缓冲区大小设置为1,而是启用行缓冲模式。通信阻塞直到写入EOL。