You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何通过Bash脚本在同一虚拟环境中同时运行Python包的稳定版与开发版(共享数据目录)

如何通过Bash脚本在同一虚拟环境中同时运行Python包的稳定版与开发版(共享数据目录)

我完全懂你的需求:在同一个工作目录里用同一个虚拟环境跑稳定版和开发版,共享data/目录,还不想因为来回切换Git分支搞得手忙脚乱。你已经摸到了正确的方向——把稳定版源码复制到Git忽略的目录,再修改sys.path优先加载它,但卡在了两个关键问题上:PYTHONSTARTUP完全没起作用,而且Git分支切换后VSCode的状态识别也出了问题。咱们一步步来解决:

先搞懂为什么PYTHONSTARTUP没用

你踩了一个很容易忽略的坑:PYTHONSTARTUP环境变量指定的脚本只在交互式Python会话启动时才会执行(比如你直接敲python3进入命令行的时候)。但当你用python3 -m mypackage这种非交互式方式运行模块时,Python根本不会去读这个脚本,所以你的sys.path修改完全没生效。

替换掉麻烦的Git checkout逻辑

你原来的脚本需要切换到稳定版标签再切回开发分支,不仅要检查未提交文件,还会导致VSCode的Git状态识别异常(因为VSCode可能缓存了分支信息,即使切回原分支也没及时刷新)。其实咱们根本不用切换分支——用git archive就能直接导出指定标签的源码,完全不干扰当前工作区:

git archive可以把仓库里指定版本(标签/提交)的某个目录直接导出到目标路径,不需要修改当前的工作区或分支状态,完美解决你的Git相关问题。

最终的run-stable.sh脚本(带完整注释)

把原来的脚本替换成下面这个版本,我会在注释里解释每一步的作用:

#!/usr/bin/bash

# 切换到项目根目录并激活虚拟环境,失败则退出
PROJECT_ROOT="$HOME/path/to/mypackage"
cd "$PROJECT_ROOT" || { echo "无法进入项目根目录" >&2; exit 1; }
. venv/bin/activate || { echo "无法激活虚拟环境" >&2; exit 1; }

# 定义要使用的稳定版标签
LATEST_STABLE="0.4.1"
# 读取已构建的稳定版版本号(如果文件存在)
CURRENT_BUILD_VER=$(cat build/stable.version 2>/dev/null)

# 如果已构建的版本和目标版本不一致,重新构建
if [[ "$CURRENT_BUILD_VER" != "$LATEST_STABLE" ]]; then
    # 创建稳定版构建目录(如果不存在)
    mkdir -p build/stable
    # 导出指定标签的src/mypackage目录到build/stable/,自动去掉src前缀
    git archive "v$LATEST_STABLE" src/mypackage | tar -x -C build/stable/ --strip-components=1
    # 记录当前构建的版本号
    echo "$LATEST_STABLE" > build/stable.version
    echo "已更新稳定版构建:$CURRENT_BUILD_VER -> $LATEST_STABLE"
fi

# 动态生成Python启动脚本,先修改sys.path再运行包
python3 <(cat << 'EOF'
import sys
import os

# 获取项目根目录(和Bash脚本里的PROJECT_ROOT一致)
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))

# 移除src/目录的路径(确保不会加载开发版代码)
SRC_PATH = os.path.join(PROJECT_ROOT, 'src')
while SRC_PATH in sys.path:
    sys.path.remove(SRC_PATH)

# 把稳定版源码目录加到sys.path的最前面
STABLE_SRC_PATH = os.path.join(PROJECT_ROOT, 'build', 'stable')
sys.path.insert(0, STABLE_SRC_PATH)

# 运行你的包的__main__模块(和python -m mypackage效果一致)
from mypackage.__main__ import main
main()
EOF
) "$@"

关键细节说明

  • Git archive的优势

    • 不需要切换分支,完全不影响当前的工作区,也不用检查未提交文件
    • 直接导出标签对应的源码,确保稳定版的代码是完全符合标签的,没有任何本地修改
  • sys.path修改的可靠性

    • 用动态生成的Python启动脚本,在加载你的包之前就修改sys.path,完全避开了PYTHONSTARTUP的局限性
    • 循环移除src/的路径,确保即使虚拟环境里因为pip install -e添加了这个路径,也会被彻底移除
    • 把稳定版的路径插在sys.path最前面,确保Python优先加载稳定版的代码
  • 参数传递

    • 脚本最后用"$@"把命令行参数传递给你的Python包,和原来的run.sh的参数行为保持一致

验证方法

你可以在启动脚本里加一行打印sys.path的代码,确认路径是否正确:

print("当前sys.path顺序:", sys.path)

运行run-stable.sh后,应该能看到build/stable/在最前面,src/不在列表里。

备注:内容来源于stack exchange,提问作者sakuragasaki46

火山引擎 最新活动