diff --git a/roboflow/core/project.py b/roboflow/core/project.py index 05b1c773..2ce22a2f 100644 --- a/roboflow/core/project.py +++ b/roboflow/core/project.py @@ -409,6 +409,12 @@ def upload( metadata (dict, optional): custom key-value metadata to attach to the image. Example: {"camera_id": "cam001", "location": "warehouse"} + Returns: + For a single image: the dict returned by ``single_upload`` (keys: ``image``, + ``annotation``, ``upload_time``, ``annotation_time``, ``upload_retry_attempts``, + ``annotation_upload_retry_attempts``). For a directory: a list of such dicts, + one per successfully uploaded image. Skipped (non-image) files are excluded. + Example: >>> import roboflow @@ -445,7 +451,7 @@ def upload( ) ) - self.single_upload( + return self.single_upload( image_path=image_path, annotation_path=annotation_path, hosted_image=hosted_image, @@ -460,11 +466,12 @@ def upload( ) else: + results = [] images = os.listdir(image_path) for image in images: path = image_path + "/" + image if self.check_valid_image(path): - self.single_upload( + result = self.single_upload( image_path=path, annotation_path=annotation_path, hosted_image=hosted_image, @@ -477,10 +484,12 @@ def upload( metadata=metadata, **kwargs, ) + results.append(result) print("[ " + path + " ] was uploaded succesfully.") else: print("[ " + path + " ] was skipped.") continue + return results def upload_image( self, diff --git a/tests/test_project.py b/tests/test_project.py index 4c7d2a78..da3478c3 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -1,4 +1,5 @@ import json +import os from unittest.mock import patch import requests @@ -155,6 +156,47 @@ def test_upload_raises_upload_annotation_error(self): self.assertEqual(str(error.exception), "Image was already annotated.") + def test_upload_single_file_returns_result(self): + """upload() should return the single_upload result dict for a single file (#254).""" + image_id = "test-upload-id" + + responses.add( + responses.POST, + f"{API_URL}/dataset/{PROJECT_NAME}/upload?api_key={ROBOFLOW_API_KEY}&batch={DEFAULT_BATCH_NAME}", + json={"success": True, "id": image_id}, + status=200, + ) + + result = self.project.upload("tests/images/rabbit.JPG") + + self.assertIsInstance(result, dict) + self.assertEqual(result["image"]["id"], image_id) + self.assertIn("upload_time", result) + self.assertIn("upload_retry_attempts", result) + + def test_upload_directory_returns_list_of_results(self): + """upload() should return a list of single_upload results for a directory (#254).""" + test_dir = "tests/images" + # Determine how many valid images are in the directory so we can mock + # exactly that many upload responses. + valid_images = [f for f in os.listdir(test_dir) if self.project.check_valid_image(os.path.join(test_dir, f))] + + for i, _ in enumerate(valid_images): + responses.add( + responses.POST, + f"{API_URL}/dataset/{PROJECT_NAME}/upload?api_key={ROBOFLOW_API_KEY}&batch={DEFAULT_BATCH_NAME}", + json={"success": True, "id": f"img-{i}"}, + status=200, + ) + + result = self.project.upload(test_dir) + + self.assertIsInstance(result, list) + self.assertEqual(len(result), len(valid_images)) + for i, entry in enumerate(result): + self.assertIsInstance(entry, dict) + self.assertEqual(entry["image"]["id"], f"img-{i}") + def test_image_success(self): image_id = "test-image-id" expected_url = f"{API_URL}/{WORKSPACE_NAME}/{PROJECT_NAME}/images/{image_id}?api_key={ROBOFLOW_API_KEY}" diff --git a/tests/test_queries.py b/tests/test_queries.py index 93c29179..47e2b119 100644 --- a/tests/test_queries.py +++ b/tests/test_queries.py @@ -60,7 +60,8 @@ def test_project_methods(self): self.assertEqual(len(version_information), 2) self.assertIsNone(print_versions) self.assertTrue(all(map(lambda x: isinstance(x, Version), list_versions))) - self.assertIsNone(upload) + self.assertIsInstance(upload, dict) + self.assertEqual(upload["image"]["id"], "hbALkCFdNr9rssgOUXug") @ordered def test_version_fields(self):