Декораторы функций Python в Google App Engine - PullRequest
2 голосов
/ 14 июля 2009

У меня проблемы с использованием декораторов функций Python в Google AppEngine. Я не очень знаком с декораторами, но они кажутся полезными в веб-программировании, когда вы можете заставить пользователя войти в систему перед выполнением определенных функций.

В любом случае, я следовал вместе с примером входа в flickr здесь , который использует django и украшает функцию, требующую входа в систему flickr. Я не могу заставить этот тип декоратора работать в AppEngine.

Я свел это к следующему:

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()

Этот код работает из командной строки, но когда я запускаю его в GoogleAppEngineLauncher (OS X), я получаю следующую ошибку:

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

И я не совсем уверен, почему ...

РЕДАКТИРОВАТЬ, чтобы включить фактический код: @ asperous.us Я изменил определение content (), добавив переменные аргументы. Это то, что вы имели в виду? @ Алекс Мартелли, «print» работает в AppEngine, но все еще является справедливой критикой. Как я уже сказал, я пытаюсь использовать логин flickr по ссылке выше. Я пытался вставить его в свое приложение так:

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()

Когда я удаляю украшение @require_flickr_auth, строка «Welcome ...» печатается очень хорошо. В противном случае я получаю большую уродливую страницу исключений AppEngine с

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

внизу.

Ответы [ 4 ]

3 голосов
/ 14 июля 2009

Вы звоните content() без каких-либо аргументов, но оформленная версия protected_view требует аргумента request. Либо добавьте аргумент в content, либо удалите его из protected_view.

Если вы получаете эту ошибку с вашей простой версией, то я подозреваю, что content - это метод класса, как предложил Алекс. В противном случае это выглядит так, будто вы говорите, что ожидаете хотя бы один аргумент, а не предоставляете его.

1 голос
/ 14 июля 2009

@ Оуэн, ошибка «принимает по крайней мере 1 аргумент» предполагает, что вы определяете контент внутри класса (т.е. как метод), а не как пустую функцию, как вы показываете - действительно, как именно вы пытаетесь выполнить этот код в GAE? То есть какой у тебя app.yaml & c? Если вы поместите свой код в точности так, как вы его указали в silly.py и в вашем app.yaml, у вас будет:

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

затем, когда вы посещаете yourapp.appspot.com/silly, вы не увидите абсолютно ничего ни в браузере, ни в журналах (кроме "GET /silly HTTP/1.1" 200 - в последнем, конечно ;-): ошибки нет, но print не делает ничего особенного тоже. Так что я должен представить, что вы пытались запустить код, отличный от того, что вы нам показываете ...! -)

0 голосов
/ 14 июля 2009

Почему

return func(*args, **kwargs)

Разве это не выполнит func, а затем вернет результат?

Если это так, вы не должны давать ему никаких аргументов, поскольку он не принимает никаких. Если вы отредактировали content () и добавили к нему аргументы (*args, **kwargs), будет ли он работать?

0 голосов
/ 14 июля 2009

Декораторы были добавлены в python 2.4 (я думаю), может быть, googleapp использует более старую версию? Вы также можете сделать:

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

он будет делать то же самое, что и декоратор, просто немного больше работы.

...