Fix 6 bugs: shared stdin reader, CDDB multiline, type annotation, crash fixes
- ripper: replace per-call stdin daemon threads with a shared module-level reader (_stdin_queue + _read_line), preventing orphan threads from stealing stdin input after photo uploads; all 8 input() calls in interactive_rip now use _read_line() - ripper: _stream_abcde return type annotation fixed (2-tuple → 3-tuple) - ripper: disc retry rejection now breaks gracefully instead of raising unhandled RuntimeError that crashed the program - ripper: int() on disc number input wrapped in try/except - cddb: multi-line DTITLE/TTITLE values are now concatenated instead of only keeping the last line (per CDDB/xmcd protocol spec) - cli: removed unreachable dead code block in apply command - scanner_server: upload form auto-resets after 3s for repeated uploads - tests: _scanner_patches() updated to mock _read_line alongside _input_or_scan (225 tests passing) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
488149b8f9
commit
8c25bc65be
5 changed files with 100 additions and 40 deletions
|
|
@ -358,7 +358,7 @@ class TestInteractiveRipEanFirst:
|
|||
config = RipperConfig(output_dir=tmp_path)
|
||||
sp = self._scanner_patches()
|
||||
with (
|
||||
sp[0], sp[1],
|
||||
sp[0], sp[1], sp[2],
|
||||
patch("musiksammlung.ripper.rip_disc", return_value=(tmp_path, None, _CDDB_TRACKS)),
|
||||
patch("builtins.input", side_effect=iter(inputs)),
|
||||
patch("musiksammlung.ripper.lookup_by_barcode", return_value=(_MB_ALBUM, "fake-mbid")),
|
||||
|
|
@ -386,7 +386,7 @@ class TestInteractiveRipEanFirst:
|
|||
config = RipperConfig(output_dir=tmp_path)
|
||||
sp = self._scanner_patches()
|
||||
with (
|
||||
sp[0], sp[1],
|
||||
sp[0], sp[1], sp[2],
|
||||
patch("musiksammlung.ripper.rip_disc", return_value=(tmp_path, None, _CDDB_TRACKS)),
|
||||
patch("builtins.input", side_effect=iter(inputs)),
|
||||
patch("musiksammlung.ripper.lookup_by_barcode",
|
||||
|
|
@ -414,7 +414,7 @@ class TestInteractiveRipEanFirst:
|
|||
config = RipperConfig(output_dir=tmp_path)
|
||||
sp = self._scanner_patches()
|
||||
with (
|
||||
sp[0], sp[1],
|
||||
sp[0], sp[1], sp[2],
|
||||
patch("musiksammlung.ripper.rip_disc", return_value=(tmp_path, None, _CDDB_TRACKS)),
|
||||
patch("builtins.input", side_effect=iter(inputs)),
|
||||
patch("musiksammlung.ripper.lookup_by_barcode",
|
||||
|
|
@ -440,7 +440,7 @@ class TestInteractiveRipEanFirst:
|
|||
|
||||
sp = self._scanner_patches()
|
||||
with (
|
||||
sp[0], sp[1],
|
||||
sp[0], sp[1], sp[2],
|
||||
patch("musiksammlung.ripper.rip_disc", return_value=(disc_dir, None, _CDDB_TRACKS)),
|
||||
patch("builtins.input", side_effect=iter(inputs)),
|
||||
patch("musiksammlung.ripper.lookup_by_barcode", return_value=(_MB_ALBUM, "fake-mbid")),
|
||||
|
|
@ -459,7 +459,11 @@ class TestInteractiveRipEanFirst:
|
|||
|
||||
@staticmethod
|
||||
def _scanner_patches():
|
||||
"""Patches für ScannerServer und _input_or_scan (alle interactive_rip-Tests)."""
|
||||
"""Patches für ScannerServer, _input_or_scan und _read_line.
|
||||
|
||||
_input_or_scan und _read_line leiten beide an builtins.input weiter,
|
||||
das in jedem Test separat mit einer Eingabeliste gemockt wird.
|
||||
"""
|
||||
mock_scanner = MagicMock()
|
||||
mock_scanner.url.return_value = "http://127.0.0.1:8765"
|
||||
mock_scanner.get_photo.return_value = None
|
||||
|
|
@ -469,6 +473,10 @@ class TestInteractiveRipEanFirst:
|
|||
"musiksammlung.ripper._input_or_scan",
|
||||
side_effect=lambda prompt, scanner: (input(prompt), None),
|
||||
),
|
||||
patch(
|
||||
"musiksammlung.ripper._read_line",
|
||||
side_effect=lambda prompt="": input(prompt),
|
||||
),
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -491,7 +499,7 @@ class TestInteractiveRipEanFirst:
|
|||
config = RipperConfig(output_dir=tmp_path)
|
||||
patches = self._fallback_patches(inputs)
|
||||
with (
|
||||
patches[0], patches[1], patches[2],
|
||||
patches[0], patches[1], patches[2], patches[3],
|
||||
patch("musiksammlung.ripper.rip_disc", return_value=(tmp_path, None, _CDDB_TRACKS)),
|
||||
patch("musiksammlung.ripper.lookup_by_barcode") as mock_lookup,
|
||||
):
|
||||
|
|
@ -514,7 +522,7 @@ class TestInteractiveRipEanFirst:
|
|||
config = RipperConfig(output_dir=tmp_path)
|
||||
patches = self._fallback_patches(inputs)
|
||||
with (
|
||||
patches[0], patches[1], patches[2],
|
||||
patches[0], patches[1], patches[2], patches[3],
|
||||
patch("musiksammlung.ripper.rip_disc", return_value=(tmp_path, None, _CDDB_TRACKS)),
|
||||
patch(
|
||||
"musiksammlung.ripper.lookup_by_barcode",
|
||||
|
|
@ -539,7 +547,7 @@ class TestInteractiveRipEanFirst:
|
|||
config = RipperConfig(output_dir=tmp_path)
|
||||
patches = self._fallback_patches(inputs)
|
||||
with (
|
||||
patches[0], patches[1], patches[2],
|
||||
patches[0], patches[1], patches[2], patches[3],
|
||||
patch("musiksammlung.ripper.rip_disc", return_value=(tmp_path, None, _CDDB_TRACKS)),
|
||||
patch("musiksammlung.ripper.lookup_by_barcode"),
|
||||
):
|
||||
|
|
@ -565,7 +573,7 @@ class TestInteractiveRipEanFirst:
|
|||
config = RipperConfig(output_dir=tmp_path)
|
||||
patches = self._fallback_patches(inputs)
|
||||
with (
|
||||
patches[0], patches[1], patches[2],
|
||||
patches[0], patches[1], patches[2], patches[3],
|
||||
patch("musiksammlung.ripper.rip_disc", return_value=(tmp_path, None, _CDDB_TRACKS)),
|
||||
patch("musiksammlung.ripper.lookup_by_barcode"),
|
||||
):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue