Make a Python process that communicates with itself over a PTY

1 week ago 5
ARTICLE AD BOX

I'm attempting to write tests using Pytest for an application that, among other things, checks to see if its standard input is connected to a terminal and changes its behavior if so. The application is structured such that the code is in a Python module that provides a main() function, then an executable exists that simply imports the module and calls main(). When testing, the test suite imports the same module, then calls main() with various mocks set.

stdin is, as far as I can tell, usually a TextIOWrapper object when running the application normally, so I've been mocking stdin like this:

stdin_buf_internal: BytesIO = BytesIO() stdin_buf: TextIOWrapper = TextIOWrapper( buffer=stdin_buf_internal, encoding="utf-8", newline="\n", errors="surrogateescape", ) with ( mock.patch.object(sys, "stdin", stdin_buf) ): ...

This works quite well, but now I need to be able to mock sys.stdin with a pty. The idea I had for doing that was to just open a PTY pair, wrap the slave pty in an io.FileIO object, then wrap that in a io.TextIOWrapper object, and be done. If that worked, I'd be able to write to the application's stdin by writing to master_pty in the test suite, then the application would read sys.stdin and get whatever I wrote. That doesn't seem to work though.

From looking at https://man7.org/linux/man-pages/man7/pty.7.html and https://docs.python.org/3/library/pty.html, it seems like I should be able to do something like this in the interactive console:

>>> import pty >>> import os >>> import io >>> master_pty, slave_pty = pty.openpty() >>> master_stream = io.FileIO(master_pty, "r+") >>> slave_stream = io.FileIO(slave_pty, "r+") >>> master_stream.write(b"hello world!\n") >>> slave_stream.read()

What I expect to have happen is slave_stream.read() should output hello world!\n What actually happens is the interactive session hangs until I press Ctrl+C. Clearly I'm missing something about how this works, but I'm not sure what.

Is there a way I can make a Python script talk to itself over a PTY, using only features in Python's standard library?

Read Entire Article