Prhub

#24487 propagate pytest exit code from test __main__ entries

原始 PR 作者 hnyls2002 合并时间 2026-05-07 09:46 文件变更 10 提交数 10 评论 3 代码增减 +90 / -3969

执行摘要

修复 CI 中 bare pytest.main 导致失败被吞没

run_files in python/sglang/test/ci/ci_utils.py decides whether a test file passed by reading the wrapping python script's process.returncode. Files using if __name__ == "__main__": pytest.main([__file__]) discard pytest's exit code, so the script returns 0 even when assertions fail. The CI runner then logs the file as PASSED while pytest's stdout reports the failure — silently masking real regressions. (Discovered when test_norm_tanh_mul_add_norm_scale.py printed 1 failed, 47 passed but the CI suite stayed green.)

该PR是典型的CI可靠性修复,设计思路清晰(AST扫描而非侵入式修改运行器)。建议阅读test_no_bare_pytest_main.py的实现,了解如何用AST做仓库级别的规则检查。对于贡献者,在提交包含pytest.main的测试文件时,务必使用sys.exit(pytest.main(...))

讨论亮点

该PR未引发实质性的review讨论,Reviewer DarkSharpness直接批准。实现过程中曾有一个包含冗余行为检查的版本,后简化为仅保留AST扫描(commit 2bbf631)。

实现拆解

  1. 新增AST守卫测试:创建test/registered/unit/test_no_bare_pytest_main.py,利用Python ast模块递归扫描python/test/目录下的所有.py文件。对于每个文件,解析AST并查找if __name__ == "__main__":条件块。在该块内部,检查是否包含裸露的pytest.main(...)调用(即直接作为表达式语句,未用sys.exit()包装)。如果发现任何违规,则断言失败,阻止CI阶段继续。关键符号包括_find_bare_pytest_main_is_main_guard_is_bare_pytest_main_calltest_no_bare_pytest_main_in_repo

  2. 删除裸露调用文件:确认并删除9个使用裸露pytest.main()的测试文件,包括:python/sglang/jit_kernel/tests/test_cast.pytest_flash_attention_3.pytest_fused_qknorm_rope.pydiffusion/test_norm_tanh_mul_add_norm_scale.pypython/sglang/multimodal_gen/test/server/test_tracing.pyunit/manual/test_patch_embed.pytest/registered/lora/test_lora_moe_runner.pytest_marlin_lora_correctness.pytest_sgemm_sorted_by_adapter.py。这些文件要么已经静默失败,要么需要原作者以后用sys.exit(pytest.main(...))重新添加。在删除前,对test_lora_moe_runner.pytest_norm_tanh_mul_add_norm_scale.py进行了修复:前者补充了MockServerArgs的全局server args补丁,后者放松了数值容差。

  3. 保持运行器不变:CI运行器仍使用python3 file.py -f方式调用测试文件(-f用于unittest模式的failfast),全局切换到python -m pytest会涉及696个unittest.main()文件,超出本PR范围。

文件 模块 状态 重要度
test/registered/unit/test_no_bare_pytest_main.py CI 守卫 added 7.7
python/sglang/jit_kernel/tests/test_flash_attention_3.py 注意力核 removed 7.48
python/sglang/jit_kernel/tests/test_fused_qknorm_rope.py 融合 RoPE removed 7.49
python/sglang/jit_kernel/tests/test_cast.py 类型转换 removed 7.21
python/sglang/multimodal_gen/test/unit/manual/test_patch_embed.py Patch 嵌入 removed 7.21
test/registered/lora/test_lora_moe_runner.py LoRA MoE removed 7.49
test/registered/lora/test_marlin_lora_correctness.py Marlin LoRA removed 7.21
test/registered/lora/test_sgemm_sorted_by_adapter.py SGEMM 测试 removed 7.19
python/sglang/multimodal_gen/test/server/test_tracing.py 追踪测试 removed 6.74
python/sglang/jit_kernel/tests/diffusion/test_norm_tanh_mul_add_norm_scale.py 规范化测试 removed 5.95

关键符号

_find_bare_pytest_main _is_main_guard _is_bare_pytest_main_call test_no_bare_pytest_main_in_repo

分析完成后,这里会展示 LLM 生成的相对完整源码片段和详细注释。

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

  1. 测试覆盖损失:删除了9个测试文件,虽然部分已静默失败,但覆盖完全移除,在原作者重新添加前相关功能的回归风险上升,尤其是JIT kernel测试(如test_downcast_fp8test_flash_attn_kvcache)和LoRA测试。
  2. 守卫假阳性:AST扫描可能产生假阳性,如间接调用无法检测,但现有设计较保守,风险较低。
  3. CI时间增加:守卫需要遍历整个仓库,但影响有限(几秒)。
  4. 撤回风险:若日后需要临时使用裸露调用,守卫会强制失败,需调整守卫规则。
  • 用户:无直接影响(仓库内部CI变更)。
  • 系统:CI测试可靠性提升,不再漏因退出码未传播导致的失败。新添加的pytest.main调用必须包装sys.exit,否则被守卫拒绝。
  • 团队:要求9个测试文件的原作者在后续PR中重新添加已删文件并确保正确包装。新增守卫需要维护(如添加异常规则)。
测试覆盖损失 守卫假阳性风险 CI 时间增加

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论