Skip to content

Instantly share code, notes, and snippets.

@gargomoma
Last active May 5, 2020 08:35
Show Gist options
  • Save gargomoma/b58348e06e6c0ba743bd099450d368ea to your computer and use it in GitHub Desktop.
Save gargomoma/b58348e06e6c0ba743bd099450d368ea to your computer and use it in GitHub Desktop.
A simple Python Class to handle basic interactions with GDrive (APIv3).
#Based on: https://github.com/samlopezf/google-drive-api-tutorial/blob/master/google-drive-api-tutorial-project/main.py
from __future__ import print_function
import os, io
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from apiclient.http import MediaFileUpload, MediaIoBaseDownload
class gDrive():
"""Connects to G-Drive using Drive v3 API.
uploadFile('unnamed.jpg','C:\\folder\\folder2\\unnamed.jpg','image/jpeg')
downloadFile('1Knxs5kRAMnoH5fivGeNsdrj_SIgLiqzV','google.jpg')
createFolder('Google')
searchFile(10,"name contains 'Getting'")
https://developers.google.com/resources/api-libraries/documentation/drive/v3/python/latest/drive_v3.files.html
"""
def pickleAuth(self,SCOPES=['https://www.googleapis.com/auth/drive'],
credentialsjson='credentials.json',tokenpickle='token.pickle'):
# If modifying these scopes, delete the file token.pickle.
creds = None
# The file token.pickle stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists( tokenpickle ):
with open( tokenpickle , 'rb') as token:
creds = pickle.load(token)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
credentialsjson , SCOPES)
creds = flow.run_local_server()
# Save the credentials for the next run
with open( tokenpickle , 'wb') as token:
pickle.dump(creds, token)
return creds
def userAuth(self,scopes=['https://www.googleapis.com/auth/drive'],
credentials='credentials.json',authorized='authorized_user.json'):
from google.oauth2.credentials import Credentials
from google.oauth2.service_account import (Credentials as ServiceAccountCredentials,)
from google_auth_oauthlib.flow import InstalledAppFlow
if os.path.exists(authorized):
return Credentials.from_authorized_user_file(authorized)
else:
flow = InstalledAppFlow.from_client_secrets_file( credentials , scopes)
creds = flow.run_local_server()
with open(authorized, 'w') as f:
f.write(creds.to_json('token'))
return creds
def __init__(self):
self.drive_service = None
def authorize( self, credentials ):
self.drive_service = build('drive', 'v3', credentials=credentials)
def listFiles(self):
results = self.drive_service.files().list(
pageSize=20, fields="nextPageToken, files(id, name)").execute()
items = results.get('files', [])
if not items:
print('No files found.')
else:
for item in items:
print(u'{0} ({1})'.format(item['name'], item['id']))
return items
def downloadFile(self,file_id,filepath):
request = self.drive_service.files().get_media(fileId=file_id)
##get_media is not appearing on any documentation, we need namereq for getting the metadata
namereq = self.drive_service.files().get(fileId=file_id, supportsTeamDrives=True).execute()
print('Pulling',namereq['name'])
fh = io.BytesIO()
downloader = MediaIoBaseDownload(fh, request)
done = False
while done is False:
status, done = downloader.next_chunk()
print("Download %d%%." % int(status.progress() * 100))
with io.open( filepath + namereq['name'] ,'wb') as f:
fh.seek(0)
f.write(fh.read())
return done
def uploadFile(self,filename,filepath,mimetype=None):
import magic #https://github.com/ahupp/python-magic
file_metadata = {'name': filename}
if mimetype == None:
mimetype = magic.from_file(filepath, mime=True)
media = MediaFileUpload(filepath,
mimetype=mimetype)
file = self.drive_service.files().create(body=file_metadata,
media_body=media,
fields='id').execute()
print('File ID: %s' % file.get('id'))
return file.get('id')
def createFolder(self,name):
file_metadata = {
'name': name,
'mimeType': 'application/vnd.google-apps.folder'
}
file = self.drive_service.files().create(body=file_metadata,
fields='id').execute()
print ('Folder ID: %s' % file.get('id'))
return file.get('id')
def searchFile(self,query,size=1,TeamDriveId=None,folderId=None):
corporaParam=None
if TeamDriveId != None:
corporaParam = 'drive'
results = self.drive_service.files().list(
pageSize=size,
fields="nextPageToken, files(id, name, kind,modifiedTime,mimeType,parents,driveId)",
q=query,supportsAllDrives=True,
includeItemsFromAllDrives=True,
driveId=TeamDriveId,corpora=corporaParam).execute()
items = results.get('files', [])
if not items:
print('No files found.')
else:
for item in items:
print('{0} ({1})'.format(item['name'], item['id']))
print(item)
return items
def searchFileByName(self,fileName,size=1,TeamDriveId=None,folderId=None):
corporaParam=None
query = str("name contains '%s'" % fileName)
if TeamDriveId != None:
corporaParam = 'drive'
results = self.drive_service.files().list(
pageSize=size,
fields="nextPageToken, files(id, name, kind,modifiedTime,mimeType,parents,driveId)",
q=query,supportsAllDrives=True,
includeItemsFromAllDrives=True,
driveId=TeamDriveId,corpora=corporaParam).execute()
items = results.get('files', [])
if not items:
print('No files found.')
return None
else:
itemId = None
for item in items:
if (item['name'] == fileName):
for folder in item['parents']:
if folder == folderId:
print('{0} - ({1})'.format(item['name'], item['id']))
itemId = str(item['id'])
if itemId == None:
print('No files found by your criteria.')
return itemId
def move_file(self, file_id, final_drive_path, copy=False):
#https://stackoverflow.com/questions/40725769/move-a-file-with-google-drive-api
"""Moves a file in Google Drive from one location to another.
service: Drive API service instance.
'filename' (string): file path on local machine, or a bytestream
to use as a file.
'init_drive_path' (string): the file path the file was initially in on Google
Drive (in <folder>/<folder>/<folder> format).
'drive_path' (string): the file path to move the file in on Google
Drive (in <folder>/<folder>/<folder> format).
'copy' (boolean): file should be saved in both locations
Returns nothing.
"""
#if init_drive_path == 'root':
# get_root_id = drive.drive_service.files().get(fileId=init_drive_path).execute()
# folder_id = namereq['id']
if not file_id or not final_drive_path:
raise Exception('Did not find file specefied: {}/{}'.format(file_id, final_drive_path))
file = self.drive_service.files().get(fileId=file_id,
fields='parents').execute()
previous_parents = ",".join(file.get('parents'))
if copy:
previous_parents = ''
file = self.drive_service.files().update(fileId=file_id,
supportsTeamDrives=True,
addParents=final_drive_path,
removeParents=previous_parents,
fields='id, parents').execute()
return True
def upload2Folder(self,fileName,destfolder,MimeType=None):
notUploaded = True
while notUploaded is True:
try:
driveFileId = self.uploadFile(filename = fileName,filepath = fileName,mimetype=MimeType)
if self.move_file(driveFileId,destfolder):
os.remove(fileName)
notUploaded = False
except ConnectionAbortedError:
print('ConnectionAbortedError: Re-connecting again...')
self.connect2service()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment