0

I have a snippet of code that creates files in a for loop in a temporary directory.

However, my goal is to zip them up but instead of storing the zipped file on the disk, I would like to store it in a variable. This is my code: https://pastebin.com/ZTbghf8S

This code would be in a class and I would give it to the user from a Flask web server like this:

@app.route("/download_file")
def downloadfile():
    Object = MyClass(variable='random_variable')
    return Response(Object.getFile()['object'])

How would I do that?

Robert
  • 113
  • 6

1 Answers1

0

I had previously answered a question to do something similar to this, although it seems to have been deleted. I came up with this gist which was themed around zipping up PIL images, but the concept is similar.

The objective was to build a ZIP file in memory, and serve with Flask without writing it to disc on the server.

To adapt this to your code you might make a function which processes ans and returns a tuple, where the first item is the output path, and the second item is a BytesIO object.

import io, os

def process_individual(ans):
        codepath = ans.find("a", {"class": "panel-group-toggle"}).text.strip().split("/") #File path and name
        codeans = ans.find("code", {"class": "brush"}).text #The answer

        # return a compatible tuple
        return ( os.path.join(q,  f'{exer_id}_template', *codepath),
                 io.BytesIO(codeans.encode(encoding='UTF-8') )

And define the business function which creates in the in memory zip, based on a list of tuples. This should take the filepath from the first item, and create that folder structure within the zip file accordingly.

import zipfile

def get_zip_buffer(list_of_tuples):
    zip_buffer = io.BytesIO()
    
    # https://stackoverflow.com/a/44946732 <3   
    with zipfile.ZipFile(zip_buffer, "a", zipfile.ZIP_DEFLATED, False) as zip_file:
        for file_name, data in list_of_tuples:
            zip_file.writestr(file_name, data.read())

    zip_buffer.seek(0)
    return zip_buffer

To pull this together within Flask, you might have a download route like:

@app.route('/downloader')
def download():
    list_of_tuples = [process_individual(a) for a in individual_ans]
    buff = get_zip_buffer(list_of_tuples)
    
    return send_file(buff,
                     mimetype='application/zip',
                     as_attachment=True,
                     attachment_filename='memoryzip.zip')

I haven't tested this with your input data, so it may need slight tweaking. Hopefully this helps.

v25
  • 7,096
  • 2
  • 20
  • 36