forked from testcontainers/testcontainers-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(core): Image build (Dockerfile support) (testcontainers#585)
As part of the effort described, detailed and presented on testcontainers#559 (Providing the implementation for testcontainers#83 - Docker file support and more) This is the first PR (out of 4) that should provide all the groundwork to support image build. This would allow users to use custom images: ```python with DockerImage(path=".") as image: with DockerContainer(str(image)) as container: # Test something with/on custom image ``` Next in line is: `feat(core): Added SrvContainer` And later on: `feat(core): Added FastAPI module` `feat(core): Added AWS Lambda module` (all of the above can be overviewed on testcontainers#559)
- Loading branch information
1 parent
a95af7d
commit 54c88cf
Showing
8 changed files
with
190 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
from typing import TYPE_CHECKING, Optional | ||
|
||
from typing_extensions import Self | ||
|
||
from testcontainers.core.docker_client import DockerClient | ||
from testcontainers.core.utils import setup_logger | ||
|
||
if TYPE_CHECKING: | ||
from docker.models.containers import Image | ||
|
||
logger = setup_logger(__name__) | ||
|
||
|
||
class DockerImage: | ||
""" | ||
Basic image object to build Docker images. | ||
.. doctest:: | ||
>>> from testcontainers.core.image import DockerImage | ||
>>> with DockerImage(path="./core/tests/image_fixtures/sample/", tag="test-image") as image: | ||
... logs = image.get_logs() | ||
:param tag: Tag for the image to be built (default: None) | ||
:param path: Path to the Dockerfile to build the image | ||
""" | ||
|
||
def __init__( | ||
self, | ||
path: str, | ||
docker_client_kw: Optional[dict] = None, | ||
tag: Optional[str] = None, | ||
clean_up: bool = True, | ||
**kwargs, | ||
) -> None: | ||
self.tag = tag | ||
self.path = path | ||
self.id = None | ||
self._docker = DockerClient(**(docker_client_kw or {})) | ||
self.clean_up = clean_up | ||
self._kwargs = kwargs | ||
|
||
def build(self, **kwargs) -> Self: | ||
logger.info(f"Building image from {self.path}") | ||
docker_client = self.get_docker_client() | ||
self._image, self._logs = docker_client.build(path=self.path, tag=self.tag, **kwargs) | ||
logger.info(f"Built image {self.short_id} with tag {self.tag}") | ||
return self | ||
|
||
@property | ||
def short_id(self) -> str: | ||
""" | ||
The ID of the image truncated to 12 characters, without the ``sha256:`` prefix. | ||
""" | ||
if self._image.id.startswith("sha256:"): | ||
return self._image.id.split(":")[1][:12] | ||
return self._image.id[:12] | ||
|
||
def remove(self, force=True, noprune=False) -> None: | ||
""" | ||
Remove the image. | ||
:param force: Remove the image even if it is in use | ||
:param noprune: Do not delete untagged parent images | ||
""" | ||
if self._image and self.clean_up: | ||
logger.info(f"Removing image {self.short_id}") | ||
self._image.remove(force=force, noprune=noprune) | ||
self.get_docker_client().client.close() | ||
|
||
def __str__(self) -> str: | ||
return f"{self.tag if self.tag else self.short_id}" | ||
|
||
def __enter__(self) -> Self: | ||
return self.build() | ||
|
||
def __exit__(self, exc_type, exc_val, exc_tb) -> None: | ||
self.remove() | ||
|
||
def get_wrapped_image(self) -> "Image": | ||
return self._image | ||
|
||
def get_docker_client(self) -> DockerClient: | ||
return self._docker | ||
|
||
def get_logs(self) -> list[dict]: | ||
return list(self._logs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import pytest | ||
from typing import Callable | ||
from testcontainers.core.container import DockerClient | ||
|
||
|
||
@pytest.fixture | ||
def check_for_image() -> Callable[[str, bool], None]: | ||
"""Warp the check_for_image function in a fixture""" | ||
|
||
def _check_for_image(image_short_id: str, cleaned: bool) -> None: | ||
""" | ||
Validates if the image is present or not. | ||
:param image_short_id: The short id of the image | ||
:param cleaned: True if the image should not be present, False otherwise | ||
""" | ||
client = DockerClient() | ||
images = client.client.images.list() | ||
found = any(image.short_id.endswith(image_short_id) for image in images) | ||
assert found is not cleaned, f'Image {image_short_id} was {"found" if cleaned else "not found"}' | ||
|
||
return _check_for_image |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
FROM alpine:latest | ||
CMD echo "Test Sample Image" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters