在从 Python subprocess.Popen() 调用的脚本中模拟 shell 命令

Mock a shell command in a script called from Python subprocess.Popen()

我有一种情况需要使用我为单元测试编写的 shell 脚本 (mock_pip) 模拟可执行文件 (pip),因此我使用 subprocess 模块来获取访问权限到 shell。我尝试了很多方法,例如:

subprocess.Popen("alias pip='/some/dir/mock_pip'", shell=True) # Create alias
subprocess.Popen("pip", shell=True) # Try to use new alias, but still points towards real pip instead

subprocess.Popen("alias pip='/some/dir/mock_pip'"; "pip", shell=True)
# Once again it uses the real pip instead of mock

我什至通过更改主目录中的 ~/.bashrc 文件(也在使用子进程的单元测试期间)尝试了此 ,但这也不起作用。
我在想问题是子进程在调用每个命令后都会擦除环境,这意味着当我尝试调用它时我的别名不存在。

如何在从我的 Python 进程启动的 bash 脚本中使用 mock_pip 而不是 pip

如果您的目标是提供 pip 的模拟实现,您可以通过以下几种方式实现:

  • 将其生成为导出函数
  • 设置指向包含包装器的目录的 PATH 值作为可执行脚本

前者是 shell-version-specific,所以我们先介绍后者:

subprocess.Popen('pip', env={'PATH': '/path/to/mock/dir:' + os.environ['PATH']})

...您的 /path/to/mock/dir 是一个包含执行所需操作的 pip 可执行文件的位置。


后者,用于 post-shellshock upstream bash 版本(以及 bash 的先前版本 shellshock fixes 与协议兼容对于上游到达的导出函数):

env = dict(os.environ)
env['BASH_FUNC_pip%%'] = '() { mock_pip "$@"; }'
subprocess.Popen(['bash', '-c', 'pip'], shell=False, env=env)

注意这里的 shell=False,明确的 ['bash', '-c', ...] —— 确保它是 bash(这将支持导出的函数)而不是默认的 shell sh 已调用。