2
votes

I'm currently using the Flask Application Factory pattern with Blueprints. The issue that I'm having is how do I access the app.config object outside of the application factory?

I don't need all the configuration options from the Flask app. I just need 6 keys. So the current way I do this is when the create_app(application factory) is called, I basically create a global_config dictionary object and I just set the global_config dictionary to have the 6 keys that I need.

Then, the other modules that need those configuration options, they just import global_config dictionary.

I'm thinking, there has to be a better way to do this right?

So, on to the code

My current init.py file:

def set_global_config(app_config):
    global_config['CUPS_SAFETY'] = app_config['CUPS_SAFETY']
    global_config['CUPS_SERVERS'] = app_config['CUPS_SERVERS']
    global_config['API_SAFE_MODE'] = app_config['API_SAFE_MODE']
    global_config['XSS_SAFETY'] = app_config['XSS_SAFETY']
    global_config['ALLOWED_HOSTS'] = app_config['ALLOWED_HOSTS']
    global_config['SQLALCHEMY_DATABASE_URI'] = app_config['SQLALCHEMY_DATABASE_URI']


def create_app(config_file):
    app = Flask(__name__, instance_relative_config=True)

    try:
        app.config.from_pyfile(config_file)
    except IOError:
        app.config.from_pyfile('default.py')
        cel.conf.update(app.config)
        set_global_config(app.config)
    else:
        cel.conf.update(app.config)
        set_global_config(app.config)

    CORS(app, resources=r'/*')
    Compress(app)

    # Initialize app with SQLAlchemy
    db.init_app(app)
    with app.app_context():
        db.Model.metadata.reflect(db.engine)
        db.create_all()

    from authenication.auth import auth
    from club.view import club
    from tms.view import tms
    from reports.view import reports
    from conveyor.view import conveyor

    # Register blueprints
    app.register_blueprint(auth)
    app.register_blueprint(club)
    app.register_blueprint(tms)
    app.register_blueprint(reports)
    app.register_blueprint(conveyor)
    return app

An example of a module that needs access to those global_config options:

from package import global_config as config

club = Blueprint('club', __name__)

@club.route('/get_printers', methods=['GET', 'POST'])
def getListOfPrinters():
    dict = {}

    for eachPrinter in config['CUPS_SERVERS']:
        dict[eachPrinter] = {
            'code': eachPrinter,
            'name': eachPrinter
        }
    outDict = {'printers': dict, 'success': True}
    return jsonify(outDict)

There has to be a better way then passing a global dictionary around the application correct?

1
in set_global_config why not just doing global_config.update(app_config) as you seem to want to copy all the keys / values as is ? or even simpler: global_config = app_config.copy(). This is not an answer, just a simple remark. - DevLounge
Hmmm that does make sense and I'll make that change right now. Thanks. Do you see any issue with storing these configuration details and passing them? - Jimmy

1 Answers

5
votes

There is no need to use global names here, that defeats the purpose of using an app factory in the first place.

Within views, such as in your example, current_app is bound to the app handling the current app/request context.

from flask import current_app

@bp.route('/')
def example():
    servers = current_app.config['CUPS_SERVERS']
    ...

If you need access to the app while setting up a blueprint, the record decorator marks functions that are called with the state the blueprint is being registered with.

@bp.record
def setup(state):
    servers = state.app.config['CUPS_SERVERS']
    ...