2009-07-14 18 views
2

Ich habe Probleme mit Python Funktion Dekoratoren in Google AppEngine. Ich bin nicht so vertraut mit Dekoratoren, aber sie scheinen nützlich in Web-Programmierung, wenn Sie einen Benutzer zur Anmeldung zwingen möchten, bevor bestimmte Funktionen ausgeführt werden.Python Funktion Dekoratoren in Google App Engine

Wie auch immer, ich folgte mit einem Flickr-Login-Beispiel here, die Django verwendet und eine Funktion dekoriert, um die Flickr-Anmeldung zu erfordern. Ich kann nicht scheinen, dass diese Art von Dekorateur in AppEngine funktioniert.

Ich habe es gekocht unten zu diesem:

def require_auth(func): 
    def check_auth(*args, **kwargs): 
     print "Authenticated." 
     return func(*args, **kwargs) 
    return check_auth 

@require_auth 
def content(): 
    print "Release sensitive data!" 

content() 

Dieser Code von der Kommandozeile funktioniert, aber wenn ich es in GoogleAppEngineLauncher (OS X) laufen lasse, erhalte ich folgende Fehlermeldung:

check_auth() takes at least 1 argument (0 given) 

Und ich bin nicht wirklich sicher, warum ...

EDIT eigentlichen Code enthalten: @ asperous.us änderte ich die Definition von Inhalten() Variable Argumente enthalten, ist was hast du gemeint? @Alex Martelli, 'print' funktioniert in AppEngine, aber immer noch eine völlig faire Kritik. Wie gesagt, ich versuche den Flickr Login über den obigen Link zu benutzen. Ich habe versucht, es in meine App zu setzen wie so:

def require_flickr_auth(view): 
    def protected_view(request,*args, **kwargs): 
     if 'token' in request.session: 
      token = request.session['token'] 
      log.info('Getting token from session: %s' % token) 
     else: 
      token = None 
      log.info('No token in session') 

     f = flickrapi.FlickrAPI(api_key, api_secret, 
           token=token, store_token=False) 

     if token: 
      # We have a token, but it might not be valid 
      log.info('Verifying token') 
      try: 
       f.auth_checkToken() 
      except flickrapi.FlickrError: 
       token = None 
       del request.session['token'] 

     if not token: 
      # No valid token, so redirect to Flickr 
      log.info('Redirecting user to Flickr to get frob') 
      url = f.web_login_url(perms='read') 
      print "Redirect to %s" % url 

     # If the token is valid, we can call the decorated view. 
     log.info('Token is valid') 
     return view(request,*args, **kwargs) 

    return protected_view 

@require_flickr_auth 
def content(*args, **kwargs): 
    print 'Welcome, oh authenticated user!' 

def main(): 
    print 'Content-Type: text/plain' 
    content() 

if __name__ == "__main__": 
    main() 

Wenn ich die @require_flickr_auth Dekoration zu entfernen, die Zeichenfolge ‚Welcome ...‘ just fine ausdruckt. Ansonsten bekomme ich eine große hässliche AppEngine-Ausnahmeseite mit

type 'exceptions.TypeError': protected_view() takes at least 1 argument (0 given) 

an der Unterseite.

Antwort

3

Sie rufen content() ohne Argumente, aber die verzierte Version protected_view erfordert das request Argument. Fügen Sie das Argument entweder zu content hinzu oder entfernen Sie es aus protected_view.

Wenn Sie diesen Fehler mit Ihrer einfachen Version bekommen, dann würde ich vermuten, dass content eine Klassenmethode ist, wie Alex vorgeschlagen hat. Sonst sieht es so aus, als ob Sie sagen, dass Sie mindestens ein Argument erwarten und es dann nicht liefern sollten.

+0

Doh - Das ist es total. Vielen Dank! – Owen

0

Decorators wurden in Python 2.4 hinzugefügt (glaube ich), googleapp verwendet möglicherweise eine ältere Version? Sie können auch tun:

def content(): 
    print "Release sensitive data!" 
    content = require_auth(content) 

es wird die gleiche Sache wie der Dekorateur tun, es ist nur ein wenig mehr Arbeit.

+0

Ja, oder zumindest die Syntax geändert oder etwas? Auf jeden Fall behauptet die AppEngine-Site, dass die Python-Version 2.5.2 ist. – Owen

+0

Nein, GAE verwendet Python 2.5. –

+0

Sie würden denken, dass ich das tun könnte, oder? Aber content = require_auth (Inhalt) gibt den gleichen Fehler ... – Owen

1

@Owen, der "takes mindest 1 argument" -Fehler deutet darauf hin, dass Sie Inhalte innerhalb einer Klasse definieren (dh als Methode) und nicht als bloße Funktion, wie Sie zeigen - ja, wie genau versuchen Sie es diesen Code in GAE ausführen? I.e. Was ist Ihre app.yaml & c? Wenn Sie Ihren Code genau setzen, wie Sie es in silly.py und in Ihrem app.yaml gab haben Sie:

handlers: 
- url: /silly 
    script: silly.py 

dann, wenn Sie besuchen yourapp.appspot.com/silly Sie absolut nichts auf entweder den Browser sehen oder die Protokolle (neben dem "GET /silly HTTP/1.1" 200 - in Letzteres natürlich ;-): Es gibt keinen Fehler, aber die print tut auch nichts besonders. Also muss ich mir vorstellen, Sie versucht, Code läuft anders aus, was du uns zeigen ...! -)

0

Warum

return func(*args, **kwargs)

würde das nicht func ausführen und dann das Ergebnis zurück?

Wenn ja, sollten Sie es keine Argumente geben, da es keine braucht. Wenn Sie Inhalt() bearbeitet und die Argumente (*args, **kwargs) hinzugefügt haben, wird es funktionieren?