0

File creation is forbidden in Google App Engine standard applications.

Even tempfile is disabled, except for TemporaryFile which is aliased to StringIO. So I need to set content of drive file with a StringIO object.

The only suitable method I found is SetContentString().

But the method is expecting a utf-8 string and I get a decode exception -

UnicodeDecodeError: 'ascii' codec can't decode byte 0x89 in position 0: ordinal not in range(128)

My code

drive = GoogleDrive(get_drive_auth())
drive_file = drive.CreateFile()
drive_file.SetContentString(stringio_object.getvalue())

Is there a way I could set the content of a GoogleDrive object from StringIO object?

snakecharmerb
  • 47,570
  • 11
  • 100
  • 153
enf644
  • 584
  • 5
  • 14

2 Answers2

2

PyDrive's GoogleDriveFile.setContentString method expects to receive a unicode string as an argument, and an optional encoding - the default is UTF-8.

The method encodes the unicode string and uses the encoded string to initialise an io.BytesIO instance, like this:

content = io.BytesIO(input_string.encode('utf-8'))

You are initialising your StringIO instance with a UTF-8 encoded bytestring, and this is causing the error:

>>> s = u'ŋđŧ¶eŋŧ¶ß¶ŋŧ¶'.encode('utf-8')                                                                                                              
>>> sio = StringIO(s)                                                                                                                                 
>>> io.BytesIO(sio.getvalue().encode('utf-8'))                                                                                                
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 0: ordinal not in range(128)

To avoid the error, initialise the StringIO with a unicode string.

>>> s = u'ŋđŧ¶eŋŧ¶ß¶ŋŧ¶'.encode('utf-8')
>>> sio = StringIO(s.decode('utf-8'))
>>> io.BytesIO(sio.getvalue().encode('utf-8'))
<_io.BytesIO object at 0x7f36c0dc0bf0>

Python2's StringIO.StringIO accepts either unicode or bytestrings as input, which can cause to confusion in cases like this. io.StringIO will only accept unicode as input, so using io.StringIO may help to keep the distinction between unicode and bytestrings clearer in your code.

snakecharmerb
  • 47,570
  • 11
  • 100
  • 153
2

I got answer on GitHub.

It is not documented, but you can set content of GoogleDrive object directly

drive = GoogleDrive(get_drive_auth())
drive_file = drive.CreateFile()
drive_file.content = stringio_object
enf644
  • 584
  • 5
  • 14
  • How do you pass a Queue.Queue() 2.7, to this? The idea is to pass a 'data descriptor' that doesnt have the whole data in memory(bytesIO) or on the physical hdd(file). I'll even take a generator.... – Edo Edo Jul 29 '19 at 23:46