Skip to content

Commit 5dd2aa1

Browse files
CarliJoyclaude
authored andcommitted
fix(weaviate): update and fix module
- Version bump 1.24.5 -> 1.28.4 - Add dedicated RFC1918 network (10.10.10.0/24) so Weaviate's memberlist gossip always advertises a private IP - Switch container config from CLI args to env vars - Replace _connect() + wait_container_is_ready with HttpWaitStrategy - Use DockerContainer as base class instead of DbContainer - fix(image): assert _image not None in get_wrapped_image() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 2007f43 commit 5dd2aa1

2 files changed

Lines changed: 39 additions & 18 deletions

File tree

src/testcontainers/community/weaviate/__init__.py

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@
1010
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1111
# License for the specific language governing permissions and limitations
1212
# under the License.
13-
from typing import TYPE_CHECKING, Optional
13+
import contextlib
14+
from typing import Optional
1415

15-
from requests import ConnectionError, get
16-
from testcontainers.core.generic import DbContainer
17-
from testcontainers.core.waiting_utils import wait_container_is_ready
16+
from docker.types import IPAMConfig, IPAMPool
17+
from testcontainers.core.container import DockerContainer
18+
from testcontainers.core.network import Network
19+
from testcontainers.core.wait_strategies import HttpWaitStrategy
20+
from typing_extensions import Self
1821

19-
if TYPE_CHECKING:
20-
from requests import Response
2122

22-
23-
class WeaviateContainer(DbContainer):
23+
class WeaviateContainer(DockerContainer):
2424
"""
2525
Weaviate vector database container.
2626
@@ -62,30 +62,46 @@ class WeaviateContainer(DbContainer):
6262

6363
def __init__(
6464
self,
65-
image: str = "semitechnologies/weaviate:1.24.5",
65+
image: str = "semitechnologies/weaviate:1.28.4",
6666
env_vars: Optional[dict[str, str]] = None,
6767
**kwargs,
6868
) -> None:
6969
super().__init__(image, **kwargs)
7070
self._http_port = 8080
7171
self._grpc_port = 50051
7272

73-
self.with_command(f"--host 0.0.0.0 --scheme http --port {self._http_port}")
73+
# Weaviate's memberlist gossip requires an RFC1918 private IP to advertise.
74+
# Docker bridge subnets are not always in RFC1918 ranges, so we create a
75+
# dedicated network using 10.10.10.0/24 which is always recognised as private.
76+
self._weaviate_network = Network(
77+
docker_network_kw={"ipam": IPAMConfig(pool_configs=[IPAMPool(subnet="10.10.10.0/24")])}
78+
)
79+
self.with_network(self._weaviate_network)
7480
self.with_exposed_ports(self._http_port, self._grpc_port)
81+
self.waiting_for(HttpWaitStrategy(self._http_port, "/v1/.well-known/ready"))
7582

7683
if env_vars is not None:
7784
for key, value in env_vars.items():
7885
self.with_env(key, value)
7986

8087
def _configure(self) -> None:
88+
self.with_env("HOST", "0.0.0.0")
89+
self.with_env("PORT", str(self._http_port))
90+
self.with_env("SCHEME", "http")
8191
self.with_env("AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED", "true")
8292
self.with_env("PERSISTENCE_DATA_PATH", "/var/lib/weaviate")
83-
84-
@wait_container_is_ready(ConnectionError)
85-
def _connect(self) -> None:
86-
url = f"http://{self.get_http_host()}:{self.get_http_port()}/v1/.well-known/ready"
87-
response: Response = get(url)
88-
response.raise_for_status()
93+
self.with_env("DEFAULT_VECTORIZER_MODULE", "none")
94+
self.with_env("CLUSTER_HOSTNAME", "node1")
95+
96+
def start(self) -> Self:
97+
self._weaviate_network.create()
98+
return super().start()
99+
100+
def stop(self, force: bool = True, delete_volume: bool = True) -> None:
101+
super().stop(force=force, delete_volume=delete_volume)
102+
if self._weaviate_network._network is not None:
103+
with contextlib.suppress(Exception):
104+
self._weaviate_network.remove()
89105

90106
def get_client(
91107
self,

src/testcontainers/core/image.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from types import TracebackType
33
from typing import TYPE_CHECKING, Any, Optional, Union
44

5+
import docker.errors
56
from typing_extensions import Self
67

78
from testcontainers.core.docker_client import DockerClient
@@ -85,8 +86,11 @@ def remove(self, force: bool = True, noprune: bool = False) -> None:
8586
:param noprune: Do not delete untagged parent images
8687
"""
8788
if self._image and self.clean_up:
88-
logger.info(f"Removing image {self.short_id}")
89-
self._image.remove(force=force, noprune=noprune)
89+
try:
90+
logger.info(f"Removing image {self.short_id}")
91+
self._image.remove(force=force, noprune=noprune)
92+
except docker.errors.NotFound:
93+
logger.debug(f"Image {self.short_id} already removed")
9094
self.get_docker_client().client.close()
9195

9296
def __str__(self) -> str:
@@ -101,6 +105,7 @@ def __exit__(
101105
self.remove()
102106

103107
def get_wrapped_image(self) -> "Image":
108+
assert self._image is not None
104109
return self._image
105110

106111
def get_docker_client(self) -> DockerClient:

0 commit comments

Comments
 (0)