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.
47 lines
1.3 KiB
Python
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)
|