打包带有依赖项的 python 项目的标准方法是什么?

What's the standard way to package a python project with dependencies?

我有一个 python 项目,它有一些依赖项(在 setup.py 中的 install_requires 下定义)。我的操作人员需要一个独立的包,并且只依赖于 python 安装。试金石是他们能够获得一个 zip 文件,然后在没有互联网连接的情况下解压缩并运行它。

有没有简单的方法来打包包含依赖项的安装?如果我必须建立在 OS/architecture 上,它最终将在 运行 上构建,这是可以接受的。

就其价值而言,我已经尝试了 setup.py buildsetup.py sdist,但它们似乎不符合要求,因为它们不包含依赖项。我也考虑过 virtualenv(如果绝对必要,可以安装),但是它有硬编码的路径,这使得它不太理想。

在大多数情况下,您应该能够 "vendor" 所有依赖项。它基本上是一个粗略的 virtualenv 版本。

例如看看 requests 包如何 includes chardet and urllib3 in its own source tree. Here's an example script that should do the initial downloading and copying for you: https://gist.github.com/proppy/1136723

安装依赖项后,您可以使用 from .some.namespace import dependency_name 引用它们以确保您使用的是本地版本。

使用最新版本的 pip 可以做到这一点(我使用的是 8.1.2)。在构建机器上:

pip install -r requirements.txt --prefix vendor

然后运行它:

PYTHONPATH=vendor/lib/python2.7/site-packages python yourapp.py

(这基本上是@valentjedi 评论的扩展。谢谢!)

pip 的工作方式有一些细微差别。不幸的是,如果这些依赖项中的任何一个或依赖项的依赖项安装到 pip 可以找到它们的位置,则使用 --prefix vendor 存储项目的所有依赖项将不起作用。它将跳过这些依赖项,并将其余的安装到您的 vendor 文件夹中。

过去我使用 virtualenv 的 --no-site-packages 选项来解决这个问题。在一家公司,我们会发布整个 virtualenv,其中包括 python 二进制文件。为了只运送依赖项,您可以结合使用 virtualenv 和 pip 上的 --prefix 开关,为自己提供一个干净的环境,安装到正确的位置。

我将提供一个示例脚本来创建一个临时的 virtualenv,激活它,然后将依赖项安装到本地 vendor 文件夹。如果您在 CI.

中 运行,这会很方便
#!/bin/bash

tempdir=$(mktemp -d -t project.XXX) # create a temporary directory
trap "rm -rf $tempdir" EXIT         # ensure it is cleaned up
# create the virtualenv and exclude packages outside of it
virtualenv --python=$(which python2.7) --no-site-packages $tempdir/venv
# activate the virtualenv
source $tempdir/venv/bin/activate    
# install the dependencies as above
pip install -r requirements.txt --prefix=vendor

假设您在 requirements.txt 文件中有 python 模块 app.py 和依赖项。

首先,在 appdeps 文件夹中安装所有依赖项。

python -m pip install -r requirements.txt --target=./appdeps 

然后在您的 app.py 模块中将此依赖文件夹添加到 python 路径

# app.py
import sys
sys.path.append('appdeps')

# rest of your module normally
#...

这将像您 运行 来自 venv 的脚本一样工作,其中安装了所有依赖项;>