Не могли бы вы сказать мне, как я могу прочитать файл, который находится внутри моего пакета Python?
Пакет, который я загружаю, имеет ряд шаблонов (текстовые файлы, используемые как строки), которые я хочу загрузить из программы. Но как мне указать путь к такому файлу?
Представьте, что я хочу прочитать файл из:
package\templates\temp_file
Какая-то манипуляция с путями? Отслеживание базового пути пакета?
, Прежде чем можно будет даже волноваться о чтении файлов ресурсов, первый шаг должен удостовериться, что файлы данных становятся упакованными в распределение во-первых - легко считать их непосредственно из исходного дерева, но важная часть удостоверяется, что эти файлы ресурсов доступны из кода в , установил пакет.
Структурируют Ваш проект как это, помещая файлы данных в подкаталог в [1 129] пакет:
.
├── package
│ ├── __init__.py
│ ├── templates
│ │ └── temp_file
│ ├── mymodule1.py
│ └── mymodule2.py
├── README.rst
├── MANIFEST.in
└── setup.py
необходимо передать include_package_data=True
в эти setup()
вызов. Файл манифеста только необходим, если Вы хотите использовать setuptools/distutils и исходные дистрибутивы сборки. Удостоверяться эти templates/temp_file
упаковывается для этой структуры проекта в качестве примера, добавьте строку как это в файл манифеста:
recursive-include package *
Историческое примечание хлама: Используя файл манифеста не нужно для современных бэкендов сборки , таких как быстрое движение, поэзия, которая будет включать файлы данных пакета по умолчанию. Так, если Вы используете pyproject.toml
, и Вы не имеете setup.py
файл затем, можно проигнорировать весь материал приблизительно [1 112].
Теперь, с упаковкой из пути, на часть чтения...
Пользуются стандартной библиотекой pkgutil
API. Это собирается быть похожим на это в коде библиотеки:
# within package/mymodule1.py, for example
import pkgutil
data = pkgutil.get_data(__name__, "templates/temp_file")
print("data:", repr(data))
text = pkgutil.get_data(__name__, "templates/temp_file").decode()
print("text:", repr(text))
Это работает в zip. Это работает над Python 2 и Python 3. Это не требует сторонних зависимостей. Я действительно не знаю ни о каких оборотных сторонах (если Вы, затем прокомментируйте ответ).
Это в настоящее время - принятый ответ. В лучшем случае это выглядит примерно так:
from pathlib import Path
resource_path = Path(__file__).parent / "templates"
data = resource_path.joinpath("temp_file").read_bytes()
print("data", repr(data))
Что случилось с этим? Предположение, что Вы имеете в наличии файлы и подкаталоги, не корректно. Этот подход не работает при выполнении кода, который упаковывается в zip или колесе, и это может полностью находиться вне контроля пользователя, извлечен ли пакет к файловой системе вообще.
Это в настоящее время - проголосовавший вершине ответ. Это выглядит примерно так:
from pkg_resources import resource_string
data = resource_string(__name__, "templates/temp_file")
print("data", repr(data))
Что случилось с этим? Это добавляет время выполнения зависимость от [1 123] setuptools, который должен предпочтительно быть установка зависимость времени только. Импорт и использование pkg_resources
могут стать действительно медленными, поскольку код создает рабочий набор [1 133] весь установленные пакеты, даже при том, что Вы только интересовались [1 134] Ваше собственное ресурсы пакета. Это не грандиозное предприятие во время установки (так как установка выключена), но это ужасно во времени выполнения.
Это - недавнее стандартная библиотека дополнение ( новый в Python 3.7 ), но существует бэкпорт, доступный также. Это похоже на это:
try:
from importlib.resources import read_binary
from importlib.resources import read_text
except ImportError:
# Python 2.x backport
from importlib_resources import read_binary
from importlib_resources import read_text
data = read_binary("package.templates", "temp_file")
print("data", repr(data))
text = read_text("package.templates", "temp_file")
print("text", repr(text))
Что случилось с этим? Ну, к сожалению, это еще не работает.... Это - все еще неполный API, использование importlib.resources
потребует, чтобы Вы добавили пустой файл templates/__init__.py
, чтобы файлы данных находились в подпакете, а не в подкаталоге. Это также выставит package/templates
подкаталог как разрешенное к ввозу package.templates
подпакет самостоятельно. Если это не грандиозное предприятие, и оно не беспокоит Вас, то можно идти вперед и добавить __init__.py
файл там и использовать систему импорта для доступа к ресурсам. Однако, в то время как Вы в нем, можно также превратить его в my_resources.py
файл вместо этого, и просто определить некоторые байты или строковые переменные в модуле, затем импортировать их в коде Python. Это - система импорта, делающая тяжелый подъем здесь так или иначе.
я создал проект в качестве примера на [1 125] github и загрузил на [1 126] PyPI, который демонстрирует все четыре подхода, обсужденные выше. Испытайте его с:
$ pip install resources-example
$ resources-example
См. https://github.com/wimglenn/resources-example для большего количества информации