代码之家  ›  专栏  ›  技术社区  ›  Puli

运行脚本的精简虚拟环境正在访问其外部的库

  •  0
  • Puli  · 技术社区  · 2 年前

    我想从Python脚本中激活一个virtualenv实例。

    我知道这很容易做到,但我看到的所有示例都使用它在env中运行命令,然后关闭子流程。

    我只想激活virtualenv并返回shell,就像bin/activate一样。

    像这样的东西:

    $me: my-script.py -d env-name
    $(env-name)me:
    

    这可能吗?

    相关的

    virtualenv › Invoking an env from a script

    0 回复  |  直到 6 年前
        1
  •  119
  •   Lie Ryan Bryan    2 年前

    如果您想在virtualenv下运行Python子进程,可以通过使用virtualenv内部的Python解释器运行脚本来实现 bin/ 目录

    import subprocess
    
    # Path to a Python interpreter that runs any Python script
    # under the virtualenv /path/to/virtualenv/
    python_bin = "/path/to/virtualenv/bin/python"
    
    # Path to the script that must run under the virtualenv
    script_file = "must/run/under/virtualenv/script.py"
    
    subprocess.Popen([python_bin, script_file])
    

    但是,如果您想在当前Python解释器而不是子进程下激活virtualenv,可以调用 exec 通过 activate_this.py 脚本,如下所示:

    # Doing exec() on this file will alter the current interpreter's
    # environment so you can import libraries in the virtualenv
    activate_this_file = "/path/to/virtualenv/bin/activate_this.py"
    
    exec(open(activate_this_file).read(), {'__file__': activate_this_file})
    

    请注意,您需要使用 virtualenv 库,不是 venv ,用于上述。

    如果您使用venv,您可以复制virtualenv的activate_this.py的实现,它应该或多或少地与venv一起工作,只需进行一些小的更改。

        2
  •  79
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    在virtualenv的解释器下运行脚本的最简单解决方案是将默认的shebang行替换为指向virtualenv解释器的路径,如脚本开头所示:

    #!/path/to/project/venv/bin/python
    

    使脚本可执行:

    chmod u+x script.py
    

    运行脚本:

    ./script.py
    

    瞧!

        3
  •  27
  •   Mariano Ruiz    5 年前

    根据官方的说法,运行另一个Python环境 Virtualenv documentation ,在命令行中,您可以指定可执行Python二进制文件的完整路径,只需(之前无需激活virtualenv):

    /path/to/virtualenv/bin/python
    

    如果您想使用virtualenv从命令行调用脚本,也同样适用。您不需要在以下时间之前激活它:

    me$ /path/to/virtualenv/bin/python myscript.py
    

    对于Windows环境也是如此(无论是从命令行还是从脚本):

    > \path\to\env\Scripts\python.exe myscript.py
    
        4
  •  25
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    事实证明,是的,问题并不简单,但解决方案是。

    首先,我必须创建一个shell脚本来包装“source”命令。也就是说,我使用了“.”,因为我读到过使用它比Bash脚本的源代码更好。

    #!/bin/bash
    . /path/to/env/bin/activate
    

    然后,通过我的Python脚本,我可以简单地执行以下操作:

    import os
    os.system('/bin/bash --rcfile /path/to/myscript.sh')
    

    整个技巧在于 --rcfile 论点

    当Python解释器退出时,它会将当前shell留在激活的环境中。

        5
  •  8
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    这只是一个对我有效的简单解决方案。我不知道为什么你需要Bash脚本,它基本上只做了一个无用的步骤(我错了吗?)

    import os
    os.system('/bin/bash  --rcfile flask/bin/activate')
    

    它基本上满足了您的需求:

    [hellsing@silence Foundation]$ python2.7 pythonvenv.py
    (flask)[hellsing@silence Foundation]$
    

    然后,不停用虚拟环境,只需 Ctrl键 + D 或退出。这是一个可能的解决方案吗?或者这不是你想要的吗?

        6
  •  8
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    最高答案仅适用于Python2.x

    对于Python 3.x,请使用以下方法:

    activate_this_file = "/path/to/virtualenv/bin/activate_this.py"
    
    exec(compile(open(activate_this_file, "rb").read(), activate_this_file, 'exec'), dict(__file__=activate_this_file))
    

    参考 What is an alternative to execfile in Python 3?

        7
  •  2
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    子进程环境在其不存在的那一刻就丢失了,将环境内容从那里移动到父进程有点棘手。

    您可能需要生成一个shell脚本(可以动态生成一个到/tmp),该脚本将把virtualenv环境变量输出到一个文件中,然后在父Python进程中读取该文件并将其放入os.environ中。

    或者,您只需使用解析activate脚本中的open(“bin/activate”)行,手动提取内容,然后放入os.environ。这很棘手,但并非不可能。

        8
  •  1
  •   Ronak Delvadiya    4 年前

    对于python2/3,使用下面的代码片段我们可以激活虚拟环境。

    activate_this = "/home/<--path-->/<--virtual env name -->/bin/activate_this.py" #for ubuntu
    activate_this = "D:\<-- path -->\<--virtual env name -->\Scripts\\activate_this.py" #for windows
    with open(activate_this) as f:
        code = compile(f.read(), activate_this, 'exec')
        exec(code, dict(__file__=activate_this))
    
        9
  •  1
  •   rahul_5409    4 年前

    我也有同样的问题,但没有 activate_this.py 在中 Scripts 我的环境的目录。

    activate_this.py

    """By using execfile(this_file, dict(__file__=this_file)) you will
    activate this virtualenv environment.
    This can be used when you must use an existing Python interpreter, not
    the virtualenv bin/python
    """
    
    try:
        __file__
    except NameError:
        raise AssertionError(
            "You must run this like execfile('path/to/active_this.py', dict(__file__='path/to/activate_this.py'))")
    import sys
    import os
    
    base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    if(sys.platform=='win32'):
         site_packages = os.path.join(base, 'Lib', 'site-packages')
    else:
         site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages')
    prev_sys_path = list(sys.path)
    import site
    site.addsitedir(site_packages)
    sys.real_prefix = sys.prefix
    sys.prefix = base
    # Move the added items to the front of the path:
    new_sys_path = []
    for item in list(sys.path):
        if item not in prev_sys_path:
            new_sys_path.append(item)
            sys.path.remove(item)
    sys.path[:0] = new_sys_path
    

    将文件复制到 脚本 目录,并像这样使用它:

    def activate_virtual_environment(environment_root):
        """Configures the virtual environment starting at ``environment_root``."""
        activate_script = os.path.join(
            environment_root, 'Scripts', 'activate_this.py')
        execfile(activate_script, {'__file__': activate_script})
    
    activate_virtual_environment('path/to/your/venv')
    

    参考: https://github.com/dcreager/virtualenv/blob/master/virtualenv_support/activate_this.py

        10
  •  0
  •   Cezar Pauxis    2 年前

    与相关 this response 关于 activate_this.py

    如果这是您的用例(在同一进程上激活virtualenv),您可能有兴趣使用 activate-virtualenv ,一个上下文管理器,它根据 activate_this.py 剧本

    用法示例:

    from activate_virtualenv import activate_virtualenv
    
    venv_path = "/path/to/virtualenv"
    with activate_virtualenv(venv_path):
        import subscript1
    

    然后 subscript1.py “将在激活virtualenv的情况下导入。它将能够加载安装在激活的virtualenv上的任何模块。AFter with 块结束时,virtualenv将自动停用,所做的更改由 activate_this.py 将被撤消,因此它不会影响脚本的其余部分。

        11
  •  0
  •   lindes    1 年前

    首先,让我说一下我是如何解释这个问题的:

    有没有一种方法可以让我运行一个命令,使某个虚拟机(在几个虚拟机中)在我的交互式shell中变得活跃?

    简短的回答是:

    并非没有shell的帮助——因为以正常方式编写的任何命令都将是一个子进程,无法直接修改shell中的设置。

    也就是说,有一些方法可以从shell获得帮助,因此,例如,假设有一个脚本如下(伪代码):

    #!/usr/bin/env python3
    
    import sys
    
    # writing this function is an exercise for the reader...
    # I don't know what you're wanting to do here, but I'll
    # assume you have some way to choose a venv directory
    # based on command-line arguments:
    env_dir = choose_env_dir_based_on(sys.ARGV)
    print(f". #{env_dir}/bin/activate")
    

    现在,假设(基于问题文本)您希望能够将其作为 my-script.py -d env-name (我可能会放弃 .py 从中,但我会继续使用它,因为这就是问题的措辞),让我们将其保存在一个名为的文件中,比如, ~/bin/_my-script.py 。从那里开始,你需要教你的shell如何以一种可以修改其自身环境的方式运行该命令。你可以用几种不同的方法来做到这一点。最简单的方法可能是使用别名:

    alias my-script.py='eval `~/bin/_myscript.py`'
    

    然而,这有一个缺点,那就是它没有一个很好的方法来获取参数,所以运行 my-script.py-d环境名称 不会真正起作用(尽管如果你只需要跑步 my-script.py ,那么它就会)。相反,可以使用shell函数来执行此操作:

    my-script.py () { eval `~/bin/_my-script.py "$@"` }
    

    无论你和谁一起去,你大概都会把它保存在你的 ~/.bashrc , ~/.zshrc ,或您碰巧使用的shell的任何等效程序。

    对于函数形式,这允许 类型 my-script.py-d环境名称 ,同时让它实际执行以下操作:

    1. ~/bin/_my-script.py 具有 -d env-name 作为参数提供)。
    2. 获取该脚本的输出,然后 eval 它(参见例如。, this Q&A 了解更多信息),以便运行 在shell的上下文中 .
    3. 自从什么 _my-script.py 实际所做的是打印出一个shell命令来为相关目录获取激活脚本,然后就会发生这种情况。

    奖励:自激活脚本:

    所以,以上都是对所问问题的回答。不过,我得出这个答案是为了找到另一个问题的解决方案。我的问题可以概括为:

    我可以运行python脚本吗 好像 它是在已经设置了特定venv的情况下运行的?

    为此,可以运行以下内容(我找到了自己的解决方案)。为了这个例子,我假设venv在一个名为 .env 存在于正在运行的脚本旁边。

    #!/usr/bin/env python3
    
    # the above "shebang" line references whatever python3
    # we happen to have, whether or not an environment is set.
    
    # But we want to run with the environment in .env relative
    # to the current script, unless an env is activated (in
    # which case, we'd use that, and do nothing special here):
    
    import os, sys
    
    if 'VIRTUAL_ENV' not in os.environ:
      # assuming .env is next to this script:
      venv = os.path.join(os.path.dirname(__file__), '.env')
      # finding the python from that env:
      newpython = os.path.join(venv, 'bin', 'python')
      # setting up a new ARGV, to start with the new python:
      args = [newpython] + sys.argv
      # Note: setting VIRTUAL_ENV isn't what causes the
      # virtualenv to be utilized.  Python has some other means
      # of doing that.  But it does signal to the if condition
      # above to not run this code more than once (lest we
      # go into an infinite execv loop).
      os.environ['VIRTUAL_ENV'] = venv
      # With that all set up, we re-run under the new python:
      os.execv(newpython, args)
    
    import somemodule # something pip installed inside the venv.
    
    # rest of code here
    

    或者,对于我们需要强制venv的内容的简短版本:

    #!/usr/bin/env python3
    
    import os, sys
    if 'VIRTUAL_ENV' not in os.environ:
      venv = os.path.join(os.path.dirname(__file__), '.env')
      newpython = os.path.join(venv, 'bin', 'python')
      args = [newpython] + sys.argv
      os.environ['VIRTUAL_ENV'] = venv
      os.execv(newpython, args)
    

    (由于缺乏 .env 目录留给读者练习。 照原样 FileNotFoundError 尝试运行时将引发错误 os.execv 。什么是“合理的”大概取决于一个人想要什么——自动创建venv?只报告一个错误?另外因此,将其作为练习。)

        12
  •  -1
  •   Peter Mortensen Pieter Jan Bonestroo    6 年前

    您应该创建所有 virtualenv s在一个文件夹中,例如 virt .

    假设您的virtualenv文件夹名称是virt,如果不更改它

    cd
    mkdir custom
    

    复制以下行。。。

    #!/usr/bin/env bash
    ENV_PATH="$HOME/virt/$1/bin/activate"
    bash --rcfile $ENV_PATH -i
    

    创建一个shell脚本文件并粘贴上面的行。。。

    touch custom/vhelper
    nano custom/vhelper
    

    授予文件可执行权限:

    sudo chmod +x custom/vhelper
    

    现在导出该自定义文件夹路径,以便您可以通过单击选项卡在命令行上找到它。。。

    export PATH=$PATH:“$HOME/custom”

    现在,只需键入以下命令,就可以在任何地方使用它。。。

    vhelper YOUR_VIRTUAL_ENV_FOLDER_NAME
    

    假设是abc,那么。。。

    vhelper abc