Skip to content

Commit 8a1f73c

Browse files
author
anna-singleton-resolver
committed
refactor: imagemagick is no longer a dependency for the functional tests
1 parent a0548b2 commit 8a1f73c

3 files changed

Lines changed: 68 additions & 45 deletions

File tree

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ You will need:
130130
- An Athena host URL.
131131
- An OAuth client ID and secret with access to the Athena environment.
132132
- An affiliate with Athena enabled.
133-
- `imagemagick` installed on your system and on your path at `magick`.
134133

135134

136135
#### Preparing your environment

tests/functional/conftest.py

Lines changed: 65 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import os
2-
import shutil
3-
import subprocess
42
import uuid
53

4+
import cv2
5+
import numpy as np
66
import pytest
77
import pytest_asyncio
88
from dotenv import load_dotenv
@@ -14,7 +14,32 @@
1414
EXPECTED_WIDTH,
1515
MAX_DEPLOYMENT_ID_LENGTH,
1616
)
17-
from tests.utils.image_generation import create_test_image
17+
18+
19+
def _create_base_test_image_opencv(width: int, height: int) -> np.ndarray:
20+
"""Create a test image using only OpenCV2.
21+
22+
Creates a simple test pattern with background and accent colors.
23+
24+
Args:
25+
width: Image width in pixels
26+
height: Image height in pixels
27+
28+
Returns:
29+
numpy array in BGR format suitable for cv2.imencode
30+
"""
31+
# Create a simple test image with random colors
32+
# Background color (blue-green)
33+
img_bgr = np.zeros((height, width, 3), dtype=np.uint8)
34+
img_bgr[:, :] = (100, 150, 200) # BGR format
35+
36+
# Add an accent rectangle for visual variation
37+
x1, y1 = width // 4, height // 4
38+
x2, y2 = (width * 3) // 4, (height * 3) // 4
39+
cv2.rectangle(img_bgr, (x1, y1), (x2, y2), (200, 100, 50), -1)
40+
41+
return img_bgr
42+
1843

1944
SUPPORTED_TEST_FORMATS = [
2045
"gif",
@@ -25,13 +50,16 @@
2550
"pbm",
2651
"pgm",
2752
"ppm",
28-
"pxm",
2953
"pnm",
3054
"sr",
3155
"ras",
3256
"tiff",
3357
"pic",
3458
"raw_uint8",
59+
60+
# pxm - OpenCV2 has issues with this format, the docs state its
61+
# supported, but pxm is also used to mean PBM/PGM/PPM which are supported,
62+
# so its unclear if this format is truly supported.
3563
]
3664

3765

@@ -91,47 +119,45 @@ def valid_formatted_image(
91119
request: pytest.FixtureRequest,
92120
tmp_path_factory: pytest.TempPathFactory,
93121
) -> bytes:
94-
image_format = request.param
95-
if (magick_path := shutil.which("magick")) is None and (
96-
magick_path := shutil.which("convert")
97-
) is None:
98-
pytest.fail(
99-
"ImageMagick 'magick' or 'convert' command not found - cannot "
100-
"run multi-format test"
101-
)
122+
"""Generate test images in various formats using OpenCV2.
102123
124+
Images are cached to disk to avoid regenerating on every test run.
125+
"""
126+
image_format = request.param
103127
image_dir = tmp_path_factory.mktemp("images")
128+
base_image = _create_base_test_image_opencv(EXPECTED_WIDTH, EXPECTED_HEIGHT)
104129

105-
base_image_format = "png"
106-
base_image = create_test_image(
107-
EXPECTED_WIDTH, EXPECTED_HEIGHT, img_format=base_image_format
108-
)
109-
base_image_path = image_dir / "base_image.png"
110-
if not base_image_path.exists():
111-
with base_image_path.open("wb") as f:
112-
_ = f.write(base_image)
113-
114-
if image_format == base_image_format:
115-
return base_image
116-
130+
# Handle raw_uint8 format separately - return raw BGR bytes
117131
if image_format == "raw_uint8":
118-
return create_test_image(
119-
EXPECTED_WIDTH, EXPECTED_HEIGHT, img_format="raw_uint8"
120-
)
132+
return base_image.tobytes()
121133

134+
# Check if image already exists in cache
122135
image_path = image_dir / f"test_image.{image_format}"
123-
if not image_path.exists():
124-
cmd = [magick_path, str(base_image_path), str(image_path)]
125-
_ = subprocess.run( # noqa: S603 - false positive :(
126-
cmd,
127-
check=True,
128-
shell=False,
129-
)
130-
131-
if not image_path.exists():
136+
if image_path.exists():
137+
with image_path.open("rb") as f:
138+
return f.read()
139+
140+
# Convert format using OpenCV2 and cache to disk
141+
try:
142+
# Encode image in the target format
143+
if image_format in ["pgm", "pbm"]:
144+
# PGM and PBM are grayscale, so convert the image to grayscale
145+
gray_image = cv2.cvtColor(base_image, cv2.COLOR_BGR2GRAY)
146+
success, encoded = cv2.imencode(f".{image_format}", gray_image)
147+
else:
148+
success, encoded = cv2.imencode(f".{image_format}", base_image)
149+
150+
if not success:
132151
pytest.fail(
133-
f"Failed to create {image_format} image with command: {cmd}"
152+
f"OpenCV failed to encode image in {image_format} format"
134153
)
135154

136-
with image_path.open("rb") as f:
137-
return f.read()
155+
image_bytes = encoded.tobytes()
156+
157+
# Cache the image to disk
158+
with image_path.open("wb") as f:
159+
_ = f.write(image_bytes)
160+
161+
return image_bytes
162+
except Exception as e:
163+
pytest.fail(f"Failed to create {image_format} image with OpenCV: {e}")

tests/functional/test_invalid_image.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from collections.abc import AsyncIterator
33

44
import pytest
5-
from PIL import UnidentifiedImageError
65

76
from resolver_athena_client.client.athena_client import AthenaClient
87
from resolver_athena_client.client.athena_options import AthenaOptions
@@ -39,12 +38,11 @@ async def test_classify_single_invalid_image(
3938
image_bytes = b"this is not a valid image file"
4039
image_data = ImageData(image_bytes)
4140

42-
with pytest.raises(UnidentifiedImageError) as e:
41+
with pytest.raises(
42+
ValueError, match="Failed to decode image data for resizing"
43+
) as e:
4344
_ = await client.classify_single(image_data)
4445

45-
expected_msg = "cannot identify image file"
46-
assert expected_msg in str(e.value)
47-
4846
except Exception as e:
4947
msg = "Unexpected exception during invalid image test"
5048
raise AssertionError(msg) from e

0 commit comments

Comments
 (0)