Skip to content

Commit 0ae9fed

Browse files
brandon-wadaclaudeAuto-format Bot
authored
Add delete_detector method to Groundlight SDK (#370)
Implement delete_detector() method in client.py --------- Co-authored-by: Claude <[email protected]> Co-authored-by: Auto-format Bot <[email protected]>
1 parent 3c9804f commit 0ae9fed

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

src/groundlight/client.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,6 +1460,43 @@ def update_detector_escalation_type(self, detector: Union[str, Detector], escala
14601460
patched_detector_request=PatchedDetectorRequest(escalation_type=escalation_type),
14611461
)
14621462

1463+
def delete_detector(self, detector: Union[str, Detector]) -> None:
1464+
"""
1465+
Delete a detector. This permanently removes the detector and all its associated data.
1466+
1467+
.. warning::
1468+
This operation is irreversible. Once a detector is deleted, it cannot be recovered.
1469+
All associated image queries and training data will also be permanently deleted.
1470+
1471+
**Example usage**::
1472+
1473+
gl = Groundlight()
1474+
1475+
# Using a detector object
1476+
detector = gl.get_detector("det_abc123")
1477+
gl.delete_detector(detector)
1478+
1479+
# Using a detector ID string directly
1480+
gl.delete_detector("det_abc123")
1481+
1482+
:param detector: Either a Detector object or a detector ID string starting with "det_".
1483+
The detector to delete.
1484+
1485+
:return: None
1486+
:raises NotFoundError: If the detector with the given ID does not exist
1487+
:raises ApiTokenError: If API token is invalid
1488+
:raises GroundlightClientError: For other API errors
1489+
"""
1490+
if isinstance(detector, Detector):
1491+
detector_id = detector.id
1492+
else:
1493+
detector_id = str(detector)
1494+
1495+
try:
1496+
self.detectors_api.delete_detector(id=detector_id, _request_timeout=DEFAULT_REQUEST_TIMEOUT)
1497+
except NotFoundException as e:
1498+
raise NotFoundError(f"Detector with id '{detector_id}' not found") from e
1499+
14631500
def create_counting_detector( # noqa: PLR0913 # pylint: disable=too-many-arguments, too-many-locals
14641501
self,
14651502
name: str,

test/integration/test_groundlight.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from groundlight.internalapi import ApiException, InternalApiError, NotFoundError
1515
from groundlight.optional_imports import *
1616
from groundlight.status_codes import is_user_error
17+
from groundlight_openapi_client.exceptions import NotFoundException
1718
from ksuid import KsuidMs
1819
from model import (
1920
BinaryClassificationResult,
@@ -848,3 +849,42 @@ def test_multiclass_detector(gl: Groundlight):
848849
mc_iq = gl.submit_image_query(created_detector, "test/assets/dog.jpeg")
849850
assert mc_iq.result.label is not None
850851
assert mc_iq.result.label in class_names
852+
853+
854+
def test_delete_detector(gl: Groundlight):
855+
"""
856+
Test deleting a detector by both ID and object, and verify proper error handling.
857+
"""
858+
# Create a detector to delete
859+
name = f"Test delete detector {datetime.utcnow()}"
860+
query = "Is there a dog to delete?"
861+
pipeline_config = "never-review"
862+
detector = gl.create_detector(name=name, query=query, pipeline_config=pipeline_config)
863+
864+
# Delete using detector object
865+
gl.delete_detector(detector)
866+
867+
# Verify the detector is actually deleted
868+
with pytest.raises(NotFoundError):
869+
gl.get_detector(detector.id)
870+
871+
# Create another detector to test deletion by ID string and that an attached image query is deleted
872+
name2 = f"Test delete detector 2 {datetime.utcnow()}"
873+
detector2 = gl.create_detector(name=name2, query=query, pipeline_config=pipeline_config)
874+
gl.submit_image_query(detector2, "test/assets/dog.jpeg")
875+
876+
# Delete using detector ID string
877+
gl.delete_detector(detector2.id)
878+
879+
# Verify the second detector is also deleted
880+
with pytest.raises(NotFoundError):
881+
gl.get_detector(detector2.id)
882+
883+
# Verify the image query is also deleted
884+
with pytest.raises(NotFoundException):
885+
gl.get_image_query(detector2.id)
886+
887+
# Test deleting a non-existent detector raises NotFoundError
888+
fake_detector_id = "det_fake123456789"
889+
with pytest.raises(NotFoundError):
890+
gl.delete_detector(fake_detector_id) # type: ignore

0 commit comments

Comments
 (0)