如何从 python 脚本调用 pip 并使其在本地安装到该脚本? [复制]

Posted

技术标签:

【中文标题】如何从 python 脚本调用 pip 并使其在本地安装到该脚本? [复制]【英文标题】:How to call pip from a python script and make it install locally to that script? [duplicate] 【发布时间】:2019-12-26 19:41:14 【问题描述】:

我们在我维护的源代码存储库中有一个 python 脚本。让我们想象它在位置

scripts/python/make_salad/make_salad.py

它按原样签入存储库。该脚本的用户只想在 Windows 资源管理器中单击该脚本,然后离开。他们拒绝使用命令行。但是,该脚本还取决于我必须安装的许多外部包。我已经使用following trick 来安装用户第一次运行脚本时所需的任何包。就像

def install(package):
    # This is an evil little function
    # that installs packages via pip.
    # This means the script can install
    # it's own dependencies.
    try:
        __import__(package)
    except:
        import subprocess
        subprocess.call([sys.executable, "-m", "pip", "install", package])

install("colorama")
install("pathlib")
install("iterfzf")
install("prompt_toolkit")
install("munch")
install("appdirs")
install("art")
install("fire")

import os
import tkFileDialog
import getpass
import json
import shutil
import subprocess
import sys
import pprint
import art

# <snip> out all my business logic
print("Making Salad")

但是我不喜欢这样,因为它将包安装到全局包存储库。我想要的是,如果所有的软件包都安装了类似的东西

scripts/python/make_salad/make_salad.py
                         /__packages__
                                      /colorama
                                      /pathlib
                                      /iterfzf
                                      ...
                                      /fire

然后当调用 import 时,这个目录将首先出现在搜索路径上。是否有可能破解上面的脚本,所以上面是可能的?

注意要求

    只有单个脚本存储在存储库中 用户必须在 Windows 资源管理器中单击脚本 需要从脚本中 pip 安装外部包 包不应该污染全局包

【问题讨论】:

所以你想在虚拟环境中安装一些东西? 是的,但我不能让用户在命令行上乱搞,否则他们会发疯的。而且我无法将任何虚拟环境签入源代码控制或预构建任何东西。 在这种情况下是否有任何 exe 构建器提供帮助(取决于软件包);因为它使用 Python 和所有相关包构建单个可执行文件。 没有。我无法将大型可执行文件签入源代码 @vinzBad 要求(其中之一)是 Python 2.7;根据您的链接,venv 自 Python 3.3 以来才内置。 【参考方案1】:

也许您可以将--prefix 选项与pip 一起使用,修改sys.path 以包含该前缀(+ lib/python2.7/site-packages/)。我认为--prefix 甚至可以使用相对路径:

def install(package):
    try:
        __import__(package)
    except:
        import subprocess
        subprocess.call([sys.executable, "-m", "pip", "install", package, "--prefix="packages"])
.
.
.
sys.path.append("packages/lib/python2.7/site-packages/")
.
.
.
import art
.
.
.

(未经测试)

【讨论】:

【参考方案2】:

事实证明,直接从脚本中使用 virtualenv 来管理这个问题并不难。我写了一个小助手类。

import sys
import subprocess

class App:
    def __init__(self, virtual_dir):
        self.virtual_dir = virtual_dir
        self.virtual_python = os.path.join(self.virtual_dir, "Scripts", "python.exe")

    def install_virtual_env(self):
        self.pip_install("virtualenv")
        if not os.path.exists(self.virtual_python):
            import subprocess
            subprocess.call([sys.executable, "-m", "virtualenv", self.virtual_dir])
        else:
            print("found virtual python: " + self.virtual_python)

    def is_venv(self):
        return sys.prefix==self.virtual_dir

    def restart_under_venv(self):
        print("Restarting under virtual environment " + self.virtual_dir)
        subprocess.call([self.virtual_python, __file__] + sys.argv[1:])
        exit(0)

    def pip_install(self, package):
        try:
            __import__(package)
        except:
            subprocess.call([sys.executable, "-m", "pip", "install", package, "--upgrade"])

    def run(self):
        if not self.is_venv():
            self.install_virtual_env()
            self.restart_under_venv()
        else:
            print("Running under virtual environment")

并且可以从主脚本的顶部使用它 ma​​ke_salad.py 像这样

pathToScriptDir = os.path.dirname(os.path.realpath(__file__))

app = App(os.path.join(pathToScriptDir, "make_salad_virtual_env"))

app.run()

app.install("colorama")
app.install("pathlib")
app.install("iterfzf")
app.install("prompt_toolkit")
app.install("munch")
app.install("appdirs")
app.install("art")
app.install("fire")
app.install("appdirs")

print "making salad"

第一次运行它将安装虚拟环境和所有必需的包。第二次它只会在虚拟环境下运行脚本。

found virtual python: C:\workspace\make_salad_virtualenv\Scripts\python.exe
Restarting under virtual environment C:\workspace\make_salad_virtualenv\Scripts
Running under virtual environment
Making Salad

【讨论】:

以上是关于如何从 python 脚本调用 pip 并使其在本地安装到该脚本? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何在服务器上部署Django项目并使其在后台一直运行

如何创建 ElasticSearch 类型并使其在索引中可搜索

如何将数据加载到 Hive 表并使其在 Impala 中也可访问

如何添加视频元素并使其在启用声音的情况下自动播放

如何捕获 UITableView / UIScrollView 的完整内容的 UIImage 并使其在 ios 设备上工作

如何在 Gitlab CI 中设置环境变量并使其在本地可测试