Извлечь папку из ресурса пакета Python - PullRequest
1 голос
/ 27 сентября 2019

В моей локальной версии пакета, который я пытаюсь распространить, у меня есть следующий код:

shutil.copytree(WWW_LOCATION, dir_path)

WWW_LOCATION - это подпапка моего модуля python, содержащая некоторые статические файлы и папки:

dv
  \dv
     mytool.py
     \www_folder
       \somefolders_and_files
  setup.py
  MANIFEST.in
  README.md
  LICENSE
  setup.cfg

В моем коде после выполнения мне нужно скопировать всю эту папку в указанное пользователем место вместе с некоторыми файлами, сгенерированными на лету.Это прекрасно работает локально, но я читал, что для распространения через pypi, я должен позаботиться, поскольку файлы могут быть заархивированы.

Этот ответ объясняет, как получить доступ Вещи в ресурсах (= читать их в Python), однако, только один файл за один раз.Какой безопасный способ вместо этого скопировать содержимое папки в указанное место?

1 Ответ

1 голос
/ 27 сентября 2019

«Более простое» решение - установить zip_safe=False в настройках вашего пакета (setup.py или setup.cfg), чтобы избежать установки пакета в виде яйца с молнией.Поскольку большинство установок выполняется с помощью pip, который никогда не создает инсталляции с заархивированными яйцами, в любом случае запуск установки с заархивированными пакетами происходит в любом случае более редко.zipfile для добавления в sys.path, вариант использования которого вы можете не поддерживать.Это другая форма упакованных пакетов;яйца - это zip-файлы для одного устанавливаемого проекта (поддерживаются pkg_resources), которые хранятся в каталоге, указанном в sys.path.pkg_resources может поддерживать только второе, а не первое.

Если вы хотите поддержать яйцо с молнией, тогда для вашего конкретного случая будет проще использовать pkg_resources APIдля извлечения ресурса , поскольку, хотя он может быть «медленнее», он также поддерживает полные деревья каталогов.Из документации resource_filename():

Если указанный ресурс является каталогом, то все ресурсы в этом каталоге (включая подкаталоги) также извлекаются.

Я быиспользуйте его следующим образом:

try:
    www_location = pkg_resources.resource_filename("dv", "www_folder")
    shutil.copytree(www_location, dir_path)
finally:
    pkg_resources.cleanup_resources()

Ресурсы внутри пакетов, найденных в zip-файле, непосредственно добавленном в sys.path, недоступны через pkg_resources.Для этого вам потребуется более новый importlib.resources модуль (или backport ), но этот API не поддерживает произвольные структуры каталогов.Функциональная документация importlib.resources.path() гласит:

package - это либо имя, либо объект модуля, который соответствует требованиям Package. resource - имя ресурса, который открывается в пакете;он может не содержать разделителей пути и может не иметь подресурсов (т. е. это не может быть каталог ).

(выделено жирным шрифтом).

Хотя вы можете найти каталоги в пакете, используя importlib.resources.contents(), вы не можете получить доступ к содержимому этих каталогов, если они сами не являются пакетами Python (поэтому в них есть файл __init__.py). реализация этих функций для традиционных, не заархивированных пакетов по-прежнему даст вам доступ к каталогу при использовании importlib.resources.path(), вы не можете сделать то же самое, когда пакет содержится в архиве .zip.

importlib.resources - лучший путь поддержки в будущем.Чтобы поддержать это, вы можете заархивировать www_folder дерево ресурсов в вашем исходном и колесном дистрибутивах , а затем использовать with importlib.resources.path("dv", "www_folder.zip") as www_location: www_zip = zipfile.open(www_location) и извлечь содержимое этого объекта zipfile к месту назначения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...