flask mail "running out of context error" even with context - python

I am trying to send mail in a celery task using flask-mail, however I continue to get this runtime error RuntimeError('working outside of application context',). This is the code I have in the file itself:
from app import app
from celery import Celery
from flask.ext.mail import Message
from flask import current_app
# config
app.config['CELERY_BROKER_URL'] = 'redis://localhost:6379/0'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:6379/0'
# set up celery
celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)
# put the processing task here
#celery.task
def send_results(filename, email_addr):
msg = Message('testing email', recipients=[email_addr])
msg.body = 'testing this funct'
with app.app_context():
current_app.mail.send(msg)
print(filename)
print(email_addr)
Note that it has the app.app_context() line in there (At this point I'm not sure if it's right or not)
Another thing to note is that the app isn't fully "completed" yet. Specifically what I mean by this is that the creation of the app is handled by a function called create_app as seen here: https://github.com/swarajd/seq2flux/blob/master/app/startup/create_app.py
That function is called in manage.py here: https://github.com/swarajd/seq2flux/blob/master/manage.py
I try to call this task in a file called views.py which handles all the views. The one function in particular that deals with this is as follows:
#core_blueprint.route('data_analysis', methods=['GET', 'POST'])
#login_required
def data_analysis():
# print(request.form)
form = DataAnalysisForm(CombinedMultiDict((request.files, request.form)))
# print(form)
if (request.method == 'POST' and form.validate()):
# print(request.form)
# print(request.files)
file = request.files['seqFile']
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
mail_engine = current_app.extensions.get('mail', None)
# print(mail_engine)
# print(current_user)
send_results.delay(filename, current_user.email)
flash('processing job scheduled!')
# Redirect to home page
return redirect(url_for('core.data_analysis'))
return render_template('core/data_analysis.html', form=form)
The important line is: send_results.delay()
My question is: even with context, why is it throwing that runtime error?

The reason this was happening was because the email MESSAGE itself was being created outside the with statement, causing the runtime error.

Related

RuntimeError: working outside of request context Flask Session

I am getting RuntimeError: working outside of request context error while running a test in Flask. I've tried multiple suggestions from other threads, but none has worked for me.
Part of my views.py:
#user_app.route('/login', methods =('GET', 'POST'))
def login():
form = LoginForm()
error = None
if form.validate_on_submit():
user = User.objects.filter(username=form.username.data).first()
if user:
if bc.hashpw(form.password.data, user.password) == user.password:
session['username']=form.username.data
return 'User Logged In'
else:
user = None
if not user:
error = 'Incorrect credentials'
return render_template('user/login.html',form=form,error=error)
Relevant part of my tests.py:
from application import create_app as create_app_base
def create_app(self):
self.db_name = 'flaskbook_test'
return create_app_base(
MONGODB_SETTINGS={'DB':self.db_name},
TESTING=True,
WTF_CSRF_ENABLED=False,
SECRET_KEY='SecretKey'
)
def setUp(self):
self.app_factory = self.create_app()
self.app = self.app_factory.test_client()
#self.app.application.app_context().push() <-- this did not help
def tearDown(self):
db = _get_db()
db.client.drop_database(db)
def test_login_user(self):
#create user
self.app.post('/register', data=self.user_dict())
#login user
rv = self.app.post('/login',data=dict(
username='username',
password='password'
))
#check session is set
with self.app as c:
rv = c.get('/')
assert session.get('username') == self.user_dict()['username']
I have already tried adding app_context and self.app.application.app_context().push() as mentioned above:
with self.app.application.app_context():
assert session.get('username') == self.user_dict()['username']
But it didn't work. Whenever I call session['username'] I get RuntimeError: working outside of request context.
My requirements.txt: Flask0.10.1 Flask-Script 2.0.5 flask-mongoengine 0.7.4
Please help.
What you want is the request context, not the app context.
Flask includes some handy functions to push a request context for you - check out the Flask testing docs and you'll see a lot of relevant info, including the test_request_context method on the app object.
Combine that with app.test_client to push a request context and then simulate client behaviour such as POSTing to your endpoint. Try this:
with self.app.test_request_context('/'), self.app.test_client() as c:
rv = c.post('/')
assert session.get('username') == self.user_dict()['username']

Use flask variable outside of context

In the Flask application (initialized in __init__.py) I have two blueprints - auth and main . In the auth blueprint I'm trying to set some variable (will be loaded from db and depends from current_user.get_id()) which should be used in main blueprint as url-prefix:
auth.py
#auth.route('/login', methods=['POST'])
def login_post():
username = request.form.get('username')
password = request.form.get('password')
user_inst = user.query.filter_by(username=username).first()
if not user_inst or not check_password_hash(user_inst.password, password):
flash('Invalid credentials. Check you input and try again.')
return redirect(url_for('auth.login'))
login_user(user_inst)
g.team_name = 'some_team_name'
#session['team_name'] = 'some_team_name'
# if the above check passes, then we know the user has the right credentials
return redirect(url_for('main.some_func'))
In the main blueprint, it's required to get the team_name variable:
main = Blueprint('main', __name__, static_folder="static", static_url_path="", url_prefix=g.team_name)
Could you please advise is there a proper way to import variable from auth to main (before its initializing) without getting:
RuntimeError: Working outside of application context.
Basic fix of your problem is registering blueprints within app.app_context():
And seems like it is your first flask project and it is a common problem with thinking about the project structure. Read about Flask application factory pattern and apply it.
your_app/__init__.py
def create_app(app_config):
app = Flask(__name__)
with app.app_context():
from your_app.somewhere import team_name
app.register_blueprint(team_name)
return app

Flask-Mail extension of flask not working in application factory structure

What I am trying to do is to configure my flask-mail extension in application factory in order to send mail from different .py files but I am unable to do so.I know my configuration are right because I had same config settings when using single file structure
__init__.py
from flask import Flask
from flask_mail import Mail,Message
def create_app():
mail = Mail()
app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT']=465
app.config['MAIL_USE_SSL']=True
app.config['MAIL_USERNAME'] = ''
app.config['MAIL_PASSWORD'] = ''
app.config['MAIL_DEFAULT_SENDER'] = ''
app.config['MAIL_USE_TLS'] = False
mail.init_app(app)
return app
and the file I am willing to send emails from:
dev.py
from flask import *
#bp.route('/login',methods=['GET','POST'])
def login():
if request.method == 'POST':
emailid = request.form['emailid']
msg = Message('Password Change', sender = '')
msg.add_recipient(emailid)
msg.html = "<b>MADHAV</b>"
mail.send(msg)
The error I am receiving is following:
NameError: name 'Message' is not defined
By looking at the imports you forgot to add the Message object in there.
If that s the only error you get, the following line should solve the issue.
dev.py
from flask-mail import Message

RQ Python "Working outside of application context"

I'm trying to use Redis & RQ to set the task of sending an email, however, the "RQ Worker" is returning runtime error while using the function to send emails outside q.enqueue works fine.
app/routes.py
routes = Blueprint("routes", __name__)
r = Redis()
q = Queue(connection=r)
def sendEmail_task(recipient, message):
msg = Message("Test Email", sender=("Me", "shawkyelshazly2#gmail.com"),
recipients=[recipient])
msg.body = message
msg.send(mail)
#routes.route("/send_email", methods=["POST", "GET"])
def send_mail():
if request.method == "POST":
recipient = request.form.get('email')
message = request.form.get('message')
job = q.enqueue(sendEmail_task, recipient, message)
return redirect(url_for("routes.email_sent"))
return render_template("send_email.html")
app/__init__.py
mail = Mail()
def create_app(config_class = Config):
app = Flask(__name__)
from app.routes import routes
app.register_blueprint(routes)
app.config.from_object(Config)
with app.app_context():
mail.init_app(app)
return app
run.py
Which is outside the app folder
from app import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=True)
You're probably missing an app.app_context().push(). The Flask Mega Tutorial does it like this, but I've done it inside the task.

Access to session in flask_wtf

In forms.py I wanna get access to sessions.
this is forms.py code:
from flask_wtf import Form
from wtforms import SelectField,FileField,TextAreaField,TextField,validators
.
.
.
class Send(Form):
group = SelectField('Group',[validators.Required('you must select a group')],coerce=int,choices=c)
title = TextField('Title',[validators.Required('you must enter a title')])
content = TextAreaField('Content',[validators.Required('you must enter a content')])
attachment = FileField('Attachment')
But when I add this code :
from flask import session
uid = session.get('user_id')
It shows me this error:
raise RuntimeError('working outside of request context')
RuntimeError: working outside of request context
So how can I solve it?
You should use uid = session.get('user_id') only on request, for example:
app = Flask(__name__)
#app.route('/')
def home():
'''dispatcher functions works with request context'''
uid = session.get('user_id')
return str(uid)
If this code calling not from request (another process, another thread, celery, unit test and etc), then you should create request context manually or avoid use context stack variables:
with app.test_request_context():
uid = session.get('user_id')
Ok , I find how to solve that problem.
I think one of the best way is to use session in the route file.
This is my form code:
from flask_wtf import Form
from wtforms import SelectField
class Test(Form):
name = SelectField('Name')
So I have an app with "our" name, I have access to session in this app:
from flask import Blueprint,session,render_template
from form import Test
our = Blueprint('our',__name__)
#our.route('/')
def index():
form = Test()
#session['name'] = 'hedi'
if session.get('name').lower() == "morteza":
form.name.choices = ((1,'mori'),(2,'hedi'))
else:
form.name.choices = ((1,'you'))
return render_template('index.html',form=form)
#return str(session.get('name'))
Now I changed my form field data via app. form.name.choices=....

Categories

Resources