Доступ к флажке.

Я использую Flask + gevent и хочу получить доступ к приложению flask.g в пределах целевой функции гриля.  Я использую декоратор copy_current_request_context и имеет ситуацию, очень похожую на пример, приведенный в документах:

import gevent
from flask import copy_current_request_context, g

@app.route('/')
def index():
    g.user_data = 'foobar'
    g.more_user_data = 'baz'

    @copy_current_request_context
    def do_some_work():
        some_func(g.user_data, g.more_user_data)
        ...  

    gevent.spawn(do_some_work)
    return 'Regular response'

Однако я получаю следующую ошибку:

AttributeError: '_AppCtxGlobals' object has no attribute 'user_data'

Я думаю, что новый контекст приложения толкается при копировании контекста запроса? Я установил трассировку в флеш-код здесь, и это похоже на случай. Таким образом, ошибка не так уж и удивительна, потому что объект flask.g - это контекст приложения с областью действия 0.10 (см. http://flask.pocoo.org/docs/0.12/api/#flask.Flask.app_ctx_globals_class).

Очевидно, что я могу просто передать пользовательские данные в целевую функцию в качестве аргументов:

import gevent
from flask import g

@app.route('/')
def index():
    g.user_data = 'foobar'
    g.more_user_data = 'baz'

    def do_some_work(user_data, more_user_data):
        some_func(user_data, more_user_data)
        ...  

    gevent.spawn(do_some_work, g.user_data, g.more_user_data)
    return 'Regular response'

И это работает отлично, но я надеялся использовать flask.g, если это возможно.

Ответ 1

flask.g привязан к контексту приложения, а не по запросу, как говорит doc:

Начиная с Flask 0.10, это сохраняется в контексте приложения и больше не находится в контексте запроса...

copy_current_request_context() только контекст запроса копирования, но дает вам новый контекст приложения. Вы можете создать его для передачи текущего контекста приложения с закрытием:

def copy_current_app_context(f):
    from flask.globals import _app_ctx_stack
    appctx = _app_ctx_stack.top
    def _(*args, **kwargs):
        with appctx:
            return f(*args, **kwargs)
    return _

Однако я предпочитаю передавать данные в greenlet явно через аргументы, которые являются более чистыми.