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]: https://pypi.python.org/pypi/appdirs

1 2

1 ответ:

Как я уже упоминал в своем комментарии, я бы рекомендовал распространить общую копию вашего файла с вашим пакетом, а затем скопировать его в конфигурационный каталог пользователя во время выполнения, если он не существует.

Это не должно быть очень трудно и включает в себя:

  1. Используя setuptools ' s package_data (вместо data_files). Это помещает файл туда, где он доступен во время выполнения с помощью pkg_resources, в "правильное" расположение для конкретной ОС

  2. Когда программа запускается, используйте appdirs для поиска пользовательский, локально установленный файл.

  3. Если он не существует, используйте 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.