Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
# 1. Go to (log in if necessary)
# 2. Select "Create App"
# 3. Configure your app:
# * Select "Dropbox API"
# * Choose whichever access level you prefer ("Full Dropbox" or "App Folder")
# * Enter the app name you wish to use for this script. It must be unique across all Dropbox apps.
# * Select the account to associate with this app.
# * Agree to the terms and conditions and click "Create app"
# 4. On the newly-created app's summary page, click the "Generate"
# button under "Generated access token"
# 5. Copy the generated token and paste it below (replace "YOUR_TOKEN_HERE").
# 6. (optional) Open the "wrench" (actions) menu in Pythonista and add
# this script, so you can run it from everywhere in Pythonista.
# Notes:
# All selected files are downloaded into the root folder of the Pythonista
# script library. If a file with the same name already exists, a numeric
# suffix is appended automatically.
import requests
import urllib.request, urllib.parse, urllib.error
import os
import ui
import collections
def list_folder(folder_path='/'):
headers = {'Authorization': 'Bearer %s' % (TOKEN,)}
r = requests.get('' % (urllib.parse.quote(folder_path.encode('utf-8')),), headers=headers)
result = r.json()
return result.get('contents', None)
def download_file(path, dest_filename, progress=None):
headers = {'Authorization': 'Bearer %s' % (TOKEN,)}
url_path = urllib.parse.quote(path.encode('utf-8'))
url = '' % (url_path,)
r = requests.get(url, stream=True, headers=headers)
dest_path = os.path.join(os.path.expanduser('~/Documents'), dest_filename)
i = 1
while os.path.exists(dest_path):
base, ext = os.path.splitext(dest_filename)
dest_path = os.path.join(os.path.expanduser('~/Documents'), base + '-' + str(i) + ext)
i += 1
size = r.headers.get('Content-Length', 0)
bytes_written = 0
canceled = False
with open(dest_path, 'wb') as f:
for chunk in r.iter_content(1024*10):
bytes_written += len(chunk)
if int(size) > 0 and isinstance(progress, collections.Callable):
p = float(bytes_written) / float(size)
should_cancel = progress(p)
if should_cancel:
canceled = True
if canceled:
class DropboxView (ui.View):
def __init__(self, path='/'):
tv = ui.TableView()
tv.frame = self.bounds
tv.flex = 'WH'
ds = ui.ListDataSource([])
ds.action = self.item_selected
tv.data_source = ds
tv.delegate = ds
self.tableview = tv
self.add_subview(self.tableview) = 'Dropbox'
label = ui.Label(frame=self.bounds)
label.flex = 'WH'
label.background_color = (1, 1, 1, 0.95)
label.text = 'Loading...'
label.touch_enabled = True
label.alignment = ui.ALIGN_CENTER
self.path = path
self.status_label = label
self.canceled = False
def will_close(self):
self.canceled = True
def item_selected(self, sender):
item = sender.items[sender.selected_row]
if item.get('is_dir', False):
self.status_label.text = 'Loading Folder...'
self.status_label.hidden = False
self.path = item['path']
elif item.get('up', False):
self.status_label.text = 'Loading Folder...'
self.status_label.hidden = False
self.path = os.path.split(self.path)[0]
path = item.get('path')
def download_file(self, path):
self.status_label.text = 'Downloading %s...' % (path,)
self.status_label.hidden = False
download_file(path, os.path.split(path)[1], self.download_progress)
self.status_label.hidden = True
def download_progress(self, p):
self.status_label.text = '%i %% Downloaded...' % (p*100,)
return self.canceled
def load_folder(self):
infos = list_folder(self.path)
items = []
if self.path != '/':
items.append({'title': '..', 'image': 'ionicons-arrow-up-c-32', 'up': True})
if not infos:
import console
console.alert('Error', 'Could not load folder. Please check if you entered the access token correctly.', 'OK', hide_cancel_button=True)
self.status_label.hidden = True
for info in infos:
path = info.get('path')
name = os.path.split(path)[1]
if name.startswith('.'):
is_dir = info.get('is_dir', False)
item = {'title': name, 'image': 'ionicons-folder-32' if is_dir else 'ionicons-ios7-download-outline-32', 'accessory_type': 'disclosure_indicator' if is_dir else 'none', 'is_dir': is_dir, 'path': info['path']}
def c(o1, o2):
u_cmp = -1 * cmp(o1.get('up', False), o2.get('up', False))
if u_cmp != 0:
return u_cmp
d_cmp = -1 * cmp(o1.get('is_dir', False), o2.get('is_dir', False))
if d_cmp == 0:
return cmp(o1.get('path', '').lower(), o2.get('path', '').lower())
return d_cmp
self.tableview.data_source.items = items
self.status_label.hidden = True = self.path
root_view = DropboxView()
root_view.frame = (0, 0, 500, 500)

This comment has been minimized.

Copy link

@Gruzzly-bear Gruzzly-bear commented May 9, 2017

Hey man, Thanks for the script. Only issue I've been getting so far is an Error that says "Could not load folder please check if you entered the access token correctly." Was I supposed to change anything else other than adding the Token from the App?


This comment has been minimized.

Copy link

@GreatCaesar GreatCaesar commented May 15, 2017

Thanks for solving the Pythonista3 external file transfer problem on my iPhone 7. DropBox turned out to be a great middle man for the job. I used iFiles 2 to migrate over to the iPhone 7. From there I had to import it to a Notes file. After that I was able to copy and paste it into a Pythonista3 script file. The script ran flawlessly. It works stellar after you get the DropBox App Token set up properly. Thanks again. Now that I can call within Pythonista3, all I need is DropBox to import Python scripts! Fantastic!


This comment has been minimized.

Copy link

@craigohh craigohh commented Nov 26, 2017

Thanks for this. I get the same "Could not load folder please check if you entered the access token correctly" error as facebawx.

I bought my .py scripts over Google Drive as text and renamed them. That worked fine.

What format does Pythonista 3 expect for text files? I moved an ANSI file from Notepad to Pythonista, but it takes about 20 sec to display in the the Pythonista editor (perhaps it's converting formats) and when I try a readline, it says "UnicodeDecodeError,
ascii codec can't decode byte 0xb7 in 15..." If I paste the first few lines of the text into a new file window, it works, but the file is too long (~1.5 MB) to paste the whole thing from a scratchpad.


This comment has been minimized.

Copy link

@loganesav loganesav commented Nov 27, 2017

Hi All,

I am new to the world of coding so this may be a dumb question.

I keep getting the attribute error: 'function' object has no attribute 'get'
Does anyone know how to fix this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.