Chirdeep Tomar
Chirdeep Tomar

Reputation: 4461

How to access app.config in a blueprint?

I am trying to access access application configuration inside a blueprint authorisation.py which in a package api. I am initializing the blueprint in __init__.py which is used in 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)

I am getting RuntimeError: working outside of application context

I understand why that is but then what is the correct way of accessing those configuration settings?

----Update---- Temporarily, I have done this.

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

Upvotes: 179

Views: 108586

Answers (8)

HyopeR
HyopeR

Reputation: 497

I know this is an old thread. But while writing a flask service, I used a method like this to do it. It's longer than the solutions above but it gives you the possibility to use customized class yourself. And frankly, I like to write services like this.

Step 1:

I added a struct in a different module file where we can make the class structs singleton. And I got this class structure from this thread already discussed. Creating a singleton in Python

class Singleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        else:
            cls._instances[cls].__init__(*args, **kwargs)

        return cls._instances[cls]

Step 2:

Then I created a Singleton EnvironmentService class from our Singleton class that we defined above, just for our purpose. Instead of recreating such classes, create them once and use them in other modules, routes, etc. import. We can access the class with the same reference.

from flask import Config
from src.core.metaclass.Singleton import Singleton


class EnvironmentService(metaclass=Singleton):
    __env: Config = None

    def initialize(self, env):
        self.__env = env
        return EnvironmentService()

    def get_all(self):
        return self.__env.copy()

    def get_one(self, key):
        return self.__env.get(key)

Step 3:

Now we include the service in the application in our project root directory. This process should be applied before the routes.

from flask import Flask
from src.services.EnvironmentService import EnvironmentService

app = Flask(__name__)

# Here is our service
env = EnvironmentService().initialize(app.config)

# Your routes...

Usage:

Yes, we can now access our service from other routes.

from src.services.EnvironmentService import EnvironmentService

key = EnvironmentService().get_one("YOUR_KEY")

Upvotes: 3

weihuang
weihuang

Reputation: 2407

Use flask.current_app in place of app in the blueprint view.

from flask import current_app

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

The current_app proxy is only available in the context of a request.

Upvotes: 239

Kyle James Walker
Kyle James Walker

Reputation: 1269

To build on tbicr's answer, here's an example overriding the register method example:

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

And an example using the record decorator:

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)

Upvotes: 17

Georg Schölly
Georg Schölly

Reputation: 126185

You could also wrap the blueprint in a function and pass the app as an argument:

Blueprint:

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

Main:

from . import my_blueprint
app.register_blueprint(my_blueprint.get_blueprint(app))

Upvotes: 1

Ashalynd
Ashalynd

Reputation: 12573

Overloading record method seems to be quite easy:

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

Upvotes: 27

Ben Usman
Ben Usman

Reputation: 8387

The current_app approach is fine but you must have some request context. If you don't have one (some pre-work like testing, e.g.) you'd better place

with app.test_request_context('/'):

before this current_app call.

You will have RuntimeError: working outside of application context , instead.

Upvotes: 6

tbicr
tbicr

Reputation: 26120

Blueprints have register method which called when you register blueprint. So you can override this method or use record decorator to describe logic which depends from app.

Upvotes: 7

Daniel Chatfield
Daniel Chatfield

Reputation: 2970

You either need to import the main app variable (or whatever you have called it) that is returned by Flask():

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

Or do that from within a request:

@api.route('/authorisation_url')
def authorisation_url():
    client_id = current_app.config.get('CLIENT_ID')
    url = auth.get_authorisation_url()
    return str(url)

Upvotes: 1

Related Questions