How to access app.config in a blueprint?

Flask

Flask Problem Overview


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)

Flask Solutions


Solution 1 - Flask

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.

Solution 2 - Flask

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

Solution 3 - Flask

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)

Solution 4 - Flask

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.

Solution 5 - Flask

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.

Solution 6 - Flask

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)

Solution 7 - Flask

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

Solution 8 - Flask

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. https://stackoverflow.com/questions/6760685/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")

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChirdeep TomarView Question on Stackoverflow
Solution 1 - FlaskweihuangView Answer on Stackoverflow
Solution 2 - FlaskAshalyndView Answer on Stackoverflow
Solution 3 - FlaskKyle James WalkerView Answer on Stackoverflow
Solution 4 - FlasktbicrView Answer on Stackoverflow
Solution 5 - FlaskBen UsmanView Answer on Stackoverflow
Solution 6 - FlaskDaniel ChatfieldView Answer on Stackoverflow
Solution 7 - FlaskGeorg SchöllyView Answer on Stackoverflow
Solution 8 - FlaskHyopeRView Answer on Stackoverflow