Repository: aiidalab/aiidalab-launch (language: python)

Issue:
Don't fail startup if image cannot be downloaded from Dockerhub
I am working with a locally built Docker image and it is a little annoying to have to specify `--no-pull` on each startup. I think it would be a reasonable behaviour to emit a warning when the image cannot be downloaded but continue with the local one (if available).


Discussion / hints:
> I am working with a locally built Docker image and it is a little annoying to have to specify `--no-pull` on each startup. I think it would be a reasonable behaviour to emit a warning when the image cannot be downloaded but continue with the local one (if available).

Agreed, I've ran into this many times as well. I see that you have already assigned it to yourself, but please let me know if you need any assistance.

Fix patch:
diff --git a/aiidalab_launch/__main__.py b/aiidalab_launch/__main__.py
index 552f013..2015258 100644
--- a/aiidalab_launch/__main__.py
+++ b/aiidalab_launch/__main__.py
@@ -327,17 +327,15 @@ async def _async_start(
 
     # Obtain image (either via pull or local).
     if pull:
-        try:
-            msg = (
-                f"Downloading image '{instance.profile.image}', this may take a while..."
-                if instance.image is None
-                else f"Downloading latest version of '{instance.profile.image}'..."
-            )
-            with spinner(msg):
-                instance.pull()
-        except RuntimeError as error:
-            raise click.ClickException(str(error))
-    elif instance.image is None:
+        msg = (
+            f"Downloading image '{instance.profile.image}', this may take a while..."
+            if instance.image is None
+            else f"Downloading latest version of '{instance.profile.image}'..."
+        )
+        with spinner(msg):
+            instance.pull()
+
+    if instance.image is None:
         raise click.ClickException(
             f"Unable to find image '{profile.image}'. "
             "Try to use '--pull' to pull the image prior to start."
diff --git a/aiidalab_launch/instance.py b/aiidalab_launch/instance.py
index 16d8aa6..4cb3b12 100644
--- a/aiidalab_launch/instance.py
+++ b/aiidalab_launch/instance.py
@@ -151,14 +151,15 @@ def configuration_changes(self) -> Generator[str, None, None]:
         if self.profile != Profile.from_container(self.container):
             yield "Profile configuration has changed."
 
-    def pull(self) -> docker.models.images.Image:
+    def pull(self) -> docker.models.images.Image | None:
         try:
             image = self.client.images.pull(self.profile.image)
             LOGGER.info(f"Pulled image: {image}")
             self._image = image
             return image
         except docker.errors.NotFound:
-            raise RuntimeError(f"Unable to pull image: {self.profile.image}")
+            LOGGER.warn(f"Unable to pull image: {self.profile.image}")
+            return None
 
     def _ensure_home_mount_exists(self) -> None:
         if self.profile.home_mount:


Test patch:
diff --git a/tests/test_instance.py b/tests/test_instance.py
index 4bda23e..18670f0 100644
--- a/tests/test_instance.py
+++ b/tests/test_instance.py
@@ -27,11 +27,13 @@ def test_instance_pull(instance, enable_docker_pull):
         .pull()
         .tags
     )
-    with pytest.raises(RuntimeError):
+    assert (
         replace(
             instance,
             profile=replace(instance.profile, image="hello-world:no-valid-tag"),
         ).pull()
+        is None
+    )
 
 
 def test_instance_unknown_image(instance, invalid_image_id):