16

So far I can upload file to the folder if it exists. I can't figure out a way to create one though. So if the folder does not exist, my script dies.

import sys
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive

gpath = '2015'
fname = 'Open Drive Replacements 06_01_2015.xls'

gauth = GoogleAuth()
gauth.LocalWebserverAuth()
drive = GoogleDrive(gauth)

file_list = drive.ListFile({'q': "'root' in parents and trashed=false"}).GetList()
for file1 in file_list:
    if file1['title'] == gpath:
        id = file1['id']

file1 = drive.CreateFile({'title': fname, "parents":  [{"kind": "drive#fileLink","id": id}]})
file1.SetContentFile(fname)
file1.Upload()

Can you please help me modify the above code to create folder gpath if it does not exist?

Gurupad Hegde
  • 2,155
  • 15
  • 30
Akshay Kalghatgi
  • 423
  • 1
  • 4
  • 11
  • 2
    According to [the documentation](https://developers.google.com/drive/web/folder): "A folder is a file with the MIME type `application/vnd.google-apps.folder` and with no extension." So you would create the folder in much the same way you're already creating the file. – kindall Jun 01 '15 at 23:58
  • possible duplicate of [How can I create a new folder with Google Drive API in Python?](http://stackoverflow.com/questions/13558653/how-can-i-create-a-new-folder-with-google-drive-api-in-python) – Gurupad Hegde Jun 02 '15 at 02:47

3 Answers3

15

Based on the documentation, it should be

file1 = drive.CreateFile({'title': fname, 
    "parents":  [{"id": id}], 
    "mimeType": "application/vnd.google-apps.folder"})

Update: As of Apr 2020, documentation (v3) has been updated with API docs and shows:

folder_id = '0BwwA4oUTeiV1TGRPeTVjaWRDY1E'
file_metadata = {
    'name': 'photo.jpg',
    'parents': [folder_id]
}
media = MediaFileUpload('files/photo.jpg',
                        mimetype='image/jpeg',
                        resumable=True)
file = drive_service.files().create(body=file_metadata,
                                    media_body=media,
                                    fields='id').execute()
print 'File ID: %s' % file.get('id')
Gurupad Hegde
  • 2,155
  • 15
  • 30
  • 3
    For completeness, you will also need to call `.Upload()` on `file1` after the above to actually commit the operation. `file1['id']` will then contain the `id` of the created folder. –  Mar 29 '16 at 12:47
  • It does not work for me. the response I get is `GoogleDriveFile({'title': 'TEST-SOLAL-API', 'mimeType': 'application/vnd.google-apps.folder'})` but it does not create any folder I check on the source code and it says `This method would not upload a file to GoogleDrive.` Am I missing something? – Solal Dec 12 '19 at 01:08
  • @Solal - documentation must've been updated. The `CreateFile` method is no longer referred to in the documentation referenced. – alofgran Apr 24 '20 at 16:18
  • 1
    @Solal @alofgran hey don't this is correct, CreateFile still works for me both for creating files and for folders. @Solan, did you call `Upload()` on the object returned by create file? – Kevin R. Jan 22 '21 at 17:43
  • I was looking for something similar, but in Go, and this doesn't work because it will create every time the folder again. Now the documentation doesn't explain how to look for files in a particular (multi-level) sub-folder ... At least in Go there is no ListFile for a particular subdirectory ... one can check if some name is in one of the parents ... but that would be something different than the exact folder. There must be a way, but it's not documented in the link you sent :( – Jan Jun 21 '21 at 18:19
2

I had the same problem and stumbled over this issue. Here is the code I came up with:

import os

from pydrive2.auth import GoogleAuth
from pydrive2.drive import GoogleDriv

class GoogleDriveConnection:

    _gauth = None
    _drive = None

    @staticmethod
    def get() -> GoogleDrive:
        """
        This will return a valid google drive connection

        :return: A valid GoogleDrive connection
        """
        if GoogleDriveConnection._gauth is None or GoogleDriveConnection._drive == None:
            GoogleDriveConnection._gauth = GoogleAuth()
            GoogleDriveConnection._gauth.LoadCredentialsFile(os.path.join(os.path.dirname(__file__), "mycredentials.txt"))  # this assume you have saved your credentials, like this: gauth.SaveCredentialsFile("mycredentials.txt")
            GoogleDriveConnection._drive = GoogleDrive(GoogleDriveConnection._gauth)
        return GoogleDriveConnection._drive

    @staticmethod
    def upload_image(image_path: str, folder_path: str) -> str:
        """
        Uploads an image to the google drive, and returns the https path to it

        :param image_path: Path to the image, has to end in an image type else the type won't be guessed correctly
        :param folder_path: The folder path it should have in the google drive (to structure the data there)
        :return: The https path to the uploaded image file, will be empty if the image_path is invalid
        """
        if os.path.exists(image_path):
            google_drive = GoogleDriveConnection.get()
            image = google_drive.CreateFile()
            image.SetContentFile(image_path)  # load local file data into the File instance
            # to remove the path from the filename
            image["title"] = os.path.basename(image_path)
            if folder_path:
                parent_id = GoogleDriveConnection.get_folder_id(folder_path)
                image["parents"] = [{"id": parent_id}]
            image.Upload()  # creates a file in your drive with the name
            return "https://drive.google.com/uc?id=" + str(image['id'])
        return ""

    @staticmethod
    def get_folder_id(folder_path: str, element_index=0, last_parent=None) -> str:
        """
        Gets the id of the given folder path, this function will create the folders, if they do not exist, so it will
        always return a valid id, the folder_path elements can be separated like normals via a slash.

        :param folder_path: Given folder path
        :param element_index: Element index needed for recursive creation of the element
        :param last_parent: Last parent only needed for recursive creation of the folder hierarchy
        :return: The id to the last folder in the path
        """
        folder_path_elements = folder_path.split("/")
        if len(folder_path_elements) == element_index:
            return last_parent
        folder_list = GoogleDriveConnection.get().ListFile({'q': "mimeType='application/vnd.google-apps.folder' and trashed=false"}).GetList()
        current_folder_name = folder_path_elements[element_index]
        for item in folder_list:
            if item['title'] == current_folder_name and item["parents"][0] == last_parent:
                return GoogleDriveConnection.get_folder_id(folder_path, element_index + 1, item['id'])
        # not in the list -> folder has to be created
        file_metadata = {'title': current_folder_name, 'mimeType': 'application/vnd.google-apps.folder'}
        if last_parent is not None:
            file_metadata['parents'] = [{"id": last_parent}]
        new_folder = GoogleDriveConnection.get().CreateFile(file_metadata)
        new_folder.Upload()
        return GoogleDriveConnection.get_folder_id(folder_path, element_index + 1, new_folder["id"])

This enables you to load up images to Google drive and if you call get_folder_id it will give you the id of that folder, if the folder does not exist it will be created.

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
M. Denninger
  • 151
  • 9
0

the answer above didnt work for me, this did work. It returns the id of the newly created folder

def createRemoteFolder(folderName, parentID ):



    folderlist = (drive.ListFile  ({'q': "mimeType='application/vnd.google-apps.folder' and trashed=false"}).GetList())

    titlelist =  [x['title'] for x in folderlist]
    if folderName in titlelist:
        for item in folderlist:
            if item['title']==folderName:
                return item['id']
  
    file_metadata = {
        'title': folderName,
        'mimeType': 'application/vnd.google-apps.folder',
        'parents': [{"id": parentID}]  
    }
    file0 = drive.CreateFile(file_metadata)
    file0.Upload()
    return file0['id']
rightsized
  • 130
  • 1
  • 8