64

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

假设我想使用 Flask,一个 webapp 框架。一篇博客文章说要这样做,这似乎不对:

$ 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用于 GAE 的命令。

(注意:有一些类似的问题—— 12345 ——但它们是针对特定情况的,并不能真正回答我的问题。)

4

7 回答 7

70

这是我的做法:

  • 项目
    • 。Python
      • python2.5
        • 网站包
          • < pip 安装包在这里 >
    • 包括
    • 源代码
      • 应用程序.yaml
      • 索引.yaml
      • 主要.yaml
      • < symlink ../lib/python2.5/site-packages 中的 pip 安装包

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

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

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

我不将我的库安装为 zip 文件,主要是为了方便我需要阅读源代码,出于好奇,我碰巧做了很多。但是,如果您真的想压缩库,请将以下代码片段放入您的 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.

于 2011-02-01T14:48:29.080 回答
46

简单地说:

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

创建/编辑<your_app_directory>/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

于 2014-08-29T08:06:44.167 回答
6

我更喜欢buildout

您在项目的 setup.py 或 buildout.cfg 中设置依赖项,在 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 的登台服务器等)。

于 2013-04-03T06:07:18.093 回答
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

于 2013-06-25T22:29:42.730 回答
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() 片段。

于 2011-03-18T17:30:09.090 回答
2

Wernight 的解决方案最接近官方 Flask 示例应用程序中的当前实践,我已经通过更改sys.path.insert()调用来改进它,以便通过处理其伴随文件(这对于 Pyramid 等框架很重要)site.addsitedir()来允许命名空间包。.pth

到目前为止一切顺利,但这会将目录附加到路径中,因此失去了用较新版本覆盖包含的库(如 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模块中并被称为 likeinsertsitedir(index, path)或其他一些变体,正如您在参加此拉取请求的讨论中看到的那样,但逻辑或多或少是无论如何它将如何工作,以允许对包括命名空间在内的所有包都很简单pip install -r requirements.txt -t lib/,并且仍然允许用新版本覆盖包含的库,因为到目前为止我还没有找到更简单的替代方案

于 2014-09-14T12:39:24.717 回答
1

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

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

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

于 2021-06-06T19:57:50.743 回答