From bf214e92303c612b6f180b7768631e5f4c4f6e39 Mon Sep 17 00:00:00 2001 From: Erle Carrara Date: Mon, 27 Oct 2025 19:53:13 +0200 Subject: [PATCH] feat: Add delete_images method to Project class and tests Add `delete_images` method to the Project class, allowing users to remove images from a project. Corresponding unit tests have been added to tests/test_project.py to ensure the method functions correctly for both successful deletions and error scenarios. --- roboflow/core/project.py | 28 ++++++++++++++++++++++++++ tests/test_project.py | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/roboflow/core/project.py b/roboflow/core/project.py index 922d7f9e..088c804f 100644 --- a/roboflow/core/project.py +++ b/roboflow/core/project.py @@ -969,3 +969,31 @@ def get_batch(self, batch_id: str) -> Dict: raise RuntimeError(f"Failed to get batch {batch_id}: {response.text}") return response.json() + + def delete_images(self, image_ids: List[str]): + """ + Delete images from a project. + + Args: + image_ids (List[str]): A list of image IDs to delete. + + Example: + >>> import roboflow + >>> rf = roboflow.Roboflow(api_key="") + >>> project = rf.workspace().project("PROJECT_ID") + >>> project.delete_images(image_ids=["image_id_1", "image_id_2"]) + """ + url = f"{API_URL}/{self.__workspace}/{self.__project_name}/images?api_key={self.__api_key}" + + payload = {"images": image_ids} + + response = requests.delete(url, headers={"Content-Type": "application/json"}, json=payload) + + if response.status_code != 204: + try: + error_data = response.json() + if "error" in error_data: + raise RuntimeError(error_data["error"]) + raise RuntimeError(response.text) + except ValueError: + raise RuntimeError(f"Failed to delete images: {response.text}") diff --git a/tests/test_project.py b/tests/test_project.py index e07c2b76..4568ed7e 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -591,6 +591,49 @@ def test_get_batch_error(self): self.assertEqual(str(context.exception), "Batch not found") + def test_delete_images_success(self): + image_ids = ["image1.jpg", "image2.jpg"] + expected_url = f"{API_URL}/{WORKSPACE_NAME}/{PROJECT_NAME}/images?api_key={ROBOFLOW_API_KEY}" + + responses.add( + responses.DELETE, + expected_url, + status=204, + match=[ + json_params_matcher( + { + "images": image_ids, + } + ) + ], + ) + + self.project.delete_images(image_ids=image_ids) + + def test_delete_images_error(self): + image_ids = ["image1.jpg", "image2.jpg"] + expected_url = f"{API_URL}/{WORKSPACE_NAME}/{PROJECT_NAME}/images?api_key={ROBOFLOW_API_KEY}" + error_response = {"error": "Failed to delete images"} + + responses.add( + responses.DELETE, + expected_url, + json=error_response, + status=400, + match=[ + json_params_matcher( + { + "images": image_ids, + } + ) + ], + ) + + with self.assertRaises(RuntimeError) as context: + self.project.delete_images(image_ids=image_ids) + + self.assertEqual(str(context.exception), "Failed to delete images") + def test_classification_dataset_upload(self): from roboflow.util import folderparser