Blender.UnpackAll(Blender.UnpackModes.USE_ORIGINAL)
Функция GetPaths() из модуля Blender выдаёт список всех файлов, используемых .blend-файлом (за исключением самого этого .blend-файла). Мы передаем ей аргумент absolute установленным в Истину, чтобы извлекать имена файлов с полным путём вместо относительных путей от текущего каталога для того, чтобы сравнить их должным образом со списком, произведённым функцией listfiles().
Снова мы также нормализуем эти имена файлов. Выделенная строка показывает, как мы извлекаем абсолютный путь текущего каталога, передавая условное обозначение для текущего каталога Блендера ( // ) в функцию expandpath():
files = [os.path.normpath(f) for f in
Blender.GetPaths(absolute=True)]
currentdir = Blender.sys.expandpath('//')
Затем мы создаём объект ZipFile в режиме write (записи). Это отбросит любой существующий архив с тем же именем, и позволит нам добавлять файлы в архив. Полное имя архива строится соединением текущего каталога Блендера и имени, которое мы хотим использовать для архива. Использование функции join() из модуля os.path обеспечивает нам создание полного имени платформо-независимым образом. Мы установили аргумент debug (отладка) объекта ZipFile в значение 3, чтобы сообщать о чём-либо необычном на консоль при создании архива:
zip = ZipFile(os.path.join(currentdir,zipname),'w')
zip.debug = 3
В переменную removefiles (удаление файлов) записываются имена файлов, которые мы хотим удалить после того, как мы создали архив. Мы можем безопасно удалить файлы и каталоги только после того, как мы создали архив, иначе может оказаться, что мы ссылаемся на каталоги, которые больше не существуют.
Архив создаётся проходом цикла по списку всех файлов в текущем каталоге Блендера и сравниванием их со списком файлов, использованных нашим .blend-файлом. Любой файл с таким расширением, как например, .blend или .blend1 пропускается (выделено), как и сам архив. Файлы добавляются к ZIP-файлу использованием метода write(), который принимает в качестве параметра имя файла с путём относительно архива (и, следовательно, текущего каталога). Этот путь удобнее для распаковки архива в новом месте. Любые ссылки на файлы за пределами текущего дерева каталогов не затрагиваются функцией relpath(). Любой файл, который мы добавляем к архиву, помечается для удаления добавлением его к списку removefiles. Наконец, мы закрываем архив - важный шаг, поскольку, если его опустить, мы можем остаться с запорченным архивом:
removefiles = []
for f in listfiles(currentdir):
if not (f in files
or os.path.splitext(f)[1].startswith('.blend')
or os.path.basename(f) == zipname):
rf = os.path.relpath(f,currentdir)
zip.write(rf)
removefiles.append(f)
zip.close()
Последней задачей будет удаление файлов, которые мы переместили в архив. Функция remove() из модуля Питона os выполнит это, но мы также хотим удалить любой каталог, который остался пустым после удаления файлов. Следовательно, для каждого файла, который мы удаляем, нам надо определить имя его каталога. Мы также удостоверяемся, этот каталог не указывает на текущий каталог, потому что мы хотим быть абсолютно уверены, что мы не удаляем его, так как это место, где находятся наши .blend-файлы. Хотя это маловероятный сценарий, что можно открыть .blend-файл в Блендере и удалить сам этот .blend файл, что могло бы оставить каталог пустым. Если мы удалим этот каталог, любое последующее (авто) сохранение должно потерпеть неудачу. Функция relpath() возвращает точку, если каталог, переданный как первый аргумент, указывает на тот же каталог, что и каталог, переданный как второй аргумент. (Функция samefile() является более надежной и прямой, но не доступна в Windows.)
Если мы убедились, что мы не ссылаемся на текущий каталог, мы используем функцию removedirs(), чтобы удалить каталог. Если каталог не пуст, произойдёт ошибка с исключением OSError (то есть, файл, который мы удалили, был не последним файлом в каталоге), которую мы игнорируем. Функция removedirs() также удалит все родительские каталоги, ведущие к каталогу только тогда, когда они пустые, и это как раз то, что нам нужно:
for f in removefiles:
remove(f)
d = os.path.dirname(f)
if os.path.relpath(d,currentdir) != '.':
try:
removedirs(d)
except OSError:
pass
if __name__ == '__main__':