如何在Mac OS X 10.6上使用virtualenv与Google App Engine SDK

30 投票
5 回答
9433 浏览
提问于 2025-04-16 04:59

我快抓狂了,因为我之前一切都好好的,直到上周突然出问题了。

我在为一个Google App Engine应用设置虚拟环境,然后用 dev_appserver.py 启动这个应用时,出现了导入标准库的错误(比如“ImportError: No module named base64”)。

我做的步骤是这样的:

(使用系统自带的Python)

virtualenv --python=python2.5 --no-site-packages ~/.virtualenv/foobar

然后我在 ~/.virtualenv/foobar/lib/python2.5/site-packages/ 里添加了一个 gae.pth 文件,里面包含了Google App Engine的库:

/usr/local/google_appengine
/usr/local/google_appengine/lib/antlr3
/usr/local/google_appengine/lib/cacerts
/usr/local/google_appengine/lib/django
/usr/local/google_appengine/lib/fancy_urllib
/usr/local/google_appengine/lib/ipaddr
/usr/local/google_appengine/lib/webob_1_1_1
/usr/local/google_appengine/lib/yaml/lib

(这个是参考了 这个回答.)

接着我激活我的“foobar”虚拟环境,然后尝试用 dev_appserver.py 启动我的应用。

服务器启动了,但第一次请求就报错,出现了之前提到的“ImportError: No module named base64”。如果我访问管理控制台,还会出现“ImportError: No module named cgi”。

如果我直接启动Python,就可以加载这些模块。

>>> import base64
>>> base64.__file__
'/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/base64.py'

看起来SDK的沙箱机制阻止了这些库的加载。但正如我所说的,我之前一切都好好的……不知道是什么改变了,或者我不小心搞坏了我的虚拟环境,现在就是想不起来我当初是怎么让它工作的。

软件版本:

Google App Engine SDK 1.3.7
Mac OS X Snow Leopard 10.6.4
virtualenv 1.5.1

更新: 针对Alan Franzoni的问题:

我使用的是Mac OS X自带的系统Python。我是通过easy_install安装的virtualenv。今天我升级到了virtualenv 1.5.1,想试着解决这个问题。

如果我用虚拟环境中的Python运行 python /usr/local/bin/dev_appserver.py,问题依然存在。如果我停用虚拟环境,用系统的python2.5运行这个命令,就可以正常工作。(另外,我也可以用GoogleAppEngineLauncher来启动我的应用。)

这里是一个完整的错误堆栈信息(这个使用的是Kay框架,但webapp的问题也是一样的):

Traceback (most recent call last):
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 3206, in _HandleRequest
    self._Dispatch(dispatcher, self.rfile, outfile, env_dict)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 3149, in _Dispatch
    base_env_dict=env_dict)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 525, in Dispatch
    base_env_dict=base_env_dict)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 2402, in Dispatch
    self._module_dict)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 2312, in ExecuteCGI
    reset_modules = exec_script(handler_path, cgi_path, hook)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 2208, in ExecuteOrImportScript
    exec module_code in script_module.__dict__
  File "/Users/look/myapp/kay/main.py", line 17, in <module>
    kay.setup()
  File "/Users/look/myapp/kay/__init__.py", line 122, in setup
    from google.appengine.ext import db
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 1287, in Decorate
    return func(self, *args, **kwargs)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 1937, in load_module
    return self.FindAndLoadModule(submodule, fullname, search_path)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 1287, in Decorate
    return func(self, *args, **kwargs)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 1839, in FindAndLoadModule
    description)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 1287, in Decorate
    return func(self, *args, **kwargs)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 1790, in LoadModuleRestricted
    description)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/db/__init__.py", line 81, in <module>
    import base64
ImportError: No module named base64

5 个回答

1

我觉得,因为你在设置虚拟环境的时候用了 --no-site-packages 这个选项,所以你需要把SDK安装到这个环境里。这个 --no-site-packages 选项的意思是把你正在配置的开发环境和你电脑上其他的Python安装隔离开来。因此,按照你现在的配置,你在调用一个在这个环境中不存在的模块,这就是为什么在关闭这个环境时可以正常工作,因为那时它是在使用操作系统默认的Python安装。 如果你想在这个环境中访问外部的模块,可以尝试不使用 --no-site-packages 选项来设置开发环境。

2

Google AppEngine SDK为了把自己安装到系统路径中,做了很多小把戏,这些把戏依赖于实际文件的路径。我觉得它失败的原因可能有很多。这个SDK并不是以真正的Python包形式安装的,而虚拟环境(virtualenv)也并没有完全隔离环境,它只是设置了一个环境(这很明显)并改变了系统路径。而GAE SDK也是这样,它们之间会互相干扰。再加上SDK的开发进展很快,变化也很多,所以这条路走起来会非常坎坷。

可能,如果你能解释一下你想要实现什么,那会更好。我猜测你是想创建一个干净的环境,以确保应用程序中没有任何第三方模块。如果我的猜测是对的,我建议你按照这里的说明,通过需求文件将GAE SDK安装到虚拟环境中。

15

这是关于GAE SDK的一个问题4339,这个问题已经确认存在,并且在这个bug记录中有两个稍微不同的补丁可以解决它。

发生的情况是,dev_appserver.py会设置一个受限的Python环境,它不允许访问任何非系统自带的Python模块。它是通过计算os模块的位置来找到系统Python的文件夹。在一个虚拟环境(virtualenv)中,os.py会被链接到虚拟环境中,但实际上是直接编译到虚拟环境里的。这样一来,dev_appserver就使用了这个路径,从而有效地阻止了访问任何没有被虚拟环境链接的系统Python库模块,而这些模块大多数都是无法访问的。解决办法就是要“认可”这两个路径。

撰写回答