Files
svfs/tests/test_contrib_optional.py
T

102 lines
3.8 KiB
Python
Raw Normal View History

"""验证"插件是可选依赖"这一契约。
这个模块在**有/没有** FastAPI 的两种环境下都会运行:
它断言的是"核心包永远不依赖第三方框架",以及"缺依赖时的报错要能直接照做"。
"""
import os
import subprocess
import sys
import unittest
import helpers
THIRD_PARTY = ("fastapi", "starlette", "anyio", "pydantic")
class OptionalDependencyTest(unittest.TestCase):
def run_snippet(self, code):
env = dict(os.environ)
env["PYTHONPATH"] = helpers.SRC_DIR + os.pathsep + env.get("PYTHONPATH", "")
env["PYTHONIOENCODING"] = "utf-8"
return subprocess.run(
[sys.executable, "-c", code],
capture_output=True,
text=True,
encoding="utf-8",
errors="replace",
env=env,
)
def test_third_party_is_installed_or_not(self):
"""只用于在输出里说明当前环境状态,不断言。"""
result = self.run_snippet(
"import importlib.util as u;"
"print({m: bool(u.find_spec(m)) for m in %r})" % (THIRD_PARTY,)
)
self.assertEqual(0, result.returncode, result.stderr)
def test_importing_core_never_pulls_in_third_party(self):
"""import sqlite_vfs 不能顺带把 fastapi/starlette 拖进来。"""
result = self.run_snippet(
"import sys\n"
"import sqlite_vfs, sqlite_vfs.core, sqlite_vfs.contrib\n"
"leaked = sorted(\n"
" m for m in sys.modules if m.split('.')[0] in %r\n"
")\n"
"print(leaked)" % (THIRD_PARTY,)
)
self.assertEqual(0, result.returncode, result.stderr)
self.assertEqual(
"[]",
result.stdout.strip(),
"导入 sqlite_vfs 时连带加载了第三方框架模块",
)
def test_plugin_module_is_not_imported_by_the_package(self):
"""contrib 子包不能自动导入插件模块(否则缺依赖时整包不可用)。"""
result = self.run_snippet(
"import sys\n"
"import sqlite_vfs.contrib\n"
"print('sqlite_vfs.contrib.fastapi_static' in sys.modules)"
)
self.assertEqual(0, result.returncode, result.stderr)
self.assertEqual("False", result.stdout.strip())
def test_missing_fastapi_gives_actionable_error(self):
"""缺少可选依赖时,报错信息必须能直接照着做。"""
probe = self.run_snippet(
"import importlib.util as u; print(bool(u.find_spec('starlette')))"
)
if probe.stdout.strip() == "True":
self.skipTest("当前环境已安装 starlette,无需检查缺失提示")
result = self.run_snippet("import sqlite_vfs.contrib.fastapi_static")
self.assertNotEqual(0, result.returncode)
self.assertIn("sqlite-vfs[fastapi]", result.stderr)
self.assertIn("pip install", result.stderr)
def test_missing_database_path_hint(self):
"""未生成资源包时的报错要给出下一步命令。"""
result = self.run_snippet(
"import tempfile, os, sys\n"
"sys.path.insert(0, %r)\n"
"try:\n"
" from sqlite_vfs.contrib.fastapi_static import SVFSStaticFiles\n"
"except ImportError as e:\n"
" print('SKIP', e); raise SystemExit(0)\n"
"try:\n"
" SVFSStaticFiles(os.path.join(tempfile.mkdtemp(), 'nope.svfs'))\n"
"except RuntimeError as e:\n"
" print(e)\n" % helpers.SRC_DIR
)
self.assertEqual(0, result.returncode, result.stderr)
output = result.stdout.strip()
if output.startswith("SKIP"):
self.skipTest("当前环境没有 FastAPI")
self.assertIn("vfspack", output)
if __name__ == "__main__":
unittest.main()