Comment accéder à app.config dans un plan directeur?

114

J'essaie d'accéder à la configuration de l'application d'accès à l'intérieur d'un plan authorisation.pyqui dans un package api. J'initialise le plan dans __init__.pylequel est utilisé dans authorisation.py.

__init__.py

from flask import Blueprint
api_blueprint = Blueprint("xxx.api", __name__, None)
from api import authorisation

authorisation.py

from flask import request, jsonify, current_app

from ..oauth_adapter import OauthAdapter
from api import api_blueprint as api

client_id = current_app.config.get('CLIENT_ID')
client_secret = current_app.config.get('CLIENT_SECRET')
scope = current_app.config.get('SCOPE')
callback = current_app.config.get('CALLBACK')

auth = OauthAdapter(client_id, client_secret, scope, callback)


@api.route('/authorisation_url')
def authorisation_url():
    url = auth.get_authorisation_url()
    return str(url)

Je reçois RuntimeError: travailler en dehors du contexte de l'application

Je comprends pourquoi, mais quelle est la manière correcte d'accéder à ces paramètres de configuration?

---- Mettre à jour ---- Temporairement, je l'ai fait.

@api.route('/authorisation_url')
def authorisation_url():
    client_id, client_secret, scope, callback = config_helper.get_config()
    auth = OauthAdapter(client_id, client_secret, scope, callback)
    url = auth.get_authorisation_url()
    return str(url)
Chirdeep Tomar
la source

Réponses:

133

Utilisez flask.current_appà la place de appdans la vue du plan.

from flask import current_app

@api.route("/info")
def get_account_num():
    num = current_app.config["INFO"]

Le current_appproxy n'est disponible que dans le cadre d'une requête .

weihuang
la source
25
Notez que le current_appproxy n'est disponible que dans le cadre d'une requête.
sepehr
1
@sephr Des conseils sur la façon d'accéder à ce contexte de demande depuis d'autres endroits (sans le passer en paramètre, mais en tant que paramètre global)?
carkod
21

La recordméthode de surcharge semble assez simple:

api_blueprint = Blueprint('xxx.api',  __name__, None)
api_blueprint.config = {}

@api_blueprint.record
def record_params(setup_state):
  app = setup_state.app
  api_blueprint.config = dict([(key,value) for (key,value) in app.config.iteritems()])
Ashalynd
la source
1
Pour Python 3, utilisez: app.config.items () au lieu de app.config.iteritems ()
DhoTjai
1
Salut, dois-je appeler ou enregistrer record_params, j'ai essayé mais cela n'a pas fonctionné. Merci beaucoup.
mrblue
Si vous avez besoin d'accéder à une application (par exemple, obtenir la configuration pour configurer le plan), c'est génial!
Peter Lada
12

Pour construire sur la réponse de tbicr , voici un exemple remplaçant l' exemple de registerméthode :

from flask import Blueprint

auth = None

class RegisteringExampleBlueprint(Blueprint):
    def register(self, app, options, first_registration=False):
        global auth

        config = app.config
        client_id = config.get('CLIENT_ID')
        client_secret = config.get('CLIENT_SECRET')
        scope = config.get('SCOPE')
        callback = config.get('CALLBACK')

        auth = OauthAdapter(client_id, client_secret, scope, callback)

        super(RegisteringExampleBlueprint,
              self).register(app, options, first_registration)

the_blueprint = RegisteringExampleBlueprint('example', __name__)

Et un exemple utilisant le recorddécorateur :

from flask import Blueprint
from api import api_blueprint as api

auth = None

# Note there's also a record_once decorator
@api.record
def record_auth(setup_state):
    global auth

    config = setup_state.app.config
    client_id = config.get('CLIENT_ID')
    client_secret = config.get('CLIENT_SECRET')
    scope = config.get('SCOPE')
    callback = config.get('CALLBACK')

    auth = OauthAdapter(client_id, client_secret, scope, callback)
Kyle James Walker
la source
'@ api.record' ne fonctionne pas pour moi,. De quel espace de noms provient "api"?
Tim Richardson
Désolé, je n'ai pas copié cela de la ligne dans la questionfrom api import api_blueprint as api
Kyle James Walker
4

L' current_appapproche est bonne mais vous devez avoir un contexte de requête. Si vous n'en avez pas (certains pré-travaux comme des tests, par exemple) vous feriez mieux de placer

with app.test_request_context('/'):

avant cet current_appappel.

Vous aurez RuntimeError: working outside of application context, à la place.

Ben Usman
la source
3
Qu'en est-il lorsque l'application est créée dans une usine et que, par conséquent, `` application '' (ou tout ce que l'on appelle l'application flask) n'est pas disponible pour être importée? À l'intérieur des demandes, ce n'est pas un problème car pendant les demandes, il existe un contexte d'application, mais lors de la définition de parties en dehors de la logique de demande qui nécessitent une configuration d'application. comment accéder à la configuration de l'application si vous ne pouvez pas utiliser l'application pour créer le contexte?
RobertoCuba
3

Vous devez soit importer la appvariable principale (ou ce que vous avez appelé) qui est retournée par Flask():

from someplace import app
app.config.get('CLIENT_ID')

Ou faites cela à partir d'une demande:

@api.route('/authorisation_url')
def authorisation_url():
    client_id = current_app.config.get('CLIENT_ID')
    url = auth.get_authorisation_url()
    return str(url)
Daniel Chatfield
la source
4
Ouais, je ne voulais faire aucun des deux. La première consiste à créer des références croisées et la seconde approche n'est pas DRY.
Chirdeep Tomar
2
@ChirdeepTomar Si la première approche consiste à créer des importations circulaires (qui cassent l'application), il y a un problème avec la structure de votre application.
Daniel Chatfield
13
@DanielChatfield ce n'est tout simplement pas vrai. L'objet app est l'objet qui enregistre les plans. Suggérer qu'il est correct pour le plan puis importer l'objet d'application entraînera toujours une dépendance circulaire. Voir les autres réponses pour une stratégie correcte.
sholsapp
@sholsapp Je sais que cela créera une importation circulaire (tout comme il le fait dans la documentation du flask: flask.pocoo.org/docs/patterns/packages ), j'ai dit si cela créait une importation circulaire qui cassait l'application .
Daniel Chatfield
1

Vous pouvez également envelopper le plan dans une fonction et passer le appcomme argument:

Plan:

def get_blueprint(app):
    bp = Blueprint()
    return bp

Principale:

from . import my_blueprint
app.register_blueprint(my_blueprint.get_blueprint(app))
Georg Schölly
la source
J'ai essayé ceci, mais j'ai eu une "erreur de serveur interne".
MD004 du
Y a-t-il des inconvénients avec cette approche?
Tuukka Mustonen
@Tuukka: Je ne me souviens pas d'inconvénients particuliers, ça fait un peu trop longtemps que je ne l'ai pas utilisé. Il peut y avoir certains avantages à utiliser flask.current_applorsque vous utilisez le plan directeur dans plusieurs applications. Je suggérerais que si cette approche résout vos problèmes pour l'utiliser, Flask n'applique pas une approche spécifique.
Georg Schölly