Поиск файла в дистрибутиве модуля Python
Я написал пакет Python, который включает базу данных bsddb предварительно вычисленных значений для одного из более трудоемких вычислений. Для простоты моя установка script устанавливает файл базы данных в том же каталоге, что и код, который обращается к базе данных (в Unix, что-то вроде /usr/lib/python 2.5/site-packages/mypackage/).
Как сохранить окончательное местоположение файла базы данных, чтобы мой код мог получить к нему доступ? Прямо сейчас я использую хак, основанный на переменной __file__
в модуле, который обращается к базе данных:
dbname = os.path.join(os.path.dirname(__file__), "database.dat")
Это работает, но кажется... хакерским. Есть лучший способ сделать это? Я хотел бы, чтобы установка script просто захватила конечное место установки из модуля distutils и вложила его в файл "dbconfig.py", который устанавливается вместе с кодом, который обращается к базе данных.
Ответы
Ответ 1
Попробуйте использовать pkg_resources, который является частью setuptools (и доступен на всех питонах, к которым у меня есть доступ прямо сейчас):
>>> import pkg_resources
>>> pkg_resources.resource_filename(__name__, "foo.config")
'foo.config'
>>> pkg_resources.resource_filename('tempfile', "foo.config")
'/usr/lib/python2.4/foo.config'
Более подробное обсуждение использования pkg_resources для получения ресурсов на странице яйца и странице pkg_resources.
Также обратите внимание, что, где это возможно, рекомендуется использовать pkg_resources.resource_stream или pkg_resources.resource_string, потому что, если пакет является частью яйца, resource_filename скопирует файл во временный каталог.
Ответ 2
Используйте pkgutil.get_data
. Его двоюродный брат pkg_resources.resource_stream
, но в стандартной библиотеке, и должен работать с установками с плоской файловой системой, а также с зашифрованными пакетами и другими импортерами.
Ответ 3
Это, вероятно, способ сделать это, не прибегая к чему-то более продвинутому, например, используя setuptools для установки файлов, в которых они находятся.
Обратите внимание, что проблема с этим подходом, потому что на ОС с реальной картой безопасности (UNIX и т.д.) пользователь, на котором запущен ваш script, может не иметь прав доступа к БД в системном каталоге, где он устанавливается.
Ответ 4
Используйте стандартный модуль Python-3.7 библиотеки importlib.resources
, который более эффективен, чем setuptools:pkg_resources
(в предыдущих версиях Python использовалась библиотека importlib_resources
).
Внимание: чтобы это работало, папка, в которой находится файл данных, должна быть обычным пакетом python. Это означает, что вы должны добавить в него файл __init__.py
, если его там еще нет.
Тогда вы можете получить к нему доступ так:
try:
import importlib.resources as importlib_resources
except ImportError:
# In PY<3.7 fall-back to backported 'importlib_resources'.
import importlib_resources
## Note that the actual package could have been used,
# not just its (string) name, with something like:
# from XXX import YYY as data_pkg
data_pkg = '.'
fname = 'database.dat'
db_bytes = importlib_resources.read_binary(data_pkg, fname)
# or if a file-like stream is needed:
with importlib_resources.open_binary(data_pkg, fname) as db_file:
...