虚拟环境中Pytest子进程调用全局Python包的问题解决
问题:如何让subprocess调用虚拟环境内的Python包?
场景说明
- Linux主机全局安装的
package版本为x.y.z,项目requirements.txt指定该包版本为a.b.c(a.b.c > x.y.z) - 项目通过bash脚本创建虚拟环境、安装依赖并运行pytest,脚本代码如下:
#!/usr/bin/env bash set -x python3 -m pip install --user virtualenv python3 -m virtualenv .env source .env/bin/activate
- 测试脚本中通过subprocess调用外部Python脚本:
command=["/usr/bin/python", "/path/to/script/script.py", ...(bunch of args)] process = subprocess.Popen(command)
问题现象
虚拟环境已确认安装了package==a.b.c:
Requirement already satisfied: package==a.b.c in ./.env/lib/python3.8/site-packages (from -r requirements.txt (line 42)) (a.b.c)
但调用script.py时出现仅全局版本x.y.z才有的硬件未找到错误,错误信息显示加载了全局路径下的包:
File "/path/to/script/script.py", line 116, in <module> run() File "/path/to/script/script.py", line 82, in run device = scan_require_one(config='auto') File "/home/jenkins/.local/lib/python3.8/site-packages/package/driver.py", line 1353, in scan_require_one raise RuntimeError("no devices found") RuntimeError: no devices found
解决方案
1. 使用虚拟环境内的Python解释器路径
直接在subcommand中指定虚拟环境的Python路径,而不是全局的/usr/bin/python:
# 方式1:硬编码虚拟环境路径 command=["./env/bin/python", "/path/to/script/script.py", ...(bunch of args)] process = subprocess.Popen(command) # 方式2:动态获取当前Python解释器路径(推荐) import sys command=[sys.executable, "/path/to/script/script.py", ...(bunch of args)] process = subprocess.Popen(command)
原理:测试脚本本身运行在虚拟环境中,sys.executable会返回虚拟环境内Python解释器的绝对路径,确保调用的脚本使用虚拟环境的依赖。
2. 传递虚拟环境的环境变量给subprocess
让subprocess继承当前虚拟环境的环境变量,确保PATH优先指向虚拟环境的bin目录:
import os import subprocess command=["python", "/path/to/script/script.py", ...(bunch of args)] # 复制当前环境变量并传递给子进程 process = subprocess.Popen(command, env=os.environ.copy())
原理:虚拟环境激活后,PATH会被修改为./env/bin在前,子进程继承这个环境变量后,执行python时会优先找到虚拟环境内的解释器。
3. 修改外部脚本的shebang(若允许修改script.py)
在/path/to/script/script.py的第一行添加指向虚拟环境Python的shebang:
#!/path/to/your/project/.env/bin/python
然后给脚本添加执行权限:
chmod +x /path/to/script/script.py
之后直接调用脚本即可,无需指定Python解释器:
command=["/path/to/script/script.py", ...(bunch of args)] process = subprocess.Popen(command)
原理:系统会通过shebang指定的路径找到虚拟环境的Python解释器,从而加载对应环境的依赖包。
内容的提问来源于stack exchange,提问作者Samyukta Ramnath
相关产品推荐
相关产品推荐

