Skip to content

Commit 3e783a8

Browse files
authored
fix(core): multiple container start invocations with custom labels (#769)
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 3e783a8

File tree

2 files changed

+16
-6
lines changed

2 files changed

+16
-6
lines changed

core/testcontainers/core/labels.py

+9-6
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

+7
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)