How to import app instance created from create_app() - python-3.x

How do I import app instance created in app/app.py's create_app() function to be used in app/api.py since the app instance returns only to my manage.py?
My project structure:
project/
app/
api.py
app.py
models.py
schema.py
...
manage.py
requirements.txt
README.md
I'm starting my dev app with command python manage.py
# manage.py
from app.app import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=True, host='localhost', port=5000)
# app/app.py
def create_app():
app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = config['mysql']['db_uri']
app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {'pool_recycle': 3000, 'pool_pre_ping': True, }
register_extensions(app)
#app.before_first_request
def setup_logging():
gunicorn_error_logger = logging.getLogger('gunicorn.error')
app.logger.handlers.extend(gunicorn_error_logger.handlers)
app.logger.setLevel(gunicorn_error_logger.level)
return app
def register_extensions(app):
db.init_app(app)
api.init_app(app)
# app/api.py
from flask import Flask, jsonify
from flask_restful import Api, Resource
api = Api()
class TestGet(Resource):
def get(self):
app.logger.info('ok') ## Here I wish to use the app instance for logging
return 'ok'
api.add_resource(TestGet, '/ok')
How do I import the app
instance into app/api.py so that I may use app.logger.info(...)?
If I call create_app() it will create a new instance and not the one that is already running?

There is no need to import app.
You can use the current_app helper.
from flask import current_app
You can think of it as a proxy to the app instance.
Links to the official documentation:
https://flask.palletsprojects.com/en/1.1.x/appcontext/#the-application-context
https://flask.palletsprojects.com/en/1.1.x/api/#flask.current_app
Miguel Grinberg also offers very good information on this topic:
https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xv-a-better-application-structure
(search for current_app on the page)

Related

Flask-login users are being logged out at random when app is live (not when run local)

I have a Flask app, with user Authentication. Its working fine when run in a venv but as soon as i deploy it as a google cloud app it starts logging users out at random, sometimes it can be minutes and other times it at one of the first requests.
Here are the most central parts of my app, I beleive the error must be here or in the App Engine configuration.
db=SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(12)
app.config['SQLALCHEMY_DATABASE_URI'] = "my_db_uri"
db.init_app(app)
from .views import views
from .auth import auth
app.register_blueprint(views, url_prefix='/')
app.register_blueprint(auth, url_prefix='/')
from .models import User
login_manager = LoginManager(app)
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
return app
app = create_app()
if __name__ == '__main__':
app.run(debug=True)
I was using os.urandom() to generate a random secret key in a settings file.
The problem was solved when I changed it to a string.
I guess the problem was that App Engine is running several instances and got differend secret keys from time to time, which made the session cookie invalid and therefor cleared the cookie content.
this link should show you how to set up environment variables on a production environment. https://dev.to/sasicodes/flask-and-env-22am
I think you are missing the os.getenv() which can be found by installing the dotenv module using pip install python-dotenv and importing it in your file either the config.py file or the file with the app engine configuration.
you can use the os.getenv as such
`
from dotenv import load_dotenv
load_dotenv()
db=SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv("my_secret_key")
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv("my_db_uri")
db.init_app(app)
from .views import views
from .auth import auth
app.register_blueprint(views, url_prefix='/')
app.register_blueprint(auth, url_prefix='/')
from .models import User
login_manager = LoginManager(app)
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
return app
app = create_app()
if __name__ == '__main__':
app.run(debug=True)
`

How do I fix 'Popped wrong app context' in Flask with APScheduler

I'm adding background tasks with APScheduler on runtime depending on an API call. In other words, there are no background tasks when the app, starts. When user makes call on an API, tasks are added on runtime. But I'm getting an error that says:
AssertionError: Popped wrong app context
The application works just fine if I comment out the lines where background tasks are scheduled.
My app structure is as follows:
/project
manage.py
requirements.txt
/app
/models
/routes
/utils
/api
config.py
__init__.py
My manage.py file looks like this:
app = create_app('dev')
app.app_context().push()
manager = Manager(app)
migrate = Migrate(app, db, render_as_batch=True)
manager.add_command('db', MigrateCommand)
with app.app_context():
scheduler = BackgroundScheduler()
scheduler.start()
#manager.command
def run():
app.run()
atexit.register(lambda: scheduler.shutdown())
if __name__ == '__main__':
manager.run()
init.py inside app folder is:
from flask import Flask
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy
from email_scheduler.routes.routes import set_routes
from .config import config_by_name
# from app.models.task import TaskModel
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config_by_name[config_name])
api = Api(app)
set_routes(api)
from email_scheduler.models.api_models import TaskModel, User
db.init_app(app)
with app.app_context():
db.create_all()
return app
My api.py file is:
class SignUp(Resource):
def clean_scheduling_time(self, schedule_time):
day = schedule_time.split(' ')[0].lower()[:3]
hour, mins = schedule_time.split(' ')[1].split(':')
return day, hour, mins
def post(self):
args = user_parser.parse_args()
username, password = args.get('username'), args.get('password')
schedule_time, email_to = args.get('schedule_time'), args.get('email_to')
if username is None or password is None:
abort(400) # missing arguments
from email_scheduler.models.api_models import User
if User.query.filter_by(username=username).first() is not None:
abort(400) # existing user
user = User(username=username, schedule_time=schedule_time.split(' ')[1], email_to=email_to)
user.hash_password(password)
user.save_to_db()
from manage import scheduler
from email_scheduler.utils.utils import send_email
day, hour, mins = self.clean_scheduling_time(args.get('schedule_time'))
trigger = CronTrigger(day_of_week=day, hour=int(hour), minute=int(mins))
scheduler.add_job(send_email, trigger=trigger)
print(scheduler.get_jobs())
return make_response(jsonify({'username': username}), 200)
What's weird is that even though I get this error on the terminal, the task somehow gets scheduled and is run. And if I take out the code from api that schedules the tasks, the API runs just fine. What am I doing wrong?
The problem is in your manage.py file.
You're running the following line globally:
app.app_context().push()
Which you correctly need for the worker to have access to app context. Move it inside the function that the worker calls.
Ie NOT this:
app = create_app()
app.app_context().push()
def your_async_fn():
# your code for the worker...
But this:
def your_async_fn():
app = create_app()
app.app_context().push()
# your code for the worker...

How can I import app from another .py file and use app.config in order to use values in config file? [duplicate]

This question already has an answer here:
Access Flask config outside of application factory
(1 answer)
Closed 4 years ago.
I wann use some values set in config files but Im not sure of how to do that. How should I fix xxx.py ?
This is init file.
def init_db(app):
db.init_app(app)
Migrate(app, db)
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
xxx.py
import create_app
impoet modulename
x = app.config["TOKEN"]
...
...
...
config.py
Class config:
TOKEN = 'token'
...
...
You need to provide app object to a call in xxx.py as result of create_app or make app global variable that will be available from anywhere. For example:
# __init__.py
def init_db(app):
db.init_app(app)
Migrate(app, db)
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
return app
# xxx.py
import create_app
import module_name
app = create_app('config/path')
x = app.config["TOKEN"]
...
...
or
# __init__.py
app = None
def init_db(app):
db.init_app(app)
Migrate(app, db)
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
# xxx.py
import create_app, app
import module_name
create_app('config/path') # can be called once anywhere in the project
x = app.config["TOKEN"]
...
...

SQLAchemy 'No application found. Either work inside a view function or push'

Ello ello,
I found similar questions on the bug i'm facing, and tried the solutions offered but it didn't work for me.
I'm trying to separate out my models in a different directory and import them into the app.py
When I try to import the db into the python terminal, i'm getting the no application found.
app.py code
from flask import Flask
from flask_restful import Resource, Api
# from flask_sqlalchemy import SQLAlchemy
from routes import test, root, user
from models.todo import db
app = Flask(__name__)
api = Api(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://username:pass123#localhost/db'
app.config['SECRET_KEY'] = 'thiskeyissecret'
# db.init_app(app)
with app.app_context():
api = Api(app)
db.init_app(app)
api.add_resource(root.HelloWorld, '/')
api.add_resource(test.Test, '/test')
api.add_resource(user.User, '/user')
if __name__ == '__main__':
app.run(debug=True)
models
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Todo(db.Model):
__tablename__ = 'Todos'
id = db.Column('id', db.Integer, primary_key=True)
data = db.Column('data', db.Unicode)
def __init__(self, id, data):
self.id = id
self.data = data
def __repr__(self):
return '<Todo %>' % self.id
my file directory looks like
Main_app
Models
Todo.py
routes
some routes
app.py
Flask-SQLAlchemy needs an active application context.
Try:
with app.app_context():
print(Todo.query.count())
From the flask documentation:
Purpose of the Context
The Flask application object has attributes, such as config, that are
useful to access within views and CLI commands. However, importing the
app instance within the modules in your project is prone to circular
import issues. When using the app factory pattern or writing reusable
blueprints or extensions there won’t be an app instance to import at
all.
Flask solves this issue with the application context. Rather than
referring to an app directly, you use the the current_app proxy, which
points to the application handling the current activity.
Flask automatically pushes an application context when handling a
request. View functions, error handlers, and other functions that run
during a request will have access to current_app.
It is ok to have db initialised in app.py
from flask import Flask
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy
from routes import test, root, user
app = Flask(__name__)
api = Api(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://username:pass123#localhost/db'
app.config['SECRET_KEY'] = 'thiskeyissecret'
db = SQLAlchemy(app)
api.add_resource(root.HelloWorld, '/')
api.add_resource(test.Test, '/test')
api.add_resource(user.User, '/user')
if __name__ == '__main__':
app.run(debug=True)
Then in your todo.py
from app import db
class Todo(db.Model):
__tablename__ = 'Todos'
id = db.Column('id', db.Integer, primary_key=True)
data = db.Column('data', db.Unicode)
def __init__(self, id, data):
self.id = id
self.data = data
def __repr__(self):
return '<Todo %>' % self.id
I get a same err
that err reason for just can operation db in viewfunc
def __init__(self, id, data):
self.id = id
self.data = data
try move that code operation to your viewfunc
In a nutshell, do something like this:
from yourapp import create_app
app = create_app()
app.app_context().push()

Why do I have to return app in Flask create_app?

from flask import Flask, render_template
from flask.ext.bootstrap import Bootstrap
from flask.ext.mail import Mail
from flask.ext.moment import Moment
from flask.ext.sqlalchemy import SQLAlchemy
from config import config
bootstrap = Bootstrap()
mail = Mail()
moment = Moment()
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
bootstrap.init_app(app)
mail.init_app(app)
moment.init_app(app)
db.init_app(app)
#
return app
Hi, I'm learning Flask by reading 'Flask Web Development by Grinberg M'.
The above code is copied from that book.
Could anyone please explain why I need to "return app" in the end?
As far as I know you haven't copied the complete code.
You've probably missed these lines or something similar:
if __name__ == '__main__':
app = create_app('Example')
app.run()
The reason the author returns the app, as #davidism has explained, is that we use the app instance to start our Flask application. Simple as that!
I hope this answers your question.

Resources