download file FROM web TO flask server - python

My flask app should download files from urls which are posted to my app by a json object.
The files should be downloaded for further processing. I do not get an error message. A lot of tutorials are about how a user uploads a file, but this is not my case. Can anyone help?
import os
from flask import Flask, request, jsonify
import urllib.request as web
app = Flask(__name__)
download_folder=os.path.join(app.instance_path,'downloads')
app.config['DOWNLOAD_FOLDER'] = download_folder
#app.route('/syncaudio', methods=['POST'])
def syncaudio():
files = request.get_json(force=True)
for file_url in files['syncFileUrls']:
local_file = os.path.join(app.config['DOWNLOAD_FOLDER'], file_url.rsplit('/')[-1])
web.urlretrieve(file_url, local_file)
if __name__ == '__main__':
app.run(debug=True)

urlretrieve(file_url,local_file) is the right way of doing it, there is nothing specific to Flask.
I suggest you to try in a Python interpreter to see if that works:
>>> import urllib.request
>>> urllib.request.urlretrieve('http://some/url', '/some/file/location.txt')
If that works, this means your code is never getting executed.
You may want to print the value of files to see if the list is not empty.

I found the solution!
for downloading FROM web TO flask server I do not need to create a folder like this:
download_folder=os.path.join(app.instance_path,'downloads')
app.config['DOWNLOAD_FOLDER'] = download_folder
I just have to create a download folder via:
os.makedirs('downloads')
really simpel :)

Related

Prevent browsers from opening json files and instead download when sent from flask app

I have a JSON file in the flask app that i send via either send_from_directory() or via send_file() i have tried both. This triggers on button click but the browser opens the file directly instead of getting a download dialog box. I researched a bit and found out Firefox and Chrome have an inbuilt option to do this, however i want it to always download instead of opening no matter the setting in the browser.
Flask Code
def download_file():
filename = "requiredFields.json"
return send_from_directory(app.config['MAIN_FOLDER'],filename,as_attachment=True)
HTML That calls it
Download
If you set mimetype to 'application/octet-stream' then browser should save it.
send_file(..., mimetype='application/octet-stream')
send_from_directory(..., mimetype='application/octet-stream')
Doc: send_file
See also: Do I need Content-Type: application/octet-stream for file download?
EDIT:
Minimal working example - you have to only set correct filenames in index()
It doesn't matter if you have file .json, .txt, image, .pdf or other. It works for all types of files.
from flask import Flask, render_template_string, send_from_directory
app = Flask(__name__)
app.config['MAIN_FOLDER'] = '.'
#app.route('/')
def index():
all_filenames = [
'requiredFields.json',
'input.txt',
'image.jpg',
'document.pdf',
]
return render_template_string('''
{% for file in all_files %}
Download {{file}}<br/>
{% endfor %}''', all_files=all_filenames)
##app.route('/download_file/<filename>')
#app.route('/download_file/<path:filename>')
def download_file(filename):
return send_from_directory(app.config['MAIN_FOLDER'], filename, as_attachment=True, attachment_filename=filename, mimetype='application/octet-stream')
if __name__ == '__main__':
app.run() #debug=True

Reading json in pythonanywhere flask app

First I have seen this question. My problem is I have a flask app running on pythonanywhere that reads info from a json file in the same directory on the server, and get the following error:
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..
I simplified the app down to:
from flask import Flask
import json
app = Flask(__name__)
#app.route('/')
#app.route('/index')
def index():
return 'Index'
#app.route('/courses')
def courses():
with open('courses.json', 'r') as f:
these_courses = json.load(f)
return str(these_courses)
If I go to the index page I see index, as expected, but if I try to go to /courses then I get the error.The whole things runs fine on localhost, then with the same code I get an error on the server, so I know reading from the file works fine. This makes me think it might be a problem unique to json combined with pythonanywhere.
Edit: Perhaps a problem with the path name for courses.json, but it's in the same directory so I feel like it should be fine, just a thought
Turns out it was a pathname problem. I guess on files need to be routed from the root directory.
I ran:
def courses():
my_dir = os.path.dirname(__file__)
json_file_path = os.path.join(my_dir, 'courses.json')
return json_file_path
to find the path, then changed the function to:
def courses():
with open('/home/username/path/to/file/courses.json', 'r') as f:
these_courses = json.load(f)
return str(these_courses)
and now it worked :D
Then to make a better version that doesn't break when you move the project I did it like this:
def courses():
my_dir = os.path.dirname(__file__)
json_file_path = os.path.join(my_dir, 'courses.json')
with open(json_file_path, 'r') as f:
these_courses = json.load(f)
return str(these_courses)
As an alternative:
import pathlib
path = pathlib.Path('courses.json').absolute()
these_courses = json.loads(path.read_text())

How do I allow users to download a MIDI file with Flask without getting a 0 byte download?

I am writing an application that creates a midi file using the MIDIUtil library. When the user submits an HTML form, a midi file object is created with MIDIUtil. How do I allow the user to download this as a .mid file? I have tried the following code, but I end up downloading a file of 0 bytes.
return Response(myMIDIFile, mimetype='audio/midi')
I use a variant of the following code to allow my users to download images they generate. The below code should work for you. Please note that you will most likely need to specify the full server path to the file being downloaded.
from flask import send_file
download_filename = FULL_PATH_TO_YOUR_MIDI_FILE
return(send_file(filename_or_fp = download_filename,mimetype="audio/midi",as_attachment=True))
I ended up using this, and it worked.
new_file = open('test.mid', 'wb')
myMIDI.writeFile(new_file)
new_file.close()
new_file = open('test.mid', 'rb')
return send_file(new_file, mimetype='audio/midi')
Might want to just try using send_file
from flask import send_file
return send_file("yourmidifile.mid", as_attachement=True, mimetype="audio\midi")

How do I open an href link in HTML to a file but not download the file in a Flask app

I'm using Flask and AutoIndex. When I go to the URL for the directory I specified with AutoIndex, I can see the files in the directory just fine. But when I click on a file to view it, the browser automatically downloads the file. I just want it to display as a plain text file when it is clicked.
You can use send_from_directory, example:
# -*- coding: utf-8 -*-
from flask import Flask, send_from_directory
app = Flask(__name__)
#app.route('/open')
def open():
"""Open in browser"""
return send_from_directory('/tmp/', 'hello.txt')
#app.route('/download')
def download():
"""Download"""
return send_from_directory('/tmp/', 'hello.txt', as_attachment=True)
if __name__ == '__main__':
app.run(debug=True)
You need to change the response to set the content-type header to 'text/plain', and maybe also remove or rewrite the content-disposition header.
You might need to create a new view to serve the files like that and change or configure AutoIndex to point the links to your view.

Is it possible to generate and return a ZIP file with App Engine?

I have a small project that would be perfect for Google App Engine. Implementing it hinges on the ability to generate a ZIP file and return it.
Due to the distributed nature of App Engine, from what I can tell, the ZIP file couldn't be created "in-memory" in the traditional sense. It would basically have to be generated and and sent in a single request/response cycle.
Does the Python zip module even exist in the App Engine environment?
zipfile is available at appengine and reworked example follows:
from contextlib import closing
from zipfile import ZipFile, ZIP_DEFLATED
from google.appengine.ext import webapp
from google.appengine.api import urlfetch
def addResource(zfile, url, fname):
# get the contents
contents = urlfetch.fetch(url).content
# write the contents to the zip file
zfile.writestr(fname, contents)
class OutZipfile(webapp.RequestHandler):
def get(self):
# Set up headers for browser to correctly recognize ZIP file
self.response.headers['Content-Type'] ='application/zip'
self.response.headers['Content-Disposition'] = \
'attachment; filename="outfile.zip"'
# compress files and emit them directly to HTTP response stream
with closing(ZipFile(self.response.out, "w", ZIP_DEFLATED)) as outfile:
# repeat this for every URL that should be added to the zipfile
addResource(outfile,
'https://www.google.com/intl/en/policies/privacy/',
'privacy.html')
addResource(outfile,
'https://www.google.com/intl/en/policies/terms/',
'terms.html')
import zipfile
import StringIO
text = u"ABCDEFGHIJKLMNOPQRSTUVWXYVabcdefghijklmnopqqstuvweyxáéöüï东 廣 広 广 國 国 国 界"
zipstream=StringIO.StringIO()
file = zipfile.ZipFile(file=zipstream,compression=zipfile.ZIP_DEFLATED,mode="w")
file.writestr("data.txt.zip",text.encode("utf-8"))
file.close()
zipstream.seek(0)
self.response.headers['Content-Type'] ='application/zip'
self.response.headers['Content-Disposition'] = 'attachment; filename="data.txt.zip"'
self.response.out.write(zipstream.getvalue())
From What is Google App Engine:
You can upload other third-party
libraries with your application, as
long as they are implemented in pure
Python and do not require any
unsupported standard library modules.
So, even if it doesn't exist by default you can (potentially) include it yourself. (I say potentially because I don't know if the Python zip library requires any "unsupported standard library modules".

Categories

Resources