Infinity8 Infinity8 - 2 months ago 21
Python Question

Flask redirect with uploaded file - I/O operation on closed file

This app should allow a user to upload a file and then depending on the file type it would perform a save task. If it's a PDF file a new selection page loads prompting the user to select a folder. Once selected the error: ValueError: I/O operation on closed file pops up and an empty PDF file is saved in the selected location.

".mxd" files process with no issues. It seems to be because I have redirected to the selection template, but I'm not sure how else I would be able to use the folder selection.

Much code has been omitted to keep things simple. Any help would be greatly appreciated.

@app.route("/", methods=['GET', 'POST'])
def upload_file():
form = ReusableForm(request.form) # calls on form

if request.method == 'POST':
global folderout
folderout = request.form['folderout']

global file
file = request.files['file']
if filename.endswith((".pdf")): # For PDF files only
return redirect("/selection")
return redirect("/editor")

if filename.endswith((".mxd")):
MXDfull.savemxd()
MXDfull.pdf()
MXDfull.thumb()
return redirect("/editor")

@app.route("/selection", methods=['GET', 'POST'])
def selection1():
form = SelectionForm(request.form)
if request.method == 'POST':
global selection
selection = request.form['selection']
pdffilesave.savepdf()

return render_template("selection.html", form=form)

class PDFFile:
def savepdf(self):
self.pdffolder = os.path.join(folderout,selection)
self.pdffilename = "K" + Fnum + ".pdf"
file.save(os.path.join(self.pdffolder, self.pdffilename))
return
pdffilesave = PDFFile()


Page 1:

Upload file

Page 2:

enter image description here

Page 3:

enter image description here

Answer

Flask creates a FileStorage object which is a thin wrapper over incoming files.

The stream attribute of this object usually points to an open temporary file (according to the documentation). I'm guessing that as soon as the request is served, this temporary file is closed and hence the reference to this stream from your global object file points to a closed file. You must have got this error ValueError: I/O operation on closed file.

One work around would be to save the file in upload_file method in a temporary location and store the location of this file in a global variable filename.

@app.route("/", methods=['GET', 'POST'])  
def upload_file(): 
....
file = request.files['file']
global file_name = '/tmp/' + file.filename

file.save(file_name)
if file.filename.endswith((".pdf")):  # For PDF files only
    return redirect("/selection")
    return redirect("/editor")
...

In the selection method, you can move the file from temporary location to the desired location.

@app.route("/selection", methods=['GET', 'POST'])
def selection1():
....
os.rename(file_name, dest_file_name)
...