#!/usr/bin/env bash # ===================================================================== # pbl_evidence 测试环境「一行激活」(发现项 DISC.2) # # 目的:让下面这条命令在**不手工注入 PYTHONPATH** 的前提下可直接执行: # source scripts/activate_test_env.sh # python3 -m pytest tests/test_m5a_idempotency.py -v # 8 passed, 1 skipped # # 做了什么(只做两件事,不改任何环境变量以外的东西): # ① 若宿主 python3 已能 import pytest(正规长期方案:宿主 pip 装了 # requirements-dev.txt / `pip install -e .[test]`)→ 什么都不做,直接返回; # ② 否则 source 模块测试 venv(默认 .venv-test,缺则先调 # scripts/setup_test_env.sh 引导),使 PATH 里的 `python3` 就是 venv 解释器。 # # 为什么不是「往 PYTHONPATH 里塞 site-packages」:那正是 DISC.2 的根因——把 # 工作空间私有临时目录(.pylibs)伪装成可用环境,换机器/换角色即失效,且 # 污染宿主其它项目的依赖解析。venv 激活是标准、显式、可复现的做法。 # # 注意:必须 `source`(或 `. `)执行;用 `bash scripts/activate_test_env.sh` # 子进程执行只会影响子 shell,退出即失效(脚本会检测并提示)。 # ===================================================================== # 被 source 时 BASH_SOURCE[0] 与 $0 不同;被直接执行时相同(此时激活无意义) _AEV_SELF="${BASH_SOURCE[0]:-$0}" _AEV_SOURCED=1 if [ "${_AEV_SELF}" = "${0}" ]; then _AEV_SOURCED=0 fi _AEV_MODULE_ROOT="$(cd "$(dirname "${_AEV_SELF}")/.." && pwd)" _AEV_VENV="${PBL_EVIDENCE_TEST_VENV:-${_AEV_MODULE_ROOT}/.venv-test}" _aev_host_has_pytest() { local _py _py="$(command -v python3 || true)" [ -n "${_py}" ] || return 1 "${_py}" -c 'import pytest' >/dev/null 2>&1 } if _aev_host_has_pytest; then echo "[activate_test_env] 宿主 python3 已有 pytest($(python3 -m pytest --version 2>&1 | head -1)),无需激活 venv" return 0 2>/dev/null || exit 0 fi if [ ! -x "${_AEV_VENV}/bin/activate" ]; then echo "[activate_test_env] 测试 venv 不存在:${_AEV_VENV}" echo "[activate_test_env] 先引导:bash ${_AEV_MODULE_ROOT}/scripts/setup_test_env.sh" if [ "${_AEV_SOURCED}" = "1" ]; then return 1; else exit 1; fi fi # shellcheck disable=SC1091 . "${_AEV_VENV}/bin/activate" echo "[activate_test_env] 已激活测试 venv: ${_AEV_VENV}" echo "[activate_test_env] python3 = $(command -v python3) ($(python3 -V 2>&1))" echo "[activate_test_env] pytest = $(python3 -m pytest --version 2>&1 | head -1)" if [ "${_AEV_SOURCED}" != "1" ]; then echo "[activate_test_env][WARN] 本脚本被当作子进程执行,激活随子 shell 结束而失效。请改用:source ${_AEV_SELF}" exit 0 fi return 0