How to instantiate my variable in another file - python

Hello everyone I'm trying to do something very simple but all the documentation out do this on the same file.
I want to use oauth in my flask app and this is my main.py file
from flask import Flask
from login_routes import login
from authlib.integrations.flask_client import OAuth
app = Flask(__name__)
oauth = OAuth(app)
app.register_blueprint(login)
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8080, debug=True)
And my login_routes.py has these lines
from flask import Blueprint, render_template, url_for, redirect, session
from authlib.integrations.flask_client import OAuth
import settings
# OAuth config
google = oauth.register(
name='google',
client_id=settings.GOOGLE_CLIENT_ID,
client_secret=settings.GOOGLE_CLIENT_SECRET,
access_token_url=settings.GOOGLE_TOKEN_URI,
access_token_params=None,
authorize_url=settings.GOOGLE_AUTH_URI,
authorize_params=None,
api_base_url='https://www.googleapis.com/oauth2/v1/',
client_kwargs={'scope': 'openid profile email'}
)
However oauth is not declared in my login_routes.py, I dont know how to bring that variable from main instance to this other file, I tried importing main.py which on my brain makes no sense because that ends up on a circular reference error please let me know how to instantiate this correctly.

Try
In main.py
app = Flask(__name__)
oauth = OAuth(app)
# assign your oauth to a variable (property) of app instance
app.OAUTH = oauth
In login_routes.py
# This pulls in the app object
from flask import Blueprint, current_app as app
# Since you're registering 'login' as a blueprint in main.py, define it here
login = Blueprint('login', __name__)
# you can do access the oauth instance as app.OAUTH e.g
abc = app.OAUTH....

Related

Flask Babel RuntimeError: Working outside of request context

I tried to set up multiple Dash Apps inside a Flask App and use Flask Babel.
from flask import Flask, request
from flask_babel import Babel, gettext
from werkzeug.middleware.dispatcher import DispatcherMiddleware
def init_app():
"""Construct core Flask application."""
app = Flask(__name__, instance_relative_config=False)
app.config.from_object("config.Config")
babel = Babel(app)
#babel.localeselector
def get_locale():
return request.accept_languages.best_match(app.config["LANGUAGES"])
with app.app_context():
# Import parts of our core Flask app
from . import routes
from .plotly.sec import init_dashboard_sec
from .plotly.bafin import init_dashboard_bafin
# app = init_dashboard(app)
app = DispatcherMiddleware(app, {
"/s": init_dashboard_sec(app),
"/b": init_dashboard_bafin(app)
})
return app
However, since I added the babel decorated function I get the following error:
RuntimeError: Working outside of request context.
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem.
I tried to move the function to a different position but the error stayed the same.
I don't know if it is the correct solution but the following is working:
from flask import Flask, request
from flask_babel import Babel, gettext
from werkzeug.middleware.dispatcher import DispatcherMiddleware
def init_app():
"""Construct core Flask application."""
app = Flask(__name__, instance_relative_config=False)
app.config.from_object("config.Config")
babel = Babel(app)
with app.app_context():
# Import parts of our core Flask app
from . import routes
from .plotly.sec import init_dashboard_sec
from .plotly.bafin import init_dashboard_bafin
# app = init_dashboard(app)
app = DispatcherMiddleware(app, {
"/s": init_dashboard_sec(app),
"/b": init_dashboard_bafin(app)
})
#babel.localeselector
def get_locale():
return request.accept_languages.best_match(["de", "en"])
return app
So babel gets initialized outside of the app context but the localselector is inside the context. For me it does not make much sense since the localeselector is still out of a request context but its working.
if you are probably working on the the terminal testing stuff out and you get the error just do this
from your_app import create_app
app = create_app()
with app.test_request_context(
'/make_report/2017', data={'format': 'short'}):
##do something here
for more information you can vist this part of the docs to learn more https://flask.palletsprojects.com/en/2.1.x/reqcontext/

Run flask app with python instead of flask run

I'm trying to run my flask app with "python app.py" instead of "flask run" command.
My goal is to launch the app on cpanel server and just about every tutorial requires the applications to be called using the "python" method.
Here is my folder structure:
project
webapp
init.py
templates
static
auth.py
main.py
app.py <-------------- I want this to be called with python instead of flask run command outside the folder
Here is my init_.py file:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
# init SQLAlchemy so we can use it later in our models
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = '9OLWxND4o83j4iuopO'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
db.init_app(app)
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
from .models import User
#login_manager.user_loader
def load_user(user_id):
# since the user_id is just the primary key of our user table, use it in the query for the user
return User.query.get(int(user_id))
# blueprint for auth routes in our app
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint)
# blueprint for non-auth parts of app
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
return app
And app.py is:
from webapp import app
I'm a newbie in flask, any help is appreciated
Insert the call to create_app at the end of init.py:
if __name__ == '__main__':
create_app().run(host='0.0.0.0', port=5000, debug=True)
The if statement avoid calling the app many times. It can only be called directly. Flask default host is 127.0.0.1 (localhost). Use 0.0.0.0 at production for better traffic monitoring. Default port is also 5000, so it's up to you to include. For better readability, you should explicit it.
Then call it
python webapp/init.py

Flask Configuration for Sharing Resources Across Blueprints

I have an extremely large application that is factored into many blueprints. I need to configure the entire application to save files into a directory when a user uploads files. So I am setting ["SESSION_FILE_DIR"] = 'C:/some/path' to the path where files would live after upload in the app.py file.
The documentation reads that configuration settings are shared across the blueprints. I'm experiencing one issue that is not working and below is a stripped down example to replicate my problem to support my question. So, to debug I've created an extremely simple version just printing the path to screen to see what is happening.
If I head over to the URL .../print_dir then the ["SESSION_FILE_DIR"] = 'C:/some/path' is printed to screen. However, if I head over to the URL defined within the blueprint .../new then I am given an error of NameError: name 'server' is not defined.
How can I configure my app such that the same ["SESSION_FILE_DIR"] can be used across blueprints?
The contents of my main app.py are as follows:
from flask import Flask, render_template, request, session
from flask_session import Session
import tempfile
server = Flask(__name__)
server.config["SESSION_PERMANENT"] = False
server.config["SESSION_TYPE"] = "filesystem"
server.config["SESSION_FILE_DIR"] = 'C:/some/path'
server.secret_key = 'abcdefg'
### Import and Register Blueprints
from tools.routes import my_bp
server.register_blueprint(my_bp)
#server.route('/')
def homepage():
return "Hello"
#server.route('/print_dir')
def homepage2():
return server.config["SESSION_FILE_DIR"]
if __name__ == '__main__':
server.run(debug=True)
and now suppose the blueprint lives in a subdirectory called tools and contains the following:
from flask import Flask, render_template, request, session, Blueprint
from flask_session import Session
my_bp = Blueprint("my_bp", __name__)
#my_bp.route('/new', methods=['POST', 'GET'])
def path():
path = server.config["SESSION_FILE_DIR"]
return path
To access the app.config from within a Blueprint, you can import current_app from flask.
Example:
# ./app.py
from flask import Flask
from views.blueprint import bp
app = Flask(__name__)
# Set the config you want:
app.config['IMPORTANT_DIRECTORY'] = '~/path/to/important/directory'
# Register your blueprint
app.register_blueprint(bp)
# ./views/blueprint.py
from flask import Blueprint, current_app
bp = Blueprint('bp', __name__)
#bp.route('/path')
def get_path():
# access the config
path = current_app.config['IMPORTANT_DIRECTORY']
return path
You can find more info in the api docs for flask.

Removing global app reference from blueprint in Flask

I'm currently working on learning Flask and create a working page with login functions. Now I want to remove the global app instance and started using blueprints for the submodules.
My project is structured like this:
+ app
+ auth
- __init__.py
- forms.py
- routes.py
+ main
+ models
+ templates
- __init__.py
+ migrations
- index.py
- config.py
No I added a blueprint to the routes.py and used the decorators there:
from flask import render_template, flash, redirect, url_for, request, Blueprint
from app import app, db
from app.auth.forms import LoginForm, RegistrationForm
# ...
from app.models.User import User
blueprint = Blueprint('auth', __name__)
#blueprint.route('/login', methods=['GET', 'POST'])
def login():
return "example login"
The __init__.py of the auth module:
from . import forms, routes
The blueprint gets added in the __init__.py of the app folder:
# ...
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
from app.auth.routes import blueprint as auth_bp
app.register_blueprint(auth_bp)
After using the #blueprint decorators, I don't need #app anymore, but how can I access the db when I want to remove the import app and the from app.models.User import User part?
from . import db
from ..models.User import User
There are two things to understand here. app as a module (the folder) and app the instance of flask inside __init__.py. When you do import app inside authentication blueprint then you are actually importing the whole app module and not the flask instance. When you do from app import app you are actually importing flask instance from app module. This can be confusing to eliminate this I advise you to change the name of app folder to something different like bacher then when you need to import db inside your authentication blueprint use from bacher import db and for User model from bacher.models.User import User

My flask application factory returns URL not found

My flask app is based on Miguel Grinberg's mega tutorial XIV with some extra stuff and it was all working fine and could be accessed from browser on localhost:5000. I decided to switch to an application factory approach as per Grinberg's XV tutorial BUT with no blueprints. Now when I enter localhost:5000 I get a URL not found. I am guessing my routes.py is not being picked up for some reason.
I have thoroughly worked through Grinberg's XV tutorial and the associated code and aligned everything less blueprints. These are the links I have explored that I have based my current app on: -
https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xv-a-better-application-structure
http://flask.pocoo.org/docs/1.0/tutorial/factory/
Dave W Smith's answer in Configure Python Flask App to use "create_app" factory and use database in model class
and others.
From what I have read implementing an application factory should be really simple. The examples work.
The flask server starts from the command prompt in a venv as always.
Here is my directory structure.
myapp
app.py
config.py
...
/app
__init__.py
routes.py
models.py
forms.py
...
Here is the code slightly simplified for clarity.
# app.py
#=============================================
from app import create_app, db
from app.models import User, Post
app = create_app()
#app.shell_context_processor
def make_shell_context():
return {'db': db, 'User': User, 'Post' :Post}
# __init__.py
#=============================================
...
import os
from flask import Flask, request, current_app
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
...
from config import Config
db = SQLAlchemy()
migrate = Migrate()
...
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)
migrate.init_app(app, db)
...
# logging, email servers, etc configured
return app
from app import models
# routes.py
#=============================================
from datetime import datetime
from flask import render_template, flash, redirect, url_for, request, g, \
jsonify, current_app
...
from app import app, db
from app.forms import LoginForm, RegistrationForm, EditProfileForm,
PostForm,ResetPassword,RequestForm, ResetPasswordForm
from app.models import User, Post
...
#app.route('/', methods=['GET', 'POST'])
#app.route('/index', methods=['GET', 'POST'])
#login_required
def index():
form = PostForm()
if form.validate_on_submit():
...
page = request.args.get('page', 1, type=int)
...
return render_template('index.html', title=_('Home'), form=form,
posts=posts.items, next_url=next_url,
prev_url=prev_url)
#app.route ....
# models.py
#=============================================
from datetime import datetime
from hashlib import md5
from time import time
from flask import current_app
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
import jwt
from app import db, login
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
...
This may be irrelevant but it is one thing I tried. Note in routes.py that I have from app import app, db, if I remove app and add from flask import current_app then the #app decorators show as undefined.
Another point, because its a problem with routes. If I change the last line of __init__.py to from app import routes, models I get a different error.
flask.cli.NoAppException
flask.cli.NoAppException: While importing "metapplica", an ImportError was raised:
Traceback (most recent call last):
File "c:\users\markko~1\dropbox\python\projects\metapp~1\venv\lib\site-packages\flask\cli.py", line 236, in locate_app
__import__(module_name)
File "C:\Users\Mark Kortink\Dropbox\Python\projects\metapplica\metapplica.py", line 1, in <module>
from app import create_app, db, cli
File "C:\Users\Mark Kortink\Dropbox\Python\projects\metapplica\app\__init__.py", line 75, in <module>
from app import routes, models
File "C:\Users\Mark Kortink\Dropbox\Python\projects\metapplica\app\routes.py", line 8, in <module>
from app import app, db
ImportError: cannot import name 'app' from 'app' (C:\Users\Mark Kortink\Dropbox\Python\projects\metapplica\app\__init__.py)
It was this error that led me to try the current_app change mentioned above.
I start the app like this.
cd C:\Users\...\myapp
venv\Scripts\activate
set FLASK_APP=app.py
set FLASK_DEBUG=1
flask run
I know the problem is probably really basic but can anyone see why the above code would give a URL not found or not be able to find the routes?
=== NEXT PHASE ================
Following the recommendations from #silver below my new names are: -
myapp
runapp.py
...
/mapp
__init__.py
...
I went through all my code and changed from app[.xxx] import yyy to from myapp[.xxx] import yyy. This flushed out a few new errors where I was referencing app which I fixed by substituting current_app.
My new error is
RuntimeError
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context(). See the
documentation for more information.
Traceback (most recent call last)
File "C:\Users\Mark Kortink\Dropbox\Python\projects\myapp\runapp.py", line 1, in <module>
from mapp import create_app, db, cli
File "C:\Users\Mark Kortink\Dropbox\Python\projects\myapp\mapp\__init__.py", line 75, in <module>
from mapp import routes, models
File "C:\Users\Mark Kortink\Dropbox\Python\projects\myapp\mapp\routes.py", line 16, in <module>
#current_app.before_request
Without being able to run it myself it's a little hard to be sure.
But I think this is the crux of the matter:
This may be irrelevant but it is one thing I tried. Note in routes.py that I have from app import app, db, if I remove app and add from flask import current_app then the #app decorators show as undefined.
If you want to register anything to the app that's actually running, it has to be through from flask import current_app. That's the thing about Flask application factories -- you only get access to the name of the application that's actually running in two places:
In the factory function itself: create_app, before you return the app object, and
Via from flask import current_app
It looks like Python is able to successfully import the name app in routes.py, since you say the application starts. The only place that from app import app could resolve to is from your app.py file at the top level of your myapp package. That means that each time routes.py is initialized, it's calling the create_app function, and getting a new app object. So understandably, the top-level app object that Flask is serving is not the same one that has routes registered to it.
I recommend renaming your files so that nothing has the name "app" except the object returned by create_app.
Then, in routes.py try:
from datetime import datetime
from flask import render_template, flash, redirect, url_for, request, g, \
jsonify
from flask import current_app as app_ref
...
from app_internals import db # assuming you've renamed the app package
from app_internals.forms import LoginForm, RegistrationForm, EditProfileForm,
PostForm,ResetPassword,RequestForm, ResetPasswordForm
from app_internals.models import User, Post
...
current_app = app_ref._get_current_object()
#current_app.route('/', methods=['GET', 'POST'])
#current_app.route('/index', methods=['GET', 'POST'])
#login_required
def index():
form = PostForm()
if form.validate_on_submit():
...
page = request.args.get('page', 1, type=int)
...
return render_template('index.html', title=_('Home'), form=form,
posts=posts.items, next_url=next_url,
prev_url=prev_url)
#current_app.route ....
In case someone is struggling with similar issues (flask 'mysteriously' not serving routes that should be there, perhaps in conjunction with a create_app factory method):
flask routes is actually showing the routes it detects. the output looks like this (for just one 'hello' endpoint at the root url):
Endpoint Methods Rule
-------- ------- -----------------------
hello GET /
static GET /static/<path:filename>
the SERVER_NAME setting can be responsible (this was the case for me). I had changed it to 0.0.0.0 without realizing it makes a difference for the routing. There is a bug report/discussion on github on that topic.
I just ran into this issue too with Miguel Grinberg's tutorial. It's a pretty fantastic tutorial till some of the later sections which feel rushed.
Anyway.
You need to pass the context.
In the factory function you need to do.
def create_app(config_class=Config):
app = Flask(__name__)
with app.app_context():
from app import routes
Then like the person posted above.
for routes.py change all the #app to #current_app
from flask import current_app
#current_app.route('/')
#current_app.route('/index', methods=['GET', 'POST'])
#login_required
def index():
this works for me.

Categories