| import json |
| import tempfile |
| import unittest |
| from pathlib import Path |
|
|
| from PIL import Image |
|
|
| from approach.pipeline_utils import ( |
| enrich_ape_results, |
| output_path_for_selection, |
| parse_orienter_image_name, |
| resolve_image_path, |
| run_optional_reflection, |
| select_jsonl_lines, |
| write_json_atomic, |
| ) |
|
|
|
|
| class PipelineUtilsTest(unittest.TestCase): |
| def test_parse_orienter_image_name_is_strict(self): |
| self.assertEqual(parse_orienter_image_name("123_4.jpg"), ("123", "4", 123004)) |
| with self.assertRaises(ValueError): |
| parse_orienter_image_name("123_4_extra.jpg") |
| with self.assertRaises(ValueError): |
| parse_orienter_image_name("nested/123_4.jpg") |
| with self.assertRaises(ValueError): |
| parse_orienter_image_name("123_1000.jpg") |
|
|
| def test_resolve_image_path_rejects_escape_from_images_directory(self): |
| with tempfile.TemporaryDirectory() as tmp_dir: |
| images_dir = Path(tmp_dir) / "images" |
| images_dir.mkdir() |
| self.assertEqual( |
| resolve_image_path(images_dir, "nested/123_4.jpg"), |
| (images_dir / "nested" / "123_4.jpg").resolve(), |
| ) |
| with self.assertRaises(ValueError): |
| resolve_image_path(images_dir, "../123_4.jpg") |
| with self.assertRaises(ValueError): |
| resolve_image_path(images_dir, str(Path(tmp_dir) / "123_4.jpg")) |
|
|
| def test_select_jsonl_lines_supports_ranges_or_shards(self): |
| lines = [f"{idx}\n" for idx in range(10)] |
| self.assertEqual(select_jsonl_lines(lines, start_index=2, end_index=8), lines[2:8]) |
| self.assertEqual( |
| select_jsonl_lines(lines, shard_index=1, num_shards=2), |
| ["1\n", "3\n", "5\n", "7\n", "9\n"], |
| ) |
| with self.assertRaises(ValueError): |
| select_jsonl_lines( |
| lines, |
| start_index=2, |
| end_index=8, |
| shard_index=1, |
| num_shards=2, |
| ) |
|
|
| def test_output_path_for_selection_prevents_shard_overwrite(self): |
| self.assertEqual( |
| output_path_for_selection("predictions.json", shard_index=1, num_shards=4), |
| "predictions.shard01-of-04.json", |
| ) |
| self.assertEqual( |
| output_path_for_selection("predictions.json", start_index=100, end_index=200), |
| "predictions.rows100-200.json", |
| ) |
| self.assertEqual(output_path_for_selection("predictions.json"), "predictions.json") |
|
|
| def test_enrich_ape_results_keeps_added_metadata(self): |
| enriched = enrich_ape_results( |
| [{"bbox": [1, 2, 3, 4], "category_name": "button"}], |
| "123_4.jpg", |
| lambda image_name: 123004, |
| ) |
| self.assertEqual(enriched[0]["image_id"], 123004) |
| self.assertEqual(enriched[0]["category_id"], "button") |
| self.assertEqual(enriched[0]["bbox"], [1, 2, 3, 4]) |
|
|
| def test_write_json_atomic_writes_one_valid_json_document(self): |
| with tempfile.TemporaryDirectory() as tmp_dir: |
| out_path = Path(tmp_dir) / "ape.json" |
| write_json_atomic(str(out_path), [{"image_id": 1}, {"image_id": 2}]) |
| self.assertEqual(json.loads(out_path.read_text()), [{"image_id": 1}, {"image_id": 2}]) |
|
|
| def test_optional_reflection_is_disabled_by_default(self): |
| self.assertIsNone( |
| run_optional_reflection( |
| "unused.png", |
| [], |
| detector=lambda candidates, previous: previous, |
| enabled=False, |
| ) |
| ) |
|
|
| def test_optional_reflection_feeds_back_to_detector(self): |
| with tempfile.TemporaryDirectory() as tmp_dir: |
| image_path = Path(tmp_dir) / "image.png" |
| Image.new("RGB", (10, 10), "white").save(image_path) |
| detector_calls = [] |
|
|
| def advisor(**kwargs): |
| if detector_calls: |
| return {"verified": [0], "needs_refinement": [], "feedback": []} |
| return {"verified": [], "needs_refinement": [0], "feedback": ["button label"]} |
|
|
| def detector(candidates, previous): |
| detector_calls.append(candidates) |
| return [{"bbox": [2, 2, 3, 3], "category_name": "button"}] |
|
|
| result = run_optional_reflection( |
| str(image_path), |
| [{"bbox": [1, 1, 3, 3], "category_name": "button"}], |
| detector=detector, |
| enabled=True, |
| advisor=advisor, |
| ) |
|
|
| self.assertEqual(detector_calls, [["button label"]]) |
| self.assertFalse(result["max_iterations_reached"]) |
|
|
|
|
| if __name__ == "__main__": |
| unittest.main() |
|
|