# -*- coding: utf-8 -*- """测试公共设施:把两个 skill 目录下的独立脚本按路径加载为模块,供单元测试直接 import。 两个被测脚本均为独立脚本(非 Python 包),用 importlib 按文件路径加载: - skills/yt-studio-url-builder/scripts/build_studio_urls.py - skills/youtube-studio-csv-download/scripts/youtube_export_download.py CLI 端到端测试则通过 subprocess 以 sys.executable 运行脚本(见 test_*_cli.py)。 """ import importlib.util import os import subprocess import sys from pathlib import Path import pytest ROOT = Path(__file__).resolve().parent.parent URL_BUILDER_SCRIPT = ROOT / "skills" / "yt-studio-url-builder" / "scripts" / "build_studio_urls.py" COUNTRIES_JSON = URL_BUILDER_SCRIPT.parent / "countries.json" DOWNLOADER_SCRIPT = ROOT / "skills" / "youtube-studio-csv-download" / "scripts" / "youtube_export_download.py" LOOKUP_SCRIPT = ROOT / "scripts" / "lookup_groups.py" def _load_module(name, path): """按文件路径加载独立脚本为 Python 模块。""" spec = importlib.util.spec_from_file_location(name, path) assert spec is not None and spec.loader is not None mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) return mod @pytest.fixture(scope="session") def url_builder(): """build_studio_urls.py 模块(会话级,加载一次)。""" return _load_module("build_studio_urls_under_test", URL_BUILDER_SCRIPT) @pytest.fixture(scope="session") def downloader(): """youtube_export_download.py 模块(会话级,加载一次)。""" return _load_module("youtube_export_download_under_test", DOWNLOADER_SCRIPT) @pytest.fixture(scope="session") def lookup_groups(): """lookup_groups.py 模块(会话级,加载一次)。""" return _load_module("lookup_groups_under_test", LOOKUP_SCRIPT) @pytest.fixture(scope="session") def real_countries(url_builder): """脚本自带 countries.json 加载出的国家映射。""" return url_builder.load_country_map(str(COUNTRIES_JSON)) def run_script(script, args, cwd=None): """以子进程运行被测脚本(uv run pytest 下 sys.executable 即 venv python)。 强制子进程 PYTHONUTF8=1,避免 Windows 管道输出按 GBK 解码导致中文乱码。 """ env = {**os.environ, "PYTHONUTF8": "1", "PYTHONIOENCODING": "utf-8"} return subprocess.run( [sys.executable, str(script), *args], capture_output=True, text=True, encoding="utf-8", errors="replace", cwd=cwd, env=env, )