2
votes

I try to download a Google Drive spreadsheet as an Excel file. As far as I can tell, the Google Drive API should make this very simple by just specifying a different mime type to the export_media request.

Based on the tutorial script I can successfully download the spreadsheet as CVS and Open Office sheet. Great!

However with the mime type set to application/vnd.openxmlformats-officedocument.spreadsheetml.sheet - as specified for MS Excel the downloader continues to read from the stream without ever stopping and without increasing the status progress.

The full script is here. To run, follow the instructions to create an app in the Google Drive API docs here

The offending code is here:

    file_id = 'my spreadsheet id'

    request = service.files().export_media(fileId=file_id, mimeType='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')

    fh = FileIO('data.xls', 'wb')
    downloader = MediaIoBaseDownload(fh, request)
    done = False
    while done is False:
        status, done = downloader.next_chunk()
        print("Download %d%%." % int(status.progress() * 100))

It continues to print Download 0% and never stops.

1
Is this the same behavior when you test across different machines? - AL.
Hi @AL. I don't know, to be honest. I only have one at hand. I could try running it in a container. If you are willing - maybe you could run it on your machine? Cheers - Dan Schien

1 Answers

1
votes

It turns out that the MediaBaseIODownload relies on 'content-rangeorcontent-length` being present to know when to stop.

  if 'content-range' in resp:
    content_range = resp['content-range']
    length = content_range.rsplit('/', 1)[1]
    self._total_size = int(length)
  elif 'content-length' in resp:
    self._total_size = int(resp['content-length'])

However, in a debugger I can see, they are not present in the response. Hence, it cannot not know when being done.

  if self._progress == self._total_size:
    self._done = True

The solution was to not run a partial download but to download in full:

request = service.files().export_media(fileId=file_id, mimeType='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
with open('data.xlsx', 'wb') as f:
    f.write(request.execute())