From 6c9b2bae1e1ce59c1e6cd6cb919d591fbfa51c00 Mon Sep 17 00:00:00 2001
From: Dan Frank <danielhfrank@gmail.com>
Date: Tue, 2 Jul 2024 14:36:35 -0700
Subject: [PATCH] Implement custom exceptions for specific error situations
 (#60)

---
 articat/catalog.py                      |  7 +++++--
 articat/exceptions.py                   |  4 ++++
 articat/tests/catalog_datastore_test.py |  5 +++--
 articat/tests/catalog_local_test.py     | 13 +++++++++++++
 articat/tests/utils_test.py             |  1 -
 5 files changed, 25 insertions(+), 5 deletions(-)
 create mode 100644 articat/exceptions.py
 create mode 100644 articat/tests/catalog_local_test.py

diff --git a/articat/catalog.py b/articat/catalog.py
index eccf082..fa7878e 100644
--- a/articat/catalog.py
+++ b/articat/catalog.py
@@ -7,6 +7,7 @@
 
 from articat.artifact import ID, Artifact, Metadata, Partition, Version, not_supplied
 from articat.config import ArticatConfig, ConfigMixin
+from articat.exceptions import MissingArtifactException
 
 logger = logging.getLogger(__name__)
 
@@ -114,7 +115,9 @@ def get(  # type: ignore[no-untyped-def]
             )
         except StopIteration as e:
             req = {"id": id, "partition": partition, "version": version, "dev": dev}
-            raise ValueError(f"Can't find requested artifact {req}") from e
+            raise MissingArtifactException(
+                f"Can't find requested artifact {req}"
+            ) from e
 
     @classmethod
     @overload
@@ -142,7 +145,7 @@ def latest_partition(  # type: ignore[no-untyped-def]
                 )
             )
         except StopIteration as e:
-            raise ValueError(f"Can't find requested artifact {id}") from e
+            raise MissingArtifactException(f"Can't find requested artifact {id}") from e
 
     @classmethod
     @overload
diff --git a/articat/exceptions.py b/articat/exceptions.py
new file mode 100644
index 0000000..3fd886e
--- /dev/null
+++ b/articat/exceptions.py
@@ -0,0 +1,4 @@
+class MissingArtifactException(ValueError):
+    """Exception raised when an artifact cannot be found."""
+
+    pass
diff --git a/articat/tests/catalog_datastore_test.py b/articat/tests/catalog_datastore_test.py
index aa27b50..17821ca 100644
--- a/articat/tests/catalog_datastore_test.py
+++ b/articat/tests/catalog_datastore_test.py
@@ -7,6 +7,7 @@
 from dateutil.tz import UTC
 
 from articat.artifact import EXECUTION_URL_ENV_NAME, ID, Metadata
+from articat.exceptions import MissingArtifactException
 from articat.fs_artifact import FSArtifact
 from articat.tests.utils import (
     TestCatalog,
@@ -234,12 +235,12 @@ def test_catalog_latest_partition(uid: ID) -> None:
 
 
 def test_catalog_get_nice_error_on_missing_get(uid: ID) -> None:
-    with pytest.raises(ValueError, match="Can't find requested artifact"):
+    with pytest.raises(MissingArtifactException, match="Can't find requested artifact"):
         TestCatalog.get(uid, version="0.1.1")
 
 
 def test_catalog_get_nice_error_on_missing_latest(uid: ID) -> None:
-    with pytest.raises(ValueError, match="Can't find requested artifact"):
+    with pytest.raises(MissingArtifactException, match="Can't find requested artifact"):
         TestCatalog.latest_partition(uid)
 
 
diff --git a/articat/tests/catalog_local_test.py b/articat/tests/catalog_local_test.py
new file mode 100644
index 0000000..0b39707
--- /dev/null
+++ b/articat/tests/catalog_local_test.py
@@ -0,0 +1,13 @@
+import pytest
+
+from articat.catalog_local import CatalogLocal
+from articat.exceptions import MissingArtifactException
+
+
+def test_catalog_local_missing_artifact_exception():
+    """
+    Test that `MissingArtifactException` is raised when an artifact cannot be found in `CatalogLocal`.
+    """
+    catalog = CatalogLocal()
+    with pytest.raises(MissingArtifactException, match="Can't find requested artifact"):
+        catalog.get("non_existing_artifact_id")
diff --git a/articat/tests/utils_test.py b/articat/tests/utils_test.py
index c70125b..3f736be 100644
--- a/articat/tests/utils_test.py
+++ b/articat/tests/utils_test.py
@@ -15,7 +15,6 @@
 from articat.utils.typing import PathType
 from articat.utils.utils import download_artifact, dummy_unsafe_cache, get_repo_and_hash
 
-
 def get_source_path_that_looks_like_path_from_catalog() -> Path:
     p = Path(
         tempfile.mkdtemp(dir=TestFSArtifact.config().fs_prod_prefix(), suffix="__ID__")