I have a Flask server that looks like this:
import flask, os, werkzeug.utils
UPLOAD_FOLDER = "files/"
ALLOWED_EXTENSIONS = {"txt"}
def isFileAllowed(file):
return str("." in file and file.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS)
app = flask.Flask(__name__)
app.config["UPLOAD_DIR"] = UPLOAD_FOLDER
#app.route("/log_receiver", methods = ["POST", "GET"])
def log_receiver():
if flask.request.method == "POST":
file = flask.request.files["file"]
if file and isFileAllowed(file):
filename = werkzeug.utils.secure_filename(file)
file.save(os.path.join(app.config["UPLOAD_DIR"], filename))
return "Sucessfully uploaded"
return "File couldn't be uploaded"
return "404, not found"
if __name__ == '__main__':
app.run()
I've made a test uploader, also in Python, that looks like this:
import requests
def log_uploader():
with open("log.txt", "rb") as log:
r = requests.post("http://localhost:5000/log_receiver", files={"log.txt": log})
print(r.text)
if __name__ == '__main__':
log_uploader()
The issue is, whenever I run it, I get a 404 error.
I've tried removing the ["file"] in flask.request.files, which removes the 400 error but brings in a 500 error with the following log:
[2022-11-29 16:05:46,547] ERROR in app: Exception on /log_receiver [POST]
Traceback (most recent call last):
File "/home/day/.local/lib/python3.9/site-packages/flask/app.py", line 2525, in wsgi_app
response = self.full_dispatch_request()
File "/home/day/.local/lib/python3.9/site-packages/flask/app.py", line 1822, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/day/.local/lib/python3.9/site-packages/flask/app.py", line 1820, in full_dispatch_request
rv = self.dispatch_request()
File "/home/day/.local/lib/python3.9/site-packages/flask/app.py", line 1796, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "/home/day/Desktop/Coding/Quickraft/Server-side/APIs/main.py", line 17, in log_receiver
filename = werkzeug.utils.secure_filename(file)
File "/home/day/.local/lib/python3.9/site-packages/werkzeug/utils.py", line 221, in secure_filename
filename = unicodedata.normalize("NFKD", filename)
TypeError: normalize() argument 2 must be str, not ImmutableMultiDict
127.0.0.1 - - [29/Nov/2022 16:05:46] "POST /log_receiver HTTP/1.1" 500 -
How could I fix this? Thanks in advance,
Daymons.
See again the flask documentation for request.files
Each value in files is a Werkzeug FileStorage object
It is not just the filename but much more than that. The error message is telling you something: That secure_filename() expects a string, but you are passing it something that isn't a string.
Have a look again at the flask documentation for file uploads: https://flask.palletsprojects.com/en/2.2.x/patterns/fileuploads/
Related
I'm trying to build a simple contact form with Flask and hosting it on GAE but I can't seem to get it right.
I'd truly appreciate your help because I've spent several days trying to figure this out without any success.
Here's the error I get when I click submit:
Internal Server Error
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
And here are the logs:
2022-02-14 23:03:33 default[20220215t000150] Traceback (most recent call last):
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 2073, in wsgi_app response = self.full_dispatch_request()
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 1518, in full_dispatch_request rv = self.handle_user_exception(e)
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 1516, in full_dispatch_request rv = self.dispatch_request()
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 1502, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "/srv/main.py", line 34, in contact message.send() File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/appengine/api/mail.py", line 1209, in send make_sync_call('mail', self._API_CALL, message, response)
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/appengine/api/apiproxy_stub_map.py", line 96, in MakeSyncCall return stubmap.MakeSyncCall(service, call, request, response)
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/appengine/api/apiproxy_stub_map.py", line 355, in MakeSyncCall rpc.CheckSuccess()
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/appengine/api/apiproxy_rpc.py", line 149, in CheckSuccess raise self.exception
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/appengine/runtime/default_api_stub.py", line 267, in _CaptureTrace f(**kwargs)
File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/appengine/runtime/default_api_stub.py", line 260, in _SendRequest raise self._TranslateToError(parsed_response) File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/appengine/runtime/default_api_stub.py", line 134, in _TranslateToError raise self._ErrorException(exception_type, msg) google.appengine.runtime.apiproxy_errors.FeatureNotEnabledError: The API call mail.Send() is currently not enabled. -- Additional details from server: App Engine APIs are not enabled, please add app_engine_apis: true to your app.yaml to enable.
Here's my main.py:
from flask import Flask, redirect, render_template, url_for
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from flask_talisman import Talisman
from google.appengine.api import mail, wrap_wsgi_app
app = Flask(__name__)
app.config['SECRET_KEY'] = 'my-very-very-secret-key'
app.wsgi_app = wrap_wsgi_app(app.wsgi_app)
Talisman(app)
EMAIL_ADDR = 'my_email#example.com'
class ContactForm(FlaskForm):
name = StringField(label='Name', validators=[DataRequired()])
submit = SubmitField(label='Submit')
#app.route('/')
def homepage():
return render_template('index.html')
#app.route('/contact', methods=['GET', 'POST'])
def contact():
form = ContactForm()
if form.validate_on_submit():
name = form.name.data
message = mail.EmailMessage(sender=EMAIL_ADDR,
subject='form test')
message.body = f'this is a test message from {name}'
message.to = EMAIL_ADDR
message.send()
return redirect(url_for('homepage'))
return render_template('contact.html', form=form)
if __name__ == '__main__':
app.run()
My app.yaml
runtime: python39
app_engine_apis: true
inbound_services:
- mail
- mail_bounce
My requirements.txt
Flask==2.0.2
flask-talisman==0.8.1
wtforms==3.0.0
Flask-WTF==1.0.0
appengine-python-standard>=0.3.1
I've stumbled upon the solution! If anyone else runs into this issue: 'gcloud beta app deploy' solves it. I used to deploy the app with 'gcloud app deploy' before.
I am using python 3.9.6 with ninja2 and blueprint.
py --version
returns:
Python 3.9.6
As far as I know, blueprint is a seperate folder, with seperate html templates and static files (css/js) , and I can have many blueprints in one runnable python project.
I have looked at Views with Jinja2 and blueprint
The hierarchy of the html+relevant files of myblueprint is:
main_project -> myblueprint -> templates -> myblueprint.html
-> static -> myblueprint.css
-> myblueprint.js
The relevant code:
import os
from flask import Flask, Blueprint, redirect, request, render_template, url_for, session
main_page = Blueprint('myblueprint', __name__)
#main_page.route("/myblueprint")
def home():
query = 'select * from users;'
users = interact_db(query=query, query_type='fetch')
return render_template('myblueprint.html')
...
#app.route('/', methods=['GET'])
def main():
return redirect("myblueprint")
if __name__ == '__main__':
# Bind to PORT if defined, otherwise default to 5000.
port = int(os.environ.get('PORT', 5000))
app.secret_key = '12345'
app.run(host='0.0.0.0', port=port)
For some reason, when I run: https://localhost:5000, I get an error:
ERROR in app: Exception on /myblueprint [GET] Traceback (most recent
call last): File
"C:\Users\myusername\AppData\Local\Programs\Python\Python36-32\lib\site-packages\flask\app.py",
line 2073, in wsgi_app
response = self.full_dispatch_request() File "C:\Users\myusername\AppData\Local\Programs\Python\Python36-32\lib\site-packages\flask\app.py",
line 1518, in full_dispatch_request
rv = self.handle_user_exception(e) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36-32\lib\site-packages\flask\app.py",
line 1516, in full_dispatch_request
rv = self.dispatch_request() File "C:\Users\myusername\AppData\Local\Programs\Python\Python36-32\lib\site-packages\flask\app.py",
line 1502, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "C:/main_project/myproject/app.py", line 17, in home
return render_template('myblueprint.html') File "C:\Users\myusername\AppData\Local\Programs\Python\Python36-32\lib\site-packages\flask\templating.py",
line 148, in render_template
ctx.app.jinja_env.get_or_select_template(template_name_or_list), File
"C:\Users\myusername\AppData\Local\Programs\Python\Python36-32\lib\site-packages\jinja2\environment.py",
line 1068, in get_or_select_template
return self.get_template(template_name_or_list, parent, globals) File
"C:\Users\myusername\AppData\Local\Programs\Python\Python36-32\lib\site-packages\jinja2\environment.py",
line 997, in get_template
return self._load_template(name, globals) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36-32\lib\site-packages\jinja2\environment.py",
line 958, in _load_template
template = self.loader.load(self, name, self.make_globals(globals)) File
"C:\Users\myusername\AppData\Local\Programs\Python\Python36-32\lib\site-packages\jinja2\loaders.py",
line 125, in load
source, filename, uptodate = self.get_source(environment, name) File
"C:\Users\myusername\AppData\Local\Programs\Python\Python36-32\lib\site-packages\flask\templating.py",
line 59, in get_source
return self._get_source_fast(environment, template) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36-32\lib\site-packages\flask\templating.py",
line 95, in _get_source_fast
raise TemplateNotFound(template) jinja2.exceptions.TemplateNotFound: myblueprint.html
127.0.0.1 - - [04/Jan/2022 08:04:31] "GET /myblueprint HTTP/1.1" 500 -
127.0.0.1 - - [04/Jan/2022 08:04:31] "GET /favicon.ico HTTP/1.1" 404 -
I have also noticed that on the chrome network console (not in code run window), I see another exception:
Request URL: http://localhost:5000/
Request Method: GET
Status Code: 500 INTERNAL SERVER ERROR
Remote Address: 127.0.0.1:5000
Referrer Policy: strict-origin-when-cross-origin
What is the cross origin for blueprint, and how can I avoid that?
What is wrong in my code above, and should I fix the heirarchy?
Two problems in your code. First you have to register your blueprint
import os
from flask import Flask, Blueprint, redirect, request, render_template, url_for, session
app = Flask(__name__)
main_page = Blueprint('myblueprint', __name__)
#main_page.route('/myblueprint', methods=['GET'])
def home():
query = 'select * from users;'
users = interact_db(query=query, query_type='fetch')
return render_template('myblueprint.html')
#app.route('/', methods=['GET'])
def main():
return redirect("myblueprint")
app.register_blueprint(main_page)
if __name__ == '__main__':
# Bind to PORT if defined, otherwise default to 5000.
port = int(os.environ.get('PORT', 5800))
app.secret_key = '12345'
app.run(host='0.0.0.0', port=port)
Then your html file must simply be in the templates folder:
> templates > myblueprint.html
I am making my api about output data from mysql. And I follow this link to do this but I get the Type Error. https://flask.palletsprojects.com/en/2.0.x/config/ I don't know what wrong in my code. And I try to fix this. I follow this link How do I save database configuration without writting them on my python file but still not work.
# -*- coding: utf-8 -*-
from flask import Flask, g, render_template, request, jsonify, json, current_app
import pymysql
import pymysql.cursors
from flask_sqlalchemy import SQLAlchemy
import flask
from global_setup import *
app = Flask(__name__)
def connect_db():
return pymysql.connect(MY_DB_SERVER,
MY_DB_USER,
MY_DB_PASS,
MY_DB_DB,
MY_DB_PORT,
charset='utf8',
cursorclass=pymysql.cursors.DictCursor)
def get_db():
'''Opens a new database connection per request.'''
if not hasattr(g, 'db'):
g.db = connect_db()
return g.db
#app.teardown_appcontext
def close_db(error):
'''Closes the database connection at the end of request.'''
if hasattr(g, 'db'):
g.db.close()
#app.route('/api/CRM',methods = ['POST'])
def index1():
cursor = get_db().cursor()
cursor.execute("select * from customer")
rows = cursor.fetchall()
return jsonify(rows)
if __name__ == '__main__':
app.config['JSON_AS_ASCII'] = False
app.run(debug=True, host='0.0.0.0', port=5000)
The error:
127.0.0.1 - - [21/Jun/2021 18:40:29] "POST /api/CRM HTTP/1.1" 500 -
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 2088, in __call__
return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 2073, in wsgi_app
response = self.handle_exception(e)
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 2070, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1515, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1513, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1499, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "/home/Teemo.Tsui/git/KF/api_123.py", line 34, in index1
cursor = get_db().cursor()
File "/home/Teemo.Tsui/git/KF/api_123.py", line 23, in get_db
g.db = connect_db()
File "/home/Teemo.Tsui/git/KF/api_123.py", line 18, in connect_db
cursorclass=pymysql.cursors.DictCursor)
TypeError: __init__() takes 1 positional argument but 6 positional arguments (and 2 keyword-only arguments) were given
This is my global_setup.py
MY_DB_SERVER = ""
MY_DB_USER = ""
MY_DB_PASS = ""
MY_DB_DB = ""
MY_DB_PORT = 3306
It looks like the pymysql.connect args need to be named, so:
def connect_db():
return pymysql.connect(host=MY_DB_SERVER,
user=MY_DB_USER,
password=MY_DB_PASS,
database=MY_DB_DB,
port=MY_DB_PORT,
charset='utf8',
cursorclass=pymysql.cursors.DictCursor)
This is my code for my main.py file which is designed to be a simple contact form built in flask.
from flask import Flask, render_template, request
from flask_mail import Mail, Message
from forms import ContactForm
app = Flask(__name__)
app.secret_key = 'YourSuperSecreteKey'
# add mail server config
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = 'YourUser#NameHere'
app.config['MAIL_PASSWORD'] = 'yourMailPassword'
mail = Mail(app)
#app.route('/')
def hello():
"""Return a friendly HTTP greeting."""
return 'Hello World!'
#app.errorhandler(404)
def page_not_found(e):
"""Return a custom 404 error."""
return 'Sorry, Nothing at this URL.', 404
#app.errorhandler(500)
def application_error(e):
"""Return a custom 500 error."""
return 'Sorry, unexpected error: {}'.format(e), 500
#app.route('/contact', methods=('GET', 'POST'))
def contact():
form = ContactForm()
if request.method == 'POST':
if form.validate() == False:
return 'Please fill in all fields <p>Try Again!!!</p>'
else:
msg = Message("Message from your visitor" + form.name.data,
sender='YourUser#NameHere',
recipients=['yourRecieve#mail.com', 'someOther#mail.com'])
msg.body = """
From: %s <%s>,
%s
""" % (form.name.data, form.email.data, form.message.data)
mail.send(msg)
return "Successfully sent message!"
elif request.method == 'GET':
return render_template('contact.html', form=form)
if __name__ == '__main__':
app.run()
I get the error: Sorry, unexpected error: 'module' object has no attribute 'SMTP_SSL'
I've called my file "main.py". Everything works fine until I try and send the actual email. Is this just because I haven't populated the settings or is something else a miss?
Sorry just figured out how to see traceback on GAE:
Exception on /contact [POST]
Traceback (most recent call last):
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/main.py", line 50, in contact
mail.send(msg)
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask_mail.py", line 491, in send
with self.connect() as connection:
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask_mail.py", line 144, in __enter__
self.host = self.configure_host()
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask_mail.py", line 156, in configure_host
host = smtplib.SMTP_SSL(self.mail.server, self.mail.port)
AttributeError: 'module' object has no attribute 'SMTP_SSL'
You have set the MAIL_USE_SSL option to True:
app.config['MAIL_USE_SSL'] = True
which means that the Flask-Mail extension will want to use the smtplib.SMTP_SSL class, but that class isn't usually available on Google App Engine.
That class is only available if the Python ssl module is available, which is only the case if your Python was built with SSL support available. This isn't normally the case in the GAE environment.
The module is not available on Google App Engine unless you specifically enable it. Enable it in your app.yaml:
libraries:
- name: ssl
version: latest
Do note that the socket support on GAE is experimental.
For sending email on GAE you are better off using the mail.send_mail() function however, so you can make use of the GAE infrastructure instead.
I'm running into an issue trying to run my python web app on EB. It runs fine locally, but I get the following exception when I run it on EB. The problem seems to be that it runs into an exception, but the stack trace is of an error that occurs after that original one, so I can't really determine what the root cause is:
Exception on /admin GET
Traceback (most recent call last):
File "/opt/python/run/venv/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/opt/python/run/venv/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/opt/python/run/venv/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/opt/python/run/venv/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/opt/python/run/venv/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functionshttp://rule.endpoint(**req.view_args)
File "/opt/python/run/venv/lib/python2.7/site-packages/sandman/sandman.py", line 459, in get_collection
cls = endpoint_class(collection)
File "/opt/python/run/venv/lib/python2.7/site-packages/sandman/sandman.py", line 185, in endpoint_class
cls = current_app.class_referencescollection
File "/opt/python/run/venv/lib/python2.7/site-packages/werkzeug/local.py", line 338, in __getattr__
return getattr(self._get_current_object(), name)
AttributeError: 'Flask' object has no attribute 'class_references'
When I manually start the app on port 5000 after SSHing into my instance, and attempted to load the same page from the console, I did not get any error (and the saved file contained the correct HTML):
wget http://127.0.0.1:5000/admin
--2014-03-23 17:01:13-- http://127.0.0.1:5000/admin
Connecting to 127.0.0.1:5000... connected.
HTTP request sent, awaiting response... 127.0.0.1 - - 23/Mar/2014 17:01:13 "GET /admin HTTP/1.1" 301 -
301 MOVED PERMANENTLY
Location: http://127.0.0.1:5000/admin/ following
--2014-03-23 17:01:13-- http://127.0.0.1:5000/admin/
Connecting to 127.0.0.1:5000... connected.
HTTP request sent, awaiting response... 127.0.0.1 - - 23/Mar/2014 17:01:13 "GET /admin/ HTTP/1.1" 200 -
200 OK
Length: 1519 (1.5K) text/html
Saving to: ‘admin’
this is the python app code I'm running: http://pastebin.com/qgnWz6aK
I managed to work around this issue by using Tornado (though I'm still not sure what the underlying issue is):
from sandman import app
from sandman.model import activate
import logging
import os, sys
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DB']
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
activate(browser=False)
app.debug = True
http_server = HTTPServer(WSGIContainer(app))
http_server.listen(os.environ['PORT'])
IOLoop.instance().start()