Current behavior
tests/test_video.py resolves ffprobe by hand, with a hardcoded Linux path as the fallback:
def _ffprobe_video_stream_fields(mp4_path: Path) -> dict[str, str]:
ffprobe_binary = ffmpeg_path().with_name("ffprobe")
if not ffprobe_binary.is_file():
ffprobe_binary = Path("/usr/bin/ffprobe")
This is the same species as #108, which #110 fixed for test_env_override_wins, but milder: on macOS with Homebrew, ffmpeg_path() falls through to the PATH binary whose sibling ffprobe normally does exist, so the fallback is usually not reached. When it is reached on a host without /usr/bin/ffprobe, the subprocess.run(..., check=True) below raises FileNotFoundError with the Linux path in it, which tells the reader nothing true about their machine.
Why it should just call the resolver
hflow.ffmpeg._binary.ffprobe_path() already implements the whole policy, and it is strictly better than the two lines above:
HFLOW_FFPROBE override if set,
- the sibling of a user-pinned
ffmpeg (exactly what the test hand-rolls),
- the pinned Linux build,
- PATH with the pinning warning,
and it raises FfprobeNotFoundError with an actionable message rather than failing on a path nobody chose. The test is reimplementing step 2 and substituting a guess for steps 1, 3, and 4.
Definition of done
_ffprobe_video_stream_fields calls ffprobe_path() and no test contains a hardcoded absolute binary path. After the change this should return nothing:
rg -n '/usr/bin|/usr/local/bin|/opt/homebrew' tests/
Note ffprobe_path() is lru_cached, so if a test in the same session repoints HFLOW_FFPROBE it needs the existing cleared_binary_caches fixture, the same way tests/test_ffmpeg.py handles it. tests/test_video.py does not currently manipulate those variables, so this is a note rather than a required change.
Pattern to copy
tests/test_ffmpeg.py imports ffprobe_path and uses it directly; #110 is the precedent for removing the hardcoded path, and its tmp_path approach is the precedent for any override a test needs to fabricate.
Validation
uv run ruff check --fix
uv run ruff format
uv run ty check
uv run pytest -q tests/test_video.py
uv run pytest -q
tests/test_video.py needs ffmpeg on PATH; those tests failing without it is pre-existing.
Context
Follow-up to #108 and #110. @WilliamK112 found this class of bug worth finishing and has first refusal; comment here and I will assign it. Otherwise it is open to anyone.
Current behavior
tests/test_video.pyresolves ffprobe by hand, with a hardcoded Linux path as the fallback:This is the same species as #108, which #110 fixed for
test_env_override_wins, but milder: on macOS with Homebrew,ffmpeg_path()falls through to the PATH binary whose siblingffprobenormally does exist, so the fallback is usually not reached. When it is reached on a host without/usr/bin/ffprobe, thesubprocess.run(..., check=True)below raisesFileNotFoundErrorwith the Linux path in it, which tells the reader nothing true about their machine.Why it should just call the resolver
hflow.ffmpeg._binary.ffprobe_path()already implements the whole policy, and it is strictly better than the two lines above:HFLOW_FFPROBEoverride if set,ffmpeg(exactly what the test hand-rolls),and it raises
FfprobeNotFoundErrorwith an actionable message rather than failing on a path nobody chose. The test is reimplementing step 2 and substituting a guess for steps 1, 3, and 4.Definition of done
_ffprobe_video_stream_fieldscallsffprobe_path()and no test contains a hardcoded absolute binary path. After the change this should return nothing:Note
ffprobe_path()islru_cached, so if a test in the same session repointsHFLOW_FFPROBEit needs the existingcleared_binary_cachesfixture, the same waytests/test_ffmpeg.pyhandles it.tests/test_video.pydoes not currently manipulate those variables, so this is a note rather than a required change.Pattern to copy
tests/test_ffmpeg.pyimportsffprobe_pathand uses it directly; #110 is the precedent for removing the hardcoded path, and itstmp_pathapproach is the precedent for any override a test needs to fabricate.Validation
tests/test_video.pyneeds ffmpeg onPATH; those tests failing without it is pre-existing.Context
Follow-up to #108 and #110. @WilliamK112 found this class of bug worth finishing and has first refusal; comment here and I will assign it. Otherwise it is open to anyone.