Merge lp:~cbrandily/python-fixtures/cleanup-context into lp:python-fixtures

Proposed by Cedric Brandily
Status: Needs review
Proposed branch: lp:~cbrandily/python-fixtures/cleanup-context
Merge into: lp:python-fixtures
Diff against target: 80 lines (+54/-5)
2 files modified
fixtures/fixture.py (+6/-5)
fixtures/tests/test_fixture.py (+48/-0)
To merge this branch: bzr merge lp:~cbrandily/python-fixtures/cleanup-context
Reviewer Review Type Date Requested Status
Robert Collins Disapprove
Review via email: mp+259725@code.launchpad.net

Description of the change

Ensure cleanups are called even if setUp fails with fixture context

This change ensures that a fixture cleanups will be called even if
its setUp fails when used as a context.

Example:

  with MyFixture() as fixture1:
    pass

fixture1.cleanUp will be called even if fixture1.setUp (called in
fixture1.__enter__) fails.

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote :

Thanks for this patch. This is a better, closer to the cause fix. It doesn't address the issue of setUp being fragile though.

Additionally - and I'm sorry about this - you got mislead by the somewhat confusing thing of us having a mirror of the code here: the code is actually on github at https://testing-cabal/fixtures. (LP does have a link to that but its not obvious - I hope I've made it clearer by editing the homepage a bit).

I've put up a patch https://github.com/testing-cabal/fixtures/pull/11 which I think fixes both angles systematically. It will require fixture authors to update, but they can do that incrementally in their own time, and the update is very easy. Reasoning behind this is at https://rbtcollins.wordpress.com/2015/06/22/revisiting-the-fixture-api-handling-leaky-resources/

review: Disapprove

Unmerged revisions

96. By Cedric Brandily

Ensure cleanups are called even if setUp fails with fixture context

This change ensures that a fixture cleanups will be called even if
its setUp fails when used as a context.

Example:

  with MyFixture() as fixture1:
    pass

fixture1.cleanUp will be called even if fixture1.setUp (called in
fixture1.__enter__) fails.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'fixtures/fixture.py'
--- fixtures/fixture.py 2014-09-25 03:01:50 +0000
+++ fixtures/fixture.py 2015-05-21 06:22:53 +0000
@@ -127,14 +127,15 @@
127 self._detail_sources = []127 self._detail_sources = []
128128
129 def __enter__(self):129 def __enter__(self):
130 self.setUp()130 try:
131 self.setUp()
132 except:
133 self.cleanUp()
134 raise
131 return self135 return self
132136
133 def __exit__(self, exc_type, exc_val, exc_tb):137 def __exit__(self, exc_type, exc_val, exc_tb):
134 try:138 self.cleanUp()
135 self._cleanups()
136 finally:
137 self._clear_cleanups()
138 return False # propogate exceptions from the with body.139 return False # propogate exceptions from the with body.
139140
140 def getDetails(self):141 def getDetails(self):
141142
=== modified file 'fixtures/tests/test_fixture.py'
--- fixtures/tests/test_fixture.py 2014-09-25 03:01:50 +0000
+++ fixtures/tests/test_fixture.py 2015-05-21 06:22:53 +0000
@@ -311,3 +311,51 @@
311 self.assertEqual(126, obj.value)311 self.assertEqual(126, obj.value)
312 fixture.cleanUp()312 fixture.cleanUp()
313 self.assertEqual(84, obj.value)313 self.assertEqual(84, obj.value)
314
315 def test_context_cleanUp(self):
316 class SimpleFixture(fixtures.Fixture):
317 def __init__(self):
318 self.cleanup_called = False
319 def cleanUp(self):
320 self.cleanup_called = True
321
322 fixture = SimpleFixture()
323 self.assertFalse(fixture.cleanup_called)
324 with fixture:
325 pass
326 self.assertTrue(fixture.cleanup_called)
327
328 def test_context_cleanUp_with_failed_suite(self):
329 class SimpleFixture(fixtures.Fixture):
330 def __init__(self):
331 self.cleanup_called = False
332 def cleanUp(self):
333 self.cleanup_called = True
334
335 fixture = SimpleFixture()
336 def func():
337 with fixture:
338 raise ValueError()
339
340 self.assertFalse(fixture.cleanup_called)
341 self.assertRaises(ValueError, func)
342 self.assertTrue(fixture.cleanup_called)
343
344 def test_context_cleanUp_with_failed_setUp(self):
345 class FailedSetUpFixture(fixtures.Fixture):
346 def __init__(self):
347 self.cleanup_called = False
348 def setUp(self):
349 super(FailedSetUpFixture, self).setUp()
350 raise ValueError()
351 def cleanUp(self):
352 self.cleanup_called = True
353
354 fixture = FailedSetUpFixture()
355 def func():
356 with fixture:
357 pass
358
359 self.assertFalse(fixture.cleanup_called)
360 self.assertRaises(ValueError, func)
361 self.assertTrue(fixture.cleanup_called)

Subscribers

People subscribed via source and target branches

to all changes: