python pytest occasionally fails with OSError: reading from stdin while output is captured

Question:

While running a particular unittest with pytest, it occasionally fails with this error (mentioned in the title) and from the stack trace it happens on the line

choice = input().lower()

when the control reaches this statement, the entire function is:

def prompt_to_activate(bear, printer):
    PROMPT_TO_ACTIVATE_STR = ('program has found {} to be useful '
                              'based of dependencies discovered from your '
                              'project files. n Would you like to activate '
                              'it? (y/n)')
    printer.print(PROMPT_TO_ACTIVATE_STR)

    choice = input().lower()

    if choice.startswith('y'):
        return True
    elif choice.startswith('n'):
        return False
    else:
        return prompt_to_activate(bear, printer)
for i in range(0, 3):
    a = i
print(a)

I tried adding some time.sleep(x) before that statement but that wouldn’t fix it. Can somebody tell me the exact reason why this is happening and how to fix it?

Asked By: Ishan Srivastava

||

Answers:

Since input() is an interactive function, you’ll want to mock out the return value in your automated tests. Something like this:

def test_prompt(capsys, monkeypatch):
    monkeypatch.setattr('path.to.yourmodule.input', lambda: 'no')
    val = prompt_to_activate(bear=..., printer=...)
    assert not val
Answered By: wim

In case someone else stumbles upon this, this error will also be raised if you forgot a pdb breakpoint (import ipdb; ipdb.set_trace()) in your code.

Answered By: Tom Bug

You might also receive this if you set a breakpoint, but didn’t use the -s flag with pytest.

Answered By: Joshua Cook

I also had the same problem and figured it out after learning more unit testing and mocking! Adding to @wim’s answer… Another way to mock input is:

@mock.patch("my_module.input")
def test_my_actual_func(self, mock_input):
    my_actual_func()

Answered By: learningshark