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

5

19

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?

Calcium answered 18/7, 2018 at 2:52 Comment(0)
H
12

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 prompt="", /: "no")
    val = prompt_to_activate(bear=..., printer=...)
    assert not val
Hedwighedwiga answered 18/7, 2018 at 2:58 Comment(1)
Similarly for click.confirm()Footpath
H
14

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

Hollow answered 10/1, 2021 at 22:46 Comment(1)
this was the solution for my issueRaddie
H
12

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 prompt="", /: "no")
    val = prompt_to_activate(bear=..., printer=...)
    assert not val
Hedwighedwiga answered 18/7, 2018 at 2:58 Comment(1)
Similarly for click.confirm()Footpath
V
5

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.

Vargueno answered 14/10, 2020 at 11:39 Comment(1)
If you want to use import ipdb; ipdb.set_trace() in your code, don't forget to add the -s flag with pytest, otherwise you will get the error.Spectacles
E
0

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()

Estradiol answered 21/3, 2023 at 16:33 Comment(0)
P
0

This can also occur if you moved a function or method that uses input() to another module and have no updated the module string in the patch decorator.

Postage answered 21/6 at 11:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.