style: clean up prose

This commit is contained in:
imSp4rky
2026-08-19 13:45:58 -06:00
parent 54adb82746
commit 29d0828c33
40 changed files with 109 additions and 110 deletions
+9 -9
View File
@@ -2,10 +2,10 @@
Test suite for the unshackle remote-services subsystem:
- `unshackle/core/remote_service.py` — `RemoteClient`, `RemoteService`, helpers
- `unshackle/core/api/` — routes, handlers, session_store, input_bridge,
- `unshackle/core/remote_service.py`: `RemoteClient`, `RemoteService`, helpers
- `unshackle/core/api/`: routes, handlers, session_store, input_bridge,
download_manager, errors, compression
- `unshackle/commands/serve.py` — CLI surface
- `unshackle/commands/serve.py`: CLI surface
Two tiers:
@@ -38,7 +38,7 @@ The suite can either:
`--server-url http://host:port`.
Spawn mode is controlled by `--spawn-serve {auto, always, never}` (default
`auto` — spawn only when `--server-url` is empty).
`auto` spawns only when `--server-url` is empty).
### Auto-spawn (recommended)
@@ -78,7 +78,7 @@ services you have access to. Schema (see the example file for full docs):
services:
EXAMPLE:
title_url: "..." # required
series_url: "..." # optional — overrides movie target when set
series_url: "..." # optional, overrides movie target when set
target_season: 1
target_episode: 1
search_query: "..."
@@ -114,9 +114,9 @@ uv run pytest tests/remote -v --live
## Markers
- `unit` — fast, mocked (default)
- `live` — needs `--live`
- `slow` — hits real services; combine with `--live`
- `unit`: fast, mocked (default)
- `live`: needs `--live`
- `slow`: hits real services; combine with `--live`
Run only fast unit tests:
@@ -127,4 +127,4 @@ uv run pytest tests/remote -m "unit and not slow"
## Adding a new service to e2e
1. Add a block under `services:` in your local `fixtures.yaml`.
2. No new Python needed — every e2e test is parametrized over the YAML.
2. No new Python needed; every e2e test is parametrized over the YAML.
+15 -15
View File
@@ -8,39 +8,39 @@
# unshackle (matches the service directory name, e.g. EXAMPLE). The keys
# below are read by the e2e tests:
#
# title_url (required) — movie URL/slug/ID accepted by the service
# series_url (optional) — series URL/slug/ID; when set, the
# title_url (required): movie URL/slug/ID accepted by the service
# series_url (optional): series URL/slug/ID; when set, the
# quality + license + download tests
# target target_season/target_episode
# instead of the movie
# target_season (optional, default 1)
# target_episode (optional, default 1)
# search_query (optional) — string to send to /api/search
# requires_auth (optional, default true) — informational
# server_cdm (optional, default false) — informational
# drm (optional) — informational ("widevine" / "playready")
# search_query (optional): string to send to /api/search
# requires_auth (optional, default true): informational
# server_cdm (optional, default false): informational
# drm (optional): informational ("widevine" / "playready")
#
# expected_quality (optional) — when present, the quality test
# expected_quality (optional): when present, the quality test
# asserts these limits against the
# discovered video tracks
# min_height (optional) — max video.height >= this
# min_codecs (optional) — codec names that must be present
# min_height (optional): max video.height >= this
# min_codecs (optional): codec names that must be present
# (AVC, HEVC, VC1, VP8, VP9, AV1)
# min_ranges (optional) — range names that must be present
# min_ranges (optional): range names that must be present
# (SDR, HDR10, HDR10P, DV, HLG, HYBRID)
# min_track_count (optional) — at least this many video tracks
# min_track_count (optional): at least this many video tracks
#
# runs_download_test (optional, default false) — when true, the
# runs_download_test (optional, default false): when true, the
# download smoke test
# runs for this service
# runs_license_test (optional, default false) — when true, the
# runs_license_test (optional, default false): when true, the
# license test runs for
# this service
# license_drm (optional, default "widevine") — DRM type the
# license_drm (optional, default "widevine"): DRM type the
# license test
# requests ("widevine"
# or "playready")
# license_quality (optional, default 1080) — pixel height of the
# license_quality (optional, default 1080): pixel height of the
# track the license test
# targets
+1 -1
View File
@@ -7,7 +7,7 @@ For any fixture service with ``runs_download_test: true``, this test:
4. Fetches the manifest URL with the resolved headers.
5. Asserts the body is non-empty and looks like DASH/HLS.
It does NOT decrypt or mux — that requires a full local CDM. It proves
It does NOT decrypt or mux; that requires a full local CDM. It proves
the end-to-end pipeline up to CDN reachability for the selected quality.
"""
+3 -3
View File
@@ -22,7 +22,7 @@ def create_session(http_session, server_url: str, service: str, title_id: str) -
payload = {
"service": service,
"title_id": title_id,
# Quality knobs — send enum names the server's session_create parser accepts.
# Quality knobs: send enum names the server's session_create parser accepts.
"range_": ["SDR", "HDR10", "DV"],
"vcodec": ["AVC", "HEVC"],
"best_available": True,
@@ -115,13 +115,13 @@ def test_track_quality_meets_expected(http_session, server_url: str, service_cas
tracks = r.json()
video = tracks.get("video") or []
summary = summarize(video)
# Print summary even when test passes — discovery aid.
# Print summary even when the test passes, as a discovery aid.
with capsys.disabled():
print(f"\n[{service}] target={kind} '{target.get('name')}' -> {summary}")
expected = conf.get("expected_quality") or {}
if not expected:
pytest.skip(f"{service}: no expected_quality in fixtures.yaml — discovered={summary}")
pytest.skip(f"{service}: no expected_quality in fixtures.yaml; discovered={summary}")
if "min_height" in expected:
assert summary["max_height"] >= expected["min_height"], (
+1 -1
View File
@@ -1,7 +1,7 @@
"""Unit tests for DownloadJob + DownloadQueueManager state machine.
These tests focus on the queue manager's data layer (create/get/list/cancel/
cleanup/serialize) — they do not exercise the actual subprocess download path.
cleanup/serialize); they do not exercise the actual subprocess download path.
"""
from __future__ import annotations
+2 -2
View File
@@ -47,7 +47,7 @@ def test_api_error_default_http_status_per_code() -> None:
APIErrorCode.NETWORK_ERROR: 503,
APIErrorCode.SERVICE_UNAVAILABLE: 503,
}
# Lock that the cases above are the *complete* live set — a new/removed code trips this.
# Lock that the cases above are the *complete* live set; a new/removed code trips this.
assert {c.name for c in cases} == {c.name for c in APIErrorCode}
for code, expected in cases.items():
assert APIError(code, "x").http_status == expected, code
@@ -142,7 +142,7 @@ def test_handle_api_exception_categorizes_generic() -> None:
assert body["error_code"] == "NETWORK_ERROR"
# Locks the FULL observable response — (http status, error_code, retryable) — that
# Locks the FULL observable response (http status, error_code, retryable) that
# a client sees for a generic (non-APIError) exception flowing through the
# handle_api_exception funnel that every route's `except Exception` path calls.
# This is the equivalence reference: after the categorize_exception collapse,
+1 -1
View File
@@ -190,5 +190,5 @@ async def test_auth_middleware_accepts_known_key(make_app, aiohttp_client) -> No
app["config"]["users"]["good-key"] = {"devices": []}
client = await aiohttp_client(app)
resp = await client.get("/api/session/nonexistent", headers={"X-Secret-Key": "good-key"})
# Auth passed; handler then 404s the session — anything other than 401 is fine here.
# Auth passed; handler then 404s the session; anything other than 401 is fine here.
assert resp.status != 401