throw
This commit is contained in:
1 parent
d5ef56c3ed
commit
9fbd222b23
2 files changed
+14
-10
No files matched your search
+6
-4
@@ -20,10 +20,12 @@ is an `if TYPE_CHECKING:` block to break a circular type-only reference.
|
|||||||
|
|
||||||
"Don't swallow into None" is a general principle at every level, including call
|
"Don't swallow into None" is a general principle at every level, including call
|
||||||
sites. An operation that fails must **let the exception propagate** — never catch
|
sites. An operation that fails must **let the exception propagate** — never catch
|
||||||
it and return `None` / an empty / degraded result. BPM/beat analysis is integral:
|
it and return `None` / an empty / degraded result. BPM/beat analysis and waveform
|
||||||
`_mixxx_analyze` raises rather than returning None, and every `Analysis.analyze`
|
extraction are integral: `_mixxx_analyze` raises rather than returning None,
|
||||||
call site (in `anlz.py`, `cli.py`, `collection/core.py`) lets failures abort the
|
`_decode_pcm` raises (`RuntimeError`) if ffmpeg is missing or fails to decode
|
||||||
run (including not catching around `ThreadPoolExecutor` `fut.result()`).
|
rather than returning an empty array, and every `Analysis.analyze` call site (in
|
||||||
|
`anlz.py`, `cli.py`, `collection/core.py`) lets failures abort the run (including
|
||||||
|
not catching around `ThreadPoolExecutor` `fut.result()`).
|
||||||
|
|
||||||
Reserve `None` returns for *legitimate absence* (e.g. a cache miss in
|
Reserve `None` returns for *legitimate absence* (e.g. a cache miss in
|
||||||
`Analysis.load`), never for *failure*. The one tolerated catch is a genuinely
|
`Analysis.load`), never for *failure*. The one tolerated catch is a genuinely
|
||||||
|
|||||||
@@ -123,11 +123,12 @@ def _project_pqtz(beatgrid: list[float], bpm: float) -> list[Beat]:
|
|||||||
def _decode_pcm(path: Path) -> np.ndarray:
|
def _decode_pcm(path: Path) -> np.ndarray:
|
||||||
"""Decode `path` to a 1D float32 numpy array of mono PCM at SAMPLE_RATE.
|
"""Decode `path` to a 1D float32 numpy array of mono PCM at SAMPLE_RATE.
|
||||||
|
|
||||||
Returns an empty array on ffmpeg failure.
|
Raises `RuntimeError` if ffmpeg is missing or fails to decode — waveform
|
||||||
|
extraction is integral, so a failure here is fatal rather than swallowed
|
||||||
|
into an empty array (which would yield a waveform-less ANLZ).
|
||||||
"""
|
"""
|
||||||
if not shutil.which("ffmpeg"):
|
if not shutil.which("ffmpeg"):
|
||||||
logger.warning("ffmpeg not on PATH; cannot extract waveform")
|
raise RuntimeError("ffmpeg not on PATH; cannot extract waveform")
|
||||||
return np.empty(0, dtype=np.float32)
|
|
||||||
proc = subprocess.run(
|
proc = subprocess.run(
|
||||||
["ffmpeg", "-nostdin", "-v", "error",
|
["ffmpeg", "-nostdin", "-v", "error",
|
||||||
"-i", str(path),
|
"-i", str(path),
|
||||||
@@ -135,9 +136,10 @@ def _decode_pcm(path: Path) -> np.ndarray:
|
|||||||
capture_output=True,
|
capture_output=True,
|
||||||
)
|
)
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
logger.warning("ffmpeg failed for {}: {}", path.name,
|
raise RuntimeError(
|
||||||
proc.stderr.decode("utf-8", "replace").strip())
|
f"ffmpeg failed for {path.name}: "
|
||||||
return np.empty(0, dtype=np.float32)
|
f"{proc.stderr.decode('utf-8', 'replace').strip()}"
|
||||||
|
)
|
||||||
return np.frombuffer(proc.stdout, dtype=np.float32)
|
return np.frombuffer(proc.stdout, dtype=np.float32)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user