Skip to content

Instantly share code, notes, and snippets.

@rsyring
Created May 26, 2022 04:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rsyring/c099ca61b9e5eeb1537829f62b733e7f to your computer and use it in GitHub Desktop.
Save rsyring/c099ca61b9e5eeb1537829f62b733e7f to your computer and use it in GitHub Desktop.
Write CSV files to a Zip file and serve with Falcon (Python)
import csv
import io
import tempfile
import zipfile
import falcon
GB = 1024 ^ 3
MEM_MAX_SIZE = 1 * GB
def add_csv(zf, fname, rows):
csv_fo = tempfile.SpooledTemporaryFile(max_size=MEM_MAX_SIZE, mode='w', encoding='utf-8')
cw = csv.writer(csv_fo)
for r in rows:
cw.writerow(r)
csv_fo.seek(0)
zf.writestr(fname, csv_fo.read())
def create_zip():
zip_fo = tempfile.SpooledTemporaryFile(max_size=MEM_MAX_SIZE, mode='w+b')
with zipfile.ZipFile(zip_fo, 'w', compression=zipfile.ZIP_DEFLATED) as zf:
add_csv(zf, 'letters.csv', (
('a', 'b', 'c'),
('d', 'e', 'f'),
))
add_csv(zf, 'numbers.csv', (
('1', '2', '3'),
('4', '5', '6'),
))
zip_fo.seek(0)
return zip_fo
class Index:
def on_get(self, req, resp):
resp.content_type = falcon.MEDIA_HTML # Default is JSON, so override
resp.text = 'Hello World!'
resp.text += '<a href="/csv">example csv</a>'
class CSV:
def on_get(self, req, resp):
resp.content_type = 'application/zip'
resp.set_header('Content-Disposition', 'attachment; filename=data.zip')
resp.stream = create_zip()
# falcon.App instances are callable WSGI apps
# in larger applications the app is created in a separate file
app = application = falcon.App()
app.add_route('/', Index())
app.add_route('/csv', CSV())
@rsyring
Copy link
Author

rsyring commented May 26, 2022

Can be ran with: $ gunicorn --reload app

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment