[pytest-dev] Trouble accessing captured stderr
Nikolaus Rath
Nikolaus at rath.org
Tue Jun 4 07:03:27 CEST 2013
Hello,
I have a problem accessing the captured stderr. I have set up the
following test:
$ ls mytest/
conftest.py test_one.py
$ cat mytest/conftest.py
import pytest
@pytest.fixture(autouse=True)
def add_stderr_check(request, capsys):
def check_stderr():
stderr = capsys.readouterr()[1]
if 'exception' in stderr.lower():
raise AssertionError('Suspicious output to stderr')
request.addfinalizer(check_stderr)
$ cat mytest/test_one.py
import threading
def test_thread():
def fail():
raise RuntimeError('Do not call me!')
t = threading.Thread(target=fail)
t.start()
t.join()
def test_del():
d = ImmortalObject()
assert d.value == 2
del d
class ImmortalObject:
def __init__(self):
self.value = 2
def __del__(self):
raise RuntimeError('You cannot kill me!')
As long as I call the tests individually, they behave exactly as expected:
> $ py.test mytest/ -v -k test_thread
> =========================================== test session starts ============================================
> platform linux -- Python 3.3.2 -- pytest-2.3.5 -- /usr/bin/python3.3
> collected 2 items
>
> mytest/test_one.py:3: test_thread PASSED
> mytest/test_one.py:3: test_thread ERROR
>
> ================================================== ERRORS ==================================================
> _____________________________________ ERROR at teardown of test_thread _____________________________________
>
> def check_stderr():
> stderr = capsys.readouterr()[1]
> if 'exception' in stderr.lower():
>> raise AssertionError('Suspicious output to stderr')
> E AssertionError: Suspicious output to stderr
>
> mytest/conftest.py:8: AssertionError
> --------------------------------------------- Captured stderr ----------------------------------------------
> Exception in thread Thread-1:
> Traceback (most recent call last):
> File "/usr/lib/python3.3/threading.py", line 637, in _bootstrap_inner
> self.run()
> File "/usr/lib/python3.3/threading.py", line 594, in run
> self._target(*self._args, **self._kwargs)
> File "/home/nikratio/in-progress/s3ql/mytest/test_one.py", line 5, in fail
> raise RuntimeError('Do not call me!')
> RuntimeError: Do not call me!
>
> ================================== 1 tests deselected by '-ktest_thread' ===================================
> ============================= 1 passed, 1 deselected, 1 error in 0.01 seconds ==============================
and:
> [1] nikratio at vostro:~/in-progress/s3ql$ py.test mytest/ -v -k test_del
> =========================================== test session starts ============================================
> platform linux -- Python 3.3.2 -- pytest-2.3.5 -- /usr/bin/python3.3
> collected 2 items
>
> mytest/test_one.py:10: test_del PASSED
> mytest/test_one.py:10: test_del ERROR
>
> ================================================== ERRORS ==================================================
> ______________________________________ ERROR at teardown of test_del _______________________________________
>
> def check_stderr():
> stderr = capsys.readouterr()[1]
> if 'exception' in stderr.lower():
>> raise AssertionError('Suspicious output to stderr')
> E AssertionError: Suspicious output to stderr
>
> mytest/conftest.py:8: AssertionError
> --------------------------------------------- Captured stderr ----------------------------------------------
> Exception RuntimeError: RuntimeError('You cannot kill me!',) in <bound method ImmortalObject.__del__ of <test_one.ImmortalObject object at 0x7f9fb945fb90>> ignored
> ==================================== 1 tests deselected by '-ktest_del' ====================================
> ============================= 1 passed, 1 deselected, 1 error in 0.01 seconds ==============================
However, if I attempt to run both tests, I get a very long and (to me)
confusing error:
> $ py.test mytest/ -v
> =========================================== test session starts ============================================
> platform linux -- Python 3.3.2 -- pytest-2.3.5 -- /usr/bin/python3.3
> collected 2 items
>
> mytest/test_one.py:3: test_thread PASSED
> mytest/test_one.py:3: test_thread ERROR
> mytest/test_one.py:10: test_del FAILED
>
> ================================================== ERRORS ==================================================
> _____________________________________ ERROR at teardown of test_thread _____________________________________
>
> def check_stderr():
> stderr = capsys.readouterr()[1]
> if 'exception' in stderr.lower():
>> raise AssertionError('Suspicious output to stderr')
> E AssertionError: Suspicious output to stderr
>
> mytest/conftest.py:8: AssertionError
> --------------------------------------------- Captured stderr ----------------------------------------------
> Exception in thread Thread-1:
> Traceback (most recent call last):
> File "/usr/lib/python3.3/threading.py", line 637, in _bootstrap_inner
> self.run()
> File "/usr/lib/python3.3/threading.py", line 594, in run
> self._target(*self._args, **self._kwargs)
> File "/home/nikratio/in-progress/s3ql/mytest/test_one.py", line 5, in fail
> raise RuntimeError('Do not call me!')
> RuntimeError: Do not call me!
>
> ================================================= FAILURES =================================================
> _________________________________________________ test_del _________________________________________________
>
> self = <CallInfo when='call' exception: 'CaptureFixture' object has no attribute 'capture'>
> func = <function call_runtest_hook.<locals>.<lambda> at 0x7f413dfc5950>, when = 'call'
>
> def __init__(self, func, when):
> #: context of invocation: one of "setup", "call",
> #: "teardown", "memocollect"
> self.when = when
> self.start = time()
> try:
> try:
>> self.result = func()
>
> ../../.local/lib/python3.3/site-packages/_pytest/runner.py:129:
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
>
>> return CallInfo(lambda: ihook(item=item, **kwds), when=when)
>
> ../../.local/lib/python3.3/site-packages/_pytest/runner.py:116:
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
>
> kwargs = {'item': <Function 'test_del'>}
> plugins = [<Session 's3ql'>, <_pytest.core.PluginManager object at 0x7f413eb6dfd0>, <module '_pytest.config' from '/home/nikrati...in.py'>, <module '_pytest.terminal' from '/home/nikratio/.local/lib/python3.3/site-packages/_pytest/terminal.py'>, ...]
>
> def call_matching_hooks(**kwargs):
> plugins = self.config._getmatchingplugins(self.fspath)
>> return hookmethod.pcall(plugins, **kwargs)
>
> ../../.local/lib/python3.3/site-packages/_pytest/main.py:159:
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
>
> self = <HookCaller 'pytest_runtest_call'>
> plugins = [<Session 's3ql'>, <_pytest.core.PluginManager object at 0x7f413eb6dfd0>, <module '_pytest.config' from '/home/nikrati...in.py'>, <module '_pytest.terminal' from '/home/nikratio/.local/lib/python3.3/site-packages/_pytest/terminal.py'>, ...]
> kwargs = {'item': <Function 'test_del'>}
> methods = [<function pytest_runtest_call at 0x7f413e9314d0>, <function pdbitem at 0x7f413e9544d0>, <bound method CaptureManager.pytest_runtest_call of <_pytest.capture.CaptureManager object at 0x7f413eb77710>>]
>
> def pcall(self, plugins, **kwargs):
> methods = self.hookrelay._pm.listattr(self.name, plugins=plugins)
>> return self._docall(methods, kwargs)
>
> ../../.local/lib/python3.3/site-packages/_pytest/core.py:445:
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
>
> self = <HookCaller 'pytest_runtest_call'>
> methods = [<function pytest_runtest_call at 0x7f413e9314d0>, <function pdbitem at 0x7f413e9544d0>, <bound method CaptureManager.pytest_runtest_call of <_pytest.capture.CaptureManager object at 0x7f413eb77710>>]
> kwargs = {'item': <Function 'test_del'>}
>
> def _docall(self, methods, kwargs):
> self.trace(self.name, kwargs)
> self.trace.root.indent += 1
> mc = MultiCall(methods, kwargs, firstresult=self.firstresult)
> try:
>> res = mc.execute()
>
> ../../.local/lib/python3.3/site-packages/_pytest/core.py:452:
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
>
> self = <MultiCall 0 results, 2 meths, kwargs={'item': <Function 'test_del'>}>
>
> def execute(self):
> while self.methods:
> method = self.methods.pop()
> kwargs = self.getkwargs(method)
>> res = method(**kwargs)
>
> ../../.local/lib/python3.3/site-packages/_pytest/core.py:370:
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
>
> self = <_pytest.capture.CaptureManager object at 0x7f413eb77710>, item = <Function 'test_del'>
>
> @pytest.mark.tryfirst
> def pytest_runtest_call(self, item):
> self.resumecapture_item(item)
>> self.activate_funcargs(item)
>
> ../../.local/lib/python3.3/site-packages/_pytest/capture.py:158:
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
>
> self = <_pytest.capture.CaptureManager object at 0x7f413eb77710>, pyfuncitem = <Function 'test_del'>
>
> def activate_funcargs(self, pyfuncitem):
> funcargs = getattr(pyfuncitem, "funcargs", None)
> if funcargs is not None:
> for name, capfuncarg in funcargs.items():
> if name in ('capsys', 'capfd'):
> assert not hasattr(self, '_capturing_funcarg')
> self._capturing_funcarg = capfuncarg
>> capfuncarg._start()
>
> ../../.local/lib/python3.3/site-packages/_pytest/capture.py:128:
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
>
> self = <_pytest.capture.CaptureFixture object at 0x7f413ea47f10>
>
> def _start(self):
>> self.capture.startall()
> E AttributeError: 'CaptureFixture' object has no attribute 'capture'
>
> ../../.local/lib/python3.3/site-packages/_pytest/capture.py:209: AttributeError
> =============================== 1 failed, 1 passed, 1 error in 0.03 seconds ================================
Can someone explain what's happening here?
Best,
-Nikolaus
--
»Time flies like an arrow, fruit flies like a Banana.«
PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6 02CF A9AD B7F8 AE4E 425C
More information about the Pytest-dev
mailing list