0

У меня есть Python Google App Engine проект структурирована следующим образом:Импорт через модули в Google App Engine

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

Файл user.py содержит класс User(ndb.Model).

Я пытаюсь получить доступ к классу User от register_user.py, чтобы создать и поместить нового пользователя в базу данных. Как правило, я бы просто импортировать его так:

from ..models.user import User 

Но это ошибка, потому что я пытаюсь импортировать что-то из выше моего корневого пакета - так что я предполагаю, модели мой корневой пакет, и я могу Не вернетесь в пакет app?

Прямо сейчас, я могу работать вокруг него за счет импорта, как это:

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

Я думаю, что это своего рода грязный, хотя. Итак, каков «правильный» способ импорта моего класса User?

Edit: Полные трассировки стеки:

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 

(имена В пакете здесь разные, я упростил их выше, чтобы сделать пример более общего)

+0

Пожалуйста, разместите ** полный текст ** трассы, которую вы получаете. – MattDMo

+1

Я не уверен, что понимаю, но что произойдет, если 'from models.user import User' –

+0

@joelgoldstick, который сделал трюк! –

ответ

1

Я думаю, что Дэн находится на правильном пути, однако нет никакой необходимости поставщика вашего собственного кода. Система вендинга предназначена для управления зависимыми от сторонних производителей с помощью пипа и должна быть совершенно ненужной для вашего случая использования, а продажа вашего собственного кода будет нарушать соглашения.

Исходя из того, что вы сказали нам, вы должны быть в состоянии импортировать код только с

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, а затем каталог приложения будет базовым каталогом.

Каждый пакет Python, содержащий модули, должен содержать файл __init__.py в его каталоге, как упоминал Дэн. В качестве дополнительной заметки, если вы используете каталог lib для стороннего кода, он не будет содержать __init__.py, так как это не пакет Python (только каталог, содержащий пакеты Python). Тот факт, что это не пакет, является причиной того, что вы используете расширение поставщика Dan, описанное, чтобы убедиться, что его пакеты находятся на пути импорта.

По моему опыту, относительный импорт редко необходим и может вызвать у вас проблемы, подобные этим, поэтому я просто избегу их.

Если вы все еще застряли, выложите всю файловую структуру вашего приложения, включая содержимое app.yaml, и каждый из подкаталогов, включая ли они __init__.py или нет.

+0

Я думаю, что раньше делал свой невозвратный импорт, но теперь они работают! 'from models.user import User' правильно импортирует из' register_user.py'. –

0

так, как я подошел к этому использовали 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 реж
  • добавили пустой __init__.py файл в models директории, чтобы сделать его пакет
  • помещен/перемещаемого/слинкован models реж внутри /app/lib dir

С этим модели можно ссылаться с помощью:

from models.user import User 

Возможно, интерес:

+0

Vendoring для стороннего кода, не должно быть необходимости использовать расширение поставщика для вашего собственного кода (и на самом деле это нарушает его правила в первую очередь). –

+0

@BillPrin Я признаю, я нашел это удобным и просто пошел на это. Что вы подразумеваете под «нарушением конвенций» - нарушением какой-либо политики Google или просто нарушением какой-либо конвенции? –

Смежные вопросы