Фильтровать каталог при использовании shutil.copytree?

Есть ли способ, которым я могу отфильтровать каталог, используя абсолютный путь к нему?

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

Это не работает при попытке отфильтровать "общий" каталог, расположенный подaDir". Если я сделаю это:

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

Это работает, но каждый каталог с именем Common будет отфильтрован в этом "дереве", а это не то, что мне нужно.

Какие-либо предложения?

Благодарю.

5 ответов

Решение

Вы можете сделать свою собственную функцию игнорирования:

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

Или, если вы хотите иметь возможность позвонить copytree с относительным путем:

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'))

Из документов:

Если задано игнорирование, это должен быть вызываемый объект, который будет получать в качестве аргументов каталог, который посещает copytree(), и список его содержимого, возвращаемый функцией os.listdir(). Поскольку copytree () вызывается рекурсивно, вызываемое игнорирование будет вызываться один раз для каждого копируемого каталога. Вызываемый объект должен возвращать последовательность имен каталогов и файлов относительно текущего каталога (т. Е. Подмножество элементов во втором аргументе); эти имена будут игнорироваться в процессе копирования. ignore_patterns() может использоваться для создания такого вызываемого объекта, который игнорирует имена на основе шаблонов в стиле glob.

API для shutil.ignore_patterns() не поддерживает абсолютные пути, но ваш собственный вариант тривиально прост.

Для начала посмотрите на исходный код *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

Вы можете видеть, что он возвращает функцию, которая принимает путь и список имен, и возвращает набор имен, которые следует игнорировать. Чтобы поддержать ваш вариант использования, создайте собственную подобную функцию, которая использует аргумент пути. Передайте вашу функцию параметру ignore в вызове copytree ().

В качестве альтернативы, не используйте shutil как есть. Исходный код короткий и приятный, поэтому его нетрудно вырезать, вставить и настроить.

Вы захотите создать свою собственную функцию игнорирования, которая проверяет текущий обрабатываемый каталог и возвращает список, содержащий "Common", только если dir равен "/Full/Path/To/aDir".

def ignore_full_path_common(dir, files):
    if dir == '/Full/Path/To/aDir':
        return ['Common']
    return []

shutil.copytree(directory, target_dir, ignore=ignore_full_path_common)

Большое спасибо за ответ. Это помогло мне разработать мою собственную функцию для немного других требований. Вставка кода здесь может кому-то помочь.

Ниже ignore_patterns() функция для исключения нескольких файлов / каталогов по абсолютному пути к ним.

myExclusionList-> Список файлов / каталогов, которые следует исключить при копировании. Этот список может содержать подстановочный знак. Пути в списке указаны относительно srcpathпри условии. Например:

[СПИСОК ИСКЛЮЧЕНИЯ]

      java/app/src/main/webapp/WEB-INF/lib/test
unittests
python-buildreqs/apps/abc.tar.gz
3rd-party/jdk*

Код вставлен ниже

      def copydir(srcpath, dstpath, myExclusionList, log):

    patternlist = []
    try:
        # Forming the absolute path of files/directories to be excluded
        for pattern in myExclusionList:
            tmpsrcpath = join(srcpath, pattern)
            patternlist.extend(glob.glob(tmpsrcpath)) # myExclusionList can contain wildcard pattern hence glob is used
        copytree(srcpath, dstpath, ignore=ignore_patterns_override(*patternlist))
    except (IOError, os.error) as why:
        log.warning("Unable to copy %s to %s because %s", srcpath, dstpath, str(why))
        # catch the Error from the recursive copytree so that we can
        # continue with other files
    except Error as err:
        log.warning("Unable to copy %s to %s because %s", srcpath, dstpath, str(err))


# [START: Ignore Patterns]
# Modified Function to ignore patterns while copying.
# Default Python Implementation does not exclude absolute path
# given for files/directories

def ignore_patterns_override(*patterns):
    """Function that can be used as copytree() ignore parameter.
    Patterns is a sequence of glob-style patterns
    that are used to exclude files/directories"""
    def _ignore_patterns(path, names):
        ignored_names = []
        for f in names:
            for pattern in patterns:
                if os.path.abspath(join(path, f)) == pattern:
                    ignored_names.append(f)
        return set(ignored_names)
    return _ignore_patterns

# [END: Ignore Patterns]

Независимая платформа. Шаблоны глобусов путей [".gitkeep","app/build","*.txt"]

          def callbackIgnore(paths):
        """ callback for shutil.copytree """
        def ignoref(directory, contents):
            arr = [] 
            for f in contents:
                for p in paths:
                    if (pathlib.PurePath(directory, f).match(p)):
                        arr.append(f)
            return arr
    
        return ignoref
Другие вопросы по тегам