Use of `create_app` parameter inside FlaskGroup - python

I have flask application which uses application factory pattern to instantiate flask application. I am trying to integrate Flask CLI command line to my flask app.
Can any one help me in understanding the use of create_app parameter inside FlaskGroup call.
Following is my code snippet.
from project import create_app, db
from flask.cli import FlaskGroup
app = create_app()
cli = FlaskGroup(create_app=create_app)
If i had used like normal flask application, then i would n't have to use create_app parameter, in which case my code snippet looks like
from project import app, db
from flask.cli import FlaskGroup
cli = FlaskGroup(app)

Upgrade to Flask 1.0. The flask command now understands how to work with factory functions.
FLASK_APP=myapp
flask run
Flask will import myapp, find the create_app function, and call it to get an app object. See the docs for more info.
Assuming you actually want a custom cli object (you most likely don't), then you're using it correctly. You pass the factory function to the group and it will call it when it needs the app object.

Related

Flask authentication using htpassword with routes in seperate files

I'm working on updating an existing university department internal website to run using Flask. Before we completely release the project where it will use shibboleth to manage authentication, I've been trying to setup authentication for testing using htpassword using this tutorial. I'm able to get authentication using htpasswords working for a single file, but I can't figure out how to add the authentication to separate files. Currently, the project looks like this:
This is my main file called app.py:
#app.py
from flask import Flask
from flask_htpasswd import HtPasswdAuth
app = Flask(__name__)
app.config['FLASK_HTPASSWD_PATH'] = '.htpasswd'
app.config['FLASK_SECRET'] = "Super secret key that I will change later"
htpasswd = HtPasswdAuth(app)
import exampleRoute
#app.route('/')
#htpasswd.required
def home(user):
return "This is the homepage"
This is an example of one of my route files called exampleRoute.py:
# exampleRoute.py
from app import app
from flask import Flask
#app.route('/exampleRoute')
def exampleRoute():
return "This is an example route in another file"
When I place the #htpassword.required decorator in front of exampleRoute(), I get an error saying that htpassword is not defined (which makes sense). I've tried to import the app configuration a few different ways and at best, I end up with a circular dependency. I know that I could place the authentication code in a separate file and then import that into all my endpoints, but I didn't think this was possible since this method is incorporated into the app configuration.
I ended up getting an answer from the reddit user alexisprince. The solution was to use Blueprints that import htpasswd from another file (called extensions.py).

Creating an API to execute a python script

I have a python script app.py in my local server (path=Users/soubhik.b/Desktop) that generates a report and mails it to certain receivers. Instead of scheduling this script on my localhost, i want to create an API which can be accessed by the receivers such that they would get the mail if they hit the API with say a certain id.
With the below code i can create an API to display a certain text. But, what do i modify to run the script through this?
Also if i want to place the script in a server instead of localhost, how do i configure the same?
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return ("hello world")
if __name__ == '__main__':
app.run(debug=True)
Python Version is 2.7
A good way to do this would be to put the script into a function, then import that function in your Flask API file and run it using that. For hosting on a web server you can use Python Anywhere if you are a beginner else heroku is also a good option.
If you are tying to achieve something using Python-Flask API than you can have a close look at this documentations and proceed further https://www.flaskapi.org/, http://flask.pocoo.org/docs/1.0/api/
Apart from these here are few basic examples and references you can refer for a quickstart :
1-https://programminghistorian.org/en/lessons/creating-apis-with-python-and-flask
2- https://flask-restful.readthedocs.io/en/latest/
3- https://realpython.com/flask-connexion-rest-api/
You could do something like this
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class ExecuteScript:
def printScript:
return "Hello World"
api.add_resource(ExecuteScript, '/printScript')
if __name__ == '__main__':
app.run(debug=True)

Access flask app endpoints in another python file?

I have a python file which defines some endpoints using flask each doing some computation and return a JSON (POST method). I want to do unit testing on this in order to do this I want to be able to access the app I created in one python file in another file so I can test my endpoints.
I see a lot of this on the internet :
from source.api import app
from unittest import TestCase
class TestIntegrations(TestCase):
def setUp(self):
self.app = app.test_client()
def test_thing(self):
response = self.app.get('/')
assert <make your assertion here>
It doesn't explain how I can define and access my app in another file. This might be a stupid question but I really don't see how.
My app is defined as follows:
from flasgger import Swagger
from flask import Flask, jsonify, request
from flask_cors import CORS
import os
def init_deserializer_restful_api():
# Initiate the Flask app
app = Flask(__name__)
Swagger(app)
CORS(app)
# Handler for deserializer
#app.route("/deserialize", methods=['POST'])
def handle_deserialization_request():
pass
I have many other end points in this fashion. Should i just do:
import my_file_name
Thanks!!
Check out this question: What does if __name__ == "__main__": do?
As long as you have that in your python program, you can both treat it as a module and you can call it directly.

Combining 2 Flask apps using DispatcherMiddleware instance results in 404 for second app

Sorry for ambiguous question, I'm not sure how better I can put it. So let me do the explanation of my problem.
I've the Flask application libindic, which has 2 Flask application one is frontend and other is api. So I've wsgi.py as follows
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware
from silpa import api, frontend
import os
conffile = os.path.join(os.path.dirname(__file__), "etc", "silpa.conf")
application = DispatcherMiddleware(frontend.create_app(conffile),
{'/api': api.create_app(conffile)})
if __name__ == "__main__":
run_simple('0.0.0.0', 5000, application,
use_reloader=True, use_debugger=True)
The front end access works properly but when I hit /api/JSONRPC I get 404 error returned. This rule is defined as follows in silpa/api/jsonrpc.py
bp = Blueprint('api_jsonrpc', __name__, url_prefix='/api')
#route(bp, '/JSONRPC', methods=['POST'])
def handle_jsonrpc_call():
...
And when I print value of application and application.app and application.mounts in python interpreter I see folllowing
>>> application.app
<Flask 'silpa.frontend'>
>>> application.mounts
{'/api': <Flask 'silpa.api'>}
I'm unable to figure out why /api/JSONRPC results in 404. I'm not sure how can I debug it. I did check the app.url_map for api application and I can see rule for /api/JSONRPC registered there.
If some one can tell me what I might be doing wrong it would be a great help.
OK after debugging and stepping through Flask code I figured out the reason for the problem. The following line actually caused the problem
bp = Blueprint('api_jsonrpc', __name__, url_prefix='/api')
url_prefix should not be present in code because I'm already mounting this app at /api. Adding a /api url_prefix will result in following url instead /api/api/JSONRPC. Removing the above line fixed the issue.
So if you are mouting your app at different mount point than / using DispatcherMiddleware you should not url_prefix in blueprint.

How can I use an app-factory in Flask / WSGI servers and why might it be unsafe?

A question on app callables, WSGI servers and Flask circular imports
I am (possibly) confused. I want to safely create Flask / WSGI apps
from app-factories and still be able to use them in WSGI servers easily.
tl;dr
Can I safely avoid creating an app on import of init (as
recommended)and instead create it later (ie with a factory method)
How do I make that app work neatly with a WSGI server? Especially
when I am passing in the config and other settings not 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 contorl config for testing etc.
I then presumably want to create a wsgi.py module that provides the app to a WSGI server.
So eventually things look a bit 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 call like wsgi.py --settings=x --host=10.0.0.1
So I don't really know how to pass the config in.
I am asking because while this seems ... OK ... it also is a bit messy.
Life was easier when everything was in the ENV.
And not only but also:
So what is unsafe about using an app-factory
The advice given 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., clearly the route decorator expects certain abilities from
an instantiated app and cannot function without them. Thats fine.
re: 1., OK we need the name correct. But what is unsafe ? And
why? Is it unsafe to import and use the app if it is uninitialised?
Well it will break but thats not unsafe.
Is it the much vaunted thread-local? Possibly. But if I am plucking
app instances willy-nilly from random modules I should expect trouble.
Implications - we do not reference the app object from anything other than the views - essentially we keep our modularisation nice and tight, and pass around
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
According to the Flask Documentation, an application factory is good because:
Testing. You can have instances of the application with different settings to test every case.
Multiple instances. Imagine you want to run different versions of the same application. Of course you could have multiple instances with different configs set up in your webserver, but if you use factories, you can have multiple instances of the same application running in the same application process which can be handy.
But, as is stated in the Other Testing Tricks section of the documentation, if you're using application factories the functions before_request() and after_request() will be not automatically called.
In the next paragraphs I will show how I've been using the application factory pattern with the uWSGI application server and nginx (I've only used those, but I can try to help you configure it with another server).
The Application Factory
So, let's say you have your application inside the folder yourapplication and inside it there's 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 app:
from yourapplication import create_app
app = create_app()
if __name__ == "__main__":
app.run()
In the code above I'm assuming there's an environment variable set with the path to the config file, but you could give the config path to the factory, like this:
app = create_app('config/prod.cfg')
Alternatively, you could have something like a dictionary with environments and corresponding config files:
CONFIG_FILES = {'development': 'config/development.cfg',
'test' : 'config/test.cfg',
'production' : 'config/production.cfg' }
In this case, the load_config function would 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's an example of a 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 those functions is that if your are calling them in other modules, those modules cannot be imported before the application has been instantiated. Again, the documentation has something to say about that:
The downside is that you cannot use the application object in the blueprints at import time. You can however use it from within a request. How do you get access to the application with the 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 could consider creating an extension, then you could import the class without any existent instances of Flask, as the class extension would only use the Flask instance after being created.

Categories

Resources