Pytest: capsys.disabled for stdin

Created on 12 Jan 2017  路  13Comments  路  Source: pytest-dev/pytest

I'm using pytest 3.0.4

Currently, using capsys.disabled prevents the capturing on stdout. But it does not do anything for stdin, which is also important for my use. (specifically, I want to be able to use input().)

Adding the -s command line option works, but I'd like to do it programmatically in a test. Ideally, you'd get something like this:

    def test_capfd_thing(capfd):
        print("this won't be visible")
        with capsys.disabled():
            print("this will be visible.")
            s = input("Type the word potato:")
            print("you said: "+ s)
        assert 'potato' in s

I'm not sure whether only disabling the capturing of stdout is expected behavior (in which case I would like a way to do what I'm doing above) or a bug.

capture

Most helpful comment

Sure, the automated tests also could simply be a script. Using a test runner instead provides a lot of convenience, just like with automated tests.

All 13 comments

Input directly kills test automation, why do you want that in automated tests?

FWIW I had this kind of scenario before (before I switched to pytest):

I wrote tests in Python for an embedded display drawing firmware (written in C). Many tests were automated (communicating with the display over serial port, checking things it gets back, etc.).

However, there is no way I could check if the actual drawing is correct automatically - so I had a test drawing a picture and asked the tester (i.e. myself) if it looks like a reference picture. That test was disabled by default and enabled with a commandline argument, but from time to time it was very valuable.

@The-Compiler but those manual tests dont need to be part of a automated testsuite, this could be just a script

Sure, the automated tests also could simply be a script. Using a test runner instead provides a lot of convenience, just like with automated tests.

Regardless of the use case, seems reasonable to me for capsys.disabled() to behave like --capture=no on the command line, if possible.

Looking at the code it seems that this is what the in_=True parameter was supposed to do, so it warrants some investigation.

I'm basically doing the same thing as @The-Compiler actually.

I'm glad to hear that I'm not crazy WRT capsys.disabled versus --capture=no in any case.

I was hoping this would work so I could make a fixture for dropping into ipdb within tests. However, I still get this output when I do ipdb.set_trace():

https://gist.github.com/dusktreader/ee17bcc1cf282093556cabc636e4ef00

Still looking for a viable workaround for debugging with ipdb

You're not crazy, I had a related problem in the past (also hardware testing) - there is a way to temporarily suspend capturing: https://github.com/pytest-dev/pytest/issues/4210#issuecomment-449484574

@bilderbuchi Thanks so much for pointing that stuff out! I was able to build my debugger() fixture using that knowledge. Still can't get it to jump into the calling code frame, but other than that it works great:

@pytest.fixture
def debugger(pytestconfig):
    """
    Provides a test fixture that starts an interactive debugger wherever the
    ``debugger()`` fixture is invoked
    """

    def _helper():
        capmanager = pytestconfig.pluginmanager.getplugin('capturemanager')
        capmanager.suspend_global_capture(in_=True)
        try:
            # Tried to use inspect.currentframe().f_back to set the calling
            # frame automatically, but it just wouldn't work
            print()
            print()
            print(enboxify(dedent(
                """
                Type 'up' to jump into the test context
                Type 'continue' to resume the test
                Type 'exit' (or ctrl-d) to abort the test
                """
            )))
            import ipdb
            ipdb.set_trace()
        finally:
            capmanager.resume_global_capture()

    return _helper

@dusktreader
Why not just use the normal --pdb / pdb.set_trace()?
Check out https://github.com/fschulze/pytest-pdb (which has goto test) and https://github.com/antocuni/pdb also.

@blueyed Because I prefer ipython as a repl

@dusktreader
Then try --pdbcls=IPython.terminal.debugger:TerminalPdb maybe.

Surfacing this very frequently esp. when we tend to use execute() API of fabfile.py in pytest to run some test case. Any workarounds. I tried with capsys.disabled(), but surface the same.
pytest test_pytest_a.py -s works fine, but with it causing exceptions.

I am using fabric 1.14.1 and pytest 3.7.2

    #test_pytest_a.py
    import pytest
    from fabfile import *
    def test_atest():
        execute(runcmd, hosts=['[email protected]:22'])


   #fabfile.py
   from fabric.api import *
   env.passwords = { '[email protected]:22' : 'xyz' }
   @task
   def runcmd(cmd='date'):
         run(cmd, shell=False)

logs of this show -

  ../py2venv/lib/python2.7/site-packages/fabric/thread_handling.py:12: in wrapper
       callable(*args, **kwargs)
 ../py2venv/lib/python2.7/site-packages/fabric/io.py:227: in input_loop
    r, w, x = select([sys.stdin], [], [], 0.0)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_pytest.capture.DontReadFromInput object at 0x7fd9a463b750>

    def fileno(self):
>       raise UnsupportedOperation("redirected stdin is pseudofile, " "has no fileno()")
E       UnsupportedOperation: redirected stdin is pseudofile, has no fileno()

../py2venv/lib/python2.7/site-packages/_pytest/capture.py:599: UnsupportedOperation
Was this page helpful?
0 / 5 - 0 ratings