Files
diodiogod-TTS-Audio-Suite/tests/unit/test_installer_runtime_repairs.py
diodiogod 2f587b22b3 Version 5.6.3
Prevent installer validation from importing engine runtimes

Technical details:
- Walk dotted module specs without importing parent packages
- Keep presence-only validation isolated from third-party startup checks
- Add regression coverage for import side effects
- Address issue #337
2026-08-01 17:46:46 -03:00

109 lines
3.6 KiB
Python

import importlib.util
import sys
import types
from pathlib import Path
import pytest
REPO_ROOT = Path(__file__).resolve().parents[2]
if str(REPO_ROOT) not in sys.path:
sys.path.insert(0, str(REPO_ROOT))
INSTALL_SPEC = importlib.util.spec_from_file_location("tts_suite_install_test_module", REPO_ROOT / "install.py")
INSTALL_MODULE = importlib.util.module_from_spec(INSTALL_SPEC)
INSTALL_SPEC.loader.exec_module(INSTALL_MODULE)
from engines.dots_tts.dots_tts_engine import DotsTTSEngine
from utils.runtimes.profiles import get_runtime_profile
@pytest.mark.unit
def test_nested_module_check_does_not_import_parent(tmp_path, monkeypatch):
package = tmp_path / "explosive_parent"
package.mkdir()
(package / "__init__.py").write_text(
"raise RuntimeError('parent package must not be imported')\n",
encoding="utf-8",
)
(package / "runtime.py").write_text("", encoding="utf-8")
monkeypatch.syspath_prepend(str(tmp_path))
monkeypatch.delitem(sys.modules, "explosive_parent", raising=False)
installer = INSTALL_MODULE.TTSAudioInstaller()
assert installer.module_available("explosive_parent.runtime") is True
assert installer.module_available("explosive_parent.missing") is False
assert "explosive_parent" not in sys.modules
@pytest.mark.unit
def test_fish_source_restore_accepts_namespace_package(tmp_path, monkeypatch):
source_root = tmp_path / "source"
source_package = source_root / "fish_speech"
(source_package / "inference_engine").mkdir(parents=True)
(source_package / "inference_engine" / "__init__.py").write_text("", encoding="utf-8")
site_root = tmp_path / "site-packages"
target_package = site_root / "fish_speech"
target_package.mkdir(parents=True)
(target_package / "content_sequence.py").write_text("", encoding="utf-8")
monkeypatch.setattr(sys, "path", [str(site_root)])
installer = INSTALL_MODULE.TTSAudioInstaller()
assert installer._restore_fish_source_package(source_root) is True
assert (target_package / "inference_engine" / "__init__.py").is_file()
@pytest.mark.unit
def test_dots_fallback_overrides_incomplete_tn_module_temporarily(monkeypatch):
unrelated_tn = types.ModuleType("tn")
monkeypatch.setitem(sys.modules, "tn", unrelated_tn)
for name in (
"tn.chinese",
"tn.chinese.normalizer",
"tn.english",
"tn.english.normalizer",
):
monkeypatch.delitem(sys.modules, name, raising=False)
with DotsTTSEngine._text_normalizer_compat():
from tn.chinese.normalizer import Normalizer as ZhNormalizer
from tn.english.normalizer import Normalizer as EnNormalizer
assert ZhNormalizer().normalize("123") == "123"
assert EnNormalizer().normalize("test") == "test"
assert sys.modules["tn"] is unrelated_tn
assert "tn.chinese" not in sys.modules
assert "tn.english" not in sys.modules
@pytest.mark.unit
def test_vibevoice_runtime_avoids_webrtc_dependency_conflict():
profile = get_runtime_profile("vibevoice_transformers4_shared")
assert profile is not None
assert "av" in profile.pip_packages
assert not {
"aiortc",
"pyee",
"dnspython",
"ifaddr",
"pylibsrtp",
"pyopenssl",
}.intersection(profile.pip_packages)
@pytest.mark.unit
@pytest.mark.parametrize(
"profile_name",
("vibevoice_transformers4_shared", "qwen3_tts_transformers4_dedicated"),
)
def test_legacy_transformers_runtime_pins_compatible_kernels(profile_name):
profile = get_runtime_profile(profile_name)
assert profile is not None
assert "kernels>=0.6.1,<=0.9" in profile.pip_packages