Flask / Python: #after_this_request is not accessed - python

I trying to delete a file I've created after it was displayed on the webservice.
However with the current placement of the function, it says 'remove_file(response) is not accessed' and when I run the webservice I get an error when outputting the file, as it apparently already has been deleted.
I don't know what to do anymore, I've tried placing the afer_this_request function right after the upload_file declaration, after the return render template, all of it never works. I'm going crazy, so any help would make my year!
#app.route('/', methods=['POST', 'GET'])
def upload_file():
if request.method == 'POST':
myuuid = uuid.uuid4()
# check if the post request has the file part
if 'file' not in request.files:
return render_template('error.html')
file = request.files['file']
# If the user does not select a file, the browser submits an
# empty file without a filename.
if file.filename == '':
return render_template('error.html')
if file and allowed_file(file.filename):
sfilename = secure_filename(file.filename)
if not os.path.exists(app.config['UPLOAD_FOLDER']):
os.mkdir(app.config['UPLOAD_FOLDER'])
output_path = os.path.join(app.config['UPLOAD_FOLDER'], sfilename)
file.save(output_path)
if 'Alpha Miner' in request.form:
Alpha(pro_file, myuuid)
img_url = url_for('static', filename=str(myuuid) + '.gv.svg')
#after_this_request
def remove_file(response):
os.remove(img_url)
return response
titel = "Petri Net for Alpha Miner: " + sfilename
return render_template('upload.html', img_url=img_url, titel = title)

Try this :
file_handle = open(img_url, 'r')
#after_this_request
def remove_file(response):
try:
os.remove(img_url)
file_handle.close()
except Exception as error:
app.logger.error("Error removing or closing downloaded file handle", error)
return response

Related

Flask: How do I pass an uploaded file as input to a method? AttributeError: '_io.BytesIO' object has no attribute 'lower'

I'm completely new to flask (in fact I've just started this morning) and so far I've only managed to implement a basic upload function (taken from the flask doc). The file upload works but I just can't seem to figure out how to pass the file into another method (mining). When I do, I always get the error message: AttributeError: '_io.BytesIO' object has no attribute 'lower'. It would mean the world to me to receive any kind of help! Thank you all in advance.
def mining(xes):
log = xes_importer.apply(xes)
tracefilter_log_pos = attributes_filter.apply_events(log, ["complete"], parameters={attributes_filter.Parameters.ATTRIBUTE_KEY: "lifecycle:transition", attributes_filter.Parameters.POSITIVE: True})
variants = pm4py.get_variants_as_tuples(tracefilter_log_pos)
Alpha(variants.keys())
Heuristic(variants.keys(), 1, 0.5)
UPLOAD_FOLDER = '/Users/jenny/processmining_lab/uploads'
ALLOWED_EXTENSIONS = set(['xes'])
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
#app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
# If the user does not select a file, the browser submits an
# empty file without a filename.
if file.filename == '':
flash('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return mining(file)
return '''
<!doctype html>
<title>Upload new File</title>
<h1>Upload new File</h1>
<form method=post enctype=multipart/form-data>
<input type=file name=file>
<input type=submit value=Upload>
</form>
'''
Here is the traceback
This depends on what you're mining function looks like.
file is a werkzeug.FileStorage object which has it's own various methods.
So (without seeing) your mining function it should probably be something like:
def mining(file_obj):
lower_fname = file_obj.filename.lower()
data = file_obj.read()
# Do something
The AttributeError you mention sounds like you're trying to run the lower method of something which doesn't return a string.
As a side-note: it's difficult to know where in your code this exception hasn't occured as you never posted the full traceback.
EDIT
My mining function is actually at the top of the code I've inserted. I've also now included the traceback.
Looks like you're using PM4Py for which this document states:
from pm4py.objects.log.importer.xes import importer as xes_importer
log = xes_importer.apply('<path_to_xes_file.xes>')
So you need to actually pass a file path to the mining function.
I suggest changing your main code to do:
if file and allowed_file(file.filename):
sfilename = secure_filename(file.filename)
output_path = os.path.join(app.config['UPLOAD_FOLDER'], sfilename)
# Now save to this `output_path` and pass that same var to your mining function
file.save(output_path)
return mining(output_path)

Uploading a text file in Flask and reading it in html

I'm trying to upload a simple text file and then display it in another URL in flask. However, I'm getting a blank output with b" as the only thing showing. Its just a regular text file with utf-8.
Here's the code -
def upload_source():
if request.method == 'POST':
# check if the post request has the file part
f = request.files['file']
if f.filename == "":
print("No file Name")
return redirect(request.url)
if not allowed_file(f.filename):
print("File extension not allowed!")
return redirect(request.url)
else:
full_filename = secure_filename(f.filename)
f.save(os.path.join(app.config['UPLOAD_FOLDER'], full_filename))
print("File saved")
content = f.read()
return render_template('source.html', text=content)
and i'm including this in the source html
<p> {{ text }} </p>
I'm relatively new to python and flask and I appreciate your help here. Thank you!
Thanks to the commenters on this post, I could come up with a fix to this. Initially, I was getting a b" as the only output after using only f.read().
When I used f.seek(0), I got the output of my text file but with a lot of encoding and formatting errors, including a new preceding b` followed by my output.
But adding content = f.read()
content = str(content, 'utf-8') fixed most of that aswell.
So here goes the final solution-
def upload_source():
if request.method == 'POST':
# check if the post request has the file part
f = request.files['file']
if f.filename == "":
print("No file Name")
return redirect(request.url)
if not allowed_file(f.filename):
print("File extension not allowed!")
return redirect(request.url)
else:
full_filename = secure_filename(f.filename)
f.save(os.path.join(app.config['UPLOAD_FOLDER'], full_filename))
f.seek(0)
print("File saved")
content = f.read()
content = str(content, 'utf-8')
return render_template('source.html', text=content)
and don't forget the same old HTML -
<p> {{ text }} </p>
I hope this can help others as well. Thank you!

Unable to download file in django

I'm new to django and I have developed a django website which allows people to download epub file by typing the book's name. I have checked the django api about download and the code seems to work fine (no error reported), but there is no download window pops up by my browser. I'm testing on 127.0.0.1:8000 and here is part of my code
view.py
def download(request, file_path, book_name):
if os.path.exists(file_path):
response = HttpResponse(content_type="application/epub+zip")
response['X-Sendfile'] = file_path
response['Content-Disposition'] = 'attachment; filename=abc.epub'
print (response)
return response
raise False
According to my console it could find the file path, and by printing the message it shows
<HttpResponse status_code=200, "application/epub+zip">
[26/Mar/2018 18:31:03] "POST / HTTP/1.1" 200 509
Everything seems to work fine, just the download window does not pop up. Does anyone have any idea where is goes wrong? Thanks!
==========
Supplementary:
To give you a full sight of the view file, download is called by index and thats all:
def index(request):
template = loader.get_template('index.html')
book_name = ''
result = ''
if request.method == "POST": # check if user actually type a book name
book_name = request.POST.get("book_name")
cwd = os.getcwd()
if book_name != '': # search and create are functions from other file which would create an epub file and put it in current directory
result = search.search_ask(book_name)
create.create(book_name)
file_path = os.path.join(cwd, book_name) + '.epub'
download(request, file_path, book_name)
context = {'return_value': book_name,
'result_1': result,
'cwd': cwd}
return HttpResponse(template.render(context, request))
you don't return the response object returned by the download method. most be:
return donwload(request, file_path, book_name)
or
download_response = donwload(request, file_path, book_name)
if download_response:
return download_response
else:
# not found or other return.
in your code always return
return HttpResponse(template.render(context, request))

Check Flask upload if user does not selected file

If user doesn't select a file in form (equals PHP UPLOAD_ERR_NO_FILE
), request.files['file'] also return a FileStorage object, I am using request.files['file'].filename == '' to check, any better way ? I have seen Flask Doc but can't find the answer.
'file' in request.files will not work on user doesn't select file, browser also will submit a 0 length and filename equals '' (empty string) part.
and how do I detect uploaded file was only partially uploaded error (equals PHP UPLOAD_ERR_PARTIAL) ?
Now I am using
if request.files['file'].filename == '':
return 'No selected file'
or using file length check
import os
file = request.files['file']
file.seek(0, os.SEEK_END)
if file.tell() == 0:
return 'No selected file'
Try:
if not request.files.get('file', None):
pass
If you want have most control over the files, you can use http://pythonhosted.org/Flask-Uploads/
import imghdr
def validate_image(stream):
header = stream.read(512)
stream.seek(0)
format = imghdr.what(None, header)
if not format:
return None
return '.'+format
class UploadFiles(Resource):
def post(self):
doc=request.files.get('image')
if validate_image(doc.stream):
print('file validated')

Flask / Python. Get mimetype from uploaded file

I am using Flask micro-framework 0.6 and Python 2.6
I need to get the mimetype from an uploaded file so I can store it.
Here is the relevent Python/Flask code:
#app.route('/upload_file', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
file = request.files['file']
mimetype = #FIXME
if file:
file.save(os.path.join(UPLOAD_FOLDER, 'File-Name')
return redirect(url_for('uploaded_file'))
else:
return redirect(url_for('upload'))
And here is the code for the webpage:
<form action="upload_file" method=post enctype=multipart/form-data>
Select file to upload: <input type=file name=file>
<input type=submit value=Upload>
</form>
The code works, but I need to be able to get the mimetype when it uploads. I've had a look at the Flask docs here: http://flask.pocoo.org/docs/api/#incoming-request-data
So I know it does get the mimetype, but I can't work out how to retrieve it - as a text string, e.g. 'txt/plain'.
Any ideas?
Thank you.
From the docs, file.content_type contains the full type with encoding, mimetype contains just the mime type.
#app.route('/upload_file', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
file = request.files.get('file')
if file:
mimetype = file.content_type
filename = werkzeug.secure_filename(file.filename)
file.save(os.path.join(UPLOAD_FOLDER, filename)
return redirect(url_for('uploaded_file'))
else:
return redirect(url_for('upload'))
You could in theory use request.files['YOUR_FILE_KEY'].content_type, but the implementation (included below, found in werkzeug.datastructures) either trust whatever the client is providing, or uses mimetypes.guess_type which only checks the file extension (see Python doc here).
class FileMultiDict(MultiDict):
"""A special :class:`MultiDict` that has convenience methods to add
files to it. This is used for :class:`EnvironBuilder` and generally
useful for unittesting.
.. versionadded:: 0.5
"""
def add_file(self, name, file, filename=None, content_type=None):
"""Adds a new file to the dict. `file` can be a file name or
a :class:`file`-like or a :class:`FileStorage` object.
:param name: the name of the field.
:param file: a filename or :class:`file`-like object
:param filename: an optional filename
:param content_type: an optional content type
"""
if isinstance(file, FileStorage):
value = file
else:
if isinstance(file, string_types):
if filename is None:
filename = file
file = open(file, 'rb')
if filename and content_type is None:
content_type = mimetypes.guess_type(filename)[0] or \
'application/octet-stream'
value = FileStorage(file, filename, name, content_type)
self.add(name, value)
Depending on your use case, you might want to use python-magic which will use the actual file to get the mimetype. It would something like that:
import magic
def get_mimetype(data: bytes) -> str:
"""Get the mimetype from file data."""
f = magic.Magic(mime=True)
return f.from_buffer(data)
get_mimetype(request.files['YOUR_FILE_KEY'].stream.read(MAX_LENGTH))

Categories

Resources