I'm a beginner in Python and flask. I am going through the Flask tutorial up to Blog Blueprint section.
I would like to know the meaning of app = ...
int the following code:
def create_app():
app = ...
# existing code omitted
from . import blog
app.register_blueprint(blog.bp)
app.add_url_rule('/', endpoint='index')
return app
In a real Flask application ... would be replaced by a call to the Flask constructor, with the desired configurations.
Check this example on how to initialize a Flask app: https://flask.palletsprojects.com/en/2.1.x/tutorial/factory/
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
)
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
# a simple page that says hello
#app.route('/hello')
def hello():
return 'Hello, World!'
return app
Related
I'm working on an API using flask. I had the code for running the app so:
def create_app():
"""Create Flask app."""
app = Flask(__name__)
# accepts both /endpoint and /endpoint/ as valid URLs
app.url_map.strict_slashes = False
# register each active blueprint
for url, blueprint in ACTIVE_ENDPOINTS:
app.register_blueprint(blueprint, url_prefix=url)
return app
So, I started to do a documentation using Flask Swagger UI, I created a static directory and into create a swagger.json file with the template. For the implementation I added this:
def create_app():
"""Create Flask app."""
app = Flask(__name__)
# accepts both /endpoint and /endpoint/ as valid URLs
app.url_map.strict_slashes = False
# register each active blueprint
for url, blueprint in ACTIVE_ENDPOINTS:
app.register_blueprint(blueprint, url_prefix=url)
# swagger configs
SWAGGER_URL = "/swagger"
API_URL = "/static/swagger.json"
SWAGGER_BLUEPRINT = get_swaggerui_blueprint(
SWAGGER_URL,
API_URL,
config={
"app_name": "iam-challenge-juanda"
}
)
app.register_blueprint(SWAGGER_BLUEPRINT, url_prefix=SWAGGER_URL)
#app.route("/static/swagger.json")
def specs():
return send_from_directory(os.getcwd(), "swagger.json")
return app
When I run de app in localhost just received: Failed to load API definition - Fetch error
NOT FOUND /static/swagger.json
Any idea why? I think so using a correct url for swagger.json file
I'm a beginner of Python and Flask.
I was going through Flask tutorial up to "Define and Access the Database" section.
Wrote up all codes, saved, and did below on Windows command prompt.
flask init-db
However, got received the error on the command prompt as follows.
AttributeError: 'ellipsis' object has no attribute 'teardown_appcontext'
I doublechecked the codes to confirm it's written exactly in a way that tutorial specifies and it actually worked fine until the previous section.
Searched through Stackoverflows if there is any similar questions, but ended up not finding out a clear cause.
Any advises? Thank you very much for your support.
--Additions--
Thanks Joost. Here is what I did.
Files layout image link
__init__.py
import os
from flask import Flask
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
)
if test_config is None:
# Load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# Load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance floder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
# a simple page that says hello
#app.route('/hello')
def hello():
return 'Hello, World!'
def create_app():
app = ...
# existing code omitted
from . import db
db.init_app(app)
return app
db.py
import sqlite3
import click
from flask import current_app, g
from flask.cli import with_appcontext
def get_db():
if 'db' not in g:
g.db = sqlite3.connect(
current_app.config['DATABASE'],
detect_types=sqlite3.PARSE_DECLTYPES
)
g.db.row_factory = sqlite3.Row
return g.db
def close_db(e=None):
db = g.pop('db', None)
if db is not None:
db.close()
def init_db():
db = get_db()
with current_app.open_resource('schema.sql') as f:
db.executescript(f.read().decode('utf8'))
#click.command('init-db')
#with_appcontext
def init_db_command():
"""Clear the exisitng data and create new tables."""
init_db()
click.echo('Initialized the database.')
def init_app(app):
app.teardown_appcontext(close_db)
app.cli.add_command(init_db_command)
schema.sql
DROP TABLE IF EXISTS user;
DROP TABLE IF EXISTS post;
CREATE TABLE user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL
);
CREATE TABLE post (
id INTEGER PRIMARY KEY AUTOINCREMENT,
author_id INTEGER NOT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
title TEXT NOT NULL,
body TEXT NOT NULL,
FOREIGN KEY (author_id) REFERENCES user (id)
);
And finally I did on the command prompt:
set FLASK_APP=flaskr
set FLASK_ENV=development
flask init-db
However it returned like this.
Any advises?
Thank you very much.
You defined create_app() twice. To solve your problem, make the following change in your __init__.py files:
import os
from flask import Flask
def create_app(test_config=None):
""" Application factory function """
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
)
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
# a simple page that says hello
#app.route('/hello')
def hello():
return 'Hello, World! Now We are Introducing Mr. Narendra Singh Parihar.THE BOSS !!'
from . import db
db.init_app(app)
return app
Actually the problem is in your init.py
I removed the second create_app() from your init file and edited it like below remember the app factory need to know where your db.py is while creating the app
import os
from flask import Flask
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
)
if test_config is None:
# Load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# Load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance floder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
# a simple page that says hello
#app.route('/hello')
def hello():
return 'Hello, World!'
from . import db
db.init_app(app)
return app
you don't replace the existing code with the new proposed one,
but you add to it,
so for example :
def create_app():
app = ...
# existing code omitted
from . import db
db.init_app(app)
return app
should be translated in your code by adding the two new lines :
from . import db
db.init_app(app)
to what's already there so far in the function, just before the last line.
return app
which should translate as other answers mentioned :
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
)
if test_config is None:
# Load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# Load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance floder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
# a simple page that says hello
#app.route('/hello')
def hello():
return 'Hello, World!'
from . import db
db.init_app(app)
return app
app_instance.py
from app import FlaskApp
app = None
def init_instance(env):
global app
app = FlaskApp(env)
def get_instance():
assert app is not None
return app
FlaskApp class is pretty much like this
class FlaskApp(object):
def __init__(self, env):
self.oauth_manager = .... bla bla ..
self.clients_manager = .. bla bla ..
app = Flask(__name__)
app.config.from_object(env)
app = app_wrapper.wrap(app, app.config['NUM_PROXY_SERVERS'])
self.app = app
self.api = Api(self.app, prefix='/v3', default_mediatype='application/json')
self.define_routes()
# Initialize the DB
self.db = Database(self.app)
fmt = "%(asctime)s - %(request_id)s - %(name)s - %(levelname)s - %(message)s"
logging.basicConfig(format=fmt, level=self.app.config.get('LOG_LEVEL'))
request_id.init(app, prefix='MY_API_', internal=False)
def run_server(self):
self.app.run(host=self.app.config['HOST'], port=self.app.config['PORT'], debug=self.app.config['DEBUG'])
def define_routes(self):
# Configure Api Resources
self.api.add_resource(VersionListController, '/my/route', endpoint='versions')
more routes here
self.api.init_app(self.app)
in my app controller
def is_valid_oauth_token(request):
from mobile_module import app_instance
app = app_instance.get_instance()
# more code here
I'm running the app on localhost and getting
assert app is not None
AssertionError
How can "fix" this code? should I be importing from mobile_module import app_instance in every route access? suggestions please
I should state that this app works in production well behind a Nginx
I guess my question is more about python (how to make this work) and less in flask.
The problem is not related to get_instance or init_instance(create_app etc.).
Flask has different states. App will work in out of request context when you initialize app instance(FlaskApp(env)).
As I see in your example, you try to get a application in context of request(def is_valid_oauth_token(request)). It means that is not initialization of application. This is processing while a request is active. This is other state of application - app was created and work in context of some request. In this case you can get application instance using from flask import current_app.
To better understanding how it works/use I recommend to read about flask._app_ctx_stack, app_context() and flask.g.
Hope this helps.
I think the best way to devellop a flask app simple is to follow the official documentation about simple flask project structure here
you need to organize your floder like this :
/yourapplication
/yourapplication
__init__.py
/static
style.css
/templates
layout.html
index.html
login.html
...
and then create your application in init.py file like as follow:
from flask import Flask
def create_app():
"""this method will initialise the flask Ap instance """
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello, World!'
return app
in your yourapplication directory add the run.py to run the app with the following code :
from yourapplication import create_app
app = create_app()
if __name__ == '__main__':
app.run()
and if you want to use your controller you can do this:
from yourapplication import create_app
def is_valid_oauth_token(request):
app = create_app()
# more code here
this is called application factory design-pattern.
And in addition if you want to put it in production you will need to use WSGI configuration find more here
Hi I have a Flask app structured in following way and I have problem with blueprints setup. Whatever I do, they only work with url_prefix set up. It works currently as /main/verify but as it is a small app I would love to have an endpoint like /verify. What's interesting I managed to make it work with / route, but for the same configuration it didn't work for the /verify. I am pretty clueless right now, I can live with it as it is, but I really wonder what am I doing wrong.
Here is the code:
__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import config
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
db.init_app(app)
from main import main
app.register_blueprint(main)
return app
main/__init__.py
from flask import Blueprint
main = Blueprint('main', __name__, url_prefix='/main')
from . import views
main/views.py
from flask import request, jsonify
from . import main
#main.route('/')
def index():
return "Hello world"
#main.route('/verify')
def verify():
url = request.args['url']
query = request.args['query']
return jsonify({ ... })
As I see you didn't register blueprint without prefix. If you need to register endpoints without prefix you must create a new instance of Blueprint
main = Blueprint('main', __name__, url_prefix='/main')
# main endpoints(with prefix /main)...
#main.route('/')
def index_main():
return "Hello world from /main/"
# routes without any prefix
default = Blueprint('default', __name__)
#default.route('/')
def index():
return "Hello world from /"
app = Flask(__name__)
app.register_blueprint(main)
app.register_blueprint(default)
Hope this helps.
I'm baffled by this. I'm using an application factory in a Flask application and under the test configuration my routes always return 404s.
However when I use Flask-Script and load the app from the interpreter everything works as expected, the response comes back as 200.
Navigating to the URL with the browser works fine
app/__init__.py
def create_app():
app = Flask(__name__)
return app
sever1.py
from flask import Flask
from flask_script import Manager
from app import create_app
app = create_app()
app_context = app.app_context()
app_context.push()
manager = Manager(app)
#app.route('/')
def index():
return '<h1>Hello World!</h1>'
#app.route('/user/<name>')
def user(name):
return '<h1>Hello, %s!</h1>' % name
#manager.command
def test():
"""Run the unit tests"""
import unittest
tests = unittest.TestLoader().discover('tests')
unittest.TextTestRunner(verbosity=2).run(tests)
if __name__ == '__main__':
manager.run()
tests/test.py
#imports committed
def setUp(self):
self.app = create_app('testing')
self.app_context = self.app.app_context()
self.app_context.push()
self.client = self.app.test_client()
def test_app_exists(self):
response = self.client.get('/', follow_redirects=True)
print(response) #404 :(
self.assertTrue("Hello World!" in response.get_data()) #this is just an example of how it fails
You're not using the factory pattern correctly. You should use blueprints to collect routes and register them with the app in the factory. (Or use app.add_url_rule in the factory.) Nothing outside the factory should affect the app.
Right now you create an instance of the app and then use that instance to register routes. Then you create a different instance in your tests, which doesn't have the routes registered. Since that instance doesn't have any registered routes, it returns 404 for requests to those urls.
Instead, register your routes with a blueprint, then register the blueprint with the app in the factory. Use the factory to create an app during tests. Pass the factory to the Flask-Script manager. You should not need to push the app context manually.
from flask import Flask, Blueprint
from flask_script import Manager
from unittest import TestCase
bp = Blueprint('myapp', __name__)
#bp.route('/')
def index():
return 'Hello, World!'
def create_app(config='dev'):
app = Flask(__name__)
# config goes here
app.register_blueprint(bp)
return app
class SomeTest(TestCase):
def setUp(self):
self.app = create_app(config='test')
self.client = self.app.test_client()
def test_index(self):
rv = self.client.get('/')
self.assertEqual(rv.data, b'Hello, World!')
manager = Manager(create_app)
manager.add_option('-c', '--config', dest='config', required=False)
if __name__ == '__main__':
manager.run()