Skip to content

Commit 847c42e

Browse files
committed
Merge branch 'main' into copy_file_tests
2 parents 1fd9831 + f608df9 commit 847c42e

File tree

21 files changed

+1733
-1389
lines changed

21 files changed

+1733
-1389
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "4.12.0"
2+
".": "4.13.2"
33
}

.github/workflows/ci-core.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
strategy:
1515
fail-fast: false
1616
matrix:
17-
python-version: ["3.9", "3.10", "3.11", "3.12"]
17+
python-version: ["3.9", "3.11", "3.12", "3.13"]
1818
steps:
1919
- uses: actions/checkout@v4
2020
- name: Set up Python
@@ -24,7 +24,7 @@ jobs:
2424
- name: Install Python dependencies
2525
run: poetry install --all-extras
2626
- name: Run twine check
27-
run: poetry build && poetry run twine check dist/*.tar.gz
27+
run: rm -f LICENSE.txt && poetry build && poetry run twine check dist/*.tar.gz
2828
- name: Set up Docker
2929
uses: docker/setup-docker-action@v4
3030
- name: Run tests

CHANGELOG.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,41 @@
11
# Changelog
22

3+
## [4.13.2](https://github.com/testcontainers/testcontainers-python/compare/testcontainers-v4.13.1...testcontainers-v4.13.2) (2025-10-07)
4+
5+
6+
### Bug Fixes
7+
8+
* **core:** Fix issues with doctests ([#893](https://github.com/testcontainers/testcontainers-python/issues/893)) ([2e4d80a](https://github.com/testcontainers/testcontainers-python/commit/2e4d80ade5a2048c8bc79d7a2438004b8e0954e4))
9+
* **core:** waiting improvements + remove decorators in core ([#894](https://github.com/testcontainers/testcontainers-python/issues/894)) ([f93f379](https://github.com/testcontainers/testcontainers-python/commit/f93f379380a9de769fe6a1e1168622865cdf613d))
10+
* issue [#889](https://github.com/testcontainers/testcontainers-python/issues/889) by changing the annotated return type of `waiting_for` to `Self`. ([#890](https://github.com/testcontainers/testcontainers-python/issues/890)) ([fe941b1](https://github.com/testcontainers/testcontainers-python/commit/fe941b17bb97aad15dc4844996f166c9308f4476))
11+
* **mongo:** mongo start waiting forever for old mongo versions ([#783](https://github.com/testcontainers/testcontainers-python/issues/783)) ([1388612](https://github.com/testcontainers/testcontainers-python/commit/13886120e9cb72666a40ea3691ea13e584805918))
12+
* **redpanda:** copy the startup script to a path that can be written … ([#867](https://github.com/testcontainers/testcontainers-python/issues/867)) ([e6b976d](https://github.com/testcontainers/testcontainers-python/commit/e6b976de43fc6fe90d7131fd25983f9c6b08429b))
13+
* **trino:** Remove deprecated class and decorator from Trino container ([#895](https://github.com/testcontainers/testcontainers-python/issues/895)) ([bb646e9](https://github.com/testcontainers/testcontainers-python/commit/bb646e903236a1df72bc38dbb47d1dba95527198))
14+
15+
## [4.13.1](https://github.com/testcontainers/testcontainers-python/compare/testcontainers-v4.13.0...testcontainers-v4.13.1) (2025-09-24)
16+
17+
18+
### Bug Fixes
19+
20+
* **core:** Added 'compose' in compose_command_property ([#879](https://github.com/testcontainers/testcontainers-python/issues/879)) ([769b7b6](https://github.com/testcontainers/testcontainers-python/commit/769b7b688fe254cb8e38e05f453c4e3fe7999ad5))
21+
* **core:** make sure context manager exits ([#876](https://github.com/testcontainers/testcontainers-python/issues/876)) ([10089f6](https://github.com/testcontainers/testcontainers-python/commit/10089f6e2fe07e53cc47a69521e67a1bf3310065))
22+
23+
## [4.13.0](https://github.com/testcontainers/testcontainers-python/compare/testcontainers-v4.12.0...testcontainers-v4.13.0) (2025-08-27)
24+
25+
26+
### Features
27+
28+
* **azurite:** Enhance connection string generation for network and local access ([#859](https://github.com/testcontainers/testcontainers-python/issues/859)) ([b21e5e3](https://github.com/testcontainers/testcontainers-python/commit/b21e5e38075ddbd71fb4f97e843abc104dec6beb))
29+
* **core:** add enhanced wait strategies ([#855](https://github.com/testcontainers/testcontainers-python/issues/855)) ([60d21f8](https://github.com/testcontainers/testcontainers-python/commit/60d21f875f49f52e170b0714e8790080a6cb4c71))
30+
* **core:** DockerCompose: support list of env_files ([#847](https://github.com/testcontainers/testcontainers-python/issues/847)) ([fe206eb](https://github.com/testcontainers/testcontainers-python/commit/fe206eb48ee9e18623761926900bfc33a8a869a7))
31+
32+
33+
### Bug Fixes
34+
35+
* assert-in-get_container_host_ip-before-start ([#862](https://github.com/testcontainers/testcontainers-python/issues/862)) ([fc4155e](https://github.com/testcontainers/testcontainers-python/commit/fc4155eb70509ba236fff771c2f8973667acb098))
36+
* **core:** improper reading of .testcontainers.properties ([#863](https://github.com/testcontainers/testcontainers-python/issues/863)) ([350f246](https://github.com/testcontainers/testcontainers-python/commit/350f246a3b6367d727046b8967a63d1c055cf324))
37+
* **core:** Make TC_POOLING_INTERVAL/sleep_time a float ([#839](https://github.com/testcontainers/testcontainers-python/issues/839)) ([a072f3f](https://github.com/testcontainers/testcontainers-python/commit/a072f3fad46b3b3e7c5bea6255f27b79826aaf5f))
38+
339
## [4.12.0](https://github.com/testcontainers/testcontainers-python/compare/testcontainers-v4.11.0...testcontainers-v4.12.0) (2025-07-21)
440

541

core/testcontainers/compose/compose.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
from dataclasses import asdict, dataclass, field, fields, is_dataclass
23
from functools import cached_property
34
from json import loads
@@ -35,8 +36,7 @@ def _ignore_properties(cls: type[_IPT], dict_: Any) -> _IPT:
3536
@dataclass
3637
class PublishedPortModel:
3738
"""
38-
Class that represents the response we get from compose when inquiring status
39-
via `DockerCompose.get_running_containers()`.
39+
Class that represents the response we get from compose when inquiring status via `DockerCompose.get_running_containers()`.
4040
"""
4141

4242
URL: Optional[str] = None
@@ -223,8 +223,12 @@ def __post_init__(self) -> None:
223223
self.env_file = [self.env_file]
224224

225225
def __enter__(self) -> "DockerCompose":
226-
self.start()
227-
return self
226+
try:
227+
self.start()
228+
return self
229+
except: # noqa: E722, RUF100
230+
self.__exit__(*sys.exc_info())
231+
raise
228232

229233
def __exit__(
230234
self, exc_type: Optional[type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType]
@@ -242,7 +246,9 @@ def docker_compose_command(self) -> list[str]:
242246

243247
@cached_property
244248
def compose_command_property(self) -> list[str]:
245-
docker_compose_cmd = [self.docker_command_path] if self.docker_command_path else ["docker", "compose"]
249+
docker_compose_cmd = (
250+
[self.docker_command_path, "compose"] if self.docker_command_path else ["docker", "compose"]
251+
)
246252
if self.compose_file_name:
247253
for file in self.compose_file_name:
248254
docker_compose_cmd += ["-f", file]
@@ -256,6 +262,7 @@ def compose_command_property(self) -> list[str]:
256262
def waiting_for(self, strategies: dict[str, WaitStrategy]) -> "DockerCompose":
257263
"""
258264
Set wait strategies for specific services.
265+
259266
Args:
260267
strategies: Dictionary mapping service names to wait strategies
261268
"""

core/testcontainers/core/container.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import contextlib
22
import io
33
import pathlib
4+
import sys
45
import tarfile
56
from os import PathLike
67
from socket import socket
@@ -23,7 +24,7 @@
2324
from testcontainers.core.transferable import Transferable, TransferSpec
2425
from testcontainers.core.utils import is_arm, setup_logger
2526
from testcontainers.core.wait_strategies import LogMessageWaitStrategy
26-
from testcontainers.core.waiting_utils import WaitStrategy, wait_container_is_ready
27+
from testcontainers.core.waiting_utils import WaitStrategy
2728

2829
if TYPE_CHECKING:
2930
from docker.models.containers import Container
@@ -42,15 +43,11 @@ class DockerContainer:
4243
4344
Args:
4445
image: The name of the image to start.
45-
docker_client_kw: Dictionary with arguments that will be passed to the
46-
docker.DockerClient init.
46+
docker_client_kw: Dictionary with arguments that will be passed to the docker.DockerClient init.
4747
command: Optional execution command for the container.
4848
name: Optional name for the container.
49-
ports: Ports to be exposed by the container. The port number will be
50-
automatically assigned on the host, use
51-
:code:`get_exposed_port(PORT)` method to get the port number on the host.
52-
volumes: Volumes to mount into the container. Each entry should be a tuple with
53-
three values: host path, container path and. mode (default 'ro').
49+
ports: Ports to be exposed by the container. The port number will be automatically assigned on the host, use :code:`get_exposed_port(PORT)` method to get the port number on the host.
50+
volumes: Volumes to mount into the container. Each entry should be a tuple with three values: host path, container path and mode (default 'ro').
5451
network: Optional network to connect the container to.
5552
network_aliases: Optional list of aliases for the container in the network.
5653
@@ -178,7 +175,7 @@ def maybe_emulate_amd64(self) -> Self:
178175
return self.with_kwargs(platform="linux/amd64")
179176
return self
180177

181-
def waiting_for(self, strategy: WaitStrategy) -> "DockerContainer":
178+
def waiting_for(self, strategy: WaitStrategy) -> Self:
182179
"""Set a wait strategy to be used after container start."""
183180
self._wait_strategy = strategy
184181
return self
@@ -229,7 +226,11 @@ def stop(self, force: bool = True, delete_volume: bool = True) -> None:
229226
self.get_docker_client().client.close()
230227

231228
def __enter__(self) -> Self:
232-
return self.start()
229+
try:
230+
return self.start()
231+
except: # noqa: E722, RUF100
232+
self.__exit__(*sys.exc_info())
233+
raise
233234

234235
def __exit__(
235236
self, exc_type: Optional[type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType]
@@ -256,8 +257,13 @@ def get_container_host_ip(self) -> str:
256257
# ensure that we covered all possible connection_modes
257258
assert_never(connection_mode)
258259

259-
@wait_container_is_ready()
260260
def get_exposed_port(self, port: int) -> int:
261+
from testcontainers.core.wait_strategies import ContainerStatusWaitStrategy as C
262+
263+
C().wait_until_ready(self)
264+
return self._get_exposed_port(port)
265+
266+
def _get_exposed_port(self, port: int) -> int:
261267
if self.get_docker_client().get_connection_mode().use_mapped_port:
262268
c = self._container
263269
assert c is not None

core/testcontainers/core/docker_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ def get_container(self, container_id: str) -> dict[str, Any]:
174174
"""
175175
Get the container with a given identifier.
176176
"""
177-
containers = self.client.api.containers(filters={"id": container_id})
177+
containers = self.client.api.containers(all=True, filters={"id": container_id})
178178
if not containers:
179179
raise RuntimeError(f"Could not get container with id {container_id}")
180180
return cast("dict[str, Any]", containers[0])

core/testcontainers/core/generic.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from testcontainers.core.container import DockerContainer
1717
from testcontainers.core.exceptions import ContainerStartException
1818
from testcontainers.core.utils import raise_for_deprecated_parameter
19-
from testcontainers.core.waiting_utils import wait_container_is_ready
2019

2120
ADDITIONAL_TRANSIENT_ERRORS = []
2221
try:
@@ -34,8 +33,11 @@ class DbContainer(DockerContainer):
3433
Generic database container.
3534
"""
3635

37-
@wait_container_is_ready(*ADDITIONAL_TRANSIENT_ERRORS)
3836
def _connect(self) -> None:
37+
from testcontainers.core.wait_strategies import ContainerStatusWaitStrategy as C
38+
39+
C().with_transient_exceptions(*ADDITIONAL_TRANSIENT_ERRORS).wait_until_ready(self)
40+
3941
import sqlalchemy
4042

4143
engine = sqlalchemy.create_engine(self.get_connection_url())

0 commit comments

Comments
 (0)