¿Cómo hacer que Pytest espere la acción (manual) del usuario?

Estamos utilizando con éxito pytest (Python 3) para ejecutar un conjunto de pruebas y probar algunos dispositivos de hardware (electrónica). Para un subconjunto de estas pruebas, necesitamos que el probador cambie la disposición del hardware y luego la vuelva a cambiar. Mi enfoque fue utilizar un dispositivo de nivel de módulo adjunto a las pruebas en cuestión (que están todas en un módulo separado), con dos llamadas de input :

 @pytest.fixture(scope="module") def disconnect_component(): input('Disconnect component, then press enter') yield # At this point all the tests with this fixture are run input('Connect component again, then press enter') 

Cuando OSError: reading from stdin while output is captured esto, obtengo OSError: reading from stdin while output is captured . Puedo evitar esto llamando a pytest con --capture=no , y he confirmado que mi enfoque funciona, lo que significa que obtengo la primera consulta antes del subconjunto de prueba en cuestión y la segunda después de que se hayan ejecutado.

El gran inconveniente es que esto desactiva la captura de stdin / stderr para todo el conjunto de pruebas, en el que confían algunas de las otras pruebas.

También intenté usar capsys.disabled ( docs ) como este

 @pytest.fixture(scope="module") def disconnect_component(capsys): with capsys.disabled(): input('Disconnect component, then press enter') yield # At this point all the tests with this fixture are run input('Connect component again, then press enter') 

pero cuando ScopeMismatch: You tried to access the 'function' scoped fixture 'capsys' with a 'module' scoped request object, involved factories esto obtengo ScopeMismatch: You tried to access the 'function' scoped fixture 'capsys' with a 'module' scoped request object, involved factories .

¿Puedo hacer que pytest espere la acción del usuario de alguna otra manera que no sea la input ? Si no, ¿puedo deshabilitar la captura solo para las pruebas que usan el dispositivo anterior?

Entonces, encontré una sugerencia de un desarrollador pytest, según la cual básicamente hago lo que hace la función capsys.disable() :

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

Esto funciona perfectamente hasta donde puedo ver. No olvides el in_=True .

Edición: Desde pytest 3.3.0 (creo), capmanager.suspendcapture y capmanager.resumecapture fueron renombrados a capmanager.suspend_global_capture y capmanager.resume_global_capture , respectivamente.

Tal vez vale la pena señalar que la solución anterior no tiene que estar en un accesorio. He hecho una función de ayuda para eso:

 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 

Para futuras referencias, si necesita usar input con pytest . Puedes hacer esto en cualquier parte de pytest, setup_class , test_... , teardown_method , etc. Esto es para 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()