Zip and server multiple in-memory files - python

I am currently using the code below to generate a word document and then serve this on the web using cherrypy.
tpl.get_docx().save(iostream)
cherrypy.response.headers['Content-Type'] = (
'application/vnd.openxmlformats-officedocument'
'.wordprocessingml.document'
)
cherrypy.response.headers['Content-Disposition'] = (
'attachment; filename={fname}.docx'.format(
fname='SP' + kwargs['sp'] + '-'+ kwargs['WO'] + ' ' + kwargs['site'] + ' - ' + 'RPC Report' +'.docx'
)
)
iostream.seek(0)
return file_generator(iostream)
I plan to create more documents, then zip them in-memory and then serve them on the web. how could this be implmented, i have tried using the zipfile library, it seems complicated zipping in-memory files.
the following example i google around may solve my issue, but not sure how to use it.
import zipfile
import StringIO
zipped_file = StringIO.StringIO()
with zipfile.ZipFile(zipped_file, 'w') as zip:
for i, file in enumerate(files):
file.seek(0)
zip.writestr("{}.csv".format(i), file.read())
zipped_file.seek(0)

After hours of persistance, i got this working, yeahhhh
iostream = BytesIO()
tpl.get_docx().save(iostream)
iostream1 = BytesIO()
tpl1.get_docx().save(iostream1)
zip_output = StringIO.StringIO()
file = zipfile.ZipFile(zip_output, "w")
file.writestr("test.docx", iostream.getvalue())
file.writestr("test1.docx", iostream1.getvalue())
file.close()
cherrypy.response.headers['Content-Type'] = 'application/zip'
cherrypy.response.headers['Content-Disposition'] = 'attachment; filename="test.zip"'
return zip_output.getvalue()

Related

Django: Download a temporary image

I am currently trying to create a function within a Django app to download a pandas dataframe as an image. I wanted to create the image as a temporary file, download it, then delete it. Does anyone know how to integrate tempfile into this code?
Views.py
def download_png(request, study):
Names(study) #Funciton to get (name) variable
Retrieve(study) #Function to get (data) variable
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
pngfilename = str(name) + "_" + str(current_time) + ".png"
temp = tempfile.NamedTemporaryFile(suffix=".png")
fig = temp.write(df2img.plot_dataframe(data))
filepath = temp.name
response = HttpResponse(df2img.save_dataframe(fig=fig, filename=filepath), content_type=mimetypes.guess_type(filepath))
response['Content-Disposition'] = "attachment; filename=%s" % pngfilename
return response
Update 06/30/22:
I had a lot of difficulty integrating the tempfile module because it requires data to be converted to bytes-like objects. Instead I simply resolved on deleting the file after creating it.
def download_png(request, study):
Names(study)
Retrieve(study)
pngfilename = str(name) + "_" + str(current_time) + ".png"
mime_type, _ = mimetypes.guess_type(pngfilename)
fig = df2img.plot_dataframe(data)
df2img.save_dataframe(fig=fig, filename=pngfilename)
response = FileResponse(open(pngfilename, 'rb'), content_type=mime_type)
response['Content-Disposition'] = "attachment; filename=%s" % pngfilename
os.remove(pngfilename)
return response
This is how you can use the tempfile library:
tempfile = tempfile.mktemp(suffix='.png')
with open(temp, 'w') as f:
f.write(df2img.plot_dataframe(data))
do_something_with_your_file(temp)
os.unlink(temp)
Edit: was just reading the tempfile documentation and apparently tempfile.mktemp is prone to race conditions, so you should either use tempfile.mkstemp like:
fd, tempf = tempfile.mkstemp()
Or there is a context manager:
with tempfile.NamedTemporaryFile() as tmp:
with open(tmp.name, 'w') as f:
f.write('some data')
# do something with your tempfile file
And then it will automatically delete the tempfile afterwards.

Python convert list of strings to zip archive of files

In a python script, I have a list of strings where each string in the list will represent a text file. How would I convert this list of strings to a zip archive of files?
For example:
list = ['file one content \nblah \nblah', 'file two content \nblah \nblah']
I have tried variations of the following so far
import zipfile
from io import BytesIO
from datetime import datetime
from django.http import HttpResponse
def converting_strings_to_zip():
list = ['file one content \nblah \nblah', 'file two content \nblah \nblah']
mem_file = BytesIO()
with zipfile.ZipFile(mem_file, "w") as zip_file:
for i in range(2):
current_time = datetime.now().strftime("%G-%m-%d")
file_name = 'some_file' + str(current_time) + '(' + str(i) + ')' + '.txt'
zip_file.writestr(file_name, str.encode(list[i]))
zip_file.close()
current_time = datetime.now().strftime("%G-%m-%d")
response = HttpResponse(mem_file, content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename="'str(current_time) + '.zip"'
return response
But just leads to 0kb zip files
Was able to solve it by swapping a couple of lines (not resorting to saving the lists as files, then zipping files on the hard drive of the server, then loading the zip into memory and piping to the client like current answers suggest).
import zipfile
from io import BytesIO
from datetime import datetime
from django.http import HttpResponse
def converting_strings_to_zip():
list = ['file one content \nblah \nblah', 'file two content \nblah \nblah']
mem_file = BytesIO()
zip_file = zipfile.ZipFile(mem_file, 'w', zipfile.ZIP_DEFLATED)
for i in range(2):
current_time = datetime.now().strftime("%G-%m-%d")
file_name = 'some_file' + str(current_time) + '(' + str(i) + ')' + '.txt'
zip_file.writestr(file_name, str.encode(list[i]))
zip_file.close()
current_time = datetime.now().strftime("%G-%m-%d")
response = HttpResponse(mem_file.getvalue(), content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename="'str(current_time) + '.zip"'
return response
You could simply write each of the string into it's own file inside a folder you mkdir and then zip it with the zipfile library or by using shutil which is part of python standard library.
Once you have written the string into a directory of your choice you can do:
import shutil
shutil.make_archive('strings_archive.zip', 'zip', 'folder_to_zip')
reference.

Error opening photos stored in zip file in Django

I'm going to create a zip file from some of the image files stored on my server.
I've used the following function to do this:
def create_zip_file(user, examination):
from lms.models import StudentAnswer
f = BytesIO()
zip = zipfile.ZipFile(f, 'w')
this_student_answer = StudentAnswer.objects.filter(student_id=user.id, exam=examination)
for answer in this_student_answer:
if answer.answer_file:
answer_file_full_path = answer.answer_file.path
fdir, fname = os.path.split(answer_file_full_path)
zip.writestr(fname, answer_file_full_path)
zip.close() # Close
zip_file_name = "student-answers_"+ str(examination.id)+"_" + str(user.id) + "_" + date=datetime.datetime.now().strftime("%Y-%m-%d-%H-%M") + '.zip'
response = HttpResponse(f.getvalue(), content_type="application/x-zip-compressed")
response['Content-Disposition'] = 'attachment; filename=%s' % zip_file_name
return response
Everything is fine and all photos are made in zip file but there is only one problem.
The problem is that the photos won't open and this error will appear in Windows:
Its look like we don't support this file format.
What is wrong with my codes?
To append data from file you have to use
write(filename)
Using writestr(filename) you add only string from variable filename but not from file.

How to upload url to s3 bucket using StringIO and put_object method with boto3

I need to upload URLs to an s3 bucket and am using boto3. I thought I had a solution with this question: How to save S3 object to a file using boto3 but when I go to download the files, I'm still getting errors. The goal is for them to download as audio files, not URLs. My code:
for row in list_reader:
media_id = row['mediaId']
external_id = row['externalId']
with open('10-17_res1.csv', 'a') as results_file:
file_is_empty = os.stat('10-17_res1.csv').st_size == 0
results_writer = csv.writer(
results_file, delimiter = ',', quotechar = '"'
)
if file_is_empty:
results_writer.writerow(['fileURL','key', 'mediaId','externalId'])
key = 'corpora/' + external_id + '/' + external_id + '.flac'
bucketname = 'my_bucket'
media_stream = media.get_item(media_id)
stream_url = media_stream['streams'][0]['streamLocation']
fake_handle = StringIO(stream_url)
s3c.put_object(Bucket=bucketname, Key=key, Body=fake_handle.read())
My question is, what do I need to change so that the file is saved in s3 as an audio file, not a URL?
I solved this by using the smart_open module:
with smart_open.open(stream_url, 'rb',buffering=0) as f:
s3.put_object(Bucket=bucketname, Key=key, Body=f.read())
Note that it won't work without the 'buffering=0' parameter.

Creating a zip file stream in python with Cherry Py?

I would like to create a zip file on the fly to serve to users through Cherry Py: I tried the following code that produced an invalid zip file:
#cherrypy.expose
def ZipDir(self, *args):
path = "\\".join(args)
output = StringIO.StringIO()
file = zipfile.ZipFile(output, "w")
zip_filename = path + ".zip"
cherrypy.response.headers['Content-Type'] = 'application/zip'
cherrypy.response.headers['Content-Disposition'] = 'attachment; filename="%s"' % (zip_filename,)
dir = filter(lambda x: x.lower().endswith(".mp3") or not ("." in x), os.listdir("G:\\Music\\" + path))
for f in dir:
file.write("G:\\Music\\" + path + "\\" + f,f,zipfile.ZIP_DEFLATED)
return output.getvalue()
The file size looks about right, but it doesnt register as a zip file with any acrhicing applications.
I forgot to call file.close() before the return. That fixed it!

Categories

Resources