Skip to content

Commit 5045e04

Browse files
committed
Fix for multiple container start invocations with custom labels
When invoking .start() multiple times on the same DockerContainer instance, the call fails with "ValueError: The org.testcontainers namespace is reserved for internal use" error. Example code: ``` from testcontainers.core.container import DockerContainer container = DockerContainer("alpine:latest").with_kwargs(labels={}) container.start() container.stop() container.start() ``` The fix is to update labels for the container in a copy of the user-provided dictionary, so that: * the code doesn't mutate user structures * avoid side effects, allowing for multiple .start() invocations
1 parent 9317736 commit 5045e04

File tree

2 files changed

+16
-6
lines changed

2 files changed

+16
-6
lines changed

core/testcontainers/core/labels.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,15 @@ def create_labels(image: str, labels: Optional[dict[str, str]]) -> dict[str, str
2121
if k.startswith(TESTCONTAINERS_NAMESPACE):
2222
raise ValueError("The org.testcontainers namespace is reserved for internal use")
2323

24-
labels[LABEL_LANG] = "python"
25-
labels[LABEL_TESTCONTAINERS] = "true"
26-
labels[LABEL_VERSION] = importlib.metadata.version("testcontainers")
24+
tc_labels = {
25+
**labels,
26+
LABEL_LANG: "python",
27+
LABEL_TESTCONTAINERS: "true",
28+
LABEL_VERSION: importlib.metadata.version("testcontainers"),
29+
}
2730

2831
if image == c.ryuk_image:
29-
return labels
32+
return tc_labels
3033

31-
labels[LABEL_SESSION_ID] = SESSION_ID
32-
return labels
34+
tc_labels[LABEL_SESSION_ID] = SESSION_ID
35+
return tc_labels

core/tests/test_labels.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,10 @@ def test_session_are_module_import_scoped():
5656
assert LABEL_SESSION_ID in first_labels
5757
assert LABEL_SESSION_ID in second_labels
5858
assert first_labels[LABEL_SESSION_ID] == second_labels[LABEL_SESSION_ID]
59+
60+
61+
def test_create_no_side_effects():
62+
input_labels = {"key": "value"}
63+
expected_labels = input_labels.copy()
64+
create_labels("not-ryuk", {"key": "value"})
65+
assert input_labels == expected_labels, input_labels

0 commit comments

Comments
 (0)