Files
alfred/tests/fixtures/releases/conftest.py
T
francwa 3737f66851 refactor(release): simplify SHITTY to dict-driven token tagging
Replace the ~480-line legacy heuristic block in services.py with a
small dict-driven pass in pipeline._annotate_shitty: each token is
looked up against the kb buckets (resolutions / sources / codecs /
distributors / year / sxxexx) with first-match-wins semantics, the
leftmost contiguous UNKNOWN run becomes the title, done.

SHITTY's scope is intentionally narrow — releases that *look* like
scene names but don't have a registered group schema. Anything more
exotic (parenthesized tech, bare-dashed title fragments, YT slugs,
franchise boxes) is PATH OF PAIN territory and stays out of here.

- annotate() no longer returns None; SHITTY is the always-on fallback
- services.py shrunk from ~525 to ~85 lines (legacy extractors gone)
- 4 fixtures get xfail markers documenting PoP-grade pathologies
  (deutschland franchise box, sleaford YT slug, super_mario bilingual,
  predator space-separators — the last one moved from shitty/ → pop/)
- ReleaseFixture grows xfail_reason; the parametrized suite wires the
  pytest.mark.xfail(strict=False) automatically
2026-05-20 01:03:25 +02:00

69 lines
2.1 KiB
Python

"""Fixture discovery and materialization helpers for release fixtures.
Each fixture is a directory under ``tests/fixtures/releases/<bucket>/<case>/``
containing one ``expected.yaml`` file. See ``releases/README.md`` for the
schema.
"""
from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
import yaml
FIXTURES_ROOT = Path(__file__).parent
@dataclass(frozen=True)
class ReleaseFixture:
"""A loaded fixture, ready to be materialized into a temp dir."""
name: str # "<bucket>/<case>", e.g. "easy/back_in_action"
path: Path # directory containing expected.yaml
data: dict # parsed YAML contents
@property
def release_name(self) -> str:
return self.data["release_name"]
@property
def expected_parsed(self) -> dict:
return self.data.get("parsed", {})
@property
def tree(self) -> list[str]:
return self.data.get("tree", [])
@property
def routing(self) -> dict:
return self.data.get("routing", {})
@property
def xfail_reason(self) -> str | None:
"""If set, the fixture is expected to fail — wrapped with
``pytest.mark.xfail`` by the test runner. Used for known
not-supported pathological cases (typically PATH OF PAIN bucket).
"""
return self.data.get("xfail_reason")
def materialize(self, root: Path) -> None:
"""Create the fixture's ``tree`` as empty files/dirs under ``root``."""
for entry in self.tree:
target = root / entry
if entry.endswith("/"):
target.mkdir(parents=True, exist_ok=True)
else:
target.parent.mkdir(parents=True, exist_ok=True)
target.touch()
def discover_fixtures() -> list[ReleaseFixture]:
"""Find all ``expected.yaml`` files under FIXTURES_ROOT."""
fixtures = []
for yaml_path in sorted(FIXTURES_ROOT.glob("*/*/expected.yaml")):
data = yaml.safe_load(yaml_path.read_text())
name = f"{yaml_path.parent.parent.name}/{yaml_path.parent.name}"
fixtures.append(ReleaseFixture(name=name, path=yaml_path.parent, data=data))
return fixtures