Repository navigation
Description
问题
tests/test_scan_streaming.py 里两个并发用例把仓库根路径写死成 E:/code/voyager:
test_two_concurrent_streaming_scans_convergetest_concurrent_creation_of_a_fresh_index_does_not_fail
它们各自拼一段子进程代码,里面是 sys.path.insert(0, 'E:/code/voyager'),再用 subprocess.Popen([sys.executable, "-c", child], cwd=str(tmp_path)) 起子进程。由于 cwd 是临时目录、且这套测试的 conftest 会把 APPDATA 重定向到沙箱(子进程的 user-site 指向空目录),子进程里根本找不到 voyager:
ModuleNotFoundError: No module named 'voyager'
在没有 E: 盘(或仓库不在这个精确路径)的机器上,这两条必然失败。我在中文 Windows / cp936 本机对当前 main 跑全量时遇到的 2 个失败就是这两条;加 PYTHONPATH=<repo> 后 4 passed,可确认是路径问题而非并发逻辑问题。
为什么单独提,不塞进 PR #19
这两行在 main 上原本就有,不在 PR #19 的 5 个改动文件内。PR #19 正文与 PR #5 回复都承诺「不扩大范围」,把它并进去会自相矛盾;而且这是个独立的、可单独评审的测试可移植性问题。故另开此 issue 并附补丁,由维护者裁定是否合入。
建议改法
对齐仓库既有写法(tests/test_scan_crash.py:24,109 用 REPO_ROOT = Path(__file__).resolve().parents[1],并给子进程传 env["PYTHONPATH"]):
- 删掉两处
sys.path.insert(0, %r)及% str(Path(r"E:/code/voyager")); - 两处
Popen(..., env=env),其中env = {**os.environ, "PYTHONPATH": str(REPO_ROOT)}; - 用
env注入仓库根比sys.path.insert稳:conftest 重定向APPDATA后子进程 user-site 为空,注入PYTHONPATH不受影响。
补丁(仅改 tests/test_scan_streaming.py):
--- a/tests/test_scan_streaming.py
+++ b/tests/test_scan_streaming.py
@@ -36,6 +36,7 @@
from voyager.store import Store
FIXTURES = Path(__file__).parent / "fixtures"
+REPO_ROOT = Path(__file__).resolve().parents[1]
# ---------------------------------------------------------------------------
@@ -538,6 +539,7 @@
Concurrent *creation* of a brand-new index is a different, separately
covered case (test_concurrent_creation_of_a_fresh_index_does_not_fail).
"""
+ import os
import subprocess
import sys
codex_tree = _codex_tree(tmp_path / "sessions")
@@ -554,7 +556,6 @@
child = (
"import sys\n"
"from pathlib import Path\n"
- "sys.path.insert(0, %r)\n"
"from voyager.store import Store\n"
"from voyager.cli import run_scan\n"
"import voyager.adapters.codex as m\n"
@@ -566,15 +567,16 @@
"run_scan(s, providers=['codex'], quiet=True)\n"
"s.close()\n"
"print('CHILD_OK')\n"
- ) % (str(Path(r"E:/code/voyager")), str(codex_tree),
+ ) % (str(codex_tree),
str(codex_tree.parent / "_absent_history.db"),
str(codex_tree.parent / "_absent_state.db"),
str(codex_tree.parent / "_absent_dev.db"),
str(index))
+ env = {**os.environ, "PYTHONPATH": str(REPO_ROOT)}
procs = [subprocess.Popen([sys.executable, "-c", child],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- text=True, cwd=str(tmp_path))
+ text=True, cwd=str(tmp_path), env=env)
for _ in range(2)]
for p in procs:
_out, err = p.communicate(timeout=180)
@@ -622,6 +624,7 @@
read), so the only thing wrong is that a concurrent setup is not tolerated.
This test drives the real ``Store`` from two real processes.
"""
+ import os
import subprocess
import sys
from voyager.store import Store
@@ -629,20 +632,20 @@
CHILD = (
"import sys\n"
"from pathlib import Path\n"
- "sys.path.insert(0, %r)\n"
"from voyager.store import Store\n"
"s = Store(Path(sys.argv[1]))\n"
"s.close()\n"
"print('OK')\n"
- ) % str(Path(r"E:/code/voyager"))
-
+ )
+
+ env = {**os.environ, "PYTHONPATH": str(REPO_ROOT)}
# Several trials: the failure is a race, so a single run proves nothing
# either way. Ten pairs is enough to catch a ~1-in-6 rate.
for trial in range(10):
db = tmp_path / ("fresh%d.db" % trial)
procs = [subprocess.Popen([sys.executable, "-c", CHILD, str(db)],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- text=True, cwd=str(tmp_path))
+ text=True, cwd=str(tmp_path), env=env)
for _ in range(2)]
failures = []
for p in procs:本机验证
| 检查 | 结果 |
|---|---|
py_compile |
0 |
2 个目标用例(补丁后,不继承 PYTHONPATH、无 E: 盘) |
2 passed |
变异:去掉两处 env=env、恢复等价硬编码条件 |
2 failed,复原后 2 passed |
| 全量(含补丁) | 1377 passed, 7 skipped, 1 failed |
全量那 1 个失败是 test_verification_harness_v2.py::test_a_successful_run_records_evidence(期望 LIVE_VERIFIED、实得 ZERO_TOUCH_LIVE_VERIFIED),单独跑 1 passed,属顺序依赖的验证态泄漏,与本补丁无关(补丁只碰 test_scan_streaming.py)。
环境:中文 Windows / cp936、仓库以 zip 检出(未 pip install),因此未生成 voyager.egg-info,另有 2 个版本用例会报 PackageNotFoundError——同属环境问题,不在此补丁范围内。
来源:PR #19 的本地全量回归副产物。补丁与验证脚本均未推入任何分支,仅作为本 issue 的附件供评审。
Activity
HarryHeYu commentedon Nov 11, 2026
已按建议改法修复,提交
b64e964(在 PR #19 合并之后单独提交,没有塞进贡献者的 PR)。sys.path.insert(0, 'E:/code/voyager')移除;REPO_ROOT = Path(__file__).resolve().parents[1],与tests/test_scan_crash.py:24一致;env={\"PYTHONPATH\": str(REPO_ROOT)}继承检出根目录,不再依赖任何绝对路径或 user-site 安装。验证:在不设置 ambient
PYTHONPATH的环境里跑tests/test_scan_streaming.py,15 passed(含那两个并发用例)。CHANGELOG 的[Unreleased] / Tests也记了这条。感谢把复现、归因和补丁一起写清楚,尤其是明确指出「加
PYTHONPATH=<repo>后 2 passed,所以不是并发逻辑缺陷」——这个对照省掉了重新定位的时间。这个 issue 先关掉;如果换机器后仍复现,随时重开。