Python Dropbox API - mikedorais/python_learning GitHub Wiki

Dropbox Python API

Notes on what I've learned about the Python Dropbox API

Complete Documentation

See: Dropbox Developer Blog

Note that if you create a temporary access code to use during development of the app, it is supposed to be kept secret. If you think you may have accidentally leaked it out or just want to be safe. You can revoke the token as follows:

dbx = dropbox.Dropbox('access token')
dbx. auth_token_revoke()

May want to look at this example application: Backup and Restore

Installing and importing the api

pip3 install dropbox
import dropbox

Uploading a file:

# open a dropbox with an access token
dbx = dropbox.Dropbox('YOUR_ACCESS_TOKEN')
# Get account information
dbx.users_get_current_account()
# List file items in folder
for entry in dbx.files_list_folder('').entries:
    print(entry.name)
# Upload a small file (150 MB or less)
text = 'Hello, World!' # For example just set a string and encode it as bytes
dbx.files_upload(text.encode('utf-8'), '/hello/hello_world.txt')

Uploading a large file

To upload a file larger than 150 MB. Instead, create an upload session with :meth:files_upload_session_start.

See: https://www.dropboxforum.com/t5/API-support/python-upload-big-file-example/m-p/166627#M6013

# TODO: Use with, exception handling, del
#       To ensure cleanup of resources?

dbx = dropbox.Dropbox('YOUR_ACCESS_TOKEN')
# TODO: Check for success

MEGABYTE = 1000000  # 1000 * 1000 Alternate would be 1024 * 1024
CHUNK_SIZE = 150 * MEGABYTE

# Source file path
file_path = '/home/michael/Pictures/2017/03/28/20170328_195058.jpg'
# Destinatoin TODO: Need to figure out mode and autorename parameter
commit_info = dropbox.files.CommitInfo(path="/Uploaded_from_SDK/20170328_195058.jpg")

with open(file_path, mode='rb') as file_to_upload:
    session_start_result = dbx.files_upload_session_start(b"",)
    # TODO: Check for successful result
    session_cursor = dropbox.files.UploadSessionCursor(session_id=session_start_result.session_id, offset=file_to_upload.tell())
    # TODO: Check for successful cursor creation
    while True:
        file_chunk = file_to_upload.read(CHUNK_SIZE)
        if len(file_chunk) == 0:
            break
        print("{} bytes read from file.".format(len(file_chunk)))
        dbx.files_upload_session_append_v2(file_chunk, session_cursor)
        session_cursor.offset = file_to_upload.tell()
        print("{} bytes uploaded.".format(session_cursor.offset))

dbx.files_upload_session_finish(b"", session_cursor, commit_info)

Smart Uploading of File of Any Size

import sys
import os
import datetime

import dropbox

# TODO: Use with, exception handling, del
#       To ensure cleanup of resources?


KILOBYTE = 1024
MEGABYTE = KILOBYTE * KILOBYTE
CHUNK_SIZE = 150 * MEGABYTE
# Try shorter sizes to test logic of multiple chunks on smaller files.
# CHUNK_SIZE = MEGABYTE
# CHUNK_SIZE = int(MEGABYTE / 2)


def upload_next_chunk(dbx, file_to_upload, commit_info, session_cursor):
    """ Upload the first, next and, last chunk of a file to Dropbox account

    Args:
        dbx (dropbox.Dropbox): Initialized Dropbox account
        file_to_upload (stream): Opened stream to upload, or being uploaded
        commit_info (dropbox.files.CommitInfo): Information for how file should be committed to account
        sesssion_cursor (dropbox.files.UploadSessionCursor): Session cursor
            at beginning of stream writing, intialized to UploadSessionCursor()
            first call will populate it appropriately for subsequent calls.

    Returns: True if there is more to read and upload, False otherwise
    """
    file_chunk = file_to_upload.read(CHUNK_SIZE)
    file_chunk_len = len(file_chunk)
    if not hasattr(session_cursor, 'session_id'):
        # First chunk read.  Either upload if less then CHUNK_SIZE or start session
        if file_chunk_len < CHUNK_SIZE:
            dbx.files_upload(file_chunk, commit_info.path, client_modified=commit_info.client_modified)
        else:
            # TODO: Check for success
            session_start_result = dbx.files_upload_session_start(file_chunk)
            session_cursor.session_id = session_start_result.session_id
    elif file_chunk_len < CHUNK_SIZE:
        # TODO: Check for success
        dbx.files_upload_session_finish(file_chunk, session_cursor, commit_info)
    else:
        # TODO: Check for success
        dbx.files_upload_session_append_v2(file_chunk, session_cursor)
    session_cursor.offset = file_to_upload.tell()
    return file_chunk_len == CHUNK_SIZE


def upload_file(dbx, src_base_path, dest_base_path, file_relative_path):
    src_file_path = os.path.join(src_base_path, file_relative_path)
    dest_file_path = os.path.join(dest_base_path, file_relative_path)

    if not os.path.exists(src_file_path):
        # TODO: throw exception? log? return an indicator?
        print("file '{}' does not exist!".format(src_file_path))

    file_mtimestamp = os.path.getmtime(src_file_path)
    # be sure and get time zone aware time in UTC time so that it saves with correct time
    # it is being saved who-knows-where in the world.
    file_client_modified = datetime.datetime.fromtimestamp(file_mtimestamp, datetime.timezone.utc)
    # Destinatoin TODO: Need to figure out mode and autorename parameter
    commit_info = dropbox.files.CommitInfo(path=dest_file_path, client_modified=file_client_modified)
    session_cursor = dropbox.files.UploadSessionCursor()
    with open(src_file_path, mode='rb') as file_to_upload:
        while upload_next_chunk(dbx, file_to_upload, commit_info, session_cursor):
            pass

Github project to upload files and folders