0

Ich habe eine Python Google App Engine-Projekt wie folgt strukturiert:Import über Module in Google App Engine

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

Die user.py-Datei enthält eine Klasse User(ndb.Model).

Ich versuche, die User Klasse von register_user.py zu erstellen und einen neuen Benutzer in der Datenbank zu erstellen. Normalerweise würde ich importieren Sie es wie folgt aus:

from ..models.user import User 

Aber diese Fehler aus, weil ich versuche, etwas von oben mein Root-Paket zu importieren - so ich Modelle bin zu raten ist mein root-Paket, und ich kann nicht zurück zum app Paket?

Gerade jetzt, ich bin in der Lage, um es zu arbeiten, indem sie wie folgt importieren:

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

Ich denke, diese Art von unordentlich ist, though. Was ist der "richtige" Weg, meine Benutzerklasse zu importieren?

Edit: Der vollständige Stack-Trace:

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 

(Das Paket hier Namen sind anders, ich sie vereinfacht über das Beispiel allgemeinere zu machen)

+0

Bitte posten Sie den ** Volltext ** der Traceback, die Sie erhalten. – MattDMo

+1

Ich bin mir nicht sicher, ich verstehe, aber was passiert, wenn 'von models.user importieren Benutzer' –

+0

@joelgoldstick, die den Trick gemacht! –

Antwort

1

Ich denke, Dan auf dem richtigen Weg ist, aber es gibt keine Notwendigkeit, Liefern Sie Ihren eigenen Code. Das vendoring-System soll Abhängigkeiten von Drittanbietern mit pip verwalten und sollte für Ihren Anwendungsfall völlig unnötig sein, und das Verleihen Ihres eigenen Codes würde die Konventionen verletzen.

Nach dem, was Sie uns gesagt haben, sollten Sie Ihren Code mit nur

from models import user

zu importieren Lage sein, Wenn das nicht funktioniert, sollten Sie herausfinden, warum, aber Sie tun auf jeden Fall nicht benötigen Sie die Vendor-Erweiterung oder Importlib, um es zu lösen.

Ihr Basismodul befindet sich überall dort, wo sich Ihre WSGI-Basisanwendung befindet. Diese wird definiert durch die Position Ihrer app.yaml. Normalerweise wird Ihre app.yaml etwas wie enthalten:

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

In diesem Fall wird im selben Verzeichnis wie app.yaml ein main.py ist, die eine app WSGI Anwendung enthält. In einigen anderen Fällen könnte scriptapplication.main.app sein, in diesem Fall ist die app Variable in application/main.py und dann wäre das Anwendungsverzeichnis das Basisverzeichnis.

Jedes Python-Paket, das Module enthält, sollte in seinem Verzeichnis eine Datei __init__.py enthalten, wie Dan erwähnt. Als Randnotiz, wenn Sie ein lib Verzeichnis für Drittanbieter-Code verwenden, wird es keine __init__.py enthalten, da es kein Python-Paket ist (nur ein Verzeichnis, das Python-Pakete enthält). Die Tatsache, dass es sich nicht um ein Paket handelt, ist der Grund, warum Sie die von Dan beschriebene Herstellererweiterung verwenden, um sicherzustellen, dass die enthaltenen Pakete im Importpfad enthalten sind.

Nach meiner Erfahrung werden relative Importe selten benötigt und können Sie in solche Probleme bringen, also würde ich sie einfach vermeiden.

Wenn Sie immer noch hängen, legen Sie die gesamte Dateistruktur Ihrer Anwendung, einschließlich der app.yaml Inhalt und jedes der Unterverzeichnisse, einschließlich, ob sie eine __init__.py enthalten oder nicht.

+0

Ich glaube, ich habe meine nicht-relativen Importe falsch gemacht, aber jetzt funktionieren sie! 'von models.user importieren Benutzer importiert korrekt aus' register_user.py'. –

0

So wie ich diese genähert wurde mit the GAE 3rd party lib vendoring technique:

  • appengine_config.py erstellt:

Gehalt:

from google.appengine.ext import vendor 

# Add any libraries installed in the "lib" folder. 
vendor.add('lib') 
  • erstellt die /app/lib DIR-
  • eine leere __init__.py Datei im models DIR- hinzugefügt, um es um ein Paket zu bilden
  • platziert/verschoben/symlinked die models DIR- innerhalb des /app/lib dir

Mit diesem Die Modelle können mit referenziert werden:

from models.user import User 

Möglicherweise von Interesse:

+0

Vendoring ist für den Code von Drittanbietern, es sollte nicht notwendig sein, die Vendor-Erweiterung für Ihren eigenen Code zu verwenden (und tatsächlich verstößt dies in erster Linie gegen die Konventionen dieses Codes). –

+0

@BillPrin Ich gebe zu, ich fand es bequem und ging einfach dafür. Was meinen Sie mit "Verstößt gegen die Konventionen" - Verstoß gegen eine Google-Richtlinie oder Verletzung einer bestimmten Konvention? –