I'm writing a unit test for a file upload function in Flask.
The app works well locally but the unit test throws a 400. Thanks!
Here's my app.py
from flask import Flask, render_template, request
app = Flask(__name__)
app.config["TESTING"] = True
#app.route('/')
def index():
return render_template('index.html')
#app.route('/uploader', methods = ['GET','POST'] )
def upload_photo():
if request.method == 'POST':
photo = request.files['photo']
resp = app.make_response(photo.read())
resp.mimetype = 'image/jpeg'
return resp
if __name__ == '__main__':
app.run(debug=True)
Here's my test:
import unittest
import io
from app import app
class TestCase(unittest.TestCase):
def setUp(self):
self.client = app.test_client()
def test_upload_photo(self):
result = self.client.post('/uploader',
content_type='multipart/form-data', follow_redirects=True,
data=dict(upload_var=(io.BytesIO(b'photo'), 'photo')))
print(result.data)
self.assertTrue(result.status_code == 200)
if __name__ == "__main__":
unittest.main()`
Change upload_var to photo in the data dictionary, as that's what your handler function is expecting the file to be called.
Related
I am facing a very weird Issue, In my Flask App when index route (https://sitename.com/) is called everything is fine, but as i navigate to a route like https://sitename.com/about it shows 404 Error, even when About route is created in main.py . This App works all perfect in localhost:5000 but when I deployed it too a VPS It is showing that Error of showing 404 on every route
My main.py
from os import environ
from flask import Flask, redirect, render_template, request, url_for
import requests
import json
import datetime
def getUserData(route):
if request.headers.getlist("X-Forwarded-For"):
ip = request.headers.getlist("X-Forwarded-For")[0]
else:
ip = request.remote_addr
with open("users.txt", "a") as f:
f.write(f"Page Visited: {route}\n")
f.write(f"User Agent: {request.headers.get('User-Agent')}\n")
f.write(f"Remote Addr: {ip}\n")
f.write(f"DateTime: {datetime.datetime.now()}\n")
f.write(f"\n\n\n")
app = Flask(__name__)
app.debug = True
# Website
#app.route('/')
def index():
getUserData("Index Page")
return render_template('index.html')
#app.route('/gallery')
def gallery():
getUserData("Gallery")
return render_template('pages/gallery.html')
#app.route('/faqs')
def faqs():
getUserData("FAQs")
return render_template('pages/faqs.html')
#app.route('/about')
def about():
getUserData("About")
return render_template('pages/about.html')
#app.route('/contact')
def contact():
getUserData("Contact")
return render_template('pages/contact.html')
# 404 Handling
#app.errorhandler(404)
def not_found(e):
getUserData("404 Page")
return render_template("pages/404.html")
if __name__ == '__main__':
app.run()
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.
I'm learning flask and am trying to associate some randomly generated data with each session.
I use the approach from this answer to set session.permanent to False, but closing the browser, then reopening it at going back to the page still displays the same code.
MWE:
from flask import Flask, session
import numpy as np
app = Flask(__name__)
app.secret_key = "supersecretkey"
#app.before_request
def make_session_permanent():
session.permanent = False
#app.route('/')
def index():
if 'id' not in session:
random_id = "".join(np.random.choice(list("abcdefg123"), 16))
session["id"] = random_id
return session['id']
if __name__ == '__main__':
app.run(debug=True)
Update: Based on this answer someone recommended to use socketio to notice disconnects. This also makes no difference, i.e. closing the browser, reopening it, and going to 127.0.0.1:5000 gives the same number as before closing. An updated MWE using this is below:
from flask import Flask, session
from flask_socketio import SocketIO
import numpy as np
app = Flask(__name__)
app.secret_key = "supersecretkey"
#app.before_request
def make_session_permanent():
session.permanent = False
#app.route('/')
def index():
if 'id' not in session:
random_id = "".join(np.random.choice(list("abcdefg123"), 16))
session["id"] = random_id
return session['id']
socketio = SocketIO(app)
#socketio.on('disconnect')
def disconnect_user():
session.pop('id', None)
if __name__ == '__main__':
app.run(debug=True)
# Instantiate a new web application called `app`,
# with `__name__` representing the current file
app = Flask(__name__)
app.config["SESSION_PERMANENT"] = False
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()
I have json data in demo_data.json that I'd like to bring into a Flask app. I'm receiving a 404 on the file which I've placed in the static directory, my code is below, thanks for any thoughts in advance:
from flask import Flask, render_template
from flask import url_for
app = Flask(__name__, static_url_path='/static/')
#app.route('/')
def home():
return render_template('home.html')
#app.route('/welcome')
def welcome():
return render_template('welcome.html')
if __name__ == '__main__':
app.run()
return send_from_directory('/static', 'demo_data.json')
You would need to define the view to send the data.
Something similar to :
from flask import Flask, render_template
from flask import url_for
app = Flask(__name__, static_url_path='/static/')
#app.route('/')
def home():
return render_template('home.html')
#app.route('/welcome')
def welcome():
return render_template('welcome.html')
#app.route('data/<filename>')
def get_json(filename):
return send_from_dir
if __name__ == '__main__':
app.run()
So, you are trying to send a file? Or show a file in an url?
I assumed the later. Notice the use of url_for.
This creates a link that will show your static file.
http://127.0.0.1:5000/send and http://127.0.0.1:5000/static/demo_data.json
from flask import Flask, render_template
from flask import url_for
app = Flask(__name__, static_url_path='/static')
#app.route('/')
def home():
return render_template('home.html')
#app.route('/send')
def send():
return "<a href=%s>file</a>" % url_for('static', filename='demo_data.json')
if __name__ == '__main__':
app.run()
But you also might want to check out https://github.com/cranmer/flask-d3-hello-world
It looks like you have a trailing slash on your static_url_path. Removing the extra character resolved the issue. Also note the removed last line. The return call wasn't necessary and the function call after the return was a syntax error.
from flask import Flask, render_template
from flask import url_for
app = Flask(__name__, static_url_path='/static')
#app.route('/')
def home():
return render_template('home.html')
#app.route('/welcome')
def welcome():
return render_template('welcome.html')
if __name__ == '__main__':
app.run()