Skip to content

Commit e1d62f5

Browse files
Disallow nesting of part_of_a_transaction
Add durable=True to the atomic call inside part_of_a_transaction so that nesting is explicitly disallowed. This prevents tests from looking like they nest partial-transaction behaviour, which does not reflect real-world usage. Fixes #150 Co-authored-by: Charlie Denton <charlie@meshy.co.uk>
1 parent d0977ae commit e1d62f5

3 files changed

Lines changed: 41 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
88
## [Unreleased]
99

1010
- Added MariaDB and SQLite to the test matrix.
11+
- Disallowed nesting of `part_of_a_transaction` to prevent nonsense
12+
implication of nested partial transactions in tests. Fixes #150.
1113

1214
## [1.0.0] - 2026-04-16
1315

src/django_subatomic/test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ def part_of_a_transaction(using: str | None = None) -> Generator[None]:
3232
Note that this does not handle after-commit callback simulation. If you need that,
3333
use [`transaction`][django_subatomic.db.transaction] instead.
3434
"""
35-
with transaction.atomic(using=using):
35+
with transaction.atomic(using=using, durable=True):
3636
yield

tests/test_test.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
from __future__ import annotations
22

3+
import re
4+
from typing import TYPE_CHECKING
5+
36
import pytest
7+
from django.db import transaction as django_transaction
48

59
from django_subatomic import db, test
610

711

812
DEFAULT = "default"
913
pytestmark = [pytest.mark.django_db(databases=[DEFAULT])]
1014

15+
if TYPE_CHECKING:
16+
import contextlib
17+
from typing import Protocol
18+
19+
class DBContextManager(Protocol):
20+
def __call__(
21+
self, *, using: str | None = None
22+
) -> contextlib.AbstractContextManager[None, None]: ...
23+
1124

1225
class TestPartOfATransaction:
1326
"""
@@ -35,3 +48,28 @@ def _callback_which_should_not_be_called() -> None:
3548

3649
with test.part_of_a_transaction():
3750
db.run_after_commit(_callback_which_should_not_be_called)
51+
52+
@pytest.mark.parametrize(
53+
"transaction_manager",
54+
(
55+
db.transaction,
56+
db.transaction_if_not_already,
57+
django_transaction.atomic,
58+
test.part_of_a_transaction,
59+
),
60+
)
61+
def test_fails_when_nested_inside_an_atomic_block(
62+
self, transaction_manager: DBContextManager
63+
) -> None:
64+
"""
65+
`part_of_a_transaction` cannot be nested inside another atomic block.
66+
"""
67+
with transaction_manager():
68+
with pytest.raises(
69+
RuntimeError,
70+
match=re.escape(
71+
"A durable atomic block cannot be nested within another atomic block."
72+
),
73+
):
74+
with test.part_of_a_transaction():
75+
...

0 commit comments

Comments
 (0)