The OneDrive API has two types of uploads:-
- Simple Upload: For files < 4MB
- Resumable Upload: For files > 4MB
The code for both has been provided below
Note: The Resumable upload works for files with size upto 100MB. When I tried with files with size greater than that, the upload kept failing
Before executing this script, you need to have an App in the Azure AD with the following delegated permissions:-
- Sites.ReadWrite.All
- Files.ReadWrite
- Files.ReadWrite.All
You also have to set the Redirect URI of your app to https://login.microsoftonline.com/{azure_active_directory_id}/oauth2/token
.
You also need to generate a client secret key referred to as client_secret
in the program.
Note: Remember to copy and store your key somewhere safely as soon as you generate it. It will not be visible for long due to security reasons.
The Python requests package should be installed
import requests
import json
import os
class OneDriveAPI:
def __init__(self, app_id, client_secret, tenant_id):
self.app_id = app_id
self.client_secret = client_secret
self.tenant_id = tenant_id
self.access_token = None
self.refresh_token = None
def authorize(self, username, password):
url = f'https://login.microsoftonline.com/{self.tenant_id}/oauth2/token'
token_data = {
'grant_type': 'password',
'client_id': self.app_id,
'client_secret': self.client_secret,
'resource': 'https://graph.microsoft.com',
'scopes': ['Sites.ReadWrite.All','Files.ReadWrite.All','onedrive.readwrite', 'offline_access'],
'username': username,
'password': password,
}
token_r = requests.post(url, data=token_data)
self.access_token = token_r.json().get('access_token')
self.refresh_token = token_r.json().get('refresh_token')
def refresh_access_token(self):
url = f'https://login.microsoftonline.com/{self.tenant_id}/oauth2/token'
token_data = {
'grant_type': 'refresh_token',
'client_id': self.app_id,
'client_secret': self.client_secret,
'resource': 'https://graph.microsoft.com',
'scopes': ['onedrive.readwrite', 'offline_access'],
'refresh_token': self.refresh_token,
}
token_r = requests.post(url, data=token_data)
self.access_token = token_r.json().get('access_token')
self.refresh_token = token_r.json().get('refresh_token')
def simple_upload(self, file_name, content):
url = f'https://graph.microsoft.com/v1.0/me/drive/root:/{file_name}:/content'
headers = {
'Authorization': 'Bearer {}'.format(self.access_token),
'Content-Type': 'text/plain'
}
return requests.put(url=url, headers=headers, data=content)
def large_file_upload(self, file_name):
url = f'https://graph.microsoft.com/v1.0/me/drive/root:/{file_name}:/createUploadSession'
headers = {
'Authorization': 'Bearer {}'.format(self.access_token),
'Content-Type': 'application/json'
}
upload_session = requests.post(url=url, headers=headers).json()
with open(file_name, 'rb') as f:
total_file_size = os.path.getsize(file_name)
chunk_size = 327680
chunk_number = total_file_size//chunk_size
chunk_leftover = total_file_size - chunk_size * chunk_number
i = 0
while True:
chunk_data = f.read(chunk_size)
start_index = i*chunk_size
end_index = start_index + chunk_size
if not chunk_data:
break
if i == chunk_number:
end_index = start_index + chunk_leftover
headers = {'Content-Length':'{}'.format(chunk_size),'Content-Range':'bytes {}-{}/{}'.format(start_index, end_index-1, total_file_size)}
chunk_data_upload = requests.put(upload_session['uploadUrl'], data=chunk_data, headers=headers)
print(chunk_data_upload)
if chunk_data_upload.status_code == 401:
self.refresh_access_token()
chunk_data_upload = requests.put(upload_session['uploadUrl'], data=chunk_data, headers=headers)
print(chunk_data_upload.json())
i = i + 1
def main():
app_id = '{app_id}'
client_secret = '{client_secret_key}'
tenant_id = '{azure_active_directory_id}'
onedrive = OneDriveAPI(app_id, client_secret, tenant_id)
onedrive.authorize('{username}', '{password}')
# To upload a single file
content = 'This is the content for a sample file uploaded using OneDrive API'
print(onedrive.simple_upload('sample.txt', content))
# To loop over and upload all the files in a directory
for file_name in os.listdir('Path/To/Directory'):
with open('Path/To/Directory/' + file_name, 'r') as f:
content = f.read()
response = onedrive.simple_upload(file_name, content)
if response .status_code == 401:
onedrive.refresh_access_token()
onedrive.simple_upload(file_name, content)
# To upload the same content from a file 'base.txt' to 50000 files
with open('base.txt', 'r') as f:
content = f.read()
for i in range(1, 50001):
file_name = 'File' + str(i).zfill(5) + '.txt'
response = onedrive.simple_upload(file_name, content)
if response .status_code == 401:
onedrive.refresh_access_token()
onedrive.simple_upload(file_name, content)
# To upload files > 4MB
onedrive.large_file_upload('100MBfile.txt')
if __name__ == '__main__':
main()
To run the program, save the above code to a file and just execute the following command from command prompt/powershell/terminal:-
$ python file_name.py