如何使用 Google App Engine 管理第三方 Python 库? (虚拟环境?点子?)

Posted

技术标签:

【中文标题】如何使用 Google App Engine 管理第三方 Python 库? (虚拟环境?点子?)【英文标题】:How do I manage third-party Python libraries with Google App Engine? (virtualenv? pip?) 【发布时间】:2011-06-19 07:29:09 【问题描述】:

使用 Google App Engine 管理第三方 Python 库的最佳策略是什么?

假设我想使用 Flask,一个 webapp 框架。 A blog entry 说要这样做,这似乎不对:

$ cd /tmp/
$ wget http://pypi.python.org/packages/source/F/Flask/Flask-0.6.1.tar.gz
$ tar zxf Flask-0.6.1.tar.gz
$ cp -r Flask-0.6.1/flask ~/path/to/project/
(... repeat for other packages ...)

必须有更好的方法来管理第三方代码,特别是如果我想跟踪版本、测试升级或两个库共享一个子目录。我知道 Python 可以从 zipfiles 导入模块,并且 pip 可以与一个很棒的 REQUIREMENTS 文件一起使用,而且我已经看到 pip 有一个 zip 命令用于盖伊。

(注意:有一些类似的问题——1、2、3、4、5——但它们是针对具体情况的,并不能真正回答我的问题。)

【问题讨论】:

【参考方案1】:

我是这样做的:

项目 .Python bin 库 python2.5 网站包 包括 源 app.yaml index.yaml main.yaml

project 目录是 virtualenv 所在的***目录。我使用以下命令获取 virtualenv:

cd project
virtualenv -p /usr/bin/python2.5 --no-site-packages --distribute .

src 目录是您所有代码所在的位置。当您将代码部署到 GAE 时,**将它们部署在 src 目录中,而不是其他任何东西。 appcfg.py 将为您解析符号链接并将库文件复制到 GAE。

我不将我的库安装为 zip 文件,主要是为了方便我需要阅读源代码,出于好奇,我碰巧做了很多。但是,如果您真的想压缩库,请将以下代码 sn-p 放入您的 main.py

import sys
for p in ['librarie.zip', 'package.egg'...]:
    sys.path.insert(0, p)

之后,您可以照常导入压缩包。

需要注意的是 setuptools 的pkg_resources.py。我将它直接复制到我的src 目录中,以便我的其他符号链接包可以使用它。注意任何使用entry_points 的东西。就我而言,我使用的是 Toscawidgets2,我不得不深入研究源代码以手动连接各个部分。如果您有很多依赖于entry_point 的库,这可能会很烦人。

【讨论】:

那么,如何在不同的文件夹中 pip 安装包? 我 pip install 到同一个 virtualenv。你 pip install 的所有东西都会自动进入 lib 目录。我只是将包和模块符号链接到 src 目录。 如何对站点包中的内容进行符号链接?我做了上述所有但仍然得到 ImportError: No module named jsonpickle【参考方案2】:

注意:此答案专门针对 Google App Engine 上的 Flask。

有关如何让 Flask 扩展程序在 App Engine 上运行的示例,请参阅 flask-appengine-template 项目。 https://github.com/kamalgill/flask-appengine-template

将扩展拖放到 src/packages/flaskext 的命名空间包文件夹中,一切就绪。 https://github.com/kamalgill/flask-appengine-template/tree/master/src/lib/flaskext

非 Flask 包可以作为 zip 文件、egg 或解压缩包放入 src/packages 文件夹,因为项目模板包含上面发布的 sys.path.insert() sn-p。

【讨论】:

查看他的文件'run.py'。 github.com/kamalgill/flask-appengine-template/blob/master/src/…【参考方案3】:

我更喜欢buildout。

您在项目或 buildout.cfg 中的 setup.py 中设置依赖项,在 buildout.cfg 中固定版本,并指定哪些包在 GAE 上不可用,应包含在 packages.zip 中。 rod.recipe.appengine 会将所需的包复制到 packages.zip 中,只要将 packages.zip 插入到 sys.path 中,就可以在任何地方导入。

如果你需要的包不在pypi上,你也可以使用来自github的fork

find-links =
    https://github.com/tesdal/pusher_client_python/tarball/rewrite#egg=pusher-2.0dev2

[versions]
pusher = 2.0dev2

所有这些设置和依赖项都在 git 中进行版本控制。

您无需担心当前包含在您的源代码树中并可能复制到您的版本控制中(或要求新开发人员手动解包和升级)的 Flask 副本,您只需检查 buildout.cfg 中的版本即可。如果您想要新版本,请更改 buildout.cfg 并重新运行 buildout。

您还可以使用它将变量插入到配置文件模板中,例如在 app.yaml 中设置应用程序 id 和版本(如果您有带有 staging.cfg 的暂存服务器等)。

【讨论】:

【参考方案4】:

我最近为此创建了一个名为 gaenv 的工具。它遵循 requirements.txt 格式,但不安装它,您可以使用 pip install -r requirements.txt 安装,然后运行命令行工具 gaenv。

$ pip install -r requirements.txt
$ gaenv

这会自动创建符号链接,您也可以在您的 virtualenv 中安装 gaenv 并从那里运行二进制文件。 这是一篇关于它的博客文章:

http://blog.altlimit.com/2013/06/google-app-engine-virtualenv-tool-that.html

也在github上

https://github.com/faisalraja/gaenv

【讨论】:

【参考方案5】:

简单地说:

$ pip install -r requirements.txt -t <your_app_directory/lib>

创建/编辑&lt;your_app_directory&gt;/appengine_config.py:

"""This file is loaded when starting a new application instance."""
import sys
import os.path

# add `lib` subdirectory to `sys.path`, so our `main` module can load
# third-party libraries.
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'lib'))

更新:

Google 将他们的示例更新为 appengine_config.py,例如:

    from google.appengine.ext import vendor
    vendor.add('lib')

注意:即使他们的示例有 .gitignore 忽略 lib/ 目录,如果您使用 git-push 部署方法,您仍然需要将该目录置于源代码管理之下。

【讨论】:

这应该是答案,因为它已经被谷歌“认可”了 更新后的答案是Google App Engine官方方法:cloud.google.com/appengine/docs/python/tools/libraries27(注意不需要下载vendor.py,在appengine_config.py中添加from google.appengine.ext import vendor即可 我一直在尝试使用google app engine python客户端。我遵循了上述所有说明。但是当我做from google.appengine.ext import db 时,我得到ImportError: No module named appengine.ext。请帮忙。 如何通过 pip freeze 列出 lib 文件夹中的包?【参考方案6】:

Wernight's solution 是official Flask example app 中最接近当前实践的,我已经通过将sys.path.insert() 调用更改为site.addsitedir() 来改进它,以便通过处理他们的服务员.pth 来允许namespace packages文件(对于 Pyramid 等框架很重要)。

到目前为止一切都很好,但是 将目录附加到路径中,因此失去了用较新版本覆盖包含的库(如 WebOb 和请求)的机会。

appengine_config.py 中需要的内容(我也在努力让官方回购也接受此更改)如下:

"""This file is loaded when starting a new application instance."""
import os.path
import site.addsitedir
import sys.path

dirname = 'lib'
dirpath = os.path.join(os.path.dirname(__file__), dirname)

# split path after 1st element ('.') so local modules are always found first
sys.path, remainder = sys.path[:1], sys.path[1:]

# add `lib` subdirectory as a site directory, so our `main` module can load
# third-party libraries.
site.addsitedir(dirpath)

# append the rest of the path
sys.path.extend(remainder)

此代码的最终版本可能最终隐藏在 vendor.py 模块中,并被称为 insertsitedir(index, path) 或其他一些变体,如您所见 in the discussion attending this pull request,但逻辑或多或少是如何工作的无论如何,允许一个简单的pip install -r requirements.txt -t lib/ 为所有包(包括命名空间包)工作,并且仍然允许用新版本覆盖包含的库,就像我迄今为止的unable to find a simpler alternative 一样。

【讨论】:

此代码的一个版本现已被 John Wayne Parrott 打包:github.com/jonparrott/Darth-Vendor【参考方案7】:

(2021 年 6 月)这篇文章已有十多年的历史,因此现在有必要更新答案。

    Python 3:在requirements.txt 中列出 3P 库以及任何所需的版本号;它们将在部署时由 Google 自动安装。 (如果您决定将应用迁移到 Google Cloud Functions 或 Cloud Run,则使用相同的技术。) Python 2 没有 built-in 3P libraries(常规 3P 库):
如上创建requirements.txt 通过pip install -t lib -r requirements.txt 将它们安装/自捆绑/复制到本地,例如lib 创建appengine_config.py,如step 5 on this page所示
    Python 2 built-in 3P libraries(一组特殊的 3P 库):
上面链接的所有列出的 3P 库都是“内置的”,这意味着它们可以在 App Engine 服务器上使用,因此您不必将它们复制/自行捆绑到您的应用中(如上面的 #2 中所示) 在app.yamllike this 的libraries: 部分中列出可用版本就足够了 (不要将内置库放在requirements.txt 中,也不要使用pip install 在本地安装它们,除非您想自行捆绑,因为如果您需要更新版本的内置库。) 像上面一样创建appengine_config.py

如果您的 Python 2 应用同时具有内置 非内置 3P 库,请使用上述 #2 和 #3 中的技术(@987654337 中的内置库@ 和requirements.txt 中的非内置库并运行上面的pip install cmd)。像 Python 3 这样的第二代运行时的改进之一是所有这些带有 3P 库的游戏都神奇地消失了(参见上面的 #1)。

【讨论】:

以上是关于如何使用 Google App Engine 管理第三方 Python 库? (虚拟环境?点子?)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Google App Engine 中计算多对多关系的双方

如何在 Google Cloud App Engine 上使用 PubSub 创建订阅者,该订阅者通过 Publisher 从 Google Cloud App Engine Flex 收听消息?

Google App Engine (Java) + Spring 管理的 PersistenceManager

如何在 Google App Engine 标准环境中使用 Google Cloud Build 或其他方法设置环境变量?

如何在 Google App Engine 中使用 sbt?

如何减少 Google App Engine 部署的 ktor App 文件大小