From 5a856b6e29172cb9f38e7e8c5413e13684307ec0 Mon Sep 17 00:00:00 2001 From: Ryan Fitzpatrick Date: Mon, 12 Jun 2017 20:39:42 -0400 Subject: [PATCH] handle and reraise subrequest finalizer exceptions --- _pytest/fixtures.py | 10 ++++++++-- changelog/2440.bugfix | 1 + testing/python/fixture.py | 26 ++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 changelog/2440.bugfix diff --git a/_pytest/fixtures.py b/_pytest/fixtures.py index 1a6e245c7..5799b00e6 100644 --- a/_pytest/fixtures.py +++ b/_pytest/fixtures.py @@ -733,10 +733,16 @@ class FixtureDef: self._finalizer.append(finalizer) def finish(self): + exceptions = [] try: while self._finalizer: - func = self._finalizer.pop() - func() + try: + func = self._finalizer.pop() + func() + except: + exceptions.append(sys.exc_info()) + if exceptions: + py.builtin._reraise(*exceptions[0]) finally: ihook = self._fixturemanager.session.ihook ihook.pytest_fixture_post_finalizer(fixturedef=self) diff --git a/changelog/2440.bugfix b/changelog/2440.bugfix new file mode 100644 index 000000000..6f64d1dee --- /dev/null +++ b/changelog/2440.bugfix @@ -0,0 +1 @@ +Exceptions in a SubRequest's finish() block are suppressed until all finalizers are called, with the initial exception reraised. \ No newline at end of file diff --git a/testing/python/fixture.py b/testing/python/fixture.py index 4c9ad7a91..ca2e078bd 100644 --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -657,6 +657,32 @@ class TestRequestBasic(object): "*1 error*" # XXX the whole module collection fails ]) + def test_request_subrequest_addfinalizer_exceptions(self, testdir): + testdir.makepyfile(""" + import pytest + l = [] + def _excepts(): + raise Exception('Error') + @pytest.fixture + def subrequest(request): + return request + @pytest.fixture + def something(subrequest): + subrequest.addfinalizer(lambda: l.append(1)) + subrequest.addfinalizer(lambda: l.append(2)) + subrequest.addfinalizer(_excepts) + @pytest.fixture + def excepts(subrequest): + subrequest.addfinalizer(_excepts) + subrequest.addfinalizer(lambda: l.append(3)) + def test_first(something, excepts): + pass + def test_second(): + assert l == [3, 2, 1] + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=2, failed=1) + def test_request_getmodulepath(self, testdir): modcol = testdir.getmodulecol("def test_somefunc(): pass") item, = testdir.genitems([modcol])