Skip to content

Commit 87a0f5a

Browse files
aapelivclaude
andcommitted
Fix mypy errors in postcard service
Add types-qrcode stubs, fix type annotations for font fallbacks, return types, and QR image handling. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6e08ac5 commit 87a0f5a

4 files changed

Lines changed: 30 additions & 9 deletions

File tree

app/backend/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ dependencies = [
4242
"statsig-python-core>=0.8.0",
4343
"pillow>=12.1.1",
4444
"qrcode>=8.2",
45+
"types-qrcode>=8.2.0.20250914",
4546
]
4647

4748
[project.scripts]

app/backend/src/couchers/postal/postcard_service.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import json
33
import logging
44
from dataclasses import dataclass
5+
from typing import Any
56

67
import qrcode
78
import requests
@@ -43,6 +44,10 @@ def _generate_postcard_image(verification_code: str, qr_code_url: str) -> bytes:
4344

4445
# Use default font at various sizes (Pillow's built-in bitmap font doesn't scale,
4546
# so we use truetype with the default font)
47+
font_large: ImageFont.FreeTypeFont | ImageFont.ImageFont
48+
font_code: ImageFont.FreeTypeFont | ImageFont.ImageFont
49+
font_medium: ImageFont.FreeTypeFont | ImageFont.ImageFont
50+
font_small: ImageFont.FreeTypeFont | ImageFont.ImageFont
4651
try:
4752
font_large = ImageFont.truetype("DejaVuSans-Bold.ttf", 80)
4853
font_code = ImageFont.truetype("DejaVuSans-Bold.ttf", 120)
@@ -111,12 +116,12 @@ def _generate_postcard_image(verification_code: str, qr_code_url: str) -> bytes:
111116
qr = qrcode.QRCode(version=1, box_size=8, border=2)
112117
qr.add_data(qr_code_url)
113118
qr.make(fit=True)
114-
qr_img = qr.make_image(fill_color="black", back_color="white").convert("RGB")
119+
qr_pil_img: Image.Image = qr.make_image(fill_color="black", back_color="white").get_image().convert("RGB")
115120
qr_size = 280
116-
qr_img = qr_img.resize((qr_size, qr_size))
121+
qr_pil_img = qr_pil_img.resize((qr_size, qr_size))
117122
qr_x = (POSTCARD_WIDTH - qr_size) // 2
118123
qr_y = 720
119-
img.paste(qr_img, (qr_x, qr_y))
124+
img.paste(qr_pil_img, (qr_x, qr_y))
120125

121126
# Instructions below QR code
122127
draw.text(
@@ -162,10 +167,10 @@ def _authenticate() -> str:
162167
if "auth_token" not in data:
163168
raise PostcardServiceError(f"MyPostcard auth failed: {data}")
164169

165-
return data["auth_token"]
170+
return str(data["auth_token"])
166171

167172

168-
def _place_order(auth_token: str, recipient_data: dict, image_data: bytes) -> dict:
173+
def _place_order(auth_token: str, recipient_data: dict[str, str], image_data: bytes) -> dict[str, Any]:
169174
"""
170175
Places a postcard order with MyPostcard API.
171176
"""
@@ -195,7 +200,8 @@ def _place_order(auth_token: str, recipient_data: dict, image_data: bytes) -> di
195200
timeout=60,
196201
)
197202
response.raise_for_status()
198-
return response.json()
203+
result: dict[str, Any] = response.json()
204+
return result
199205

200206

201207
def send_postcard(

app/backend/src/tests/test_postcard_service.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ def test_auth_failure_returns_error(self, mock_image, mock_auth):
165165
)
166166

167167
assert result.success is False
168-
assert "Connection refused" in result.error_message
168+
assert "Connection refused" in (result.error_message or "")
169169

170170
@patch("couchers.postal.postcard_service._authenticate")
171171
@patch("couchers.postal.postcard_service._generate_postcard_image")
@@ -186,7 +186,7 @@ def test_auth_service_error_returns_error(self, mock_image, mock_auth):
186186
)
187187

188188
assert result.success is False
189-
assert "auth failed" in result.error_message
189+
assert "auth failed" in (result.error_message or "")
190190

191191
@patch("couchers.postal.postcard_service._place_order")
192192
@patch("couchers.postal.postcard_service._authenticate")
@@ -209,4 +209,4 @@ def test_order_failure_returns_error(self, mock_image, mock_auth, mock_order):
209209
)
210210

211211
assert result.success is False
212-
assert "500 Server Error" in result.error_message
212+
assert "500 Server Error" in (result.error_message or "")

app/backend/uv.lock

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)