Skip to content

Commit e8bf224

Browse files
authored
fix(core): Typing in docker_client (#702)
Supports: #305 Related : #691 #692 #700 Based on #504, kudos @alexanderankin ``` poetry run mypy --config-file pyproject.toml core/testcontainers/core/docker_client.py Success: no issues found in 1 source file ``` Old ``` Error Summary ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┓ ┃ File Path ┃ Errors ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━┩ │ core/testcontainers/core/version.py │ 12 │ │ core/testcontainers/core/docker_client.py │ 14 │ │ core/testcontainers/core/image.py │ 17 │ │ core/testcontainers/core/waiting_utils.py │ 8 │ │ core/testcontainers/core/container.py │ 20 │ │ core/tests/test_new_docker_api.py │ 4 │ │ core/tests/test_docker_in_docker.py │ 2 │ │ core/testcontainers/compose/compose.py │ 22 │ │ core/testcontainers/compose/__init__.py │ 2 │ │ core/tests/test_version.py │ 2 │ │ core/tests/test_ryuk.py │ 2 │ │ core/tests/test_registry.py │ 1 │ │ core/tests/test_image.py │ 3 │ │ core/tests/test_compose.py │ 7 │ └───────────────────────────────────────────┴────────┘ Found 116 errors in 14 files. ``` New ``` Error Summary ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┓ ┃ File Path ┃ Errors ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━┩ │ core/testcontainers/core/version.py │ 12 │ │ core/testcontainers/core/network.py │ 3 │ │ core/testcontainers/core/image.py │ 17 │ │ core/testcontainers/core/waiting_utils.py │ 8 │ │ core/testcontainers/core/container.py │ 19 │ │ core/tests/test_new_docker_api.py │ 4 │ │ core/tests/test_docker_in_docker.py │ 2 │ │ core/testcontainers/compose/compose.py │ 22 │ │ core/testcontainers/compose/__init__.py │ 2 │ │ core/tests/test_version.py │ 2 │ │ core/tests/test_ryuk.py │ 2 │ │ core/tests/test_registry.py │ 1 │ │ core/tests/test_image.py │ 3 │ │ core/tests/test_compose.py │ 7 │ └───────────────────────────────────────────┴────────┘ Found 104 errors in 14 files. ```
1 parent 9dc2a02 commit e8bf224

File tree

2 files changed

+21
-20
lines changed

2 files changed

+21
-20
lines changed

core/testcontainers/core/config.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def use_mapped_port(self) -> bool:
2121
2222
This is true for everything but bridge mode.
2323
"""
24-
if self == self.bridge_ip:
24+
if self == self.bridge_ip: # type: ignore[comparison-overlap]
2525
return False
2626
return True
2727

@@ -63,7 +63,7 @@ def get_user_overwritten_connection_mode() -> Optional[ConnectionMode]:
6363
"""
6464
Return the user overwritten connection mode.
6565
"""
66-
connection_mode: str | None = environ.get("TESTCONTAINERS_CONNECTION_MODE")
66+
connection_mode: Union[str, None] = environ.get("TESTCONTAINERS_CONNECTION_MODE")
6767
if connection_mode:
6868
try:
6969
return ConnectionMode(connection_mode)

core/testcontainers/core/docker_client.py

+19-18
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import urllib
2020
import urllib.parse
2121
from collections.abc import Iterable
22-
from typing import Callable, Optional, TypeVar, Union
22+
from typing import Any, Callable, Optional, TypeVar, Union, cast
2323

2424
import docker
2525
from docker.models.containers import Container, ContainerCollection
@@ -59,7 +59,7 @@ class DockerClient:
5959
Thin wrapper around :class:`docker.DockerClient` for a more functional interface.
6060
"""
6161

62-
def __init__(self, **kwargs) -> None:
62+
def __init__(self, **kwargs: Any) -> None:
6363
docker_host = get_docker_host()
6464

6565
if docker_host:
@@ -82,14 +82,14 @@ def run(
8282
self,
8383
image: str,
8484
command: Optional[Union[str, list[str]]] = None,
85-
environment: Optional[dict] = None,
86-
ports: Optional[dict] = None,
85+
environment: Optional[dict[str, str]] = None,
86+
ports: Optional[dict[int, Optional[int]]] = None,
8787
labels: Optional[dict[str, str]] = None,
8888
detach: bool = False,
8989
stdout: bool = True,
9090
stderr: bool = False,
9191
remove: bool = False,
92-
**kwargs,
92+
**kwargs: Any,
9393
) -> Container:
9494
# If the user has specified a network, we'll assume the user knows best
9595
if "network" not in kwargs and not get_docker_host():
@@ -112,7 +112,7 @@ def run(
112112
return container
113113

114114
@_wrapped_image_collection
115-
def build(self, path: str, tag: str, rm: bool = True, **kwargs) -> tuple[Image, Iterable[dict]]:
115+
def build(self, path: str, tag: str, rm: bool = True, **kwargs: Any) -> tuple[Image, Iterable[dict[str, Any]]]:
116116
"""
117117
Build a Docker image from a directory containing the Dockerfile.
118118
@@ -151,43 +151,43 @@ def find_host_network(self) -> Optional[str]:
151151
except ipaddress.AddressValueError:
152152
continue
153153
if docker_host in subnet:
154-
return network.name
154+
return cast(str, network.name)
155155
except (ipaddress.AddressValueError, OSError):
156156
pass
157157
return None
158158

159-
def port(self, container_id: str, port: int) -> int:
159+
def port(self, container_id: str, port: int) -> str:
160160
"""
161161
Lookup the public-facing port that is NAT-ed to :code:`port`.
162162
"""
163163
port_mappings = self.client.api.port(container_id, port)
164164
if not port_mappings:
165165
raise ConnectionError(f"Port mapping for container {container_id} and port {port} is " "not available")
166-
return port_mappings[0]["HostPort"]
166+
return cast(str, port_mappings[0]["HostPort"])
167167

168-
def get_container(self, container_id: str) -> Container:
168+
def get_container(self, container_id: str) -> dict[str, Any]:
169169
"""
170170
Get the container with a given identifier.
171171
"""
172172
containers = self.client.api.containers(filters={"id": container_id})
173173
if not containers:
174174
raise RuntimeError(f"Could not get container with id {container_id}")
175-
return containers[0]
175+
return cast(dict[str, Any], containers[0])
176176

177177
def bridge_ip(self, container_id: str) -> str:
178178
"""
179179
Get the bridge ip address for a container.
180180
"""
181181
container = self.get_container(container_id)
182182
network_name = self.network_name(container_id)
183-
return container["NetworkSettings"]["Networks"][network_name]["IPAddress"]
183+
return str(container["NetworkSettings"]["Networks"][network_name]["IPAddress"])
184184

185185
def network_name(self, container_id: str) -> str:
186186
"""
187187
Get the name of the network this container runs on
188188
"""
189189
container = self.get_container(container_id)
190-
name = container["HostConfig"]["NetworkMode"]
190+
name = str(container["HostConfig"]["NetworkMode"])
191191
if name == "default":
192192
return "bridge"
193193
return name
@@ -198,7 +198,7 @@ def gateway_ip(self, container_id: str) -> str:
198198
"""
199199
container = self.get_container(container_id)
200200
network_name = self.network_name(container_id)
201-
return container["NetworkSettings"]["Networks"][network_name]["Gateway"]
201+
return str(container["NetworkSettings"]["Networks"][network_name]["Gateway"])
202202

203203
def get_connection_mode(self) -> ConnectionMode:
204204
"""
@@ -235,9 +235,10 @@ def host(self) -> str:
235235
return "localhost"
236236
if "http" in url.scheme or "tcp" in url.scheme and url.hostname:
237237
# see https://github.com/testcontainers/testcontainers-python/issues/415
238-
if url.hostname == "localnpipe" and utils.is_windows():
238+
hostname = url.hostname
239+
if not hostname or (hostname == "localnpipe" and utils.is_windows()):
239240
return "localhost"
240-
return url.hostname
241+
return cast(str, url.hostname)
241242
if utils.inside_container() and ("unix" in url.scheme or "npipe" in url.scheme):
242243
ip_address = utils.default_gateway_ip()
243244
if ip_address:
@@ -251,9 +252,9 @@ def login(self, auth_config: DockerAuthInfo) -> None:
251252
login_info = self.client.login(**auth_config._asdict())
252253
LOGGER.debug(f"logged in using {login_info}")
253254

254-
def client_networks_create(self, name: str, param: dict):
255+
def client_networks_create(self, name: str, param: dict[str, Any]) -> dict[str, Any]:
255256
labels = create_labels("", param.get("labels"))
256-
return self.client.networks.create(name, **{**param, "labels": labels})
257+
return cast(dict[str, Any], self.client.networks.create(name, **{**param, "labels": labels}))
257258

258259

259260
def get_docker_host() -> Optional[str]:

0 commit comments

Comments
 (0)