We are sucessfully using pytest (Python 3) to run a test suite testing some hardware devices (electronics). For a subset of these tests, we need the tester to change the hardwa
So, I found a hint by a pytest dev, based on which I basically do what the capsys.disable()
function does:
@pytest.fixture(scope="module")
def disconnect_component(pytestconfig):
capmanager = pytestconfig.pluginmanager.getplugin('capturemanager')
capmanager.suspend_global_capture(in_=True)
input('Disconnect component, then press enter')
capmanager.resume_global_capture()
yield # At this point all the tests with this fixture are run
capmanager.suspend_global_capture(in_=True)
input('Connect component again, then press enter')
capmanager.resume_global_capture()
This works flawlessly as far as I can see. Don't forget the in_=True
bit.
Edit: From pytest 3.3.0 (I think), capmanager.suspendcapture
and capmanager.resumecapture
were renamed to capmanager.suspend_global_capture
and capmanager.resume_global_capture
, respectively.
Maybe it's worth noting that above solution doesn't have to be in a fixture. I've made a helper function for that:
import pytest
def ask_user_input(msg=''):
""" Asks user to check something manually and answer a question
"""
notification = "\n\n???\tANSWER NEEDED\t???\n\n{}".format(msg)
# suspend input capture by py.test so user input can be recorded here
capture_manager = pytest.config.pluginmanager.getplugin('capturemanager')
capture_manager.suspendcapture(in_=True)
answer = raw_input(notification)
# resume capture after question have been asked
capture_manager.resumecapture()
logging.debug("Answer: {}".format(answer))
return answer
For future reference, if you need to use input
with pytest
. You can do this in any part of your pytest, setup_class
, test_...
, teardown_method
, etc. This is for pytest > 3.3.x
import pytest
capture_manager = pytest.config.pluginmanager.getplugin('capturemanager')
capture_manager.suspend_global_capture(in_=True)
answer = input('My reference text here')
capture_manager.resume_global_capture()
As of pytest 5, as a fixture, you can use this:
@pytest.fixture
def suspend_capture(pytestconfig):
class suspend_guard:
def __init__(self):
self.capmanager = pytestconfig.pluginmanager.getplugin('capturemanager')
def __enter__(self):
self.capmanager.suspend_global_capture(in_=True)
def __exit__(self, _1, _2, _3):
self.capmanager.resume_global_capture()
yield suspend_guard()
Example usage:
def test_input(suspend_capture):
with suspend_capture:
input("hello")
Solutions that use the global pytest.config
object no longer work. For my use case, using --capture=sys
together with a custom input()
that uses stdin
and stdout
directly works well.
def fd_input(prompt):
with os.fdopen(os.dup(1), "w") as stdout:
stdout.write("\n{}? ".format(prompt))
with os.fdopen(os.dup(2), "r") as stdin:
return stdin.readline()