Files
Eric Mey 6d6b535266 chore(review): address code-review findings
Three logical changes rolled into one commit:

1. stdlib HTTP read timeout. urlopen's `timeout=` only bounds connect,
   and CPython versions disagree on whether the resulting socket keeps
   that pinned. A half-dead Immich server that has sent headers but
   stalls on the body would hang the whole batch. Pin a read-side
   timeout on every HTTPConnection/HTTPSConnection at import so the
   bound holds across versions and reading paths. Verified with a
   stand-alone server/client pair: with the fix, a stalled body read
   fails in 0.5s with TimeoutError; without the fix, the same script
   hangs past the test timeout.

   Also distinguish `_add_to_album` ambiguity from failure: an entry
   that omits `success` is now treated the same way as an empty body
   (downgrade to `album: "unconfirmed"`), not as a ValueError. Only an
   entry that explicitly says `success: false` raises. Broadens the
   transient-error catch in `_wait_for_storage_settle` from
   (HTTPError, URLError) to OSError so socket timeouts and connection
   resets during polling do not abort the wait.

2. CI matrix now includes 3.11. tomllib is stdlib from 3.11, and the
   packaging-drift test in tests/test_packaging.py uses it. Without
   3.11 the 3.10 job importorskip-s that test, leaving drift
   detection silent at the lowest supported interpreter.

3. Test ergonomics. tests/conftest.py extracts the per-test image
   batch fixture (was duplicated across 10+ tests). README clarifies
   that retry_archive's exit code reflects `errors` entries only —
   `unconfirmed` album results exit 0, not non-zero.

Plus a User-Agent string that reports the installed package version
(via importlib.metadata) so the value cannot drift from pyproject.toml.
70 tests pass; was 62. ruff + mypy clean. Verified on Python 3.11
and 3.12 locally.
2026-09-22 15:40:28 -04:00

47 lines
1.3 KiB
Python

"""Shared fixtures for the test suite.
Keeps the per-test boilerplate (`MagicMock` image tensors, the four-line
setup for `images.shape`/`images.__getitem__`) out of every test that needs
a fake ComfyUI image batch.
"""
from unittest.mock import MagicMock
import numpy as np
import pytest
def _make_image_batch(count, size=32):
"""Return a MagicMock batch of `count` 32x32x3 float tensors.
Mimics the parts of a torch tensor the node actually uses: `.shape`,
`[i]` indexing, `.cpu().numpy()`. The numpy payload is real so any test
that lets PIL actually decode a frame exercises a real encoder path.
"""
tensor = MagicMock()
tensor.cpu.return_value = tensor
tensor.numpy.return_value = np.random.rand(size, size, 3).astype(np.float32)
images = MagicMock()
images.shape = [count]
images.__getitem__ = lambda _self, i: tensor
return images
@pytest.fixture
def image_batch():
"""Single-image batch — the most common shape in the suite."""
return _make_image_batch(1)
@pytest.fixture
def image_batch_of_two():
"""Two-image batch for batch-containment tests."""
return _make_image_batch(2)
@pytest.fixture
def image_batch_of_three():
"""Three-image batch for batch-containment tests."""
return _make_image_batch(3)