Python setuptools: распространение файлов конфигурации в определенные каталоги ОС
У меня есть своего рода курица или яйцо проблемы с Python setuptools.
Чего я пытаюсь достичь, так это распространить конфигурационный файл с моим pip-пакетом (что само по себе вполне возможно с параметром data_files
в setup.py
) в определенные ОС общие места для пользовательских конфигурационных файлов (например, ~/.config
в Linux).
Я выяснил, что "специфичность" ОС может быть решена с помощью пакета appdirs
[1] PyPi. И есть моя проблема - appdirs
не гарантируется быть установленным, когда устанавливаю свой собственный пакет, так как он является зависимостью от моего пакета и таким образом устанавливается после него (обещанная курица или яйцо :))
Мой setup.py
содержит что-то вроде этого:
from setuptools import setup
from appdirs import AppDirs
...
setup(
...
data_files=[
(AppDirs(name, author).user_config_dir, ['config/myconfig'])
],
...
)
Можно ли это решить без написания моей собственной версии setuptools (подразумевается аллюзия;))?
1 ответ:
Как я уже упоминал в своем комментарии, я бы рекомендовал распространить общую копию вашего файла с вашим пакетом, а затем скопировать его в конфигурационный каталог пользователя во время выполнения, если он не существует.
Это не должно быть очень трудно и включает в себя:
Используя
setuptools
' spackage_data
(вместоdata_files
). Это помещает файл туда, где он доступен во время выполнения с помощьюpkg_resources
, в "правильное" расположение для конкретной ОСКогда программа запускается, используйте
appdirs
для поиска пользовательский, локально установленный файл.Если он не существует, используйте
pkg_resources
, чтобы найти файл и скопировать его в папку, предоставленнуюappdirs
Хотя я этого не делал, этот процесс должен хорошо работать для нескольких ОС и сред и в качестве бонуса, во время разработки тоже из-за того, как
pkg_resources
работает.Пример
setup.py
В setup.py, вы должны обязательно включить файл данных для вашего пакета, используя
package_data
:setup( # ... data_files={ "my_package": [ "my_package.conf.dist" } # ... )
Пример кода приложения:
Я надеюсь, что это прояснит использованиеimport os.path import pkg_resources import appdirs def main(): """Your app's main function""" config = get_config() # ... # ... def get_config(): """Read configuration file and return its contents """ cfg_dir = appdirs.user_config_dir('MyApplication') cfg_file = os.path.join(cfg_dir, 'my_application.conf') if not os.path.isfile(cfg_file): create_user_config(cfg_file) with open(cfg_file) as f: data = f.read() # ... probably parse the file contents here ... return data def create_user_config(cfg_file): """Create the user's config file Note: you can replace the copying of file contents using shutil.copyfile """ source = pkg_resources.resource_stream(__name__, 'my_package.conf.dist') with open(cfg_file, 'w') as dest: dest.writelines(source)
pkg_resources
иpackage_data
.