chore: apply pre-commit auto-fixes (trim trailing whitespace, EOF)

This commit is contained in:
2026-05-17 23:41:54 +02:00
parent e07c9ec77b
commit 891ba502a2
26 changed files with 238 additions and 168 deletions
+1 -3
View File
@@ -185,9 +185,7 @@ class TestCompleteHappyPath:
class TestCompleteErrors:
def test_timeout_wrapped(self, client):
with patch(
"alfred.agent.llm.ollama.requests.post", side_effect=Timeout("t")
):
with patch("alfred.agent.llm.ollama.requests.post", side_effect=Timeout("t")):
with pytest.raises(LLMAPIError, match="timeout"):
client.complete([{"role": "user", "content": "q"}])
+3 -9
View File
@@ -136,17 +136,13 @@ class TestAudio:
assert p.audio_channels == "5.1"
def test_channel_count_unknown_falls_back(self):
info = MediaInfo(
audio_tracks=[AudioTrack(0, "aac", 4, "quad", "eng")]
)
info = MediaInfo(audio_tracks=[AudioTrack(0, "aac", 4, "quad", "eng")])
p = _bare()
enrich_from_probe(p, info)
assert p.audio_channels == "4ch"
def test_unknown_audio_codec_uppercased(self):
info = MediaInfo(
audio_tracks=[AudioTrack(0, "newcodec", 2, "stereo", "eng")]
)
info = MediaInfo(audio_tracks=[AudioTrack(0, "newcodec", 2, "stereo", "eng")])
p = _bare()
enrich_from_probe(p, info)
assert p.audio_codec == "NEWCODEC"
@@ -158,9 +154,7 @@ class TestAudio:
assert p.audio_channels is None
def test_does_not_overwrite_existing_audio_fields(self):
info = MediaInfo(
audio_tracks=[AudioTrack(0, "ac3", 6, "5.1", "eng")]
)
info = MediaInfo(audio_tracks=[AudioTrack(0, "ac3", 6, "5.1", "eng")])
p = _bare(audio_codec="DTS-HD.MA", audio_channels="7.1")
enrich_from_probe(p, info)
assert p.audio_codec == "DTS-HD.MA"
+3 -1
View File
@@ -142,7 +142,9 @@ class TestHelpers:
def test_pair_placed_falls_back_to_positional(self):
# Placed source path doesn't match any track.file_path → fallback uses tracks[0].
t = _track(file_path=Path("/in/known.srt"))
p = PlacedTrack(source=Path("/in/ghost.srt"), destination=Path("/x"), filename="x")
p = PlacedTrack(
source=Path("/in/ghost.srt"), destination=Path("/x"), filename="x"
)
pairs = _pair_placed_with_tracks([p], [t])
assert pairs == [(p, t)]
+42 -19
View File
@@ -78,7 +78,9 @@ class TestFindExistingTvshowFolders:
(tmp_path / "oz.1997.bluray-OTHER").mkdir()
(tmp_path / "OtherShow.1999").mkdir()
out = _find_existing_tvshow_folders(tmp_path, "Oz", 1997)
assert out == ["Oz.1997.WEBRip-KONTRAST", "oz.1997.bluray-OTHER"] or set(out) == {
assert out == ["Oz.1997.WEBRip-KONTRAST", "oz.1997.bluray-OTHER"] or set(
out
) == {
"Oz.1997.WEBRip-KONTRAST",
"oz.1997.bluray-OTHER",
}
@@ -103,28 +105,42 @@ class TestResolveSeriesFolderInternal:
def test_confirmed_folder_when_exists(self, tmp_path):
(tmp_path / "Oz.1997.X-GRP").mkdir()
out = _resolve_series_folder(
tmp_path, "Oz", 1997, "Oz.1997.WEBRip-KONTRAST", confirmed_folder="Oz.1997.X-GRP"
tmp_path,
"Oz",
1997,
"Oz.1997.WEBRip-KONTRAST",
confirmed_folder="Oz.1997.X-GRP",
)
assert out == ("Oz.1997.X-GRP", False)
def test_confirmed_folder_when_new(self, tmp_path):
out = _resolve_series_folder(
tmp_path, "Oz", 1997, "Oz.1997.WEBRip-KONTRAST", confirmed_folder="Oz.1997.New-X"
tmp_path,
"Oz",
1997,
"Oz.1997.WEBRip-KONTRAST",
confirmed_folder="Oz.1997.New-X",
)
assert out == ("Oz.1997.New-X", True)
def test_no_existing_returns_computed_as_new(self, tmp_path):
out = _resolve_series_folder(tmp_path, "Oz", 1997, "Oz.1997.WEBRip-KONTRAST", None)
out = _resolve_series_folder(
tmp_path, "Oz", 1997, "Oz.1997.WEBRip-KONTRAST", None
)
assert out == ("Oz.1997.WEBRip-KONTRAST", True)
def test_single_existing_matching_computed_returns_existing(self, tmp_path):
(tmp_path / "Oz.1997.WEBRip-KONTRAST").mkdir()
out = _resolve_series_folder(tmp_path, "Oz", 1997, "Oz.1997.WEBRip-KONTRAST", None)
out = _resolve_series_folder(
tmp_path, "Oz", 1997, "Oz.1997.WEBRip-KONTRAST", None
)
assert out == ("Oz.1997.WEBRip-KONTRAST", False)
def test_single_existing_different_name_returns_clarification(self, tmp_path):
(tmp_path / "Oz.1997.BluRay-OTHER").mkdir()
out = _resolve_series_folder(tmp_path, "Oz", 1997, "Oz.1997.WEBRip-KONTRAST", None)
out = _resolve_series_folder(
tmp_path, "Oz", 1997, "Oz.1997.WEBRip-KONTRAST", None
)
assert isinstance(out, _Clarification)
assert "Oz" in out.question
assert "Oz.1997.BluRay-OTHER" in out.options
@@ -185,7 +201,9 @@ class TestSeason:
assert out.series_folder_name.startswith("Oz.1997")
assert out.season_folder_name.startswith("Oz.S03")
assert out.series_folder == str(tv / out.series_folder_name)
assert out.season_folder == str(tv / out.series_folder_name / out.season_folder_name)
assert out.season_folder == str(
tv / out.series_folder_name / out.season_folder_name
)
def test_clarification_path(self, cfg_memory):
_, tv, _ = cfg_memory
@@ -222,32 +240,29 @@ class TestEpisode:
)
def test_ok_path_without_episode_title(self, cfg_memory):
out = resolve_episode_destination(
REL_EPISODE, "/dl/source.mkv", "Oz", 1997
)
out = resolve_episode_destination(REL_EPISODE, "/dl/source.mkv", "Oz", 1997)
assert out.status == "ok"
# No '..' from blank ep title.
assert ".." not in out.filename
def test_extension_taken_from_source_file(self, cfg_memory):
out = resolve_episode_destination(
REL_EPISODE, "/dl/source.mp4", "Oz", 1997
)
out = resolve_episode_destination(REL_EPISODE, "/dl/source.mp4", "Oz", 1997)
assert out.filename.endswith(".mp4")
def test_clarification_path(self, cfg_memory):
_, tv, _ = cfg_memory
(tv / "Oz.1997.BluRay-OTHER").mkdir()
out = resolve_episode_destination(
REL_EPISODE, "/dl/source.mkv", "Oz", 1997
)
out = resolve_episode_destination(REL_EPISODE, "/dl/source.mkv", "Oz", 1997)
assert out.status == "needs_clarification"
def test_confirmed_folder_threaded_through(self, cfg_memory):
_, tv, _ = cfg_memory
(tv / "Oz.1997.BluRay-OTHER").mkdir()
out = resolve_episode_destination(
REL_EPISODE, "/dl/source.mkv", "Oz", 1997,
REL_EPISODE,
"/dl/source.mkv",
"Oz",
1997,
confirmed_folder="Oz.1997.BluRay-OTHER",
)
assert out.status == "ok"
@@ -340,13 +355,21 @@ class TestDTOToDict:
d = ResolvedSeasonDestination(
status="error", error="library_not_set", message="missing"
).to_dict()
assert d == {"status": "error", "error": "library_not_set", "message": "missing"}
assert d == {
"status": "error",
"error": "library_not_set",
"message": "missing",
}
def test_season_clarification(self):
d = ResolvedSeasonDestination(
status="needs_clarification", question="which?", options=["a", "b"]
).to_dict()
assert d == {"status": "needs_clarification", "question": "which?", "options": ["a", "b"]}
assert d == {
"status": "needs_clarification",
"question": "which?",
"options": ["a", "b"],
}
def test_episode_ok(self):
d = ResolvedEpisodeDestination(
+20 -10
View File
@@ -20,8 +20,9 @@ from alfred.domain.shared.media import AudioTrack, MediaInfo, SubtitleTrack, Vid
class TestTracks:
def test_audio_track_defaults(self):
t = AudioTrack(index=0, codec="aac", channels=2, channel_layout="stereo",
language="eng")
t = AudioTrack(
index=0, codec="aac", channels=2, channel_layout="stereo", language="eng"
)
assert t.is_default is False
def test_subtitle_track_defaults(self):
@@ -36,7 +37,9 @@ class TestTracks:
class TestVideoTrackResolution:
def test_no_dimensions(self):
assert VideoTrack(index=0, codec=None, width=None, height=None).resolution is None
assert (
VideoTrack(index=0, codec=None, width=None, height=None).resolution is None
)
@pytest.mark.parametrize(
"w,expected",
@@ -50,11 +53,16 @@ class TestVideoTrackResolution:
],
)
def test_width_priority(self, w, expected):
assert VideoTrack(index=0, codec=None, width=w, height=1080).resolution == expected
assert (
VideoTrack(index=0, codec=None, width=w, height=1080).resolution == expected
)
def test_widescreen_scope_crop(self):
# 1920x960 (scope crop) → still 1080p because width-priority
assert VideoTrack(index=0, codec=None, width=1920, height=960).resolution == "1080p"
assert (
VideoTrack(index=0, codec=None, width=1920, height=960).resolution
== "1080p"
)
@pytest.mark.parametrize(
"h,expected",
@@ -67,11 +75,15 @@ class TestVideoTrackResolution:
],
)
def test_height_fallback_when_width_missing(self, h, expected):
assert VideoTrack(index=0, codec=None, width=None, height=h).resolution == expected
assert (
VideoTrack(index=0, codec=None, width=None, height=h).resolution == expected
)
def test_width_below_buckets_falls_to_height(self):
# width=320 falls below every bucket; falls back to f"{h}p"
assert VideoTrack(index=0, codec=None, width=320, height=240).resolution == "240p"
assert (
VideoTrack(index=0, codec=None, width=320, height=240).resolution == "240p"
)
def test_width_only_below_buckets(self):
# width=200, no height → f"{w}w" sentinel
@@ -127,9 +139,7 @@ class TestAudioLanguages:
assert m.audio_languages == []
def test_is_multi_audio_false_single_lang(self):
m = MediaInfo(
audio_tracks=[AudioTrack(0, "aac", 2, "stereo", "eng")]
)
m = MediaInfo(audio_tracks=[AudioTrack(0, "aac", 2, "stereo", "eng")])
assert m.is_multi_audio is False
def test_is_multi_audio_true(self):
+6 -5
View File
@@ -49,8 +49,11 @@ def identifier(kb):
return SubtitleIdentifier(kb)
def _pattern(strategy: ScanStrategy, root_folder: str | None = None,
detection: TypeDetectionMethod = TypeDetectionMethod.TOKEN_IN_NAME) -> SubtitlePattern:
def _pattern(
strategy: ScanStrategy,
root_folder: str | None = None,
detection: TypeDetectionMethod = TypeDetectionMethod.TOKEN_IN_NAME,
) -> SubtitlePattern:
return SubtitlePattern(
id=f"test-{strategy.value}",
description="",
@@ -70,9 +73,7 @@ class TestTokenize:
assert _tokenize("Show.S01E01.French") == ["show", "s01e01", "french"]
def test_mixed_separators(self):
assert _tokenize("Show_S01-E01 French") == [
"show", "s01", "e01", "french"
]
assert _tokenize("Show_S01-E01 French") == ["show", "s01", "e01", "french"]
def test_strips_parenthesized(self):
assert _tokenize("episode (Brazil).French") == ["episode", "french"]
+6 -18
View File
@@ -77,9 +77,7 @@ class TestUnresolved:
def test_threshold_exact_passes(self, matcher):
t = _track(confidence=0.7)
rules = SubtitleMatchingRules(
min_confidence=0.7, preferred_languages=["fra"]
)
rules = SubtitleMatchingRules(min_confidence=0.7, preferred_languages=["fra"])
matched, unresolved = matcher.match([t], rules)
assert matched == [t]
@@ -92,17 +90,13 @@ class TestUnresolved:
class TestLanguageFilter:
def test_preferred_languages_filters_out(self, matcher):
t_eng = _track(lang=ENG)
rules = SubtitleMatchingRules(
preferred_languages=["fra"], min_confidence=0.0
)
rules = SubtitleMatchingRules(preferred_languages=["fra"], min_confidence=0.0)
matched, _ = matcher.match([t_eng], rules)
assert matched == []
def test_preferred_language_match_passes(self, matcher):
t_fra = _track(lang=FRA)
rules = SubtitleMatchingRules(
preferred_languages=["fra"], min_confidence=0.0
)
rules = SubtitleMatchingRules(preferred_languages=["fra"], min_confidence=0.0)
matched, _ = matcher.match([t_fra], rules)
assert matched == [t_fra]
@@ -118,17 +112,13 @@ class TestLanguageFilter:
class TestFormatFilter:
def test_format_outside_preferred_filtered(self, matcher):
t = _track(fmt=ASS)
rules = SubtitleMatchingRules(
preferred_formats=["srt"], min_confidence=0.0
)
rules = SubtitleMatchingRules(preferred_formats=["srt"], min_confidence=0.0)
matched, _ = matcher.match([t], rules)
assert matched == []
def test_no_format_attribute_filtered_when_pref_set(self, matcher):
t = _track(fmt=None)
rules = SubtitleMatchingRules(
preferred_formats=["srt"], min_confidence=0.0
)
rules = SubtitleMatchingRules(preferred_formats=["srt"], min_confidence=0.0)
matched, _ = matcher.match([t], rules)
assert matched == []
@@ -144,9 +134,7 @@ class TestTypeFilter:
def test_allowed_type_passes(self, matcher):
t = _track(stype=SubtitleType.STANDARD)
rules = SubtitleMatchingRules(
allowed_types=["standard"], min_confidence=0.0
)
rules = SubtitleMatchingRules(allowed_types=["standard"], min_confidence=0.0)
matched, _ = matcher.match([t], rules)
assert matched == [t]
+22 -10
View File
@@ -83,11 +83,15 @@ class TestSubtitleCandidateDestName:
assert t.destination_name == "fra.sdh.srt"
def test_forced(self):
t = SubtitleCandidate(language=FRA, format=SRT, subtitle_type=SubtitleType.FORCED)
t = SubtitleCandidate(
language=FRA, format=SRT, subtitle_type=SubtitleType.FORCED
)
assert t.destination_name == "fra.forced.srt"
def test_unknown_treated_as_standard(self):
t = SubtitleCandidate(language=FRA, format=SRT, subtitle_type=SubtitleType.UNKNOWN)
t = SubtitleCandidate(
language=FRA, format=SRT, subtitle_type=SubtitleType.UNKNOWN
)
# UNKNOWN doesn't add a suffix → same as standard.
assert t.destination_name == "fra.srt"
@@ -110,7 +114,9 @@ class TestSubtitleCandidateDestName:
class TestSubtitleCandidateRepr:
def test_embedded_repr(self):
t = SubtitleCandidate(language=FRA, format=None, is_embedded=True, confidence=1.0)
t = SubtitleCandidate(
language=FRA, format=None, is_embedded=True, confidence=1.0
)
r = repr(t)
assert "fra" in r
assert "embedded" in r
@@ -118,9 +124,7 @@ class TestSubtitleCandidateRepr:
def test_external_repr_uses_filename(self, tmp_path):
f = tmp_path / "fr.srt"
f.write_text("")
t = SubtitleCandidate(
language=FRA, format=SRT, file_path=f, confidence=0.85
)
t = SubtitleCandidate(language=FRA, format=SRT, file_path=f, confidence=0.85)
r = repr(t)
assert "fra" in r
assert "fr.srt" in r
@@ -159,7 +163,9 @@ class TestMediaSubtitleMetadata:
def test_unresolved_tracks_only_external_with_none_lang(self):
# An embedded with None language must NOT appear in unresolved_tracks
# (the property only iterates external_tracks).
embedded_unknown = SubtitleCandidate(language=None, format=None, is_embedded=True)
embedded_unknown = SubtitleCandidate(
language=None, format=None, is_embedded=True
)
external_known = SubtitleCandidate(
language=FRA, format=SRT, file_path=Path("/a.srt")
)
@@ -184,10 +190,16 @@ class TestAvailableSubtitles:
def test_dedup_by_lang_and_type(self):
ENG = SubtitleLanguage(code="eng", tokens=["en"])
tracks = [
SubtitleCandidate(language=FRA, format=SRT, subtitle_type=SubtitleType.STANDARD),
SubtitleCandidate(language=FRA, format=SRT, subtitle_type=SubtitleType.STANDARD),
SubtitleCandidate(
language=FRA, format=SRT, subtitle_type=SubtitleType.STANDARD
),
SubtitleCandidate(
language=FRA, format=SRT, subtitle_type=SubtitleType.STANDARD
),
SubtitleCandidate(language=FRA, format=SRT, subtitle_type=SubtitleType.SDH),
SubtitleCandidate(language=ENG, format=SRT, subtitle_type=SubtitleType.STANDARD),
SubtitleCandidate(
language=ENG, format=SRT, subtitle_type=SubtitleType.STANDARD
),
]
result = available_subtitles(tracks)
keys = [(t.language.code, t.subtitle_type) for t in result]
+7 -7
View File
@@ -182,11 +182,13 @@ class TestEpisode:
assert e.has_audio_in("ger") is False
def test_has_audio_in_with_language(self):
lang = Language(iso="fre", english_name="French", native_name="Français",
aliases=("fr", "fra", "french"))
e = self._ep(
audio_tracks=[AudioTrack(0, "ac3", 6, "5.1", "fr")]
lang = Language(
iso="fre",
english_name="French",
native_name="Français",
aliases=("fr", "fra", "french"),
)
e = self._ep(audio_tracks=[AudioTrack(0, "ac3", 6, "5.1", "fr")])
# str query "fre" wouldn't match "fr" directly — but Language does cross-format
assert e.has_audio_in(lang) is True
assert e.has_audio_in("fre") is False # direct compare misses
@@ -205,9 +207,7 @@ class TestEpisode:
# ── Subtitle helpers ───────────────────────────────────────────────
def test_has_subtitles_in(self):
e = self._ep(
subtitle_tracks=[SubtitleTrack(0, "subrip", "fre")]
)
e = self._ep(subtitle_tracks=[SubtitleTrack(0, "subrip", "fre")])
assert e.has_subtitles_in("fre") is True
assert e.has_subtitles_in("eng") is False
@@ -79,9 +79,7 @@ def client():
class TestInit:
def test_explicit_args(self):
c = QBittorrentClient(
host="http://x:1", username="u", password="p", timeout=99
)
c = QBittorrentClient(host="http://x:1", username="u", password="p", timeout=99)
assert c.host == "http://x:1"
assert c.username == "u"
assert c.password == "p"
@@ -265,9 +263,7 @@ class TestMutations:
def test_delete_no_files_default(self, client):
self._ok(client)
client.delete_torrent("hash1")
assert (
client.session.post.call_args.kwargs["data"]["deleteFiles"] == "false"
)
assert client.session.post.call_args.kwargs["data"]["deleteFiles"] == "false"
def test_pause(self, client):
self._ok(client)
@@ -328,9 +324,7 @@ class TestFindByName:
def test_case_insensitive_match(self, client):
client._authenticated = True
client.session.get.return_value = _resp(
[_torrent_dict("foundation.s01")]
)
client.session.get.return_value = _resp([_torrent_dict("foundation.s01")])
result = client.find_by_name("Foundation.S01")
assert result is not None
assert result.name == "foundation.s01"
+2 -8
View File
@@ -231,11 +231,7 @@ class TestSearchMedia:
def test_tv_uses_name_field(self, mock_get, client):
mock_get.side_effect = [
_ok_response(
{
"results": [
{"id": 1396, "media_type": "tv", "name": "Breaking Bad"}
]
}
{"results": [{"id": 1396, "media_type": "tv", "name": "Breaking Bad"}]}
),
_ok_response({"imdb_id": "tt0903747"}),
]
@@ -281,9 +277,7 @@ class TestSearchMedia:
def test_external_ids_failure_returns_result_without_imdb(self, mock_get, client):
# Second call (external IDs) fails — the search should still succeed.
mock_get.side_effect = [
_ok_response(
{"results": [{"id": 1, "media_type": "movie", "title": "X"}]}
),
_ok_response({"results": [{"id": 1, "media_type": "movie", "title": "X"}]}),
Timeout("slow"),
]
result = client.search_media("X")
+9 -7
View File
@@ -160,13 +160,15 @@ class TestUpdateParseAndProbe:
class TestUpdateTmdb:
def test_promotes_identity_to_top_level(self, tmp_path):
s = MetadataStore(tmp_path)
s.update_tmdb({
"status": "ok",
"imdb_id": "tt1375666",
"tmdb_id": 27205,
"media_type": "movie",
"title": "Inception",
})
s.update_tmdb(
{
"status": "ok",
"imdb_id": "tt1375666",
"tmdb_id": 27205,
"media_type": "movie",
"title": "Inception",
}
)
data = s.load()
assert data["imdb_id"] == "tt1375666"
assert data["tmdb_id"] == 27205
+17 -13
View File
@@ -38,17 +38,23 @@ def _write(path: Path, data: dict) -> None:
class TestFilterOverride:
def test_keeps_only_valid_keys(self):
out = _filter_override({
"languages": ["fra"],
"formats": ["srt"],
"types": ["standard"],
"format_priority": ["srt"],
"min_confidence": 0.8,
"unknown_key": "ignored",
"another": 42,
})
out = _filter_override(
{
"languages": ["fra"],
"formats": ["srt"],
"types": ["standard"],
"format_priority": ["srt"],
"min_confidence": 0.8,
"unknown_key": "ignored",
"another": 42,
}
)
assert set(out) == {
"languages", "formats", "types", "format_priority", "min_confidence"
"languages",
"formats",
"types",
"format_priority",
"min_confidence",
}
assert "unknown_key" not in out
@@ -113,9 +119,7 @@ class TestLoad:
{"override": {"min_confidence": 0.99}},
)
repo = RuleSetRepository(tmp_path)
rules = repo.load(
release_group="GRP", subtitle_preferences=prefs
).resolve()
rules = repo.load(release_group="GRP", subtitle_preferences=prefs).resolve()
# All three levels visible — local overrides on top
assert rules.preferred_languages == ["jpn"]
assert rules.format_priority == ["ass"]
@@ -30,7 +30,9 @@ FRA = SubtitleLanguage(code="fra", tokens=["fr"])
ENG = SubtitleLanguage(code="eng", tokens=["en"])
def _track(lang=FRA, *, embedded: bool = False, confidence: float = 0.92) -> SubtitleCandidate:
def _track(
lang=FRA, *, embedded: bool = False, confidence: float = 0.92
) -> SubtitleCandidate:
return SubtitleCandidate(
language=lang,
format=SRT,