mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-06 07:56:52 +08:00
feat: 新增 Python 3.14t 自由线程镜像 (#6434)
* fix(resource): select free-threaded extension ABI * chore(deps): require moviepilot-rust 0.2.9 * perf: add free-threaded runtime comparison * feat: add free-threaded runtime profile * chore(deps): require moviepilot-rust 0.3.0 * test: isolate system endpoint import graph * fix(docker): preserve runtime profile during recovery * feat(runtime): expose active GIL state * feat(plugin): log GIL fallback attribution * test: refresh runtime observability dependency baseline * fix(plugin): validate the active uv runtime profile * test(runtime): expand free-threaded benchmark evidence * docs(runtime): define v3t governance gates * test(runtime): separate rust benchmark modes * docs: sync free-threaded architecture baseline * perf: add PostgreSQL driver comparison * docs(runtime): record final free-threaded evidence * fix(runtime): converge dual-profile dependency verification * fix(runtime): scope Python 3.14 warning filter * fix(runtime): match actual oss2 syntax warning * docs(runtime): refresh free-threaded benchmark evidence * test(architecture): refresh runtime dependency baseline * ci: skip unused Trivy Java database * build: exclude local verification artifacts * docs(runtime): refresh PostgreSQL driver benchmarks * docs(runtime): record plugin restore acceptance * docs(runtime): record amd64 candidate acceptance * ci: pin beta image publisher action * test(architecture): merge runtime dependency baseline * feat(runtime): expose Python GIL status * docs(runtime): document Python runtime status fields
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
"""主程序运行依赖的轻量可用性探针。"""
|
||||
|
||||
import argparse
|
||||
from importlib import import_module
|
||||
import sys
|
||||
import sysconfig
|
||||
import warnings
|
||||
|
||||
|
||||
CORE_MODULES = (
|
||||
"alembic",
|
||||
"cloakbrowser",
|
||||
"fastapi",
|
||||
"pydantic",
|
||||
"pydantic_core",
|
||||
"pydantic_settings",
|
||||
"sqlalchemy",
|
||||
"starlette",
|
||||
"uvicorn",
|
||||
)
|
||||
NATIVE_MODULES = (
|
||||
("asyncpg", "asyncpg"),
|
||||
("bcrypt", "bcrypt._bcrypt"),
|
||||
("brotli", "brotli"),
|
||||
("crcmod", "crcmod.crcmod"),
|
||||
("cryptography", "cryptography.hazmat.bindings._rust"),
|
||||
("greenlet", "greenlet._greenlet"),
|
||||
("lxml", "lxml.etree"),
|
||||
("orjson", "orjson"),
|
||||
("oss2", "oss2"),
|
||||
("pillow", "PIL._imaging"),
|
||||
("pillow-avif-plugin", "pillow_avif"),
|
||||
("pydantic-core", "pydantic_core._pydantic_core"),
|
||||
("zstandard", "zstandard"),
|
||||
)
|
||||
|
||||
|
||||
def _verify_text_capabilities(*, free_threaded: bool) -> None:
|
||||
"""验证标准与 free-threaded profile 共同依赖的文本能力。"""
|
||||
moviepilot_rust = import_module("moviepilot_rust")
|
||||
if not moviepilot_rust.is_available() or not moviepilot_rust.jieba_cut("中文分词"):
|
||||
raise RuntimeError("中文分词运行依赖不可用")
|
||||
|
||||
if free_threaded:
|
||||
converted = moviepilot_rust.zhconv_fast("后台", "zh-hant")
|
||||
else:
|
||||
converted = import_module("zhconv_rs").zhconv("后台", "zh-hant")
|
||||
if not converted:
|
||||
raise RuntimeError("中文转换运行依赖不可用")
|
||||
|
||||
|
||||
def _verify_native_profile(*, free_threaded: bool) -> None:
|
||||
"""验证 ABI 敏感依赖提供预期的原生能力。"""
|
||||
warnings.filterwarnings(
|
||||
"ignore",
|
||||
message=r'"\\&" is an invalid escape sequence\..*',
|
||||
category=SyntaxWarning,
|
||||
)
|
||||
imported = {}
|
||||
profile_modules = (
|
||||
(("psycopg", "psycopg"),)
|
||||
if free_threaded
|
||||
else (("psycopg2", "psycopg2"), ("zhconv-rs", "zhconv_rs"))
|
||||
)
|
||||
for name, module_name in (*NATIVE_MODULES, *profile_modules):
|
||||
imported[name] = import_module(module_name)
|
||||
if free_threaded and sys._is_gil_enabled():
|
||||
raise RuntimeError(f"原生依赖 {name} 启用了 GIL")
|
||||
|
||||
if not imported["crcmod"]._usingExtension:
|
||||
raise RuntimeError("crcmod 原生实现不可用")
|
||||
if free_threaded and imported["psycopg"].pq.__impl__ != "c":
|
||||
raise RuntimeError("psycopg C 实现不可用")
|
||||
|
||||
|
||||
def main(*, full: bool = False) -> None:
|
||||
"""验证 Web 栈和启动关键能力可导入、可执行。"""
|
||||
free_threaded = sysconfig.get_config_var("Py_GIL_DISABLED") == 1
|
||||
for module_name in CORE_MODULES:
|
||||
import_module(module_name)
|
||||
|
||||
_verify_text_capabilities(free_threaded=free_threaded)
|
||||
if full:
|
||||
_verify_native_profile(free_threaded=free_threaded)
|
||||
if free_threaded and sys._is_gil_enabled():
|
||||
raise RuntimeError("核心运行依赖启用了 GIL")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--full", action="store_true")
|
||||
main(full=parser.parse_args().full)
|
||||
Reference in New Issue
Block a user