I have a Dash application that I would like the user to download a zip folder from. The following reproducible Python code creates an app that downloads a zip folder with some dummy tables in csv
format:
import dash
from dash.dependencies import Output, Input
import dash_html_components as html
import dash_core_components as dcc
import os
import zipfile
import tempfile
# helper function for closing temporary files
def close_tmp_file(tf):
try:
os.unlink(tf.name)
tf.close()
except:
pass
# app layout
app = dash.Dash(prevent_initial_callbacks=True)
app.layout = html.Div(
[
html.Button("Download ZIP folder with dummy csv", id="btn_zip"),
dcc.Download(id="download-dataframe-zip"),
]
)
# sample dataframes for zipping
import pandas as pd
df1 = pd.DataFrame({"a": [1, 2, 3, 4], "b": [2, 1, 5, 6], "c": ["x", "x", "y", "y"]})
df2 = pd.DataFrame({"d": [6, 2, 3, 9], "e": [3, 2, 7, 8], "f": ["t", "v", "s", "b"]})
df_dict = {"df1":df1,"df2":df2}
# app callbacks
@app.callback(
Output("download-dataframe-zip", "data"),
Input("btn_zip", "n_clicks"),
prevent_initial_call=True,
)
def func(n_clicks):
zip_dict = {}
# add dataframes to zip file using temporary files
for name,df in df_dict.items():
df_temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.csv')
df.to_csv(df_temp_file.name)
df_temp_file.flush()
zip_dict[name] = df_temp_file.name
zip_tf = tempfile.NamedTemporaryFile(delete=False, suffix='.zip')
zf = zipfile.ZipFile(zip_tf, mode='w', compression=zipfile.ZIP_DEFLATED)
for name,fn in zip_dict.items():
zf.write(fn,f"{name}.csv")
# close uploaded temporary files
zf.close()
zip_tf.flush()
zip_tf.seek(0)
[close_tmp_file(_tf) for _tf in zip_dict]
close_tmp_file(zip_tf) # the app works if I remove this
return dcc.send_file(zip_tf.name,filename="mydfs.zip")
if __name__ == "__main__":
app.run_server(debug=True)
The app works locally, but once its deployed I get the following error message :
FileNotFoundError: [Errno 2] No such file or directory: '/opt/rstudio-connect/mnt/tmp/tmp76hltf2h.zip'
It seems like it's trying to access the temporary file but it may have already been deleted before its returns .
The problem is solved if I don't close the temporary file (remove line close_tmp_file(zip_tf)
prior to the return dcc.send_file(zip_tf.name,filename="mydfs.zip")
command
My concern is that this temporary stays in the RSConnect server and won't be deleted/closed. Or perhaps it will when the app is closed by the user?
Thanks for the help in advanced!