|
9 | 9 |
|
10 | 10 | from roboflow.adapters.rfapi import AnnotationSaveError |
11 | 11 | from roboflow.config import API_URL |
12 | | -from roboflow.core.project import Project |
| 12 | +from tests import PROJECT_NAME, ROBOFLOW_API_KEY, WORKSPACE_NAME, RoboflowTest |
13 | 13 |
|
14 | 14 |
|
15 | | -class TestVideoSegmentAnnotation(unittest.TestCase): |
| 15 | +class TestVideoSegmentAnnotation(RoboflowTest): |
16 | 16 | def setUp(self): |
17 | | - self.project = Project( |
18 | | - "test-key", |
19 | | - { |
20 | | - "annotation": "actions", |
21 | | - "classes": {}, |
22 | | - "colors": {}, |
23 | | - "created": 0, |
24 | | - "id": "my-workspace/actions", |
25 | | - "images": 0, |
26 | | - "name": "Actions", |
27 | | - "public": False, |
28 | | - "splits": {}, |
29 | | - "type": "action-recognition", |
30 | | - "unannotated": 0, |
31 | | - "updated": 0, |
32 | | - }, |
33 | | - ) |
34 | | - self.url = f"{API_URL}/my-workspace/actions/annotate/final-source-id" |
| 17 | + super().setUp() |
| 18 | + self.project.type = "action-recognition" |
| 19 | + self.url = f"{API_URL}/{WORKSPACE_NAME}/{PROJECT_NAME}/annotate/final-source-id" |
35 | 20 | self.document = { |
36 | 21 | "info": {"format": "roboflow-video-coco"}, |
37 | 22 | "videos": [ |
@@ -59,56 +44,46 @@ def setUp(self): |
59 | 44 | ], |
60 | 45 | } |
61 | 46 |
|
62 | | - def test_acceptance_and_identical_retry_forward_the_canonical_document(self): |
| 47 | + def test_finalized_source_and_identical_retry_forward_the_canonical_document(self): |
63 | 48 | first = {"success": True, "inDataset": True, "createdClasses": ["jumping"]} |
64 | 49 | retry = {"success": True, "inDataset": True, "createdClasses": []} |
65 | 50 | with responses.RequestsMock() as http: |
| 51 | + http.add( |
| 52 | + responses.GET, |
| 53 | + f"{API_URL}/{WORKSPACE_NAME}/upload/video/reservation-id", |
| 54 | + json={"status": "uploaded", "videoId": "final-source-id"}, |
| 55 | + ) |
66 | 56 | http.add(responses.POST, self.url, json=first) |
67 | 57 | http.add(responses.POST, self.url, json=retry) |
68 | | - self.assertEqual(self.project.annotate_video_segments("final-source-id", self.document), first) |
69 | | - self.assertEqual(self.project.annotate_video_segments("final-source-id", self.document), retry) |
| 58 | + status = self.project.wait_for_video_upload("reservation-id") |
| 59 | + self.assertEqual(self.project.annotate_video_segments(status["videoId"], self.document), first) |
| 60 | + self.assertEqual(self.project.annotate_video_segments(status["videoId"], self.document), retry) |
70 | 61 |
|
71 | | - self.assertEqual(len(http.calls), 2) |
72 | | - for call in http.calls: |
| 62 | + self.assertEqual([call.request.method for call in http.calls], ["GET", "POST", "POST"]) |
| 63 | + for call in http.calls[1:]: |
73 | 64 | query = parse_qs(urlparse(call.request.url).query) |
74 | | - self.assertEqual(query, {"api_key": ["test-key"], "name": ["annotations.json"]}) |
| 65 | + self.assertEqual(query, {"api_key": [ROBOFLOW_API_KEY], "name": ["annotations.json"]}) |
75 | 66 | self.assertEqual(json.loads(call.request.body), {"annotationFile": json.dumps(self.document)}) |
76 | 67 |
|
77 | 68 | def test_conflict_is_raised_and_explicit_overwrite_and_split_are_forwarded(self): |
78 | | - def annotate(request): |
79 | | - query = parse_qs(urlparse(request.url).query) |
80 | | - if "overwrite" not in query: |
81 | | - return ( |
82 | | - 409, |
83 | | - {"Content-Type": "application/json"}, |
84 | | - json.dumps( |
85 | | - { |
86 | | - "error": { |
87 | | - "message": "This video already has annotations. Send overwrite=true to replace them." |
88 | | - } |
89 | | - } |
90 | | - ), |
91 | | - ) |
92 | | - self.assertEqual(query["overwrite"], ["true"]) |
93 | | - self.assertEqual(query["split"], ["valid"]) |
94 | | - self.assertEqual(query["addToDataset"], ["false"]) |
95 | | - return ( |
96 | | - 200, |
97 | | - {"Content-Type": "application/json"}, |
98 | | - json.dumps({"success": True, "inDataset": False, "createdClasses": []}), |
99 | | - ) |
100 | | - |
| 69 | + message = "This video already has annotations. Send overwrite=true to replace them." |
| 70 | + accepted = {"success": True, "inDataset": False, "createdClasses": []} |
101 | 71 | with responses.RequestsMock() as http: |
102 | | - http.add_callback(responses.POST, self.url, callback=annotate) |
| 72 | + http.add(responses.POST, self.url, json={"error": {"message": message}}, status=409) |
| 73 | + http.add(responses.POST, self.url, json=accepted) |
103 | 74 | with self.assertRaises(AnnotationSaveError) as error: |
104 | 75 | self.project.annotate_video_segments("final-source-id", self.document) |
105 | 76 | self.assertEqual(error.exception.status_code, 409) |
106 | | - self.assertIn("already has annotations", str(error.exception)) |
| 77 | + self.assertEqual(str(error.exception), message) |
107 | 78 |
|
108 | 79 | result = self.project.annotate_video_segments( |
109 | 80 | "final-source-id", self.document, overwrite=True, split="valid", add_to_dataset=False |
110 | 81 | ) |
111 | | - self.assertEqual(result, {"success": True, "inDataset": False, "createdClasses": []}) |
| 82 | + self.assertEqual(result, accepted) |
| 83 | + query = parse_qs(urlparse(http.calls[-1].request.url).query) |
| 84 | + self.assertEqual(query["overwrite"], ["true"]) |
| 85 | + self.assertEqual(query["split"], ["valid"]) |
| 86 | + self.assertEqual(query["addToDataset"], ["false"]) |
112 | 87 |
|
113 | 88 | def test_server_validation_and_transport_errors_are_not_recast_as_success(self): |
114 | 89 | with responses.RequestsMock() as http: |
|
0 commit comments