disabling capture makes the capfd funcarg break py.test

Issue #124 resolved
Ronny Pfannschmidt
created an issue

the bottom line is getting a invalid fd in the terminalwriter

{{{

!text

$ py.test -v testing/ -k test_stdouterrin_setnull inserting into sys.path: /home/ronny/Projects/py ==================================================================== test session starts ==================================================================== platform linux2 -- Python 2.6.5 -- pytest-1.4.0a1 -- /usr/bin/python gateway test setup scope: session execnet: /home/ronny/Projects/execnet/execnet/init.pyc -- 1.0.9.dev0 test path 1: testing/

testing/test_basics.py:145: test_stdouterrin_setnull PASSED

==================================================== 324 tests deselected by 'test_stdouterrin_setnull' ===================================================== ========================================================= 1 passed, 324 deselected in 0.27 seconds ========================================================== 16:28:15 | ~/Projects/execnet $ py.test -v testing/ -ks test_stdouterrin_setnull inserting into sys.path: /home/ronny/Projects/py ==================================================================== test session starts ==================================================================== platform linux2 -- Python 2.6.5 -- pytest-1.4.0a1 -- /usr/bin/python gateway test setup scope: session execnet: /home/ronny/Projects/execnet/execnet/init.pyc -- 1.0.9.dev0 ERROR: file not found: /home/ronny/Projects/execnet/test_stdouterrin_setnull 16:28:20 | ~/Projects/execnet $ py.test -vs -k test_stdouterrin_setnull inserting into sys.path: /home/ronny/Projects/py ==================================================================== test session starts ==================================================================== platform linux2 -- Python 2.6.5 -- pytest-1.4.0a1 -- /usr/bin/python gateway test setup scope: session execnet: /home/ronny/Projects/execnet/execnet/init.pyc -- 1.0.9.dev0 test path 1: /home/ronny/Projects/execnet

testing/test_basics.py:145: test_stdouterrin_setnull Traceback (most recent call last): File "/home/ronny/Projects/py/bin/py.test", line 3, in <module> py.cmdline.pytest() File "/home/ronny/Projects/py/py/_cmdline/pytest.py", line 5, in main raise SystemExit(py.test.cmdline.main(args)) File "/home/ronny/Projects/py/py/_test/session.py", line 21, in main exitstatus = config.hook.pytest_cmdline_main(config=config) File "/home/ronny/Projects/py/py/_test/pluginmanager.py", line 352, in call return self.hookrelay._performcall(self.name, mc) File "/home/ronny/Projects/py/py/_test/pluginmanager.py", line 338, in _performcall return multicall.execute() File "/home/ronny/Projects/py/py/_test/pluginmanager.py", line 244, in execute res = method(kwargs) File "/home/ronny/Projects/py/py/_plugin/pytest_default.py", line 8, in pytest_cmdline_main return Session(config).main() File "/home/ronny/Projects/py/py/_test/session.py", line 77, in main self.config.pluginmanager.notify_exception(excinfo) File "/home/ronny/Projects/py/py/_test/pluginmanager.py", line 166, in notify_exception return self.hook.pytest_internalerror(excrepr=excrepr) File "/home/ronny/Projects/py/py/_test/pluginmanager.py", line 352, in __call__ return self.hookrelay._performcall(self.name, mc) File "/home/ronny/Projects/py/py/_test/pluginmanager.py", line 338, in _performcall return multicall.execute() File "/home/ronny/Projects/py/py/_test/pluginmanager.py", line 244, in execute res = method(kwargs) File "/home/ronny/Projects/py/py/_plugin/pytest_terminal.py", line 120, in pytest_internalerror self.write_line("INTERNALERROR> " + line) File "/home/ronny/Projects/py/py/_plugin/pytest_terminal.py", line 112, in write_line self._tw.line(line, markup) File "/home/ronny/Projects/py/py/_io/terminalwriter.py", line 182, in line self.write(s, kw) File "/home/ronny/Projects/py/py/_io/terminalwriter.py", line 168, in write self._file.flush() IOError: [Errno 9] Bad file descriptor

}}}

Comments (4)

  1. Holger Krekel repo owner

    I analysed this and running this with py.test -s will break as a minimal example:

    # this will crash when run with "-s"
    import os, sys
    
    k = []
    
    def test_open_file_and_keep_alive(capfd):
        stdout = os.fdopen(1, 'w', 1)
        k.append(stdout)
    
    def test_close_kept_alive_file():
        stdout = k.pop()
        stdout.close()
    

    Reason being:

    1. the first test creates a file with fileno() == 1. It is not closed.

    2. the second test (having no capfd!) then closes the file created by the first. This will immediately break the terminal reporter.

    In practise if you do "sys.stdout = os.fdopen(1, ...)" in the first test how and when it breaks depends on Garbage collection i suspect.

    I am not entirely sure yet what to do about this.

    best, holger

  2. Log in to comment