开发者

python copytree with negated ignore pattern

开发者 https://www.devze.com 2022-12-30 06:05 出处:网络
I\'m trying to use python to copy a tree of files/directories. is it possible to use copytree to copy everything that ends in foo?

I'm trying to use python to copy a tree of files/directories.

is it possible to use copytree to copy everything that ends in foo?

There is an ignore_patterns patterns function, can I give it a negated regular expression? Are they supported in python?

eg.

copytree(src, dest, False, ignore_patt开发者_StackOverflowern('!*.foo')) Where ! means NOT anything that ends in foo. thanks.


shutil.copytree has an ignore keyword. ignore can be set to any callable. Given the directory being visited and a list of its contents, the callable should return a sequence of directory and filenames to be ignored.

For example:

import shutil
def ignored_files(adir,filenames):
    return [filename for filename in filenames if not filename.endswith('foo')]

shutil.copytree(source, destination, ignore=ignored_files)


Building on unutbu's answer. The following takes a list of all files, then removes the ones matched by "ignore_patterns", then returns that as a list of files to be ignored. That is, it does a double negation to only copy the files you want.

import glob, os, shutil

def copyonly(dirpath, contents):
    return set(contents) - set(
        shutil.ignore_patterns('*.py', '*.el')(dirpath, contents),
        )

shutil.copytree(
    src='.',
    dst='temp/',
    ignore=copyonly,
    )
print glob.glob('temp/*')


def documentation(format):
    call(['make', format, '-C', DOC_SOURCE_DIR])

    if (os.path.exists(DOC_DIR)):
        shutil.rmtree(DOC_DIR)

    ignored = ['doctrees']
    shutil.copytree('{0}/build/'.format(DOC_SOURCE_DIR), DOC_DIR, ignore=shutil.ignore_patterns(*ignored))


Building on top of @unutbu and @johntellsall, this solution also works recursively.

def inverse_ignore_patterns(*patterns: str):
    def _inverse_ignore_patterns(path, names):
        ignored_names = set(names)
        for pattern in patterns:
            ignored_names -= set(fnmatch.filter(names, pattern))

        # Keep folders
        ignored_names -= {
            name for name in ignored_names
            if os.path.isdir(os.path.join(path, name))
        }
        return ignored_names

    return _inverse_ignore_patterns

One downside is that will create empty directories if they don't contain any matching files. You can easily fix that with:

def rm_empty_folders(rootdir: str):
    for dirpath, dirnames, filenames in os.walk(rootdir, topdown=False):
        if not os.listdir(dirpath):
            os.rmdir(dirpath)

Use as:

copytree(src, dest, False, inverse_ignore_patterns("*.foo"))
rm_empty_folders(dest)
0

精彩评论

暂无评论...
验证码 换一张
取 消