Hi, new to Anvil and would appreciate advice.
I’m trying to read a file directly from an API (can be CSV, XLSX or ZIP) and save it to the user’s local machine. So far I’ve tried
@anvil.server.callable
def DownloadFile():
filename = 'test.csv'
url = base_url + '/file/' + filename
headers={'Content-Type': 'application/octet-stream'}
response = anvil.http.request(url, method="GET", headers=headers, username=username, password=password)
return response
on the server.
Then in a form’s event handler
def button_1_click(self, **event_args):
r = anvil.server.call('DownloadFile')
r1 = BlobMedia(r.content_type, r.get_bytes(), name='test.csv')
anvil.media.download(r1)
This works for CSV files, but not for XLSX or ZIP files, which appear to have a lot of extra characters inserted. Is there a way to keep files unchanged here?
In addition, is there a way to invoke the ‘Save As’ dialog for the file so the user can choose where to put it etc?
Any tips much appreciated.
Andrew Colin.
ianb
August 24, 2023, 1:19pm
2
What happens if you just:
def button_1_click(self, **event_args):
r = anvil.server.call('DownloadFile')
anvil.media.download(r)
The result of an anvil.http.request()
should already be a media object.
If that does not work, try putting r
in a link and see if that makes a difference. (It shouldn’t)
1 Like
Calling anvil.http.request appears to corrupt an existing media object.
For instance, I ran
@anvil.server.callable
def DownloadFile():
filename = 'FTREER.jpg'
url = base_url + '/file/' + filename
response = anvil.http.request(url, method="GET", json=False, username=username, password=password)
print (response.length)
return response
The size of the jpg file is 99 kb on my server, but is 182 kb after running the above code. The issue also applies to XLSX and ZIP files. I suspect the issue is something to do with UTF-8 encoding as the downloaded file has lots of ‘\x’ characters.
I’ve tried setting
headers={'content-type': 'application/octet-stream'}
and
headers={'content-type': 'Content-type: image/jpeg'}
but no luck.
I can download the file from stand-alone Python code using the requests library, so I know the file mechanics are working OK:
def DownloadFile (filename, username):
url = base_url + '/file/' + filename
response = requests.get(url, stream=True, auth=HTTPBasicAuth(username, password))
with open(filename, 'wb') as f:
for chunk in response.iter_content(chunk_size = 1024):
f.write(chunk)
f.close()
print(response.status_code, 'Downloaded', filename)
return response.status_code
Can you suggest a fix or a work-around?
Thanks
Andrew.
Can you please flag this as a bug (‘Calling anvil.http.request appears to corrupt an existing media object ’). I’ve been through the forums several times but have been unable to find a fix.
Thanks!
Andrew.
For anyone else who has this issue, here is a workaround I found, using the requests library and the tmp directory, rather than anvil.http.request .
On the server:
@anvil.server.callable
def DownloadFile():
filename = 'test.zip'
url = base_url + '/file/' + filename
response = requests.get(url, stream=True, auth=HTTPBasicAuth(username, password))
with open('/tmp/' + filename, 'wb') as f:
f.write (response.content)
f.close()
X_media = anvil.media.from_file('/tmp/' + filename, 'application/octet-stream', filename)
return X_media
On the client
def button_1_click(self, **event_args):
x_media =anvil.server.call('DownloadFile')
anvil.media.download(x_media)
I’d be keen to know whether there is a simpler way to do this.
A BlobMedia can be constructed from a byte string. If you can get a byte string from the requests object, then you should be able to bypass the temporary file.