Skip to content

Commit ea8449b

Browse files
kocabiyikclaude
andcommitted
Fix Windows CI test failures
- Fix file handle leaks by using context managers for PIL Image.open() - Properly close image files to prevent PermissionError during temp cleanup - Fix permission denied test for Windows platform compatibility - Use platform-specific file permission handling in tests 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent eb4547e commit ea8449b

3 files changed

Lines changed: 41 additions & 14 deletions

File tree

src/withoutbg/api.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ def _encode_image(self, image: Union[str, Path, Image.Image, bytes]) -> str:
4949
def _decode_image(self, base64_string: str) -> Image.Image:
5050
"""Decode base64 string to PIL Image."""
5151
image_bytes = base64.b64decode(base64_string)
52-
return Image.open(io.BytesIO(image_bytes))
52+
with Image.open(io.BytesIO(image_bytes)) as img:
53+
return img.copy()
5354

5455
def _resize_for_api(
5556
self, image: Image.Image, max_size: int = 1024
@@ -134,11 +135,13 @@ def remove_background(
134135
try:
135136
# Store original image for local alpha application
136137
if isinstance(input_image, (str, Path)):
137-
original_image = Image.open(input_image)
138+
with Image.open(input_image) as img:
139+
original_image = img.copy()
138140
elif isinstance(input_image, Image.Image):
139141
original_image = input_image.copy()
140142
elif isinstance(input_image, bytes):
141-
original_image = Image.open(io.BytesIO(input_image))
143+
with Image.open(io.BytesIO(input_image)) as img:
144+
original_image = img.copy()
142145
else:
143146
raise APIError(f"Unsupported image type: {type(input_image)}")
144147

src/withoutbg/models.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,9 +435,11 @@ def remove_background(
435435
"""
436436
# Load image
437437
if isinstance(input_image, (str, Path)):
438-
image = Image.open(input_image)
438+
with Image.open(input_image) as img:
439+
image = img.copy()
439440
elif isinstance(input_image, bytes):
440-
image = Image.open(io.BytesIO(input_image))
441+
with Image.open(io.BytesIO(input_image)) as img:
442+
image = img.copy()
441443
elif isinstance(input_image, Image.Image):
442444
image = input_image.copy()
443445
else:

tests/test_cli_e2e.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -420,24 +420,46 @@ def test_e2e_permission_denied_output(self, real_test_image_path, temp_dir):
420420
if not real_test_image_path.exists():
421421
pytest.skip("Real test image not available")
422422

423-
# Create a read-only directory
423+
import platform
424+
import stat
425+
426+
# Create a read-only directory - Windows requires different approach
424427
readonly_dir = temp_dir / "readonly"
425428
readonly_dir.mkdir()
426-
readonly_dir.chmod(0o444) # Read-only
427-
428-
try:
429+
430+
# Use platform-specific permission handling
431+
if platform.system() == "Windows":
432+
# On Windows, create a file first, then make it read-only
429433
output_path = readonly_dir / "output.png"
430-
434+
output_path.touch()
435+
output_path.chmod(stat.S_IREAD)
436+
431437
result = self.runner.invoke(
432438
main, [str(real_test_image_path), "--output", str(output_path)]
433439
)
434-
440+
435441
# Should fail due to permission error
436442
assert result.exit_code == 1
437-
438-
finally:
443+
439444
# Restore permissions for cleanup
440-
readonly_dir.chmod(0o755)
445+
output_path.chmod(stat.S_IWRITE | stat.S_IREAD)
446+
else:
447+
# Unix-style read-only directory
448+
readonly_dir.chmod(0o444)
449+
450+
try:
451+
output_path = readonly_dir / "output.png"
452+
453+
result = self.runner.invoke(
454+
main, [str(real_test_image_path), "--output", str(output_path)]
455+
)
456+
457+
# Should fail due to permission error
458+
assert result.exit_code == 1
459+
460+
finally:
461+
# Restore permissions for cleanup
462+
readonly_dir.chmod(0o755)
441463

442464
@pytest.mark.real_processing
443465
def test_e2e_disk_space_simulation(self, real_test_image_path, temp_dir):

0 commit comments

Comments
 (0)