Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filter directory when using shutil.copytree?

Is there a way I can filter a directory by using the absolute path to it?

shutil.copytree(directory,
                target_dir,
                ignore = shutil.ignore_patterns("/Full/Path/To/aDir/Common")) 

This doesn't seem to work when trying to filter the "Common" Directory located under "aDir". If I do this:

shutil.copytree(directory,
                target_dir,
                ignore = shutil.ignore_patterns("Common"))

It works, but every directory called Common will be filtered in that "tree", which is not what I want.

Any suggestions ?

Thanks.

like image 732
Goles Avatar asked Oct 20 '11 20:10

Goles


People also ask

How does Shutil Copytree work?

shutil. copytree() method recursively copies an entire directory tree rooted at source (src) to the destination directory. The destination directory, named by (dst) must not already exist. It will be created during copying.

What is the difference between Shutil copy () and Shutil Copytree ()?

While shutil. copy() will copy a single file, shutil. copytree() will copy an entire folder and every folder and file contained in it.

How do I copy a folder using Shutil?

shutil. copytree() method recursively copies an entire directory tree rooted at source (src) to the destination directory. The destination directory, named by (dst) must not already exist. It will be created during copying.


2 Answers

You can make your own ignore function:

shutil.copytree('/Full/Path', 'target',
              ignore=lambda directory, contents: ['Common'] if directory == '/Full/Path/To/aDir' else [])

Or, if you want to be able to call copytree with a relative path:

import os.path
def ignorePath(path):
  def ignoref(directory, contents):
    return (f for f in contents if os.abspath(os.path.join(directory, f)) == path)
  return ignoref

shutil.copytree('Path', 'target', ignore=ignorePath('/Full/Path/To/aDir/Common'))

From the docs:

If ignore is given, it must be a callable that will receive as its arguments the directory being visited by copytree(), and a list of its contents, as returned by os.listdir(). Since copytree() is called recursively, the ignore callable will be called once for each directory that is copied. The callable must return a sequence of directory and file names relative to the current directory (i.e. a subset of the items in its second argument); these names will then be ignored in the copy process. ignore_patterns() can be used to create such a callable that ignores names based on glob-style patterns.

like image 125
phihag Avatar answered Sep 19 '22 15:09

phihag


The API for shutil.ignore_patterns() doesn't support absolute paths, but it is trivially easy to roll your own variant.

As a starting point, look at the source code for *ignore_patterns*:

def ignore_patterns(*patterns):
    """Function that can be used as copytree() ignore parameter.

    Patterns is a sequence of glob-style patterns
    that are used to exclude files"""
    def _ignore_patterns(path, names):
        ignored_names = []
        for pattern in patterns:
            ignored_names.extend(fnmatch.filter(names, pattern))
        return set(ignored_names)
    return _ignore_patterns

You can see that it returns a function that accepts a path and list of names, and it returns a set of names to ignore. To support your use case, create you own similar function that uses takes advantage of path argument. Pass your function to the ignore parameter in the call to copytree().

Alternatively, don't use shutil as-is. The source code is short and sweet, so it isn't hard to cut, paste, and customize.

like image 28
Raymond Hettinger Avatar answered Sep 18 '22 15:09

Raymond Hettinger