【问题标题】:how do you install requirements to arbitrary virtualenv in python scripts?如何在 python 脚本中将要求安装到任意 virtualenv?
【发布时间】:2016-03-01 01:05:58
【问题描述】:

我正在尝试将列表中每个项目的要求自动安装到其自己的 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 安装,在一种情况下,我需要运行“python setup.py mycommand”,它会自动为每个项目进行设置。如何像激活 virtualenv 一样运行命令,并在 python 脚本中将依赖项安装到任意 venv?

我发现的唯一方法是手动打开 virtualenv,然后手动调用我的 python 脚本。我很惊讶,通过 bash 将其打开有效,但调用 python 脚本被轰炸(可能是因为它与 bash 的进程不同)

谢谢

【问题讨论】:

    标签: python bash scripting virtualenv virtualenvwrapper


    【解决方案1】:

    这是因为每个 call_sp 调用都会创建一个新的 shell,所以在第一次 call_sp 调用结束后,由 virtualenvwrapper 的源创建的所有设置都消失了。您必须将所有命令组合到单个 call_sp 链中。否则,您可以使用“Popen”启动 shell 并使用通信向它提供命令。

    如果您选择后者,则需要小心同步和检测需求安装何时结束。 Pip 可能需要很长时间才能下载和安装具有复杂依赖项的包。

    【讨论】:

    • 我的同事说我可以用 venv 中的 python 和 venv 中的 pip 文件调用它。我现在正在测试它。感谢您的解释,将 bash 和 python 结合起来很麻烦
    【解决方案2】:

    这就是我为虚拟环境进行这种引导的方式。让脚本处理它自己的环境并运行脚本。运行此 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 脚本字符串)。另一个很酷的事情是 bash 进程的 pid 与 python 进程的 pid 相同。因此,任何照顾它的守护程序实用程序仍然会看到它启动的 pid。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-14
      • 2012-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多