【问题标题】:Import across modules in Google App Engine在 Google App Engine 中跨模块导入
【发布时间】:2016-07-24 14:48:58
【问题描述】:

我有一个 Python Google App Engine 项目,其结构如下:

app/
    handlers/
        register_user.py
    models/
        user.py

user.py 文件包含一个类 User(ndb.Model)

我正在尝试从register_user.py 访问User 类以创建新用户并将其放入数据库中。通常,我会像这样导入它:

from ..models.user import User

但是这个错误是因为我试图从我的根包上方导入一些东西 - 所以我猜测模型是我的根包,我无法回到 app 包?

现在,我可以通过这样的导入来解决它:

import importlib
User = importlib.import_module('models.user').User

不过,我认为这有点混乱。那么导入我的 User 类的“正确”方式是什么?

编辑:完整的堆栈跟踪:

Attempted relative import beyond toplevel package (/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py:1552)
Traceback (most recent call last):
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1535, in __call__
    rv = self.handle_exception(request, response, e)
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1529, in __call__
    rv = self.router.dispatch(request, response)
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher
    return route.handler_adapter(request, response)
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1102, in __call__
    return handler.dispatch()
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 572, in dispatch
    return self.handle_exception(e, self.app.debug)
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 570, in dispatch
    return method(*args, **kwargs)
  File "/base/data/home/apps/s~polly-chat/1.394430414829237783/main.py", line 48, in post
    receive_message(messaging_event)
  File "/base/data/home/apps/s~polly-chat/1.394430414829237783/messaging/handler.py", line 39, in receive_message
    intent_picker.respond_to_postback(messaging_event)
  File "/base/data/home/apps/s~polly-chat/1.394430414829237783/messaging/intent_picker.py", line 71, in respond_to_postback
    intent = importlib.import_module('intents.register_user')
  File "/base/data/home/runtimes/python27/python27_dist/lib/python2.7/importlib/__init__.py", line 37, in import_module
    __import__(name)
  File "/base/data/home/apps/s~polly-chat/1.394430414829237783/intents/register_user.py", line 1, in <module>
    from ..models import messenger_user
ValueError: Attempted relative import beyond toplevel package

(这里的包名不同,我在上面简化了,让例子更通用)

【问题讨论】:

  • 请发布您获得的回溯的全文
  • 我不确定我是否理解,但如果 from models.user import User
  • @joelgoldstick 成功了!

标签: python google-app-engine python-import google-app-engine-python


【解决方案1】:

我认为 Dan 走在正确的轨道上,但是没有必要提供您自己的代码。 vendoring 系统是使用 pip 管理第三方依赖项,对于您的用例应该完全没有必要,并且 vendoring 您自己的代码会违反约定。

根据您告诉我们的内容,您应该可以只使用

from models import user

如果这不起作用,您应该找出原因,但您绝对不需要供应商扩展或 importlib 来解决它。

您的基础模块是您的基础 WSGI 应用程序所在的位置,这将由您的 app.yaml 路由到的位置来定义。通常,您的 app.yaml 将包含以下内容:

- url: .*  # This regex directs all routes to main.app
  script: main.app

在这种情况下,在与app.yaml 相同的目录中,有一个main.py,其中包含一个app WSGI 应用程序。在其他一些情况下,script 可能是 application.main.app,在这种情况下,app 变量位于 application/main.py 中,然后应用程序目录将是基本目录。

正如 Dan 所说,每个包含模块的 Python 包都应该在其目录中包含一个 __init__.py 文件。附带说明一下,如果您确实将 lib 目录用于第三方代码,则它不会包含 __init__.py,因为它不是 Python 包(只是包含 Python 包的目录)。它不是一个包的事实是你使用 Dan 描述的供应商扩展来确保它包含的包在导入路径上的原因。

根据我的经验,相对导入很少需要,并且可能会让您陷入此类问题,所以我会避免它们。

如果您仍然卡住,请布置应用程序的整个文件结构,包括 app.yaml 内容和每个子目录,包括它们是否包含 __init__.py

【讨论】:

  • 我想我以前做错了非相对导入,但现在他们工作了! from models.user import User 正确地从 register_user.py 导入。
【解决方案2】:

我处理这个问题的方法是使用the GAE 3rd party lib vendoring technique

  • 创建appengine_config.py:

内容:

from google.appengine.ext import vendor

# Add any libraries installed in the "lib" folder.
vendor.add('lib')
  • 创建了/app/lib 目录
  • models 目录中添加了一个空的__init__.py 文件以使其成为一个包
  • /app/lib 目录中放置/移动/符号链接models 目录

有了这个模型,可以使用:

from models.user import User

可能感兴趣:

【讨论】:

  • Vendoring 是针对第三方代码的,你自己的代码应该不需要使用 vendor 扩展(事实上这样做首先违反了它的约定)。
  • @BillPrin 我承认,我发现它很方便,就去做了。您所说的“违反惯例”是什么意思 - 违反了某些 Google 政策或只是违反了某些约定?
猜你喜欢
  • 2011-02-12
  • 1970-01-01
  • 1970-01-01
  • 2015-02-19
  • 2012-04-02
  • 2014-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多