在 GAE 中使用 gcloud-python

Posted

技术标签:

【中文标题】在 GAE 中使用 gcloud-python【英文标题】:Using gcloud-python in GAE 【发布时间】:2014-11-21 09:22:38 【问题描述】:

我有一堆运行一些 python 代码的小树莓派,这些代码使用 gcloud-python 数据存储包直接保存到数据存储(跳过 GAE)。这很好用。我现在想使用 Google App Engine 通过网络和移动客户端呈现数据。在我的 MacBook 上,我使用安装程序和 gcloud 通过 pip 安装了 GAE。我可以编写一个简单的 python 脚本并直接从终端执行它,该终端能够通过 gcloud 从数据存储中写入和读取 - 这也很好。

但是,当我尝试将相同的代码合并到 GAE 中时,它失败了。根据我的研究,我认为这是一个 PATH 问题,但经过几个小时的各种尝试,我无法解决这个问题。建议将不胜感激。

我相信这篇文章与我的问题相似:Google App Engine, Change which python version

以下是一些可能相关的信息:

Python 版本

$ which python
/usr/bin/python

根据引用的 Stack Overflow 问题,我将 GAE 的首选项设置为具有 /usr/bin/python 的 Python 路径。我试过了

$PATH

$ echo $PATH
/Users/sheridangray/Projects/adt-bundle-mac-x86_64-20140702/sdk/google-cloud-sdk/bin:/Users/sheridangray/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin

来自 Python 解释器的 os.path

$ python
Python 2.7.6 (default, Sep  9 2014, 15:04:36)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

gcloud 安装

$ pip install --upgrade gcloud
Requirement already up-to-date: gcloud in /Library/Python/2.7/site-packages
...

Python 2.7 参考

$ sudo find / -name python2.7
Password:
/Applications/Dropbox.app/Contents/Frameworks/Python.framework/Versions/2.7/include/python2.7
/Applications/Dropbox.app/Contents/Frameworks/Python.framework/Versions/2.7/lib/python2.7
/Applications/Dropbox.app/Contents/Resources/include/python2.7
/Applications/Dropbox.app/Contents/Resources/lib/python2.7
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/python2.7
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/python2.7
find: /dev/fd/3: Not a directory
find: /dev/fd/4: Not a directory
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
/System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7
/usr/bin/python2.7
/usr/lib/python2.7

相关代码

from gcloud import datastore

class MainHandler(webapp.RequestHandler):
  def get(self):
     dataset = datastore.get_dataset(dataset_id, email_address, private_key_file)

GAE 日志文件

*** Running dev_appserver with the following flags:
--skip_sdk_update_check=yes --port=8080 --admin_port=8000
Python command: /usr/bin/python
INFO     2014-11-21 09:02:03,276 devappserver2.py:745] Skipping SDK update check.
INFO     2014-11-21 09:02:03,288 api_server.py:172] Starting API server at: http://localhost:49183
INFO     2014-11-21 09:02:03,292 dispatcher.py:185] Starting module "default" running at: http://localhost:8080
INFO     2014-11-21 09:02:03,294 admin_server.py:118] Starting admin server at: http://localhost:8000
INFO     2014-11-21 09:02:34,319 module.py:709] default: "GET / HTTP/1.1" 200 2
INFO     2014-11-21 09:02:34,455 module.py:709] default: "GET /favicon.ico HTTP/1.1" 200 8348
INFO     2014-11-21 09:02:44,359 module.py:387] Detected file changes:
  /Users/sheridangray/Projects/city-pulse-web/main.py
ERROR    2014-11-21 09:02:46,443 webapp2.py:1552] gcloud
Traceback (most recent call last):
      File "/Users/sheridangray/Projects/adt-bundle-mac-x86_64-20140702/sdk/google-cloud-sdk/platform/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1535, in __call__
rv = self.handle_exception(request, response, e)
  File "/Users/sheridangray/Projects/adt-bundle-mac-x86_64-20140702/sdk/google-cloud-sdk/platform/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1529, in __call__
rv = self.router.dispatch(request, response)
  File "/Users/sheridangray/Projects/adt-bundle-mac-x86_64-20140702/sdk/google-cloud-sdk/platform/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
  File "/Users/sheridangray/Projects/adt-bundle-mac-x86_64-20140702/sdk/google-cloud-sdk/platform/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1102, in __call__
return handler.dispatch()
  File "/Users/sheridangray/Projects/adt-bundle-mac-x86_64-20140702/sdk/google-cloud-sdk/platform/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 572, in dispatch
return self.handle_exception(e, self.app.debug)
  File "/Users/sheridangray/Projects/adt-bundle-mac-x86_64-20140702/sdk/google-cloud-sdk/platform/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 570, in dispatch
return method(*args, **kwargs)
  File "/Users/sheridangray/Projects/city-pulse-web/main.py", line 63, in get
dataset = datastore.get_dataset(dataset_id, email_address, private_key_file)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/gcloud/datastore/__init__.py", line 103, in get_dataset
connection = get_connection(client_email, private_key_path)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/gcloud/datastore/__init__.py", line 65, in get_connection
    from gcloud.datastore.connection import Connection
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/gcloud/datastore/connection.py", line 3, in <module>
    from gcloud import connection
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/gcloud/connection.py", line 8, in <module>
class Connection(object):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/gcloud/connection.py", line 24, in Connection
USER_AGENT = "gcloud-python/0".format(get_distribution('gcloud').version)
  File "/Users/sheridangray/Projects/adt-bundle-mac-x86_64-20140702/sdk/google-cloud-sdk/platform/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/setuptools-0.6c11/pkg_resources.py", line 311, in get_distribution
if isinstance(dist,Requirement): dist = get_provider(dist)
  File "/Users/sheridangray/Projects/adt-bundle-mac-x86_64-20140702/sdk/google-cloud-sdk/platform/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/setuptools-0.6c11/pkg_resources.py", line 197, in get_provider
return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0]
  File "/Users/sheridangray/Projects/adt-bundle-mac-x86_64-20140702/sdk/google-cloud-sdk/platform/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/setuptools-0.6c11/pkg_resources.py", line 666, in require
needed = self.resolve(parse_requirements(requirements))
  File "/Users/sheridangray/Projects/adt-bundle-mac-x86_64-20140702/sdk/google-cloud-sdk/platform/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/setuptools-0.6c11/pkg_resources.py", line 565, in resolve
    raise DistributionNotFound(req)  # XXX put more info here
DistributionNotFound: gcloud
INFO     2014-11-21 09:02:46,456 module.py:709] default: "GET / HTTP/1.1" 500 5010
INFO     2014-11-21 09:02:46,514 module.py:709] default: "GET /favicon.ico HTTP/1.1" 304 -

【问题讨论】:

【参考方案1】:

您可以在 App Engine 上运行 gcloud-python,但它需要 一点额外的工作。看看我写的骨架project 这可以正常工作。

要涵盖的主要基础是:

获取依赖项

install_gcloud.sh中,pip用于安装gcloud及其 应用程序内部的依赖项使用

pip install --target="application/vendor/" gcloud

(如other answer 中所述,本地安装不会上传 部署到 App Engine。)

修改依赖

通过pip-安装--target 设置,pkg_resources.get_distribution 将按预期工作(它在您的堆栈跟踪中失败)。

此外,pytz 默认情况下读取过多,无法正常工作 App Engine,因此改用 gae-pytz。结果,一些pytz 需要修改导入。

此外,为了减少 Compute Engine 检查开销(网络开销), oauth2client.client 模块可以修改。

这两个调整都可以在单个 commit 中找到。

使导入工作

上面的脚本将所有依赖项放在一个名为 vendor/ 的目录中,并且 appengine_config.py 将此添加到导入路径中 Darth Vendor:

import darth
darth.vendor('vendor')

此外,由于protobuf 依赖也是 google 包(就像所有 App Engine 导入一样,例如 google.appengine.ext.ndb) 你需要修改__path__ 与该软件包相关联:

import os
import google

curr_dir = os.path.abspath(os.path.dirname(__file__))
vendor_dir = os.path.join(curr_dir, 'vendor')
google.__path__.append(os.path.join(vendor_dir, 'google'))

CAVEAT(截至 2015 年 1 月 22 日)

请注意,在 App Engine 中使用 gcloud-python 将 比使用原生 App Engine 库 dbndb 慢 3-5 倍。 这是因为那些使用直接 RPC 进入 App Engine 运行时,而 gcloud-python 将使用 App Engine 之外的 HTTP 与云端通信 数据存储 API。


注意:我在最初发布后更新了此内容,其中引用了 历史上以前的point。

【讨论】:

让我补充一点,如果您(多余地)在您的 app.yaml 中包含一些 google-cloud-python 依赖项,则仍然会发生 DistributionNotFound 错误。清除 app.yaml 中的包含以进行修复。【参考方案2】:

Mac 上的 GAE 无法访问安装在 Mac 上默认位置的 Python 包。你需要这样做:

ln -s /Library/Python/2.7/site-packages/.../gcloud /Users/sheridangray/Projects/city-pulse-web/gcloud

(需要用相关的路径信息替换...)

【讨论】:

我试着像你说的那样添加一个符号链接,结果还是同样的错误。这也让我想到,当我部署代码时,本地包将不可用,这也是有问题的。所以我找到了这个***.com/questions/10648256/…。当我打印出 list(sys.modules.keys()) 时,我可以看到模块实际上正在被导入,但我仍然收到 DistributionNotFound 错误。 @SheridanGray 你有想过这个吗?如果是这样,您介意发布答案吗?谢谢! 当我在 GAE 工作时,我最终使用 gcloud 直接写入数据存储并绕过 GAE 并使用 NDB。

以上是关于在 GAE 中使用 gcloud-python的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在 gcloud-python 中保存嵌套实体?

在 GAE 中使用 Spring Security 时面临的问题

使用 JPA 在 GAE 中保存许多实体

在 GAE 中使用任务队列插入批量数据

使用 Jinja2 在 GAE 中存储 Javascript 对象

如何使用 app.yaml 在 GAE(python) 中上传静态文件?