традиционный pkg_resources
из setuptools
больше не рекомендуется из-за соображений производительности .
Сначала я сохранил традиционное перечисленное, чтобы объяснить различия с новым методом при переносе существующего кода (портирование также объяснено здесь ).
Предположим, что ваши шаблоны находятся в папке, вложенной в пакет вашего модуля:
<your-package>
+--<module-asking-the-file>
+--templates/
+--temp_file <-- We want this file.
Примечание 1: Конечно, мы НЕ должны возиться с атрибутом __file__
(например, код будет поврежден при подаче из почтового индекса).
Примечание 2: Если высобирая этот пакет, не забудьте объявить ваши файлы данных как package_data
или data_files
в вашем setup.py
.
1) Используя pkg_resources
из setuptools
(медленно)
Вы можете использовать пакет pkg_resources
из setuptools дистрибутива, но , который идет со стоимостью, производительность :
import pkg_resources
# Could be any dot-separated package/module name or a "Requirement"
resource_package = __name__
resource_path = '/'.join(('templates', 'temp_file')) # Do not use os.path.join()
template = pkg_resources.resource_string(resource_package, resource_path)
# or for a file-like stream:
template = pkg_resources.resource_stream(resource_package, resource_path)
Советы:
Это будет считывать данные, даже есливаш дистрибутив заархивирован, так что вы можете установить zip_safe=True
в вашем setup.py
и / или использовать долгожданный zipapp
упаковщик из python-3.5 для создания собственногодистрибутивы.
Не забудьте добавить setuptools
в ваши требования времени выполнения (например, в install_requires`).
... и обратите внимание, что в соответствии с документацией Setuptools / pkg_resources
вы не должны использовать os.path.join
:
Обратите внимание, что ресурсимена должны быть /
-разделенными путями и не могут быть абсолютными (то есть без начального /
) или содержать относительные имена, такие как "..
". не используйте os.path
подпрограммы для манипулирования путями ресурсов, поскольку они являются не путями файловой системы.
2) Python> = 3.7, или используйтеbackported importlib_resources
библиотека
Используйте модуль importlib.resources
стандартной библиотеки , который более эффективен, чем setuptools
, выше:
try:
import importlib.resources as pkg_resources
except ImportError:
# Try backported to PY<37 `importlib_resources`.
import importlib_resources as pkg_resources
from . import templates # relative-import the *package* containing the templates
template = pkg_resources.read_text(templates, 'temp_file')
# or for a file-like stream:
template = pkg_resources.open_text(templates, 'temp_file')
Внимание:
Относительно функции read_text(package, resource)
:
-
package
может быть либо строкой, либо модулем. -
resource
больше не является путем, а просто именем файла ресурса, который нужно открыть в существующем пакете;он может не содержать разделителей пути и не может иметь подресурсов (то есть он не может быть каталогом).
Для примера, заданного в вопросе, мы должны теперь:
- превратить
<your_package>/templates/
в правильный пакет, создав в нем пустой файл __init__.py
, - , поэтому теперь мы можем использовать простое (возможно относительное) выражение
import
(нетбольше парсинга имен пакетов / модулей), - и просто запросите
resource_name = "temp_file"
(без пути).
Советы:
- Все становится интересным, когда запрашивается фактическое имя файла с
path()
, так как теперь контекстные менеджеры используются для временно созданных файлов (читай this ). - Добавьте резервную библиотеку, условно для старых Pythons, с
install_requires=[" importlib_resources ; python_version<'3.7'"]
(отметьте this , если вы упаковываете свой проект с setuptools<36.2.1
). - Не забудьте удалить
setuptools
библиотека из ваших требований времени выполнения , если вы перешли с традиционного метода. - Вы также можете установить
zip_safe=True
в вашем setup.py
.