Reputation: 4461
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
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
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
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
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
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
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
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
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