如何从 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")
并且可以从主脚本的顶部使用它 make_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 并使其在本地安装到该脚本? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
如何创建 ElasticSearch 类型并使其在索引中可搜索
如何将数据加载到 Hive 表并使其在 Impala 中也可访问
如何捕获 UITableView / UIScrollView 的完整内容的 UIImage 并使其在 ios 设备上工作