How can I use the factory application in Flask / WSGI servers and why can it be unsafe?

Question about calling applications, WSGI servers, and circular import disks

I am (possibly) confused. I want to safely create Flask / WSGI applications from applications, and you can still easily use them in WSGI servers.

TL; dg

  • Can I safely avoid creating the application when importing init (as recommended) and instead create it later (i.e. using the factory method)

  • How can I make this application work with a WSGI server? Especially when I transfer configuration and other settings without pulling them from ENV

For example:

def make_app(configdict, appname): app = Flask(appname) app.config.update(configdict) init_db(configdict) set_app_in_global_namespace(app) #importing now will allow from pkg import app from mypackage import views return app 

I would like to use the above β€œfactory” because I want to easily configure the configuration for testing, etc.

Then I presumably want to create the wsgi.py module, which provides an application for the WSGI server.

So, in the end, everything looks something like this.

INIT .py ::

 app = None def make_app(configdict, appname): flaskapp = Flask(appname) flaskapp.config.update(configdict) init_db(configdict) global app app = flaskapp #importing now will allow from pkg import app from mypackage import views return flaskapp 

wsgi.py ::

 from mypackage import app app = make_app(configfromsomewhere, "myname") 

uWSGI ::

 uwsgi --module=mypackage.wsgi:app 

But still wsgi.py is NOT something I can name as wsgi.py --settings = x -host = 10.0.0.1 So I really don't know how to pass the configuration.

I ask because for now it seems ... OK ... this is also a little dirty.

Life was easier when everything was in ENV.

And not only, but also:

So what is unsafe to use factory application

Recommendation here <http://flask.pocoo.org/docs/patterns/packages> _ is ::

 1. the Flask application object creation has to be in the __init__.py file. That way each module can import it safely and the __name__ variable will resolve to the correct package. 2. all the view functions (the ones with a route() decorator on top) have to be imported in the __init__.py file. Not the object itself, but the module it is in. Import the view module after the application object is created. 

re: 2., obviously, the route decorator expects certain capabilities from the instance application and cannot function without them. Thats fine.

re: 1., OK we need the name correctly. But what is unsafe? And why? Is it unsafe to import and use the application if it is not initialized? Well, it will break, but it is unsafe. Is this exalted thread local? Maybe. But if I tweak applications willy-nilly from random modules, I should expect a problem.

Consequences - we do not refer to the application object from anything other than representations - in fact, we keep our modulation pleasant and dense and bypass dicts, error objects, or even WebObs.

http://flask.pocoo.org/docs/patterns/appdispatch http://flask.pocoo.org/docs/deploying/#deployment http://flask.pocoo.org/docs/patterns/packages/#larger- applications http://flask.pocoo.org/docs/becomingbig

+7
source share
1 answer

According to Flask Documentation , the factory application is good because:

  • Testing. You may have application instances with different settings to test each case.

  • Several copies. Imagine that you want to run different versions of the same application. Of course, you can have several instances with different settings configured on your web server, but if you use factories, you can have several instances of the same application running in the same application, which can be convenient.

But, as stated in the Other Testing Tricks section of the documentation, if you use application factories, the before_request() and after_request() functions will not be called automatically.

In the following paragraphs, I will show how I used the factory application template with the uWSGI and nginx application server (I only used them, but I can try to help you configure it on another server).

Factory application

So, let's say you have an application inside the yourapplication folder and inside it is the __init__.py file:

 import os from flask import Flask def create_app(cfg=None): app = Flask(__name__) load_config(app, cfg) # import all route modules # and register blueprints return app def load_config(app, cfg): # Load a default configuration file app.config.from_pyfile('config/default.cfg') # If cfg is empty try to load config file from environment variable if cfg is None and 'YOURAPPLICATION_CFG' in os.environ: cfg = os.environ['YOURAPPLICATION_CFG'] if cfg is not None: app.config.from_pyfile(cfg) 

Now you need a file to create an instance of the application:

 from yourapplication import create_app app = create_app() if __name__ == "__main__": app.run() 

In the above code, I assume that the environment variable is set using the path to the configuration file, but you can specify the configuration path to the factory, for example:

 app = create_app('config/prod.cfg') 

In addition, you may have something like a dictionary with environments and related configuration files:

 CONFIG_FILES = {'development': 'config/development.cfg', 'test' : 'config/test.cfg', 'production' : 'config/production.cfg' } 

In this case, the load_config function will look like this:

 def load_config(app, env): app.config.from_pyfile('config/default.cfg') var = "YOURAPPLICATION_ENV" if env is None and var in os.environ: env = os.environ[var] if env in CONFIG_FILES: app.config.from_pyfile(CONFIG_FILES[env]) 

Nginx and uWSGI

Here is an example configuration file for nginx:

 server { listen 80; server_name yourapplication.com; access_log /var/www/yourapplication/logs/access.log; error_log /var/www/yourapplication/logs/error.log; location / { try_files $uri @flask; } location @flask { include uwsgi_params; uwsgi_pass unix:/tmp/yourapplication.sock; # /env is the virtualenv directory uwsgi_param UWSGI_PYHOME /var/www/yourapplication/env; # the path where the module run is located uwsgi_param UWSGI_CHDIR /var/www/yourapplication; # the name of the module to be called uwsgi_param UWSGI_MODULE run; # the variable declared in the run module, an instance of Flask uwsgi_param UWSGI_CALLABLE app; } } 

And the uWSGI configuration file looks like this:

 [uwsgi] plugins=python vhost=true socket=/tmp/yourapplication.sock env = YOURAPPLICATION_ENV=production logto = /var/www/yourapplication/logs/uwsgi.log 

How to use before_request() and after_request()

The problem with these functions is that if you call them in other modules, these modules cannot be imported before the application is created. Again, the documentation has something to say about this:

The disadvantage is that you cannot use the application object in drawings during import. However, you can use it from the request. How do you access the application using config? Use current_app:

 from flask import current_app, Blueprint, render_template admin = Blueprint('admin', __name__, url_prefix='/admin') @admin.route('/') def index(): return render_template(current_app.config['INDEX_TEMPLATE']) 

Or you might consider creating an extension , then you can import the class without any existing Flask instances, since the class extension will only use the Flask instance after it is created.

+17
source

All Articles