refactor: config objects for feature toggles in ConversionRequest

This commit is contained in:
Artem Akymenko
2026-07-24 19:17:36 +03:00
parent 7d28b7eb52
commit 0ee5bb0496
10 changed files with 247 additions and 106 deletions
+21 -21
View File
@@ -10,6 +10,7 @@ from unittest.mock import MagicMock, patch
import pytest
from abogen.application.conversion_request import ConversionRequest
from abogen.application.conversion_config import ChapterChunkConfig, PronunciationConfig
from abogen.application.conversion_ports import ResolvedVoice
@@ -112,25 +113,22 @@ class TestWebUIAdapter:
assert req.output_folder is None
assert req.cover_image_path is None
def test_chapter_overrides_mapped(self):
def test_chapter_chunk_mapped(self):
from abogen.webui.conversion_adapter import build_conversion_request_from_job
chapters = [{"title": "Ch1", "voice": "F1"}]
job = self._make_job(chapters=chapters)
req = build_conversion_request_from_job(job)
assert req.chapter_overrides == chapters
def test_chunks_mapped(self):
from abogen.webui.conversion_adapter import build_conversion_request_from_job
chunks = [{"text": "Hello", "speaker": "A"}]
job = self._make_job(chunks=chunks)
job = self._make_job(chapters=chapters, chunks=chunks)
req = build_conversion_request_from_job(job)
assert req.chunks == chunks
assert isinstance(req.chapter_chunk, ChapterChunkConfig)
assert req.chapter_chunk.chapter_overrides == chapters
assert req.chapter_chunk.chunks == chunks
assert req.chapter_chunk.chunk_level == "paragraph"
assert req.chapter_chunk.speaker_mode == "single"
assert req.chapter_chunk.speakers == {}
def test_pronunciation_overrides_mapped(self):
def test_pronunciation_mapped(self):
from abogen.webui.conversion_adapter import build_conversion_request_from_job
job = self._make_job(
@@ -140,9 +138,10 @@ class TestWebUIAdapter:
)
req = build_conversion_request_from_job(job)
assert req.pronunciation_overrides == ["word=pron"]
assert req.manual_overrides == ["manual=override"]
assert req.heteronym_overrides == ["read=reed"]
assert isinstance(req.pronunciation, PronunciationConfig)
assert req.pronunciation.pronunciation_overrides == ["word=pron"]
assert req.pronunciation.manual_overrides == ["manual=override"]
assert req.pronunciation.heteronym_overrides == ["read=reed"]
def test_none_defaults_handled(self):
from abogen.webui.conversion_adapter import build_conversion_request_from_job
@@ -399,17 +398,18 @@ class TestPyQtAdapter:
assert req.supertonic_total_steps == 5
assert req.max_subtitle_words == 50
def test_chapter_chunks_not_mapped(self):
def test_chapter_chunk_default(self):
from abogen.pyqt.conversion_adapter import build_conversion_request_from_thread
thread = self._make_thread()
req = build_conversion_request_from_thread(thread)
assert req.chapter_overrides == []
assert req.chunks == []
assert req.chunk_level == "paragraph"
assert req.speaker_mode == "single"
assert req.speakers == {}
assert isinstance(req.chapter_chunk, ChapterChunkConfig)
assert req.chapter_chunk.chapter_overrides == []
assert req.chapter_chunk.chunks == []
assert req.chapter_chunk.chunk_level == "paragraph"
assert req.chapter_chunk.speaker_mode == "single"
assert req.chapter_chunk.speakers == {}
class TestPyQtEvents:
+14 -9
View File
@@ -25,6 +25,7 @@ from abogen.application.conversion_models import (
OutputLayout,
SegmentPlan,
)
from abogen.application.conversion_config import ChapterChunkConfig
from abogen.application.conversion_planner import build_conversion_plan
from abogen.application.conversion_request import ConversionRequest
@@ -74,10 +75,12 @@ class TestBuildConversionPlan:
req = ConversionRequest(
direct_text="Some text",
voice="M1",
chunks=[
{"text": "Chunk 1", "speaker_id": "narrator"},
{"text": "Chunk 2", "speaker_id": "narrator"},
],
chapter_chunk=ChapterChunkConfig(
chunks=[
{"text": "Chunk 1", "speaker_id": "narrator"},
{"text": "Chunk 2", "speaker_id": "narrator"},
],
),
)
plan = build_conversion_plan(req)
@@ -92,11 +95,13 @@ class TestBuildConversionPlan:
req = ConversionRequest(
direct_text="Text",
voice="M1",
chunks=[
{"text": "Narrator speaks", "speaker_id": "narrator"},
{"text": "Character speaks", "speaker_id": "alice", "voice": "F1"},
],
speakers={"alice": {"voice": "F1"}},
chapter_chunk=ChapterChunkConfig(
chunks=[
{"text": "Narrator speaks", "speaker_id": "narrator"},
{"text": "Character speaks", "speaker_id": "alice", "voice": "F1"},
],
speakers={"alice": {"voice": "F1"}},
),
)
plan = build_conversion_plan(req)
+5 -4
View File
@@ -16,6 +16,7 @@ from pathlib import Path
from unittest.mock import MagicMock
from abogen.application.conversion_request import ConversionRequest, ConversionRequestError
from abogen.application.conversion_config import ChapterChunkConfig, WordSubstitutionConfig
from abogen.domain.enums import Language, OutputFormat, SaveMode, SubtitleFormat, SubtitleMode
from abogen.domain.normalization import TTSContext
from abogen.domain.settings_core import settings_defaults
@@ -248,12 +249,12 @@ class TestConversionRequestValidation:
assert req.chapter_intro_delay == 0.0
def test_invalid_chunk_level_raises(self):
with pytest.raises(ConversionRequestError, match="chunk_level"):
ConversionRequest(chunk_level="invalid")
with pytest.raises(ValueError, match="chunk_level"):
ConversionRequest(chapter_chunk=ChapterChunkConfig(chunk_level="invalid"))
def test_invalid_speaker_mode_raises(self):
with pytest.raises(ConversionRequestError, match="speaker_mode"):
ConversionRequest(speaker_mode="invalid")
with pytest.raises(ValueError, match="speaker_mode"):
ConversionRequest(chapter_chunk=ChapterChunkConfig(speaker_mode="invalid"))
def test_invalid_max_subtitle_words_type_raises(self):
with pytest.raises(ConversionRequestError, match="max_subtitle_words"):