Skip to content

Instantly share code, notes, and snippets.

@dreikanter
Created May 25, 2013 22:23
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dreikanter/5650973 to your computer and use it in GitHub Desktop.
Save dreikanter/5650973 to your computer and use it in GitHub Desktop.
A missing python function to copy directory tree and overwrite existing files.
import os
import random
import shutil
def copydir(source, dest, indent = 0):
"""Copy a directory structure overwriting existing files"""
for root, dirs, files in os.walk(source):
if not os.path.isdir(root):
os.makedirs(root)
for each_file in files:
rel_path = root.replace(source, '').lstrip(os.sep)
dest_path = os.path.join(dest, rel_path, each_file)
shutil.copyfile(os.path.join(root, each_file), dest_path)
# Tests
src_path = 'test-source'
dest_path = 'test-dest'
source_files = [
'1.txt',
'2.txt',
'3.txt',
'subdir/4.txt',
'subdir/5.txt',
'subdir/subsubdir/6.txt',
'subdir/subsubdir/7.txt',
]
dest_files = [
'1.txt',
'4.txt',
'5.txt',
'subdir/4.txt',
'subdir/6.txt',
'subdir/subsubdir/6.txt',
'subdir/subsubdir/9.txt',
]
result_files = [
'1.txt',
'2.txt',
'3.txt',
'4.txt',
'5.txt',
'subdir/4.txt',
'subdir/5.txt',
'subdir/6.txt',
'subdir/subsubdir/6.txt',
'subdir/subsubdir/7.txt',
'subdir/subsubdir/9.txt',
]
def test():
"""Use nosetests (http://nose.readthedocs.org/en/latest/usage.html)"""
_create_samples(src_path, dest_path)
copydir(src_path, dest_path)
result = []
for root, dirs, files in os.walk(dest_path):
for each_file in files:
each_file = os.path.join(root, each_file).replace(dest_path, '')
each_file = each_file.lstrip(os.sep).replace(os.sep, '/')
result.append(each_file)
assert set(result) == set(result_files)
shutil.rmtree(src_path)
shutil.rmtree(dest_path)
def _create_samples(src_path, dest_path):
_create_files(src_path, source_files)
_create_files(dest_path, dest_files)
def _create_files(root_path, files):
for each in files:
each = os.path.join(root_path, each)
dirpath = os.path.dirname(each)
if not os.path.isdir(dirpath):
os.makedirs(dirpath)
open(each, 'w').write(_random_contents())
def _random_contents(length = 100):
return ' '.join([str(random.randint(0, 100)) for i in range(0, length)])
@dreikanter
Copy link
Author

Use nosetests copydir.py for testing.

@bhdrk
Copy link

bhdrk commented Feb 3, 2017

This function copies files only. Does not include folders. I also added folders here.

def copydir(source, dest):
    """Copy a directory structure overwriting existing files"""
    for root, dirs, files in os.walk(source):
        if not os.path.isdir(root):
            os.makedirs(root)

        for file in files:
            rel_path = root.replace(source, '').lstrip(os.sep)
            dest_path = os.path.join(dest, rel_path)

            if not os.path.isdir(dest_path):
                os.makedirs(dest_path)

            shutil.copyfile(os.path.join(root, file), os.path.join(dest_path, file))

@ArtemSBulgakov
Copy link

From Python 3.8 you can just use

import shutil
shutil.copytree("src", "dst", dirs_exist_ok=True)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment