4

I have a silly question about PyDrive. I try to make a REST API using FastAPI that will upload an Image to Google Drive using PyDrive. Here is my code:

from fastapi import FastAPI, File
from starlette.requests import Request
from starlette.responses import JSONResponse
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive

app = FastAPI()


@app.post('/upload')
def upload_drive(img_file: bytes=File(...)):
    g_login = GoogleAuth()
    g_login.LoadCredentialsFile("google-drive-credentials.txt")

    if g_login.credentials is None:
        g_login.LocalWebserverAuth()
    elif g_login.access_token_expired:
        g_login.Refresh()
    else:
        g_login.Authorize()
    g_login.SaveCredentialsFile("google-drive-credentials.txt")
    drive = GoogleDrive(g_login)
 
    file_drive = drive.CreateFile({'title':'test.jpg'})
    file_drive.SetContentString(img_file) 
    file_drive.Upload()

After try to access my endpoint, i get this error:

file_drive.SetContentString(img_file)
  File "c:\users\aldho\anaconda3\envs\fastai\lib\site-packages\pydrive\files.py", line 155, in SetContentString
    self.content = io.BytesIO(content.encode(encoding))
AttributeError: 'bytes' object has no attribute 'encode'

What should i do to complete this very simple task?

thanks for your help!

**

UPDATED - SOLVED

**

Thanks for answer and comment from Stanislas Morbieu and the pydrive documentation example, here is my updated and working code:

from fastapi import FastAPI, File
from starlette.requests import Request
from starlette.responses import JSONResponse
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from PIL import Image
import os

app = FastAPI()


@app.post('/upload')
def upload_drive(filename, img_file: bytes=File(...)):
    try:
        g_login = GoogleAuth()
        g_login.LocalWebserverAuth()
        drive = GoogleDrive(g_login)
     
        file_drive = drive.CreateFile({'title':filename, 'mimeType':'image/jpeg'})
        
        if not os.path.exists('temp/' + filename):
            image = Image.open(io.BytesIO(img_file))
            image.save('temp/' + filename)
            image.close()

        file_drive.SetContentFile('temp/' + filename)
        file_drive.Upload()

        return {"success": True}
    except Exception as e:
        print('ERROR:', str(e))
        return {"success": False}

Thanks guys

2 Answers2

4

SetContentString requires a parameter of type str not bytes. Here is the documentation:

Set content of this file to be a string.

Creates io.BytesIO instance of utf-8 encoded string. Sets mimeType to be ‘text/plain’ if not specified.

You should therefore decode img_file (of type bytes) in utf-8:

file_drive.SetContentString(img_file.decode('utf-8'))
Stanislas Morbieu
  • 1,721
  • 7
  • 11
  • Hello @stanislas-morbieu, thanks for your answer, however after try your code, i get this error: `UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte` – Aldo Suhartono Putra Oct 27 '19 at 15:23
  • 1
    I forgot to consider this. I think you cannot use ``SetContentString`` then. ``SetContentFile`` might be the only option: you might have to save it to a temporary file though, in order to pass the filename as argument to ``SetContentFile``. – Stanislas Morbieu Oct 27 '19 at 23:20
  • Thanks, i also not know about this, i will post my updated and working code. Thank you very much for your answer – Aldo Suhartono Putra Oct 28 '19 at 02:38
1

Use file_drive.SetContentFile(img_path)

This solved my problem

Lakhani Aliraza
  • 435
  • 6
  • 8