-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Closed
Labels
topic: fixturesanything involving fixtures directly or indirectlyanything involving fixtures directly or indirectlytype: bugproblem that needs to be addressedproblem that needs to be addressed
Description
When an exception occurs in a SubRequest's registered finalizer, no further registered finalizers are invoked, causing incomplete teardown. This is not the case for FixtureRequests:
import pytest
class Factory(object):
@classmethod
def __call__(cls, request, to_teardown):
def teardown():
print 'in ', teardown, request, to_teardown
to_teardown()
print 'register', teardown, request, to_teardown
request.addfinalizer(teardown)
@pytest.fixture
def factory(request):
def _factory(to_teardown):
return Factory()(request, to_teardown)
return _factory
def _in(num):
print '_in({0})'.format(num)
raise Exception(num)
def one():
_in('one')
def two():
_in('two')
def test_with_factory_and_fixturerequest(request):
factory = Factory()
for to_teardown in (one, two):
factory(request, to_teardown)
def test_with_factory_and_subrequest(factory):
for to_teardown in (one, two):
factory(to_teardown)
(pytest) user$ pytest -vs test.py
====================================================================================== test session starts =======================================================================================
platform darwin -- Python 2.7.13, pytest-3.1.1.dev23+g7950c26, py-1.4.33, pluggy-0.4.0 -- /.virtualenvs/pytest/bin/python2.7
cachedir: .cache
rootdir: user, inifile:
plugins: hypothesis-3.11.0
collected 2 items
test.py::test_with_factory_and_fixturerequest register <function teardown at 0x110e6d2a8> <FixtureRequest for <Function 'test_with_factory_and_fixturerequest'>> <function one at 0x110e37e60>
register <function teardown at 0x110e6d320> <FixtureRequest for <Function 'test_with_factory_and_fixturerequest'>> <function two at 0x110e37ed8>
PASSEDin <function teardown at 0x110e6d320> <FixtureRequest for <Function 'test_with_factory_and_fixturerequest'>> <function two at 0x110e37ed8>
_in(two)
in <function teardown at 0x110e6d2a8> <FixtureRequest for <Function 'test_with_factory_and_fixturerequest'>> <function one at 0x110e37e60>
_in(one)
test.py::test_with_factory_and_fixturerequest ERROR
test.py::test_with_factory_and_subrequest register <function teardown at 0x110e6d320> <SubRequest 'factory' for <Function 'test_with_factory_and_subrequest'>> <function one at 0x110e37e60>
register <function teardown at 0x110e6d2a8> <SubRequest 'factory' for <Function 'test_with_factory_and_subrequest'>> <function two at 0x110e37ed8>
PASSEDin <function teardown at 0x110e6d2a8> <SubRequest 'factory' for <Function 'test_with_factory_and_subrequest'>> <function two at 0x110e37ed8>
_in(two)
test.py::test_with_factory_and_subrequest ERROR
============================================================================================= ERRORS =============================================================================================
___________________________________________________________________ ERROR at teardown of test_with_factory_and_fixturerequest ____________________________________________________________________
def teardown():
print 'in ', teardown, request, to_teardown
> to_teardown()
test.py:14:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
test.py:41: in two
_in('two')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
num = 'two'
def _in(num):
print '_in({0})'.format(num)
> raise Exception(num)
E Exception: two
test.py:33: Exception
_____________________________________________________________________ ERROR at teardown of test_with_factory_and_subrequest ______________________________________________________________________
def teardown():
print 'in ', teardown, request, to_teardown
> to_teardown()
test.py:14:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
test.py:41: in two
_in('two')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
num = 'two'
def _in(num):
print '_in({0})'.format(num)
> raise Exception(num)
E Exception: two
test.py:33: Exception
=============================================================================== 2 passed, 2 error in 0.03 seconds ================================================================================
Notice in test_with_factory_and_fixturerequest
that both registered finalizers are invoked but in test_with_factory_and_subrequest
only two()
is. A workaround is to wrap any teardown calls that can potentially raise exceptions in a try/except
, but this isn't ideal since the exceptions are informative.
(pytest) user$ pip list
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
appdirs (1.4.3)
enum34 (1.1.6)
hypothesis (3.11.0)
packaging (16.8)
pip (9.0.1)
py (1.4.33)
pyparsing (2.2.0)
pytest (3.1.1.dev23+g7950c26, /user/pytest)
setuptools (35.0.2)
six (1.10.0)
wheel (0.30.0a0)
edit: removed unnecessary functions
Metadata
Metadata
Assignees
Labels
topic: fixturesanything involving fixtures directly or indirectlyanything involving fixtures directly or indirectlytype: bugproblem that needs to be addressedproblem that needs to be addressed