如何在python脚本中安装任意virtualenv的需求?

时间:2015-11-26 21:11:47

标签: python bash scripting virtualenv virtualenvwrapper

我正在尝试将列表中的每个项目的需求自动安装到自己的virtualenv中。我已经达到了正确制作virtualenv的程度,但是我无法将它激活并安装到仅仅那个virtualenv:

#!/usr/bin/env python

import subprocess, sys, time, os

HOMEPATH = os.path.expanduser('~')

CWD = os.getcwd()

d = {'cwd': ''}


if len(sys.argv) == 2:
    projects = sys.argv[1:]


def call_sp(command, **arg_list):
    p = subprocess.Popen(command, shell=True, **arg_list)
    p.communicate()

def my_makedirs(path):
    if not path.startswith('/home/cchilders'):
        path = os.path.join(HOMEPATH, path)
    try: os.makedirs(path)
    except: pass

for project in projects:
    path        = os.path.join(CWD, project)
    my_makedirs(path)
    git_string = 'git clone git@bitbucket.org:codyc54321/{}.git {}'.format(project, d['cwd'])
    call_sp(git_string)
    d = {'executable': 'bash'}
    call_sp("""source /usr/local/bin/virtualenvwrapper.sh && mkvirtualenv --no-site-packages {}""".format(project), **d)
    # call_sp("""source /usr/local/bin/virtualenvwrapper.sh && workon {}""".format(project), **d)
    # below, the dot (.) means the same as 'source'. the dot doesn't error, calling source does
    call_sp('. /home/cchilders/.virtualenvs/{}/bin/activate'.format(project))
    d = {'cwd': path}
    call_sp("pip install -r requirements.txt", **d)

最终可以

call_sp("""source /usr/local/bin/virtualenvwrapper.sh && mkvirtualenv --no-site-packages {}""".format(project), **d)

但是当脚本结束时,我在venv中没有活动,并且venv没有任何来自要求的包。采购venv(注释和生存的)的两种努力都失败了。

帮助我让mkvirtualenv工作的答案是subprocess.Popen: mkvirtualenv not found

我还注意到我需要做的不仅仅是pip install,在一种情况下我需要运行'python setup.py mycommand'来自动化每个项目的设置。如何运行命令就像激活virtualenv一样,并且还可以在python脚本中为任意venv安装依赖项?

我找到的唯一方法就是手动启动virtualenv,然后手动调用我的python脚本。我很惊讶,通过bash工作打开它,但调用python脚本被轰炸(可能是因为它与bash不同的过程)

谢谢

2 个答案:

答案 0 :(得分:1)

这是因为每个call_sp调用都会创建一个新的shell,因此在第一次调用call_sp之后,所有由virtualenvwrapper的源代码创建的设置都将消失。您必须将所有命令组合到单个call_sp链中。否则你可以使用'Popen'启动shell并使用通信向它发送命令。

如果您使用后者,则需要注意同步和检测何时安装需求结束。 Pip可能需要很长时间才能下载和安装具有复杂依赖关系的包。

答案 1 :(得分:1)

这是我为虚拟环境完成这种引导的方式。让脚本处理它自己的环境并运行脚本。如果缺少,运行这个 app.py 将设置它的 VE 和模块。

./requirements.txt 文件

flask

./app.py 脚本

#!/bin/bash
""":"
VENV=$(realpath -s $(dirname $0)/ve)
PYTHON=$VENV/bin/python

if [ ! -f "$PYTHON" ]; then
    echo "installing env app"
    python3 -m venv $VENV
    ${VENV}/bin/pip install -r $(dirname $0)/requirements.txt
fi

exec $PYTHON $0 $@
"""

import flask
print("I am Python with flask", flask)

无论我们在哪个目录中,app.py 都会通过 bash 脚本头进行引导,如果 python 不存在,则安装 ve,运行 pip,以及您需要的任何其他内容。然后 exec $PYTHON $0 $@ 是一种将 bash 进程替换为 python 进程保持相同 pid 的巧妙方法。

当 python 接管时,它会跳过 bash 部分,因为该脚本位于三引号字符串中。所以python执行的第一行是import flask(它丢弃了bash脚本字符串1st)。另一个很酷的事情是 bash 进程的 pid 与 python 进程的 pid 相同。因此,任何照顾它的守护程序实用程序仍将看到它启动的 pid。

最后一个技巧是 bash 需要一个额外的引号来平衡其顶部的字符串 """:"。 Python 不关心那个额外的引用

我希望你能看到这个模式。要升级 requirements.txt 中的模块,只需 rm ve 并再次运行应用程序。简单。