I'm working on uploading some countries' admin data to my Dropbox app. Here below is my code that does that:
# importing the required libraries
import dropbox, sys, os
import requests
# Get your app key and secret from the Dropbox developer website
app_key = 'qie********'
app_secret = 'qom**********'
dbx = dropbox.Dropbox('YYPRp-*******************_JzclLe-***************-3Js')
# verify if the account is connected
dbx.users_get_current_account()
#find all the folders present
for entry in dbx.files_list_folder('').entries:
print(entry.name)
# creating a path to where all the data to be uploaded is
root_dir = "H:/WORK/Upwork/Project 7 - Python School Data Analysis/Planning and Costing Model/Updated Script/Extracted"
print ("Attempting to upload...")
z = 1
for dir, dirs, files in os.walk(root_dir):
# the first dir is the root dir itself so we skip it
if z == 1:
z = z + 1
continue
# uploading contents of the file path
elif z > 15:
# split the path to get the country, which is the very last item after split (-1)
split_dir = dir.split('\\')
folder_name = split_dir[-1] # country name
# creating a new folder in my Dropbox for each country
country_name = dbx.files_create_folder('/Data/'+ folder_name)
dropbox_folder = country_name.path_display #obtaining the name of the folder
folder_split = dropbox_folder.split('/') # splitting the path to get root folder and created folder
folder_created = folder_split[-1] #created/country folder
dest_path = os.path.join('/Data/', folder_created) #joining the two to make a full path
print(dest_path)
# looping through the files in each of the country's folder
for file in files:
try:
# getting the path for each of the file in the folder
file_path = os.path.join(dir, file)
print(f'Uploading to {folder_name} in Dropbox')
f = open(file_path, 'rb')
connect = '/' # will be used to separate the destination path and the file
# this is where the file will be saved
d_path = os.path.join(dest_path, connect, file)
dbx.files_upload(f.read(), d_path, mode=dropbox.files.WriteMode.overwrite)
print(dest_path)
print(file_path)
print(dir)
print('\n')
except Exception as err:
print("Error!", file, err)
z = z + 1
The code runs successfully with no errors. Here is how it looks at the console:
It successfully creates the folders for each of the countries. Note that in my countries' folders, it has several files (max of 15). When I visit my dropbox app, the folders are there but nothing is inside the folders. There are completely not files, I receive the message notification that says:
This Folder is Empty
See below the images:
With folders created
One of the countries, with no files:
I have given it over an hour but nothing changes. Also note that I configured all permissions necessary for writing files and folders. Could there be something I may have done wrong? I will appreciate any assistance. Thanks!
After some help from Greg, I was able to find where the issue was. The files_upload class functions expects a working path as part of its parameters. The path provided could not be found in the App and so I added the following to make it work: d_path = dest_path+d_path
Here is the full working code:
# importing the required libraries
import dropbox, sys, os
import requests
# Get your app key and secret from the Dropbox developer website
app_key = 'qie********'
app_secret = 'qom**********'
dbx = dropbox.Dropbox('YYPRp-*******************_JzclLe-***************-3Js')
# verify if the account is connected
dbx.users_get_current_account()
#find all the folders present
for entry in dbx.files_list_folder('').entries:
print(entry.name)
# creating a path to where all the data to be uploaded is
root_dir = "H:/WORK/Upwork/Project 7 - Python School Data Analysis/Planning and Costing Model/Updated Script/Extracted"
print ("Attempting to upload...")
z = 1
for dir, dirs, files in os.walk(root_dir):
# the first dir is the root dir itself so we skip it
if z == 1:
z = z + 1
continue
# uploading contents of the file path
elif z > 15:
# split the path to get the country, which is the very last item after split (-1)
split_dir = dir.split('\\')
folder_name = split_dir[-1] # country name
# creating a new folder in my Dropbox for each country
country_name = dbx.files_create_folder('/Data/'+ folder_name)
dropbox_folder = country_name.path_display #obtaining the name of the folder
folder_split = dropbox_folder.split('/') # splitting the path to get root folder and created folder
folder_created = folder_split[-1] #created/country folder
dest_path = os.path.join('/Data/', folder_created) #joining the two to make a full path
print(dest_path)
# looping through the files in each of the country's folder
for file in files:
try:
# getting the path for each of the file in the folder
file_path = os.path.join(dir, file)
print(f'Uploading to {folder_name} in Dropbox')
f = open(file_path, 'rb')
connect = '/' # will be used to separate the destination path and the file
# this is where the file will be saved
d_path = os.path.join(dest_path, connect, file)
d_path = dest_path+d_path
dbx.files_upload(f.read(), d_path, mode=dropbox.files.WriteMode.overwrite)
print(dest_path)
print(file_path)
print(dir)
print('\n')
except Exception as err:
print("Error!", file, err)
z = z + 1
I have made a flask server REST API that does an upload to a specific folder.
The upload must comply to a specific file extension, and must be in a specific folder.
So i made these two app.configs:
app.config['UPLOAD_EXTENSIONS'] = ['.stp', '.step']
app.config['UPLOAD_PATH'] = 'uploads'
However, i want to make a new route, for a new upload of a specific file extension to another folder.
So can i have two sets of app.config['UPLOAD_EXTENSIONS'] and app.config['UPLOAD_PATH']?
One set will be for extension1 in folder1 and the other set for extension2 in folder2.
Try using the extension Flask-Uploads .
Or, proceeding from the file format, form a subdirectory in your UPLOAD_PATH.
import os
def select_directory(filename: str) -> str:
file_format = filename.split('.')[1]
your_path1 = 'path1'
your_path2 = 'path2'
if file_format in ('your format1', 'your format2'):
full_path = os.path.join(app.config['UPLOAD_FOLDER'], your_path1, filename)
else:
full_path = os.path.join(app.config['UPLOAD_FOLDER'], your_path2, filename)
return full_path
I'm trying to upload a whole folder to dropbox but only the files get uploaded. Should I create a folder programatically or can I solve the folder-uploading so simple? Thanks
import os
import dropbox
access_token = '***********************'
dbx = dropbox.Dropbox(access_token)
dropbox_destination = '/live'
local_directory = 'C:/Users/xoxo/Desktop/man'
for root, dirs, files in os.walk(local_directory):
for filename in files:
local_path = root + '/' + filename
print("local_path", local_path)
relative_path = os.path.relpath(local_path, local_directory)
dropbox_path = dropbox_destination + '/' + relative_path
# upload the file
with open(local_path, 'rb') as f:
dbx.files_upload(f.read(), dropbox_path)
error:
dropbox.exceptions.ApiError: ApiError('xxf84e5axxf86', UploadError('path', UploadWriteFailed(reason=WriteError('disallowed_name', None), upload_session_id='xxxxxxxxxxx')))
[Cross-linking for reference: https://www.dropboxforum.com/t5/API-support/UploadWriteFailed-reason-WriteError-disallowed-name-None/td-p/245765 ]
There are a few things to note here:
In your sample, you're only iterating over files, so you won't get dirs uploaded/created.
The /2/files/upload endpoint only accepts file uploads, not folders. If you want to create folders, use /2/files/create_folder_v2. You don't need to explicitly create folders for any parent folders in the path for files you upload via /2/files/upload though. Those will be automatically created with the upload.
Per the /2/files/upload documentation, disallowed_name means:
Dropbox will not save the file or folder because of its name.
So, it's likely you're getting this error because you're trying to upload an ignored filed, e.g., ".DS_STORE". You can find more information on those in this help article under "Ignored files".
I need to pass path of subdirectory of a temporary directory to another function.
Real scenario:
User will upload a zip or tar archive then it will be extracted inside a temporary directory, now I need the path of that extracted directory.
is there a way to get path of a subdirectory in case we couldn't known the name of that directory?
Here's what I'm doing in code;
views.py
if form.is_valid():
deployment = TarWithDocker()
deployment.name = form.cleaned_data['name']
deployment.user = request.user
deployment.archive = form.cleaned_data['archive']
deployment.save()
tmpdir = tempfile.mkdtemp()
saved_umask = os.umask(0o077)
path = os.path.join(tmpdir)
arpath = deployment.archive.path
patoolib.extract_archive(arpath, outdir=path)
client = docker.from_env()
dirp = os.path.join(path)
client.images.build(path=# Here i need to pass sub path of directory of temp dir #}
, gzip=False, tag='newdep')
os.umask(saved_umask)
shutil.rmtree(tmpdir)
Help me, please!
Thanks in Advance!
Given that you are running
client = docker.from_env()
client.images.build(...)
I will assume that you are expecting a Dockerfile in the archive.
So after extracting the data into tmpdir, try this:
import glob
docker_glob = os.path.join(tmpdir, "*", "Dockerfile")
docker_file = glob.glob(docker_glob)[0]
docker_folder = os.path.dirname(docker_file)
client.images.build(path=docker_folder, ...)
This will not download the contents of sub-directories; how can I do so?
import ftplib
import configparser
import os
directories = []
def add_directory(line):
if line.startswith('d'):
bits = line.split()
dirname = bits[8]
directories.append(dirname)
def makeDir(archiveTo):
for dir in directories:
newDir = os.path.join(archiveTo, dir)
if os.path.isdir(newDir) == True:
print("Directory \"" + dir + "\" already exists!")
else:
os.mkdir(newDir)
def getFiles(archiveTo, ftp):
files = ftp.nlst()
for filename in files:
try:
directories.index(filename)
except:
ftp.retrbinary('RETR %s' % filename, open(os.path.join(archiveTo, filename), 'wb').write)
def runBackups():
#Load INI
filename = 'connections.ini'
config = configparser.SafeConfigParser()
config.read(filename)
connections = config.sections()
i = 0
while i < len(connections):
#Load Settings
uri = config.get(connections[i], "uri")
username = config.get(connections[i], "username")
password = config.get(connections[i], "password")
backupPath = config.get(connections[i], "backuppath")
archiveTo = config.get(connections[i], "archiveto")
#Start Back-ups
ftp = ftplib.FTP(uri)
ftp.login(username, password)
ftp.cwd(backupPath)
#Map Directory Tree
ftp.retrlines('LIST', add_directory)
#Make Directories Locally
makeDir(archiveTo)
#Gather Files
getFiles(archiveTo, ftp)
#End connection and increase counter.
ftp.quit()
i += 1
print()
print("Back-ups complete.")
print()
this should do the trick :)
import sys
import ftplib
import os
from ftplib import FTP
ftp=FTP("ftp address")
ftp.login("user","password")
def downloadFiles(path,destination):
#path & destination are str of the form "/dir/folder/something/"
#path should be the abs path to the root FOLDER of the file tree to download
try:
ftp.cwd(path)
#clone path to destination
os.chdir(destination)
os.mkdir(destination[0:len(destination)-1]+path)
print destination[0:len(destination)-1]+path+" built"
except OSError:
#folder already exists at destination
pass
except ftplib.error_perm:
#invalid entry (ensure input form: "/dir/folder/something/")
print "error: could not change to "+path
sys.exit("ending session")
#list children:
filelist=ftp.nlst()
for file in filelist:
try:
#this will check if file is folder:
ftp.cwd(path+file+"/")
#if so, explore it:
downloadFiles(path+file+"/",destination)
except ftplib.error_perm:
#not a folder with accessible content
#download & return
os.chdir(destination[0:len(destination)-1]+path)
#possibly need a permission exception catch:
with open(os.path.join(destination,file),"wb") as f:
ftp.retrbinary("RETR "+file, f.write)
print file + " downloaded"
return
source="/ftproot/folder_i_want/"
dest="/systemroot/where_i_want_it/"
downloadFiles(source,dest)
This is a very old question, but I had a similar need that i wanted to satisfy in a very general manner. I ended up writing my own solution that works very well for me. I've placed it on Gist here https://gist.github.com/Jwely/ad8eb800bacef9e34dd775f9b3aad987
and pasted it below in case i ever take the gist offline.
Example usage:
import ftplib
ftp = ftplib.FTP(mysite, username, password)
download_ftp_tree(ftp, remote_dir, local_dir)
The code above will look for a directory called "remote_dir" on the ftp host, and then duplicate the directory and its entire contents into the "local_dir".
It invokes the script below.
import ftplib
import os
def _is_ftp_dir(ftp_handle, name, guess_by_extension=True):
""" simply determines if an item listed on the ftp server is a valid directory or not """
# if the name has a "." in the fourth to last position, its probably a file extension
# this is MUCH faster than trying to set every file to a working directory, and will work 99% of time.
if guess_by_extension is True:
if name[-4] == '.':
return False
original_cwd = ftp_handle.pwd() # remember the current working directory
try:
ftp_handle.cwd(name) # try to set directory to new name
ftp_handle.cwd(original_cwd) # set it back to what it was
return True
except:
return False
def _make_parent_dir(fpath):
""" ensures the parent directory of a filepath exists """
dirname = os.path.dirname(fpath)
while not os.path.exists(dirname):
try:
os.mkdir(dirname)
print("created {0}".format(dirname))
except:
_make_parent_dir(dirname)
def _download_ftp_file(ftp_handle, name, dest, overwrite):
""" downloads a single file from an ftp server """
_make_parent_dir(dest)
if not os.path.exists(dest) or overwrite is True:
with open(dest, 'wb') as f:
ftp_handle.retrbinary("RETR {0}".format(name), f.write)
print("downloaded: {0}".format(dest))
else:
print("already exists: {0}".format(dest))
def _mirror_ftp_dir(ftp_handle, name, overwrite, guess_by_extension):
""" replicates a directory on an ftp server recursively """
for item in ftp_handle.nlst(name):
if _is_ftp_dir(ftp_handle, item):
_mirror_ftp_dir(ftp_handle, item, overwrite, guess_by_extension)
else:
_download_ftp_file(ftp_handle, item, item, overwrite)
def download_ftp_tree(ftp_handle, path, destination, overwrite=False, guess_by_extension=True):
"""
Downloads an entire directory tree from an ftp server to the local destination
:param ftp_handle: an authenticated ftplib.FTP instance
:param path: the folder on the ftp server to download
:param destination: the local directory to store the copied folder
:param overwrite: set to True to force re-download of all files, even if they appear to exist already
:param guess_by_extension: It takes a while to explicitly check if every item is a directory or a file.
if this flag is set to True, it will assume any file ending with a three character extension ".???" is
a file and not a directory. Set to False if some folders may have a "." in their names -4th position.
"""
os.chdir(destination)
_mirror_ftp_dir(ftp_handle, path, overwrite, guess_by_extension)
this is an alternative. you can try using ftputil package. You can then use it to walk the remote directories and get your files
Using ftp.mlsd() instead of ftp.nlst():
import sys
import ftplib
import os
from ftplib import FTP
def fetchFiles(ftp, path, destination, overwrite=True):
'''Fetch a whole folder from ftp. \n
Parameters
----------
ftp : ftplib.FTP object
path : string ('/dir/folder/')
destination : string ('D:/dir/folder/') folder where the files will be saved
overwrite : bool - Overwrite file if already exists.
'''
try:
ftp.cwd(path)
os.mkdir(destination[:-1] + path)
print('New folder made: ' + destination[:-1] + path)
except OSError:
# folder already exists at the destination
pass
except ftplib.error_perm:
# invalid entry (ensure input form: "/dir/folder/")
print("error: could not change to " + path)
sys.exit("ending session")
# list children:
filelist = [i for i in ftp.mlsd()]
print('Current folder: ' + filelist.pop(0)[0])
for file in filelist:
if file[1]['type'] == 'file':
fullpath = os.path.join(destination[:-1] + path, file[0])
if (not overwrite and os.path.isfile(fullpath)):
continue
else:
with open(fullpath, 'wb') as f:
ftp.retrbinary('RETR ' + file[0], f.write)
print(file[0] + ' downloaded')
elif file[1]['type'] == 'dir':
fetchFiles(ftp, path + file[0] + '/', destination, overwrite)
else:
print('Unknown type: ' + file[1]['type'])
if __name__ == "__main__":
ftp = FTP('ftp address')
ftp.login('user', 'password')
source = r'/Folder/'
dest = r'D:/Data/'
fetchFiles(ftp, source, dest, overwrite=True)
ftp.quit()
Using ftputil, a fast solution could be:
def download(folder):
for item in ftp.walk(folder):
print("Creating dir " + item[0])
os.mkdir(item[0])
for subdir in item[1]:
print("Subdirs " + subdir)
for file in item[2]:
print(r"Copying File {0} \ {1}".format(item[0], file))
ftp.download(ftp.path.join(item[0],file), os.path.join(item[0],file))
It is non-trivial at least. In the simplest case, you only assume you have files and directories. This isn't always the case, there are softlinks and hardlinks and Windows-style shortcut. Softlink and directory shortcut are particularly problematic since they make recursive directory possible, which would confuse naive-ly implemented ftp grabber.
How would you handle such recursive directory depends on your need; you might simply not follow softlinks or you might try to detect recursive links. Detecting recursive link is inherently tricky, you cannot do it reliably.