Skip to content

Commit 263ca6d

Browse files
committed
fixtures: ensure db blocker is always restored
As the code is written currently, it's possible the `restore` is not called in case of exception. Use the context manager to ensure that it does. This is not to fix an observed issue, just a fix from reviewing the code.
1 parent 113b578 commit 263ca6d

File tree

1 file changed

+52
-55
lines changed

1 file changed

+52
-55
lines changed

pytest_django/fixtures.py

Lines changed: 52 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -197,66 +197,63 @@ def _django_db_helper(
197197
"django_db_serialized_rollback" in request.fixturenames
198198
)
199199

200-
django_db_blocker.unblock()
201-
202-
import django.db
203-
import django.test
204-
205-
if transactional:
206-
test_case_class = django.test.TransactionTestCase
207-
else:
208-
test_case_class = django.test.TestCase
209-
210-
_reset_sequences = reset_sequences
211-
_serialized_rollback = serialized_rollback
212-
_databases = databases
213-
_available_apps = available_apps
214-
215-
class PytestDjangoTestCase(test_case_class): # type: ignore[misc,valid-type]
216-
reset_sequences = _reset_sequences
217-
serialized_rollback = _serialized_rollback
218-
if _databases is not None:
219-
databases = _databases
220-
if _available_apps is not None:
221-
available_apps = _available_apps
222-
223-
# For non-transactional tests, skip executing `django.test.TestCase`'s
224-
# `setUpClass`/`tearDownClass`, only execute the super class ones.
225-
#
226-
# `TestCase`'s class setup manages the `setUpTestData`/class-level
227-
# transaction functionality. We don't use it; instead we (will) offer
228-
# our own alternatives. So it only adds overhead, and does some things
229-
# which conflict with our (planned) functionality, particularly, it
230-
# closes all database connections in `tearDownClass` which inhibits
231-
# wrapping tests in higher-scoped transactions.
232-
#
233-
# It's possible a new version of Django will add some unrelated
234-
# functionality to these methods, in which case skipping them completely
235-
# would not be desirable. Let's cross that bridge when we get there...
236-
if not transactional:
237-
238-
@classmethod
239-
def setUpClass(cls) -> None:
240-
super(django.test.TestCase, cls).setUpClass()
241-
242-
@classmethod
243-
def tearDownClass(cls) -> None:
244-
super(django.test.TestCase, cls).tearDownClass()
245-
246-
PytestDjangoTestCase.setUpClass()
247-
248-
test_case = PytestDjangoTestCase(methodName="__init__")
249-
test_case._pre_setup()
200+
with django_db_blocker.unblock():
201+
import django.db
202+
import django.test
250203

251-
yield
204+
if transactional:
205+
test_case_class = django.test.TransactionTestCase
206+
else:
207+
test_case_class = django.test.TestCase
208+
209+
_reset_sequences = reset_sequences
210+
_serialized_rollback = serialized_rollback
211+
_databases = databases
212+
_available_apps = available_apps
213+
214+
class PytestDjangoTestCase(test_case_class): # type: ignore[misc,valid-type]
215+
reset_sequences = _reset_sequences
216+
serialized_rollback = _serialized_rollback
217+
if _databases is not None:
218+
databases = _databases
219+
if _available_apps is not None:
220+
available_apps = _available_apps
221+
222+
# For non-transactional tests, skip executing `django.test.TestCase`'s
223+
# `setUpClass`/`tearDownClass`, only execute the super class ones.
224+
#
225+
# `TestCase`'s class setup manages the `setUpTestData`/class-level
226+
# transaction functionality. We don't use it; instead we (will) offer
227+
# our own alternatives. So it only adds overhead, and does some things
228+
# which conflict with our (planned) functionality, particularly, it
229+
# closes all database connections in `tearDownClass` which inhibits
230+
# wrapping tests in higher-scoped transactions.
231+
#
232+
# It's possible a new version of Django will add some unrelated
233+
# functionality to these methods, in which case skipping them completely
234+
# would not be desirable. Let's cross that bridge when we get there...
235+
if not transactional:
236+
237+
@classmethod
238+
def setUpClass(cls) -> None:
239+
super(django.test.TestCase, cls).setUpClass()
240+
241+
@classmethod
242+
def tearDownClass(cls) -> None:
243+
super(django.test.TestCase, cls).tearDownClass()
244+
245+
PytestDjangoTestCase.setUpClass()
246+
247+
test_case = PytestDjangoTestCase(methodName="__init__")
248+
test_case._pre_setup()
252249

253-
test_case._post_teardown()
250+
yield
254251

255-
PytestDjangoTestCase.tearDownClass()
252+
test_case._post_teardown()
256253

257-
PytestDjangoTestCase.doClassCleanups()
254+
PytestDjangoTestCase.tearDownClass()
258255

259-
django_db_blocker.restore()
256+
PytestDjangoTestCase.doClassCleanups()
260257

261258

262259
def validate_django_db(marker: pytest.Mark) -> _DjangoDb:

0 commit comments

Comments
 (0)