Skip to content

Commit

Permalink
Merge pull request #344 from roboflow/image-details-endpoint
Browse files Browse the repository at this point in the history
Add support for the Image Details endpoint
  • Loading branch information
stellasphere authored Feb 11, 2025
2 parents 01d713f + 0708987 commit 5b46359
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 4 deletions.
2 changes: 1 addition & 1 deletion roboflow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from roboflow.models import CLIPModel, GazeModel # noqa: F401
from roboflow.util.general import write_line

__version__ = "1.1.53"
__version__ = "1.1.54"


def check_key(api_key, model, notebook, num_retries=0):
Expand Down
34 changes: 34 additions & 0 deletions roboflow/core/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -767,3 +767,37 @@ def __str__(self):
json_str = {"name": self.name, "type": self.type, "workspace": self.__workspace}

return json.dumps(json_str, indent=2)

def image(self, image_id: str) -> Dict:
"""
Fetch the details of a specific image from the Roboflow API.
Args:
image_id (str): The ID of the image to fetch.
Returns:
Dict: A dictionary containing the image details.
Example:
>>> import roboflow
>>> rf = roboflow.Roboflow(api_key="YOUR_API_KEY")
>>> project = rf.workspace().project("PROJECT_ID")
>>> image_details = project.image("image-id")
"""
url = f"{API_URL}/{self.__workspace}/{self.__project_name}/images/{image_id}?api_key={self.__api_key}"

data = requests.get(url).json()

if "error" in data:
raise RuntimeError(data["error"])

if "image" not in data:
print(data, image_id)
raise RuntimeError("Image not found")

image_details = data["image"]

return image_details
3 changes: 1 addition & 2 deletions roboflow/core/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,8 +539,7 @@ def __download_zip(self, link, location, format):

def bar_progress(current, total, width=80):
progress_message = (
"Downloading Dataset Version Zip in "
f"{location} to {format}: "
f"Downloading Dataset Version Zip in {location} to {format}: "
f"{current / total * 100:.0f}% [{current} / {total}] bytes"
)
sys.stdout.write("\r" + progress_message)
Expand Down
64 changes: 63 additions & 1 deletion tests/test_project.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import requests
import responses

from roboflow import API_URL
from roboflow.adapters.rfapi import AnnotationSaveError, ImageUploadError
from roboflow.config import DEFAULT_BATCH_NAME
from tests import PROJECT_NAME, ROBOFLOW_API_KEY, RoboflowTest
from tests import PROJECT_NAME, ROBOFLOW_API_KEY, WORKSPACE_NAME, RoboflowTest


class TestProject(RoboflowTest):
Expand Down Expand Up @@ -82,3 +83,64 @@ def test_upload_raises_upload_annotation_error(self):
)

self.assertEqual(str(error.exception), "Image was already annotated.")

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}"
mock_response = {
"image": {
"id": image_id,
"name": "test_image.jpg",
"annotation": {
"key": "some-key",
"width": 640,
"height": 480,
"boxes": [{"label": "person", "x": 100, "y": 150, "width": 50, "height": 80}],
},
"labels": ["person"],
"split": "train",
"tags": ["tag1", "tag2"],
"created": 1616161616,
"urls": {
"original": "https://example.com/image.jpg",
"thumb": "https://example.com/thumb.jpg",
"annotation": "https://example.com/annotation.json",
},
"embedding": [0.1, 0.2, 0.3],
}
}

responses.add(responses.GET, expected_url, json=mock_response, status=200)

image_details = self.project.image(image_id)

self.assertIsInstance(image_details, dict)
self.assertEqual(image_details["id"], image_id)
self.assertEqual(image_details["name"], "test_image.jpg")
self.assertIn("annotation", image_details)
self.assertIn("labels", image_details)
self.assertEqual(image_details["split"], "train")

def test_image_not_found(self):
image_id = "nonexistent-image-id"
expected_url = f"{API_URL}/{WORKSPACE_NAME}/{PROJECT_NAME}/images/{image_id}?api_key={ROBOFLOW_API_KEY}"
mock_response = {"error": "Image not found."}

responses.add(responses.GET, expected_url, json=mock_response, status=404)

with self.assertRaises(RuntimeError) as context:
self.project.image(image_id)

self.assertIn("HTTP error occurred while fetching image details", str(context.exception))

def test_image_invalid_json_response(self):
image_id = "invalid-json-image-id"
expected_url = f"{API_URL}/{WORKSPACE_NAME}/{PROJECT_NAME}/images/{image_id}?api_key={ROBOFLOW_API_KEY}"
invalid_json = "Invalid JSON response"

responses.add(responses.GET, expected_url, body=invalid_json, status=200)

with self.assertRaises(requests.exceptions.JSONDecodeError) as context:
self.project.image(image_id)

self.assertIn("Expecting value", str(context.exception))

0 comments on commit 5b46359

Please sign in to comment.